The MK 3880 Mostek CPU Technical manual (it's the Z80 implementation from Mostek) has a section called "Hardware implementation examples" which may help you.
Besides, the Thomas Scherrer Z80-Family Official Support Page has a section devoted to circuit schematics based upon the Z80 processor.
If you are in Facebook, there is a group devoted to share knowledge about system design on the Z80 called Z80 DIY/Homebrew Computers & Projects.
The simplest schematic I can think of, uses:
- A Z80
- A ROM chip (actually, EEPROM chip)
- A RAM chip (actually, SRAM chip)
- An 8-bit latch which will store data written to a specific I/O port
- A 8-bit transceiver which supplies 8 bit input data when read from a specific I/O port
- Some logic gates for decoding purposes
You have first to define your memory map: the Z80 starts executing from address 0000h after powerup or reset, so it's usual to place the ROM memory mapped to lower addresses. Say your ROM is a 32KB chip (27256 for example). It will be mapped from address 0000h to address 7FFFh. RAM can map the remainder of the address space, from address 8000h to address FFFFh. A 62256 SRAM chip can do the job.
Note that, as I/O address space is separated from memory address space, you don't have to open a gap into the memory address space in order to accomodate I/O devices. They can share addresses with memory and there won't be collisions between both because memory will only be asserted when MREQ is low, and I/O devices will be asserted when IORQ is low.
Dividing the memory space into two 32KB regions allows for a very easy decoding. Address line A15 will be used for that: if it is low and there is a memory bus cycle executing, then ROM is selected. If it is high and a memory bus cycle is executing, then RAM is selected.
Normally, chip select pins on ROMs and RAMs chips are enabled low, so we will need some logic gates to generate chip selects according to this memory map. Take A15 and OR it with MREQ. The output can be used as CS for the 27256 chip (ROM).
Take A15, negate it with an inverter and OR it with MREQ. The output can be used as CS for the 62256 chip (RAM).
The 27256 chip also uses an OE pin to output data into the bus. Just connect it to the RD pin on the Z80. Do the same with the OE pin on the 62256 chip and connect it to the RD pin on the Z80. Last, wire the WE pin from the 62256 chip to the WR pin on the Z80, so the RAM will be put into write mode only when it is selected AND there is a write bus cycle executing.
I/O devices are used the same. For a very simple design, we will use lazy decoding, using only A0 to select between an input I/O device and an output I/O device. When A0 is low, the input device is selected and with A1 high, the output device is selected. Thus, even numbered I/O ports will access the input device and odd numbered I/O ports, the output device.
Take A0 and OR it with IORQ and with RD (3-input OR gate). The output will be the select signal for the transceiver that will act as input device. Take A0 again, negate it, and OR it with IORQ and with WR (3-input OR gate). The output will be the load enable signal for the latch.
Note that, when decoding I/O devices, use both IORQ signal and WR and RD signals. Don't decode just IORQ, as the INTA bus cycle also asserts IORQ, and this may confuse the I/O logic by thinking that an I/O bus cycle is executing. The INTA cycle asserts both IORQ and M1, but not RD nor WR.
The outputs from the latch can go to eigth LED's. Each LED will have a 330 ohm limiting resistor to GND, and connected, anode to each output from the latch and cathode, to the resistor.
The inputs on the transceiver can be pulled up to +5V using a 4.7K resistor array. Reading the input device with nothing connected to its input will read $FF.
The following picture is an almost-complete schematic of a minimal Z80 system. It misses some decoupling capacitors here and there, and logic gate power supplies should be connected. Also, inputs from unused logic gates should be tied to GND so you can use either LS or HCT chips (I would recommend to use HCT chips because they impose a very small load to the Z80 output pins, which being a NMOS device, have a small fanout. In fact, a proper Z80 based design should buffer all output pins). Besides, it lacks a circuit to supply a proper clock signal, but I think the main idea is there. I have changed the output device to drive a seven segment display instead of eigth discrete LEDs.
A small program to demonstrate this system could be as this (it doesn't even need RAM in order to work, just ROM and both I/O devices). To use it, plug one end of a piece of wire to GND and touch with the other end each of the eight input pads of the pin header connected to the input device. The number (0 to 7) of the pad contacted is showed on the LED display and stays there until you touch another pin.
PINHEADER equ 0
DISPLAY equ 1
; Bit of B register to build digits from 0 to 7
; Bit 7 is always 0 for this example
; | |
; 5 | 6 | 1
; | |
; 4 | | 2
out (DISPLAY),a ;clear display
Again in a,(PINHEADER) ;read pins
ld b,00111111b ;prepare to display 0
bit 0,a ;is pin 0 grounded?
jr z,Found ;if so, go ahead and display 0
ld b,00000110b ;prepare to display 1
bit 1,a ;is pin 1 grounded?
jr z,Found ;if so, go ahead and display 1
ld b,01011011b ;and so on...
Found ld a,b