Z80 I/O peripherals can be emulated by the PSoC. The Z80 I/O timing is:
The Z80 address bus is stable 107 nS min (26) prior to IORQ* falling edge which provides the setup time for the address register. PSoC AdrLowIn status register is the Z80 latched address which is read by the PSoC. The register is latched with the falling edge of IORQ*.
The PSoC reads the AdrLowIn status register and determines which peripheral needs to be emulated based on the address. This operation is gated by an interrupt generated when IORQ* and (CPURD* or CPUWR*) are present. This looks like:
The qualified I/O transfer sets the RS Flip-Flop for the interrupt to the PSoC and automatically causes the WAIT* to be asserted to the Z80. This is cleared by a write to the IO_Ctrl_Reg which is configured to generate a pulse when the CLR_IO_INT bit is written.
The PSoC reads the IO_Stat_Reg to determine the operation that the Z80 requests with the IO_Stat_Reg.
There are two 8-bit mailboxes. There is a send mailbox (to Z80 from perspective of the PSoC) There is also a receive mailbox (from Z80 from the perspective of the PSoC).
Sequence works like this:
- Z80 asserts IORQ*
- Falling edge of IORQ* latches the Z80 address into the D Flip-Flops
- Z80 asserts CPURD* or CPUWR*
- The assertion of IORQ* and CPURD* or CPUWR* sets the R-S Flip Flop which asserts IO_Op_Int (interrupt to PSoC) and asserts WAIT* to Z80
- The PSoC reads IO_Stat_Reg to determine the Read/Write direction
- The PSoC reads the lower address bits from the Z80 from the AdrLowIn status register
- PSoC determines the peripheral action from the address and CPURD* or CPUWR* lines
- The peripheral action can be performed by looking up the address and read write in a C function pointer table or with if-else code (depending on the number of peripherals being emulated
- If the operation is a write, the data is read from the Z80_Data_Out status register
- If the operation is a read, the data is placed into the Z80_Data_In control register
- The transfer is acknowledged by writing to the CLR_IO_IN register