RLV12 V2.0 CPLD Design


CPLD Functional Description

The following sections describe the functions of the two CPLDs. The two CPLD design files are named QBUSRLV12V2-A-v2-1.pld and QBUSRVL12V2-B-v2-1.pld and are referred to as CPLD A and CPLD B.

CPLD A - ATF1508

This CPLD handles the transmit data path to the Q‐Bus and the Q‐Bus control functions. The interface towards the MCU consists of the data bus AD0..7 and the control signals ALEW, WR, INTI, INTQ, IRQST, CRDY, ABORT, DMR and DMG.

Register Interface

The MCU can only write to registers in the CPLD. The registers are

  • Q-Bus Data Register
  • DMA Data Register
  • DMA Address Register
  • Control Register

To access a register the MCU has first to set up the register address. First the MCU must deassert WR, then it must place the register address to the data bus. It then must assert the ALEW signal to load the register address.

Now it can place the value to be written to the register onto the data bus and then assert WR to write the data to the register in the CPLD. To write another register it must again deassert WR. Deasserting WR will change the register address previously loaded. This happens for every WR cycle and depending on the initial register address loaded the register address will advance as follows

  • 0->1->0->1->0->1… This will toggle between the low and high byte of the 16-bit Q-Bus data register
  • 2->3->2->3->2->3… This will toggle between the low and high byte of the 16-bit Q-Bus DMA data register
  • 4->5->6->4->5->6… This will walk through the low, high and extended byte of the 22-bit Q-Bus DMA address register

This is so we can write either of the Q-Bus registers in a series of bytes by just using subsequent WR cycles without having to individually address each byte of the Q-Bus registers.

Register 7 is used to control the BootROM feature of the RLV12 Emulator. Even so the next register addressed is register 0 this mostly has no advantage.

Register Address Description
0 Q-Bus Write Data Register Low Byte
1 Q-Bus Write Data Register High Byte
2 Q-Bus DMA Write Data Register Low Byte
3 Q-Bus DMA Write Data Register High Byte
4 Bit0: DMA direction 0=DMA Write, 1=DMA Read, Bits1...7: Q-Bus DMA Start Address A1..7
5 Q-Bus DMA Start Address A8..15
6 Q-Bus DMA Start Address A16..21
7 Bit0: BootROM Control 0=BootROM disabled, 1=BootROM enabled
Q-Bus DATI/DATO interface

Whenever the RLV12 Q-Bus registers, default range is 174400..174417 or the IO-page ROM range 173000..173777 is addressed CPLD B will assert CSRADDR or ROMADDR respectively.

When CSRADDR is asserted and the controller is ready, i.e. the MCU has asserted the CRDY control signal, or when ROMADDRis asserted and the Bit0 in the BootROM control register is set to one, the CPLD will deassert INTQ when the BSYNCL is asserted on the Q-Bus.

As INTQ is connected to the interrupt signal INT0 of the MCU This will rise an interrupt. Therefore INT0 is configured as a low-level interrupt. The MCU will then execute the code at the vector associated with this interrupt. First the MCU will read the status register from CPLD B. The value in this register will tell the MCU which type of Q-Bus cycle was the reason of the interrupt. The MCU needs to process the request and create a pulse on IACK to inform the CPLD A that the Q-Bus cycle can be finished, i.e. assert BRPLYL and clear the interrupt.

Q-Bus interrupt interface

The MCU can initiate an interrupt cycle on the Q-Bus by asserting IRQST. This will assert BIRQ4L on the Q-Bus. Eventually the host will start a interrupt acknowledge cycle. In case the RLV12 Emulator has initiated the interrupt the CPLD will receive the BIACKI signal and deassert INTI to interrupt the MCU. As with the the DATI/DATO interface the MCU is interrupted, now via the INT1 interrupt input. The MCU will then write the interrupt vector to the Q-Bus data register and acknowledge the interrupt with a pulse on IACK. This will cause the CPLD to assert BRPLYL, the host will then fetch the vector address and continue.

In case the CPLD receives the BIACKIsignal without the MCU having initiated the interrupt, the CPLD will propagate the signal to BIACKO and the MCU will not be interrupted.

Q-Bus DMA interface

To perform a DMA the CPLD imlementes a single word DMA interface. The MCU first has to first set the DMA start address together with the DMA direction in the Q-Bus DMA address registers 4, 5 and 6. In case of a DMA write it also has to load the Q-Bus DMA write data register using CPLD registers 2 and 3. When the MCU asserts DMR the CPLD will try to perform a single DMA cycle. When the DMA finished successfully the CPLD will assert DMG and waits for the MCU to deassert DMR.

The MCU should terminated a DMA request by using the ABORT signal to avoid bus-timeouts in case DMA accesses non-existing memory when DMG is not asserted within a given time, typically 10µsecs.

For DMA reads the result will be available in the Q-Bus DMA read data register implemented in CPLD B.

BINIT interface

To reset the CPLD and to inform the MCU BINITL is propagated via a receiver to both devices. The current MCU firmware will use this signal as a pin change interrupt and resets the units.

CPLD A Design File

As you can see the design file already has some mentions of a new adapter. You can ignore the comments at the beginning as they are not relevant to the RLV12 EMulator V2.0.

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

/*
	2022-05-23	Adapter-B was intended to replace the ATmega1284P with a
			AVR128DB48. The MVIO was left a 5V so we could use the
			same break-out board. However for some reason SPI is not
			working correctly. In the meantime the CPLD interface for
			the Q-Bus version has changed again. This is now known as
			the RVL12Emu-v21. When Adapter-B was developped another
			interface was used. To continue to analyze the SPI problem
			with Adapter-B we need to switch some pins on the CPLD.

			Pin Name	ATmega1284P	AVR128DB48
			CLK		83		2
			ALEW		2		83
			INTQ		4		80
			INTI		6		64
			ACK		64		6

ATmega1284P and AVR128DB48 Adapter-C

DEFINE PINCLK	83
DEFINE PINALEW	2
DEFINE PININTQ	4
DEFINE PININTI	6
DEFINE PINACK	64

AVR128DB48 Adapter-B

DEFINE PINCLK	2
DEFINE PINALEW	83
DEFINE PININTQ	80
DEFINE PININTI	64
DEFINE PINACK	6

A new Adapter-C has been designed that keeps the PIN Layout and has a 3V3 LDO for
MVIO Port C

 */

$DEFINE PINCLK	83
$DEFINE PINALEW	2
$DEFINE PININTQ	4
$DEFINE PININTI	6
$DEFINE PINACK	64

PIN			16	=  TDAL15;	/* Transmit Data/Address	*/
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;	/* Receive RPLY			*/
PIN			57	=  RDIN;	/* Receive DIN			*/
PIN			55	=  RDOUT;	/* Receive DOUT			*/
PIN			54	=  RSYNC;	/* Receive SYNC			*/
PIN			1	=  RINIT;	/* Receive INIT			*/
PIN			52	=  TRPLY;	/* Transmit RPLY		*/
PIN			46	=  TDIN;	/* Transmit DIN			*/
PIN			48	=  TDOUT;	/* Transmit DOUT		*/
PIN			50	=  TWTBT;	/* Transmit WTBT		*/
PIN			51	=  TSYNC;	/* Transmit SYNC		*/
PIN			49	=  RIAKI;	/* Receive IAKI			*/
PIN			41	=  TIAKO;	/* Transmit IAKO		*/
PIN			44	=  TDMR;	/* Transmit DMR			*/
PIN			45	=  RDMGI;	/* Receive DMGI			*/
PIN			39	=  TDMGO;	/* Transmit DMGO		*/
PIN			40	=  TSACK;	/* Transmit SACK		*/
PIN			81	=  WR;		/* Register WR Clock		*/
PIN			PINCLK	=  CLK;		/* System Clock			*/
PIN                     PINALEW =  ALEW;	/* Address Latch Enable Write	*/
PIN			74	=  AD0;		/* MCU Address/Data Bus		*/
PIN			73	=  AD1;
PIN			75	=  AD2;
PIN			68	=  AD3;
PIN			69	=  AD4;
PIN			76	=  AD5;
PIN			70	=  AD6;
PIN			67	=  AD7;
PIN			8	=  IRQST;	/* Interrupt Request		*/
PIN			79	=  DMR;		/* DMA Requst			*/
PIN			5	=  DMG;		/* DMA Granted/Finished		*/
PIN			PININTQ	=  INTQ;	/* Q-Bus DATI/DATO Interrupt	*/
PIN			PININTI	=  INTI;	/* Q-Bus IACK Interrupt		*/
PIN			77	=  CRDY;	/* Controller Ready		*/
PIN			PINACK	=  IACK;	/* MCU Interrupt Acknowledge	*/
PIN			63	=  ABORT;	/* Abort DMA			*/
PIN			9	=  ROMADDR;	/* ROM Address Enable		*/
PIN			10	=  CSRADDR;	/* CSR Address Enable		*/
PIN			11	=  LD;		/* Load Q-Bus DMA Read Data	*/

/*
	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 data for CSR only if CRDY is set. We need this to 
	still be able to read the ROM during controller busy
	
	2022-05-06
	
	Comment for the four unused signals LED, ALER, SIG, RWTBT, they are
	connected on the initial PCB but are not required.

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

 */
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 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;

}

/*
	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.
	
	The same is true for boot ROM access. Here we have the ROMEN 
	register to enable or disable the boot ROM via software
 */
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	*/

/*
	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;

/*
	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;

/*
	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 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;

/*
	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;

CPLD B ATF1504

Register Interface

Similar to the CPLD A there is a register interface. In this case the register interface is controller via ALER and RD. The first signal ALER latches the register address when RDis deasserted. When RD is asserted the CPLD enables the outputs to the data bus and the MCU can then read the contents of the register. Again the register address proceeds to the next reasonable register address when RDis deasserted to be able to read 16‐bit values without having to load the register address for the high byte. CPLD B registers can only be read. The sequences are implemented as follows

  • 0->1->2->3->0->1… This will walk throug the status, Q‐bus Data and ROM address register
  • 4->5->4->5->4->5… This will walk through the low, high byte of Q-Bus DMA read data register
Register Address Description
0 Status Register
1 Q-Bus Read Data Register Low Byte
2 Q-Bus Read Data Register High Byte
3 Q-Bus ROM Address Bits A1..8
4 Q-Bus DMA Read Data Register Low Byte
5 Q-Bus DMA Read Data Register High Byte

The Status register has the following definitions

Bit Name Description
0 WTBT The status of the BWTBTL signal during Q-Bus addressing to identify the cycle, 0=DATI, 1=DATO/DATOB
1 C1 Device Regiser address bit A1
2 C2 Device Regiser address bit A2
3 C3 Device Regiser address bit A3
4 C4 Device Regiser address bit A4
5 ROM This bit is cleared if a device register is addressed and set if an address of the ROM range is accessed
6 LB This bit is cleared if the lower byte if written during a DATO/DATOB cycle
7 UB This bit is cleared if the higher byte if written during a DATO/DATOB cycle
CPLD A to CPLD B interconnection

There are three signals running between the two CPLDs.

Signal Name Description
CSRADDR Created by CPLD B signals to CPLD A that a device register is addressed
ROMADDR Created by CPLD B signals to CPLD A that a word in the ROM is addressed
LD Created by CPLD A signals to CPLD B to load the value of the Q-bus data to the Q-Bus DMA Read data register
CPLD B Design File

The logic of the CPLD B is very simple as all control functions are handled within the CPLD A.

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	*/

/*
	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 Data Register for DMA reads
 */
[Q15..0].l	= [RDAL15..0];
[Q15..0].le	=  LD;

/*
	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;
}

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;

When placing signals ot the PINs you need to pay special attention to the RD and the ALEsignal 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, perfect for the 5 byte registers to read. The second important point is that ALE is using one of the global clock inputs because only then you can use the clock enable input of a macro-cell.