Z80 Microcomputer with SRAM and K1-Bus

My 68008 system is waiting for production and this is, because it uses only 1/2 of an Euro board which i prefer to order, because this size is the cheapest. So finally i finished a Z80 board for the K1-bus as well.

The system consists of a CMOS Z80 CPU running at 6 MHz, one 32kB SRAM and one 32kB EPROM or EEPROM. It has no I/O except a K1-bus connector. The K1-Bus allows attachment of 16 bit peripherals. K1-bus card selection is restricted to D0 .. D7.

Memory Map

The Z80 uses separate instructions for I/O and memory access. Therefore the I/O address space is not part of the memory address space.

RAM is mapped to $0000 .. $7FFF and ROM is mapped to $8000 .. $FFFF. This allows modifying the RST vectors at run time.

After reset the ROM is mapped to the whole address space because the CPU starts execution at address $0000 and needs to find code there.

Pin header JP3 allows using an EPROM or an EEPROM. The EEPROM is writable by the Z80.

RAM / ROM select circuit

The RD and WR outputs of the CPU are directly connected to the RAM and ROM's corresponding inputs. Activation of the memory chips is done using their CE input.

RAM is enabled when IORQ is low and A15 is low,
ROM is enabled when IORQ is low and A15 is high.

There is a 'init state FF' which is set by RESET and cleared by any I/O operation. Thus the FF is set after reset, will be cleared by the first I/O instruction and remain cleared throughout the rest of it's life. While it is set it forces A15 high in the RAM/ROM select circuit so that the CPU will always read from ROM.

Reset circuit

The reset circuit was elaborated in great detail in my hardware blog. It is a little bit load dependent but should work up to 5mA pull-up current, which is much more than is to be expected, unless you attach a LED here. ;-)

With the selected value of the timing capacitor the reset pulse will be approx. 2 ms.


The CPU board does not contain any peripherals, not even a timer interrupt. All Peripherals are expected to be connected at the K1-bus.

The K1-bus provides an I²C bus to attach EEPROMs with driver code and is 16 bit wide. Therefore two data latches are required for buffering data from the Z80's 8 bit bus to the upper half of the K1-bus.
I/O therefore is divided into I²C bus access, high-to-low and low-to-high data latch access and actual bus access.

The K1-bus is specified for symmetrical signals (HC, AC not HCT or TTL) therefore some signals may not have required levels without help.

K1-bus IRPT is directly connected to the IRPT input of the CPU. The interrupt source is determined in software.

K1-bus WAIT is directly connected to the WAIT input of the CPU. Any peripheral board which can issue WAIT fast enough can be used with this CPU board. Since the Z80 is pretty slow this probably means all peripheral boards.

The K1-bus address lines A0 to A5 are directly connected to the corresponding CPU address lines. They are pulled up with 3.3kΩ resistors to help the CPU to pull them up: The CPU has very little driving capabilities and driving high is even less than driving low:
    IOL = 2.0mA     @0.4V
    IOH = -1.6mA    @2.4V (which is too low for HC inputs)
    IOH = -250µA    @4.2V
Eventually 4k7Ω is a better choice. To be tested.

The K1-bus data lines D0 to D7 are directly connected to the CPU as well, which is an allowed design for very small systems. Expect problems with the third card added! They are pulled up with 3.3kΩ resistors to help the CPU to pull them up for the same reason as above. The K1-bus data lines D8 to D15 don't need pull-ups because they are driven by the 74HCT574 which has symmetrical outputs (though TTL inputs) and slightly higher driving capabilities as well.

K1-bus select and strobe generation

Any I/O instruction addresses the K1-bus. This is centered around a 74HCT138 3-to-8 decoder. It is enabled by IORQ=0 && M1=1. It then activates one of 8 strobe lines, depending on A6, A7 and WR. Pin headers JP4 allow to use A6, A7 and A8 instead and IORQ has a "strong" pull-up resistor. The reason for these circuit options are explained below.

The following strobe signals are generated by the 74HCT138:

Signal on the K1-bus to select a card for subsequent I/O operations. I/O cycles on the K1-bus do not contain the address of the talked-to card, instead a card must be 'selected'.

Signal on the K1-bus to read in the interrupt states of all cards to detect which one actually activates the IRPT line.

Signal on the K1-bus to mask off interrupts on some or all card. Can be used to implement interrupts with priority levels.

Read data from a K1-bus card. The lower data byte is read by the CPU directly while the upper data byte (if present) is latched into the high-to-low data latch.

Write data to a K1-bus card. The lower data byte is supplied by the CPU directly while the upper data byte (if required) is supplied by the low-to-high data latch.

Write one byte of data into the low-to-high data latch for use in the next (probably immediately following) WR_DATA cycle.

Read the upper data byte from the last RD_DATA cycle from the high-to-low data latch.

Read or write to the I2C bus. Both is done by reading. The I2C data and I2C clock lines are set by A6 and A7, the value from the I2C data line is read on D7. The circuit is taken directly from my K1-bus page and was the only idea i had to use only one IC.

The two LEDs are for debugging. It took me some time to find a place for some debugging lights on a CPU board without any i/o circuitry (except K1-bus) on it. :-)

74HCT138 enable:

A Z80 I/O bus cycle is strobed with IORQ by the CPU, so this is the first signal used to enable the signal decoder. But the CPU issues this signal for interrupt acknowledge cycles as well. This can be distinguished by the M1 signal, which is activated for interrupts but not for I/O cycles, so M1 must be high to detect an I/O cycle. M1 starts 2.5 cycles (that is: long) before IORQ and remains approx. 10ns longer active (M1: 80ns max. and IORQ 70ns max. after T3↑. These are marked with reference number 20 and 52 in the timing chart below) so it should be possible to use M1 directly to mask the IORQ signal.

Next is a timing problem: WR (and RD) and IORQ go up simultaneously: 70ns max. after T3↓ as can be seen in the I/O timing chart below. This may result in spurious pulses at arbitrary outputs of the 74HCT138.
note: T3 in an I/O cycle is one cycle earlier than T3 in an int ack cycle: int ack inserts 2 automatic wait cycles before T3 and I/O only one.

There are some ideas to overcome this:

  • Make the IORQ signal end earlier:
    Problem: edges can be delayed and not be brought forward. So some very clever circuitry would be needed to do this.
  • Make the WR signal longer:
    Adding a delay to the signal would do the job. But it would also delay the starting edge of the signal: One HCT gate adds approx. 10ns, so the front edge would at least move from 60ns to 70ns, which is now after the 65ns of the IORQ signal. Whatever we do with the WR signal, it will always at least add one gate latency to the front edge as well! So this is no easy solution either.
  • Delay both signals to have time for front and end shaping:
    Unfortunately we don't have any time available for delaying the end of the IORQ signal: in an output cycle data is only guaranteed to be stable for 30ns after IORQ goes up (time #35) which is just enough to propagate IORQ through the '138 to the strobe signal (HCT: typ. 19ns, 40ns max, HC: typ. 17ns, 30ns max)
  • Use an address line instead of WR:
    This is what i do in the Z80 reference design on my K1-bus webpage. This is safe in respect to no spikes on the strobe lines but has a small risk of bus collisions, e.g. if a program crashes. Since all lower 8 address lines are currently used up, we'd need A8 as well, which will make block I/O opcodes impossible to use. But this restriction could be limited to K1-bus cards which actually use all 6 address lines if we reassign the address lines, so that the rarely used K1-bus A5 will be driven by Z80 A8. I will use this design as a fallback for safety. This is what pin-header JP4 in the "IO strobe signal decoder" image above is for.
  • Use a "strong" pull-up:
    A method i have already used on my K1 CPU is "signal shaping" with "strong" pull-ups: If you add a low pull-up or pull-down resistor which draws "high" current, it will aid signal flipping into the pull-up's direction and delay signal flipping in the other. Applying a "strong" pull-up to the IORQ signal will slightly delay the starting edge of the pulse and slightly bring forward the ending edge. So what is "strong" here? The CMOS Z80 can only sink 2.0mA @ 0.4V, so a pull-up which supplies just this will be a reasonable choice: This is approx. 2.5kΩ. Disadvantage: The amount of time which can be shifted this way is tiny: some few ns only, but they may just be enough here.

Besides WR (or A8, if nothing else works) A6 and A7 are chosen for strobe selection, because they are in the low address half, making all I/O instructions usable and they are the only unused address lines because A0 to A5 are already used for addressing K1-bus card registers.

The board

This is a view of the component placement on the board. The board will be produced within the next few weeks in one go with the 68008 board because they can be placed on one Euro board (160x100mm). More material can be found on the project's web page on my web site.

No comments:

Post a Comment