RLV12 V2.0 Hardware Description


Schematic

I use the following naming convention of digital, signals start with B for Bus. For other signals R stands for Receive and T for Transmit and have an optional L at the end of the name if they are active low. The Q-Bus is an inverted, active low, bus and therefore no L is added to the signal names.

Except for some SMD packages that can be easily soldered by hand, all components are through-hole components.

The first pages shows the section with the signals I receive from the Q-Bus. I’m using 74HC4049 and operate them with 3.3V. At this voltage the 74HC4049 have a threshold of approximatively 1.7V, which is the standard for Q-Bus receivers. They also accept input voltages above the operating voltage and even are protected against input voltages when no power is applied. In addition they have a low input capacitance and a very low input leakage current, as required by Q-Bus receivers.

Schematic

The next page shows the lower 16 bits of the multiplexed address/data bus. The Q-Bus is bidirectional but as I only use receivers and transmitters and no transceivers, like the DC005, I end with 16 bits receive and 16 bits transmit data signals.

Schematic

The third section shows the Q-Bus signals I need to transmit. So for each Q-Bus signal I have to be able to transmit and receive I end up with two signals I have to interface with.

Schematic

This is the reason I need a lot more PINs on the CPLD. Therefore I added a second CPLD and divided the functions among the two CPLDs. At the same time I tried to avoid that a Q-Bus signal, receive or transmit, is being required by both CPLDs. The only exceptions are RSYNC and RWTBT. Also only three signals run between the CPLDs themselves.

Schematic

Although ALER connects to both CPLDs it is only used on the second CPLD. The reason it is connected to the first CPLD in the schematic is because the updated version of the RLV12 emulator uses exactly the same PCB as the first RLV12 Emulator V2.0.

The rest of the schematic is very simple, there is the MCU and the IDC-34 connector for the ribbon cable that runs to the break-out board

Schematic

and of course the Q-Bus interface.

Schematic

Function Blocks

The RLV12 Emulator consist of the following main functions

  • Device register interface, whenever the PDP-11 reads or writes a device register the MCU is informed and processes the data.
  • DMA State Machine
  • Interrupt Logic for Interrupt Acknowledge Cycles
  • Optional boot ROM

CPLD Functions

The GLUE logic has now been split into two CPLDs. The main CPLD still implements most of the control functions and all data/address transmit lines.

The second CPLD covers the receive data/address signals. It decodes the address and receives the bus data.

There are only very few signals required between the two CPLD. There are two select signals, one for the device register addresses CSRADDR and one for the boot ROM addresses ROMADDR. And there is one signal LD used to load the data received from the Q-Bus during a DMA read.

Main CPLD

The main CPLD is an ATF1508. It deals with all bus cycles and is responsible for the DMA address and the data transmit functions. It has the following building blocks

For documentation purposes I have split the CPLD design file into several pieces and give an explanation to every section.

Header and Pin Definitions

The first section just defines the header of the design file and all IO pins. Normally I add as well a description to each PIN definition, but in this case the names are quite obvious with the exception of the MCU interface which is however described in a separate chapter.

Name     QBUS RLV12 Version 2 ;
PartNo   A ;
Date     15.04.2022 ;
Revision 02 ;
Designer cbscpe ;
Company  PRIVAT ;
Assembly None ;
Location ATHOME ;
Device   f1508ispplcc84 ;

PIN			16	=  TDAL15;
PIN			15	=  TDAL14;
PIN			24	=  TDAL13;
PIN			22	=  TDAL12;
PIN			18	=  TDAL11;
PIN			20	=  TDAL10;
PIN			12	=  TDAL9;
PIN			17	=  TDAL8;
PIN			21	=  TDAL7;
PIN			25	=  TDAL6;
PIN			27	=  TDAL5;
PIN			28	=  TDAL4;
PIN			34	=  TDAL3;
PIN			35	=  TDAL2;
PIN			36	=  TDAL1;
PIN			37	=  TDAL0;
PIN			58	=  TDAL16;
PIN			60	=  TDAL17;
PIN			29	=  TDAL18;
PIN			30	=  TDAL19;
PIN			31	=  TDAL20;
PIN			33	=  TDAL21;
PIN			61	=  RRPLY;
PIN			57	=  RDIN;
PIN			55	=  RDOUT;
PIN			56	=  RWTBT;
PIN			54	=  RSYNC;
PIN			1	=  RINIT;
PIN			52	=  TRPLY;
PIN			46	=  TDIN;
PIN			48	=  TDOUT;
PIN			50	=  TWTBT;
PIN			51	=  TSYNC;
PIN			49	=  RIAKI;
PIN			41	=  TIAKO;
PIN			44	=  TDMR;
PIN			45	=  RDMGI;
PIN			39	=  TDMGO;
PIN			40	=  TSACK;
PIN			81	=  WR;		
PIN			83	=  CLK;
PIN                     2       =  ALEW;
PIN			74	=  AD0;
PIN			73	=  AD1;
PIN			75	=  AD2;
PIN			68	=  AD3;
PIN			69	=  AD4;
PIN			76	=  AD5;
PIN			70	=  AD6;
PIN			67	=  AD7;
PIN			8	=  IRQST;
PIN			79	=  DMR;
PIN			5	=  DMG;
PIN			4	=  INTQ;	
PIN			6	=  INTI;	
PIN			77	=  CRDY;	
PIN			64	=  IACK;
PIN			63	=  ABORT;
PIN			9	=  ROMADDR;
PIN			10	=  CSRADDR;
PIN			11	=  LD;		
Description

I usually put a lot of description into the CPLD design files in order to be able to understand what I did in a later stage or just to keep track about changes.

/*
	CPLD A implements the following functions
	
	-	MCU Interface for CSR Access
	-	DMA Write Data Register
	-	Q-Bus Data Register
	-	DMA Address Register
	-	DMA State Machine
	
	CPLD B implements the following functions
	-	Device Select
	-	Device Register Address and Byte Select 
	-	Direct Q-Bus Read for DATO/DATOB cycles
	-	DMA Read Data Register

	2022-04-15
	
	New CPLD Interface for MCU. To access any register in CPLD A or B
	you need first to load the register address. The register address
	register is part of a state machine. Depending on the address
	loaded each register write will advance the state. This is made
	because CPLD registers are typically written as 16-bit registers
	or as DMA address with 22-bits. Therefore only the first register
	address must be loaded. You still can access individual registers.
	To set the write register address you use ALEW to set the read
	register address you use ALER. Note this CPLD only implements
	the writeable registers.
	
	0->1->0->1	Write Q-Bus Data Register
	2->3->2->3	Write DMA Data Register
	4->5->6->4	Write DMA Address and direction register
	7->0		Just to avoid undefined states

	CPLD A creates the MCU interrupts and controls the following bus cycles
	-	DATI/DATO to device registers
	-	Interrupt Acknowledge
	-	DMA
	
	CPLD A implements the DMA interface to read or write one 16-bit
	word from or to the host memory.	

	2022-04-26
	
	Boot ROM option using unused CPLD interconnection to signal a ROM
	address range
	Add a Boot ROM Enable flag using Register 7 to allow enabling or
	disabling Boot ROM via software
	Enable Q-Bus for CSR only if CRDY is set. We need this to still
	be able to read the ROM during controller busy

	!!!!!!!!!	This CPLD requires the interface '22' in the MCU firmware
	!!!!!!!!!	#define	rlv12	  22		; Select Assembler Option

 */
Internal Nodes and Field Definitions

Using a CPLD allows us to have also internal nodes and signals and we also can define FIELDS, that is a group of indexed signals, like buses, registers and synonmys.


PROPERTY ATMEL {preassign KEEP};
PROPERTY ATMEL {SOFT_BUFFER=I14, I7};

PINNODE         =  [Q15..0]      ; /* Data Output Register			*/
PINNODE         =  [D15..0]      ; /* DMA Data Register				*/
PINNODE         =  [A21..1]      ; /* DMA Address				*/
PINNODE         =  CSR           ; /*						*/
PINNODE         =  ROM           ; /*						*/
PINNODE         =  [DMA5..0]     ; /* DMA State Machine				*/
PINNODE         =  SYNC          ; /*						*/
PINNODE         =  DMGI          ; /*						*/
PINNODE         =  SACK          ; /*						*/
PINNODE         =  DATA          ; /*						*/
PINNODE         =  RPLY          ; /*						*/
PINNODE         =  DMARW         ; /* Control bit: DMA read(1) or DMA write(0) */
PINNODE         =  ROMEN         ; /* Enable Bootrom                            */
PINNODE         =  DACK          ; /* Device Interrupt Acknowledge		*/
PINNODE         =  RECI          ; /*						*/
PINNODE         =  [RS2..0];
PINNODE         =  EN;
PINNODE         =  I7;
PINNODE         =  I14;

/*
	Field definitions
 */
FIELD  RS       = [RS2..0];	/* Register Select Address for Atmega1281 reads/writes	*/
FIELD  DMA      = [DMA5..0];	/* DMA State Machine					*/
Register Selection

The logic to address and select registers has completely changed in comparison the the first release of the RLV12 Emulator V2.0. I have added an internal register select that first needs to be loaded with the register number to be written, respectively read in case of the second CPLD. To load the register address you place the register number onto the data bus AD7..0 and then use ALEW to latch the register number.

Once you have loaded the address of the selected register you can then load the data into the register using the WR write signal. The data is latched either using the leading edge of the signal or latched when the signal is asserted. When the signal WR is de-asserted the register address is advanced.

In this way you can load the 16-bit data registers and the DMA direction and address register with just loading the first register number and the further registers are selected automatically with each byte loaded.

E.g. you can address register 0 which is the low byte Q-Bus data register, then the register address increments to 1 and then you can load the high byte Q-Bus data register without having to load the register number 1 into the address register. The same is true for the 16-bit DMA write data register with register addresses 2 and 3 and the DMA direction and address register with register addresses 4, 5 and 6. This is achieved with a small state machine.

/*
	Register Select for DMA Address Registers
 */
RS.ar           =  ALEW & ![AD2..0];
RS.ap           =  ALEW &  [AD2..0];
RS.ck           = !WR;

sequence RS {

  PRESENT 0   NEXT  1;
  PRESENT 1   NEXT  0;
  
  PRESENT 2   NEXT  3;
  PRESENT 3   NEXT  2;

  PRESENT 4   NEXT  5;
  PRESENT 5   NEXT  6;
  PRESENT 6   NEXT  4;
  PRESENT 7   NEXT  0;

}
Select and MCU Q-Bus DATI/DATO Interrupt

When any of the device registers is addressed on the Q-Bus CSRADDR is asserted by the second CPLD and when any of the boot ROM addresses on the Q-Bus is accessed ROMADDR is asserted. The status will be latched with every RSYNC.

At the same time INTQ will be reset if the conditions are met, i.e. either the a device register is accessed and the controller ready CRDY is asserted or if the boot ROM is accessed and the boot ROM is enabled using ROMEN of CPLD register 7.

INTQ is a low level interrupt of the MCU. The MCU will then perform the data transfer and when finished will clear the interrupt using IACK.

The CPLD will assert TRPLYwhenever the cycle has been finished, this is either immediatly when a device register has been accessed while the controller is busy, i.e. CRDY is de-asserted or when the MCU has clread the interrupt by setting INTQ using IACK.

Note that either DATI or DATO cycles will create an interrupt. Also we assume that no DATIO is used to access the device register or boot ROM. This is not supported and will fail to update the data. This is perfectly fine as the real RLV12 does not support DATIO cycles either.

/*
	CSR is set during every cycle the device is selected

 */
CSR.ck		=  RSYNC;
CSR.d		=  CSRADDR;

ROM.ck		=  RSYNC;
ROM.d           =  ROMADDR & ROMEN;

/*
	Raise an interrupt for every access to any of the device registers
	note that an interrupt is only generated in case CRDY is set. In
	case of CRDY cleared the MCU will not be interrupted and the cycle
	will be acknowledged by the CPLD and the last value written to the
	Q-Bus data register will be placed onto the Q-Bus, in other words
	you should load the Q-Bus data register with an appropriate value
	to indicate the device is busy. Mostly a zero value is appropriate.
 */
INTQ.d		= !(CSRADDR & CRDY
                #   ROMADDR & ROMEN);

INTQ.ck		=  RSYNC;
INTQ.ap		=  IACK;

TRPLY		=  CSR &  RSYNC &  INTQ &  RDIN		/* Assert RPLY when MCU is done	*/
		#  CSR &  RSYNC &  INTQ &  RDOUT;	/* Assert RPLY when MCU is done	*/

APPEND
TRPLY		=  ROM &  RSYNC &  INTQ &  RDIN		/* Assert RPLY when MCU is done	*/
		#  ROM &  RSYNC &  INTQ &  RDOUT;	/* Assert RPLY when MCU is done	*/
Interrupt Cycle Handling

The MCU can initiate a Q-Bus interrupt cycle by asserting IRQST. This signal is also present on the bus using a ¼ of a 74S38 open collector 4‑NAND gate device. With every DATI cycle RDIN will be asserted which will latch the interrupt status to the DACK flip‑flop. When RIAKI is asserted the CPLD will either propagate the signal to TIAKO in case DACKis not asserted or it will interrupt the MCU using the INTI flip‑flop. Note that an interrupt acknowledge cycle is always started by the PDP‑11 asserting first BDIN and then BIAKO of the CPU. The PDP‑11 expects a BRPLY when the device has placed the interrupt vector to the Q-Bus. In our case the MCU will have to load the Q-Bus data register with the interrupt vector address and then acknowledge the MCU interrupt INTI using IACK. INTI is as well a low-level interrupt of the MCU. Once INTI is set the CPLD will assert TRPLY and the Q-Bus interrupt acknowledge cycle will be finished.

You might think that BDIN is not only asserted during IACK cycles but with any DATI cycle then you are correct, however as each IACK cycle is initiated by asserting BDIN the IACK cycle always makes sure that the current status of the interrupt requests is latched internally in each device of the Q-Bus. There is no harm to always sample the interrupt request with every BDIN.


/*
	Latch the interrupt request with every RDIN
 */
DACK.d		=  IRQST;
DACK.ck		=  RDIN;
DACK.ar		=  RINIT;

TIAKO		=  RIAKI & !DACK;

INTI.d		= !DACK;
INTI.ck		=  RIAKI;
INTI.ap		=  IACK;

APPEND
TRPLY		=  RIAKI & RDIN & DACK & INTI;
Registers

The CPLD implements a set of currently 8 registers. Registers 0&1 build the Q-Bus data register which can be loaded by the MCU during DATI and IACK cycles. Registers 2&3 implement the DMA write data register that will be written to the PDP‑11 memory during a DMA write cycle and registers 4,5&6 implement the DMA address registers. Note that the LSB of the DMA address register holds the DMA direction. It must be cleared for a DMA write and set for a DMA read when loading the DMA start address.

An 8th registers holds the boot ROM enable bit. The CPLD will only respond to access to the boot ROM at 173000 if ROMEN is set. How to enable or disable the boot ROM is described in the firmware documentation.


/*
	Q-Bus Data Register
 */
[Q7..0].d	=  [AD7..0];
[Q7..0].ce	=  RS:['d'0];
[Q15..8].d	=  [AD7..0];
[Q15..8].ce	=  RS:['d'1];
[Q15..0].ck	=  WR;

/*
	DMA Data Register
 */
[D7..0].d	=  [AD7..0];
[D7..0].ce	=  RS:['d'2];
[D15..8].d	=  [AD7..0];
[D15..8].ce	=  RS:['d'3];
[D15..0].ck	=  WR;

/*
	DMA Address
 */
DMARW.ar	=  WR &  RS:['d'4] & !AD0;
DMARW.ap	=  WR &  RS:['d'4] &  AD0;
DMARW.ck	= 'b'0;
DMARW.d		= 'b'0;

[A7..1].ar	=  WR &  RS:['d'4] & ![AD7..1];
[A7..1].ap	=  WR &  RS:['d'4] &  [AD7..1];

[A15..8].ar	=  WR &  RS:['d'5] & ![AD7..0];
[A15..8].ap	=  WR &  RS:['d'5] &  [AD7..0];

[A21..16].ar	=  WR &  RS:['d'6] & ![AD5..0];
[A21..16].ap	=  WR &  RS:['d'6] &  [AD5..0];

/*
	Enable Boot ROM 
 */
ROMEN.ck	= 'b'0;
ROMEN.d		= 'b'0;
ROMEN.ar        =  WR &  RS:['d'7] & !AD0;
ROMEN.ap        =  WR &  RS:['d'7] &  AD0;
DMA Address Autoincrement

After every DMA cycle the CPLD increments the DMA address by two. Note that the address can only be incremented by two and only word transfers are supported. Note DMA5 is asserted during an active DMA and thus the address is incremented after every DMA cycle.

/*
	Synchronous counter for DMA address which is updated after every DMA
	cycle. The address is incremented whenever a DMA cycle has finished.
 */	
[A21..1].ck	= !DMA5;

A1.t		= 'b'1;
A2.t		= A1;
A3.t		= A1  & A2;
A4.t		= A1  & A2  &  A3;
A5.t		= A1  & A2  &  A3  & A4;
A6.t		= A1  & A2  &  A3  & A4  & A5;
A7.t		= A1  & A2  &  A3  & A4  & A5  & A6;
I7		= A1  & A2  &  A3  & A4  & A5  & A6  & A7;

A8.t		= I7;
A9.t		= I7  & A8;
A10.t		= I7  & A8  &  A9;
A11.t		= I7  & A8  &  A9  & A10;
A12.t		= I7  & A8  &  A9  & A10 & A11;
A13.t		= I7  & A8  &  A9  & A10 & A11 & A12;
A14.t		= I7  & A8  &  A9  & A10 & A11 & A12 & A13;
I14		= I7  & A8  &  A9  & A10 & A11 & A12 & A13 & A14;

A15.t		= I14;
A16.t		= I14 & A15;
A17.t		= I14 & A15 & A16;
A18.t		= I14 & A15 & A16 & A17;
A19.t		= I14 & A15 & A16 & A17 & A18;
A20.t		= I14 & A15 & A16 & A17 & A18 & A19;
A21.t		= I14 & A15 & A16 & A17 & A18 & A19 & A20;
Q-Bus DATA and ADDRESS transmit

The data/address bus can be presented with one of the following 5 values

  • Q-Bus data register in case of a DATI to any of the device registers. When accessinig the device registers when the controller is busy a read will always return a zero value for all device registers
  • Q-Bus data register in case of a DATI to the boot ROM
  • The DMA address during the address portion of the DMA cycle
  • The DMA data written to the host memory for DMA writes
  • The vector address during interrupt acknowledge cycles

The interrupt vector address has been made programable on purpose as I still plan to once emulate a MSCP controller with this hardware.


/*
	Q-Bus Output Select and Output Enable
	
	DMA5	DMA is active
	DMA4	DMA read
	DMA3	DMA data transfer
	EN	Enable Output during DMA
 */
[TDAL15..0]	= !RIAKI & !DMA5  &  CSR   &  RDIN  &  [Q15..0] & CRDY
		# !RIAKI & !DMA5  &  ROM   &  RDIN  &  [Q15..0]
		# !RIAKI &  EN             & !DMA3  &  [A15..1, 'b'0]
		# !RIAKI &  EN             &  DMA3  &  [D15..0];
		
APPEND
[TDAL8..2]	=  RIAKI          &  DACK  &  RDIN  &  [Q8..2];

/*
	The upper address bits are just a copy of the DMA address.
 */
[TDAL21..16]	=  [A21..16] &  EN;
DMA state machine

The most sophisticted part of the CPLD is the DMA state machine.



/*
	The rising edge of DMR from the MCU triggers BDMR of the Q-Bus when
	the DMA is granted BDMR is cleared but DMR will be kept asserted by
	the MCU until the MCU has finished the DMA. Used to control the state
	machine.
 */
TDMR.d		= 'b'1;
TDMR.ck		=  DMR;
TDMR.ar		=  DMA5 # ABORT;
 
TSYNC.ck	=  CLK;
TDOUT.ck	=  CLK;
TDIN.ck		=  CLK;
/*
	Synchronous Signals
 */
DMGI.ck		=  CLK;
DMA.ck		=  CLK;
RPLY.ck		=  CLK;
DMG.ck		=  CLK;
LD.ck		=  CLK;
EN.ck           =  CLK;

DMA.ar		=  ABORT;
/*
	Latched BDMGI and BRPLY as we need a stable DMGI and RPLY for the state machine
 */
DMGI.d		=  RDMGI;
RPLY.d		=  RRPLY;

/*
	DMA state machine, the state machine has now 6 bits with certain
	bits directly linked to a function.
	
	DMA5	is asserted during an active DMA
	DMA4	is asserted for a DMA write cycle and de-asserted for a DMA
		read cycle
	DMA3	is de-asserted during the address portion of a DMA cycle
		and is asserted during the data transfer portion of a DMA
		cycle

	For DMA writes the MCU must first load the DMA start address register
	with the LSB cleared. Then it loads the DMA data register with the 
	value to be written and then asserts DMR. This will assert TDMG.

	When DMR is set and DMA is granted it will execute a DMA write, if
	DMR is not set and DMA is granted it will assert TDMGO and grant
	DMA to the next device.	
	
	When the DMA has been executed the state machine asserts DMG and
	waits for the MCU to de-assert DMR to release the bus.

	For DMA reads the MCU must first load the DMA start address register
	with the LSB set. Then it asserts DMR. This will assert TDMG.

	When DMR is set and DMA is granted it will execute a DMA write, if
	DMR is not set and DMA is granted it will assert TDMGO and grant
	DMA to the next device.	
	
	When the DMA has been executed the state machine asserts DMG and
	waits for the MCU to de-assert DMR to release the bus. Now the 
	MCU can read the DMA data latched into CPLD B.

	In both cases the DMA address will be incremented by 2 and thus
	for further DMA requests of the same type, read or write, the 
	DMA start address and direction register must no be loaded with
	the next address.	

 */
sequence DMA {
/*
	Wait for DMA grant
 */
   PRESENT 'h'00 IF !DMGI                    NEXT 'h'00;
                 IF  DMGI                    NEXT 'h'01;
    
   PRESENT 'h'01 IF !DMR                     NEXT 'h'02;
                 IF  DMR                     NEXT 'h'03;
 
   PRESENT 'h'02 IF !DMGI                    NEXT 'h'00;
                 IF  DMGI OUT TDMGO;         NEXT 'h'02;
 
   PRESENT 'h'03 IF !DMARW                   NEXT 'h'20;
                 IF  DMARW                   NEXT 'h'30;

/*
     At the end of the DMA cycle the state machine asserts DMG to let the MCU
     know that the DMA has ended. The MCU then must de-assert DMR before it can
     start another DMA. This is placed to a state with TSACK de-asserted to 
     release the bus while we are waiting for the MCU.
 */
   PRESENT 'h'04 IF  DMR                     NEXT 'h'04           OUT DMG;
                 IF !DMR                     NEXT 'h'00;
/*
     DMA Write Cycle
 */
   PRESENT 'h'20                             NEXT 'h'21 OUT EN;
  
   PRESENT 'h'21                             NEXT 'h'22 OUT EN;
 
   PRESENT 'h'22                             NEXT 'h'23 OUT EN;
 
   PRESENT 'h'23                             NEXT 'h'24 OUT EN OUT TSYNC;
 
   PRESENT 'h'24                             NEXT 'h'25 OUT EN OUT TSYNC;
 
   PRESENT 'h'25                             NEXT 'h'28 OUT EN OUT TSYNC;
 
   PRESENT 'h'28 IF !RPLY                    NEXT 'h'28 OUT EN OUT TSYNC OUT TDOUT;
                 IF  RPLY                    NEXT 'h'29 OUT EN OUT TSYNC OUT TDOUT;
 
   PRESENT 'h'29                             NEXT 'h'2A OUT EN OUT TSYNC OUT TDOUT;
   
   PRESENT 'h'2A                             NEXT 'h'2B OUT EN OUT TSYNC OUT TDOUT;
   
   PRESENT 'h'2B                             NEXT 'h'2C OUT EN OUT TSYNC OUT TDOUT;
   
   PRESENT 'h'2C IF  RPLY                    NEXT 'h'2C OUT EN OUT TSYNC;
                 IF !RPLY                    NEXT 'h'2D;
 
   PRESENT 'h'2D                             NEXT 'h'04           OUT DMG;
/*
     DMA Read Cycle
 */
   PRESENT 'h'30                             NEXT 'h'31 OUT EN;
  
   PRESENT 'h'31                             NEXT 'h'32 OUT EN;
 
   PRESENT 'h'32                             NEXT 'h'33 OUT EN;
 
   PRESENT 'h'33                             NEXT 'h'34 OUT EN OUT TSYNC;
 
   PRESENT 'h'34                             NEXT 'h'35 OUT EN OUT TSYNC;
 
   PRESENT 'h'35                             NEXT 'h'38 OUT EN OUT TSYNC;
 
   PRESENT 'h'38 IF !RPLY                    NEXT 'h'38 OUT TSYNC OUT TDIN OUT LD;
                 IF  RPLY                    NEXT 'h'39 OUT TSYNC OUT TDIN OUT LD;
 
   PRESENT 'h'39                             NEXT 'h'3A OUT TSYNC OUT TDIN OUT LD;
 
   PRESENT 'h'3A                             NEXT 'h'3B OUT TSYNC OUT TDIN OUT LD;
 
   PRESENT 'h'3B                             NEXT 'h'3C OUT TSYNC OUT TDIN OUT LD;
 
   PRESENT 'h'3C IF  RPLY                    NEXT 'h'3C OUT TSYNC;
                 IF !RPLY                    NEXT 'h'3D;

   PRESENT 'h'3D                             NEXT 'h'04           OUT DMG;
}

TSACK		=  DMA5;
TWTBT		=  DMA5 & !DMA4 & !DMA3;

Second CPLD

The ATF1504 deals primarily with the receive side of the address/data bus and implements the following functions.

The logic of the second CPLD is rather simple. A similar logic is used to address the registers as in the main CPLD. First you need to load the register index of the first register to be read using ALER. For this you have to de-assert RD in order to turn of the bus drivers of the CPLD. In fact RD should be de-asserted almost always except for the time when you need to read one of the registers of the second CPLD. Note that the data bus AD7..0 is shared by the MCU and both CPLDs. Therefore asserting RD also requires to set the direction of the data port on the MCU before. Again you can read consecutive registers by just de-asserting and asserting RD to advance the register index to the next CPLD register. There are two read sequences defined and implemented in the register index state machine.

With every SYNC it latches the address bits RDAL8..0 and the RWTBT into internal registers. In addition it asserts CSRADDR in case a device register is accessed and ROMADDR to inform the main CPLD that a boot ROM address is being addressed.

CPLD header and PIN definitions
Name     QBUS RLV12 Version 2 ;
PartNo   B ;
Date     15.04.2022 ;
Revision 02 ;
Designer cbscpe ;
Company  PRIVAT ;
Assembly None ;
Location ATHOME ;
Device   f1504ispplcc44 ;

/*
	Second CPLD which only performs read of the data bus there are 5 registers
	that can be read
	
	Device Address	This 8-bit register holds the direction of the
			bus cycle in bit 0, address bits A1..5 and whether
			the upper or lower byte are updated
	Q-Bus Data	This register provides the current status of the
			16-bits of the multiplexed address/data bus and
			are used to read the data in a DATO/DATOB cycle
	DMA Data	This 16-bit register will store the data of a DMA
			read cycle

	2022-04-15
	
	New CPLD Interface for MCU. To access any register in CPLD A or B
	you need first to load the register address. The register address
	register is part of a state machine. Depending on the address
	loaded each register write will advance the state. This is made
	because CPLD registers are typically read as 16-bit registers
	or as a combination of register address and Q-Bus data.
	You still can access individual registers.
	To set the read register address you first need to de-assert RD
	and then use ALER to set the read register start address. Then
	you need to assert RD to read the value of the first register
	then you can use ALER to advance the state machine and read the
	next byte value.
	This CPLD implements only the readable registers	

	0->1->2->3->0	Read Device Register address followed by Q-Bus data
	4->5->4->5	Read DMA Data Register

	CPLD decodes the address and asserts CSRADDR in case the device is
	selected and it loads the 16-bit Q-Bus data to the DMA data register
	using the LD input. Both signals connect to CPLD A
	
	2022-04-24
	
	New Register 3 which reads latched bus address A8..1 and modified
	register 0 which now reads latched bus address A9 instead of A5. 
	With this A9 is cleared when a RLV12 register has been accessed and
	is set if a 'o'173000 boot ROM address has been accessed. The first
	sequence now changes from register 2 to register 3 so we can read
	register 3 by simply advancing the counter using ALER without
	the need to load register select, just skip address 1 and 2

	2022-04-26
	
	Boot ROM option using unused interconnection between the two CPLD


	!!!!!!!!!	This CPLD requires the interface '22' in the MCU firmware
	!!!!!!!!!	#define	rlv12	  22		; Select Assembler Option

 */
PIN	28	=  RDAL0;
PIN	27	=  RDAL1;
PIN	26	=  RDAL2;
PIN	25	=  RDAL3;
PIN	24	=  RDAL4;
PIN	21	=  RDAL5;
PIN	19	=  RDAL6;
PIN	20	=  RDAL7;
PIN	18	=  RDAL8;
PIN	17	=  RDAL9;
PIN	16	=  RDAL10;
PIN	14	=  RDAL11;
PIN	12	=  RDAL12;
PIN	11	=  RDAL13;
PIN	9	=  RDAL14;
PIN	8	=  RDAL15;
PIN	6	=  AD0;
PIN	5	=  AD1;
PIN	4	=  AD2;
PIN	39	=  AD3;
PIN	40	=  AD4;
PIN	34	=  AD5;
PIN	37	=  AD6;
PIN	36	=  AD7;
PIN	41	=  RSYNC;
PIN	33	=  RWTBT;
PIN	1	=  RBS7;
PIN	29	=  CSRADDR;	/* Asserted if device is selected		*/
PIN	31	=  ROMADDR;	/* Asserted if ROM is selected                  */
PIN	43	=  LD;		/* Load Q-Bus data into the DMA data register	*/
PIN	44	=  RD;
PIN	2	=  ALER;

PROPERTY ATMEL {preassign=KEEP};
PROPERTY ATMEL {CASCADE_LOGIC=ON};
PROPERTY SOFT_BUFFER {UB, LB};

PINNODE		= [Q15..0];
PINNODE		= [RS2..0];
PINNODE         = [C8..0];	/* CSR Address						*/
PINNODE		=  WTBT;
PINNODE		=  ROM;

FIELD  ADDR    	= [C8..0];	/* Latched address used for register address		*/
FIELD  RS      	= [RS2..0];	/* Register Select Address for Atmega1281 reads/writes	*/
FIELD  IOADDR  	= [RDAL12..0];	/* Access to IO Page only requires address lines 0..12	*/
Address Latch and Address Decoder

With every SYNC we will latch the bus addresses BDAL8..0, RWTBT and ROM which is asserted when a boot ROM address is accessed.


/*
	Device Address is also generated by this CPLD as only we see the address
 */
ADDR.d		= [RDAL8..0];
ADDR.ck		=  RSYNC;

WTBT.d		=  RWTBT;
WTBT.ck		=  RSYNC;

ROM.d		=  RBS7 &  IOADDR:['o'173000..173777];
ROM.ck		=  RSYNC;

/*
	CSR Select must be generated in this CPLD as we are the only CPLD that receives
	the DAL status from the BUS
 */
CSRADDR		=  RBS7 &  IOADDR:['o'174400..174417];
ROMADDR		=  RBS7 &  IOADDR:['o'173000..173777];
DMA read data register

The DMA Read Data Register. Remember this CPLD is the only one that can read data from the Q-Bus. Therefore there is a DMA Read Data register that latches the data from the Q-Bus during DMA Read. The LD signal is created by the DMA statemachine of the main CPLD. After a DMA read the MCU can then retrieve the data from the second CPLD DMA read data register.

/*
	DMA Data Register for DMA reads
 */
[Q15..0].l	= [RDAL15..0];
[Q15..0].le	=  LD;
Register Select Logic

MCU Interface Control Interface is implemented as a register select address and a state machine. The MCU can address the five readable register individually. But it can also access them sequentially. There are two sequences typically required. The first is the sequence is used for DATO/DATOB cycles

  • Device Register Address
  • Q-Bus data low byte
  • Q-Bus data high byte
  • ROM Address

and the second sequence is used to read the DMA Read data register

  • DMA Read data low byte
  • DMA Read data high byte

Adding a statemachine to the register select address increases the performance of the interface between the CPLD and the MCU. The MCU has no external memory interface which would make all this obsolete. Note that to load a register address start you need to de-assert RD first and then load the register address using ALER address latch enable read. Once the start address has been loaded you can read the value of the first byte by asserting RD and then by de-asserting and asserting RD you proceed to the next register


/* 
	Register Select we support two sequences
	
	0->1->2->3->0	to read the Device Address, followed by the Q-Bus
	4->5->4->5	to read the DMA data register (6 is not used)
 */ 
RS.ar		= ![AD2..0].io & ALER & !RD;
RS.ap		=  [AD2..0].io & ALER & !RD;
RS.ce		=  RD;
RS.ck		=  ALER;

sequence RS {

	present 'd'0	next 'd'1;
	
	present 'd'1	next 'd'2;
	
	present 'd'2	next 'd'3;
	
	present 'd'3	next 'd'0;
	
	present 'd'4	next 'd'5;
	
	present 'd'5	next 'd'4;
	
	present 'd'6	next 'd'4;
	
	present 'd'7	next 'd'4;
}
Register Data Multiplexor

The MCU Data Interface provides 6 registers the MCU can read. Note how the device address register is encoded. Bit0 is cleared for DATI and set for DATO cycles. ROM will be cleared for device registers and set set for boot ROM. In addition the two signals UB and LB that inform the MCU whether the upper or lower byte are written by a DATO/DATOB.

The other five registers are used to read the boot ROM address, the Q-Bus data and the DMA Read data register.


UB		= !RWTBT
		#  RWTBT  &  C0;
LB		= !RWTBT
		#  RWTBT  & !C0;

[AD7..0]	=  RS:['d'0] &  [!UB, !LB, ROM, C4, C3, C2, C1, WTBT]
		#  RS:['d'1] &  [RDAL7..0].io
		#  RS:['d'2] &  [RDAL15..8].io
		#  RS:['d'3] &  [C8, C7, C6, C5, C4, C3, C2, C1]
		#  RS:['d'4] &  [Q7..0]
		#  RS:['d'5] &  [Q15..8];
 
[AD7..0].oe	=  RD;

CPLD Pin assignements

When placing signals ot the PINs you need to pay special attention to the RD and the ALER signal so they are using one of the global output enable or clock signals. By using a global output enable input for RD the output enable term is not using a macro-cell product-term so a single macro-cell can be used as a 5-to-1 multiplexor. With the support to emulate the boot ROM the multiplexor now requires two macro-cells per AD7..0 bus signal as this adds a 6th input to the multiplexor. But as the logic of the CPLD is very simple and only a few signals are handled within the CPLD this can still be handled by the same PIN layout without reaching the limit of the FAN‑IN of the macro‑cell blocks. The second important point is that ALER is using one of the global clock inputs because only then you can use the clock enable input of a macro-cell as is the case for the register address state machine proceed clock. In our case both signals RD and ALER perform a double function of clock, output enable, clock enable and preset/reset enable.