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.
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.
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.
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.
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
and of course the Q-Bus interface.
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 TRPLY
whenever 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 DACK
is 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.