Retro Z80: Lessons learned IO

Well it took me a while but I finally have the System Controller picking up the Z80 Input and Output instructions.

There were several problems I have faced and a couple of them took me a while to get my head around.

This is the hardware logic that is in the SystemController to manage the Z80 Wait states. I have decided to always engage wait-states when the Z80 perorms IO. Any optimization that I may think of will come later.

So the hardware in the PSoC SystemController detects when IO is happening and triggers the wait-state (RS-FlipFlop) and the software interrupt (ISR_IO). The And-gate on the left just makes sure that only happens when this part of the hardware is enable. An Enable signal is necessary because the software may request the Z80 Bus (BUSREQ/BUSACK) which will automatically disable this logic so we don’t get any interrupts from DMA sequences the SystemController may be performing.

Z80-WaitStateLogic

The CPUWAIT output is connect to the Z80-Wait signal to stall its processing. The EnableDataOutput signal is connected to the output buffer of the Data Bus on the SystemController. So when the logic detects an Input instruction (IOREQ | RD), it automatically enables the outgoing direction of the Data Bus. The actual value is determined by software in the ISR_IO interrupt handler.

Activation of the Z80 IORQ line also clocks in a 1 so set the RS-FlipFlop that activiates the Z80 Wait line (active low – so inverted). The risaing edge of the (Z80) CPU Clock will latch the set value nicely in-sync with the Z80. This is because the SystemController supports a wide range of CPU clock speeds. The extra D-FlipFlop that Sets the value is used to also to be able to reset the value. One problem I had was that the Z80 needs time between us inactivating the Wait signal and the Z80 being done with the IOREQ. That caused the RS-FlipFlop to be set again causing the mechanism to hang.

The ISR handler grabs the address and the data of the bus (also hardware supported but not shown here) and determines what to do with the data of an Output instruction or which data to fetch for an Input instruction. When its done, it pulses the WaitCtrlReg (Bit0) that sends a pulse into the ClearWaitState pulse converter.The incoming pulse from the register is sampled at Bus speed (a built-in clock of the PSoC5)) but the outgoing pulse is synchronized to the CPU clock – again because we allow for a wide range of clock speeds.

When the pulse from the converter resets the RS-FlipFlop, the Wait line is deactivated and the Z80 finishes up the IO sequence. The reset also resets the D-FlipFlop that was triggered when the IO operation started, allowing it to be triggered again by the next IO operation. When the IO sequence ends and it was an Input instruction, the SystemController releases its hold over the Data bus (EnableDataBus goes low).

Now I have got the IO working between the Z80 and the SystemController I can finally focus more on starting to write the beginnings of the BIOS code. I plan to program the Z80 BIOS code in the Flash of the PSoC so it can initialize the system on startup. The user can always stop the Z80, perform DMA to download some other code and start that. This will not be the usual way to start programs however, they will be written against the BIOS.

Advertisements
Published in: on March 18, 2016 at 5:41 pm  Comments (1)