Z80 Special Reset

Although not mentioned in Zilog databooks the Z80 CPU supports two types of reset cycle, normal and special. A normal reset disables the maskable interrupt, selects interrupt mode 0, zeroes registers I & R and zeroes the program counter (PC). A special reset only does the last of these. Zilog literature also states that RESET must be active for at least three clock cycles (3T) before being properly accepted. Tests with short reset pulses 1T or 2T long have shown that this is not true and the reason for Zilog saying otherwise is explained later.

What is the special reset?

US Patent 4486827 describes the Z80 special reset and the abstract is succinct:

"A special reset function is provided in the CPU, using the same control input to the CPU as a normal reset, to reset only the program counter to facilitate the use of a single CPU in a microprocessor development system."

The patent document should be downloaded to learn more about the intended application of the special reset. It enables breakpoints whilst debugging Z80 code that preserve the complete state of the system, except for PC which is easily saved. Nothing is put on the stack unlike when taking a "snapshot" using the non-maskable interrupt (possibly destroying data) and in any case the NMI pin might not be available. Sharing the same 64K address space does mean that during development the user cannot access the very top of memory where the monitoring software is located but changes to assembly code to cater for this are normally trivial.

I used such a development system, a Zilog in-circuit emulator (ICE), whilst working for Memotech at Oxford and Witney thirty years ago but was unaware of the special reset and the crucial part it played in the ICE until a few weeks ago.

How the special reset is generated

Very precise timing is required to generate a special reset signal. The figure above shows a Z80 instruction opcode fetch (M1 cycle). To be special RESET must be low only at the rising edge of clock state M1T2 as shown in red (the low pulse width is illustrative). A reset will be normal if RESET is low at any rising edge of CLK other than M1T2. The results of tests with reset pulses 1T and 2T long during M1 cycles are shown below. (Other M cycles were not considered as a special reset during these is impossible.)

RESET low at rising edge of   Type of
 M1T1 M1T2 M1T3 M1T4 ....      reset

   X                           Normal
        X                     Special
             X                 Normal
                  X            Normal

   X    X                      Normal
        X    X                 Normal
             X    X            Normal
                  X    X       Normal

Note that a reset pulse that is very short (much less than 1T long) will still generate a reset provided the minimum RESET to rising edge of CLK setup and hold times are met. For the Z80A these are 60 ns and 0 ns respectively for the NMOS version or 60 ns and 10 ns respectively for the CMOS version. (The 10 ns hold time for CMOS also applies to WAIT, BUSREQ and INT.)

How the CPU detects the special reset

Below is a modified version of Fig. 11 from the patent with changes made for clarity and consistency. The external logic with two D-type flip-flops is just one way to create the special reset pulse (note that M1 here is M1 inverted). In the tests performed the RESET signal was a registered output from a programmable logic device (PLD) clocked on the falling edge of CLK, enabled when M1 is low and MREQ is high for the special reset.

As there is only one reset pin the Z80 designers needed to include extra circuitry to distinguish between the two reset functions. Inside the chip are the equivalent of three D-type flip-flops, two with enable and one with enable and clear. The RESI f-f samples the RESET input on every rising edge of CLK, the normal reset f-f samples RESI on every falling edge of CLK except in M1T2 and the special reset f-f samples RESI on the falling edge in M1T2 only.

NRES acts as an asynchronous clear for the special reset f-f. After RESET goes low during M1T1 RESI goes high on the rising edge of M1T2 and CLRPC goes high on the falling edge. If RESET is still low at the next rising edge (at the start of M1T3) NRES will go low on the falling edge and clear CLRPC. Similarly if RESET is low at the rising edges of both M1T1 and M1T2 NRES will prevent CLRPC going high.

Therefore a 2T reset pulse is sufficient to produce a normal reset provided the minimum setup and hold times are met and the tests shown earlier prove this to be the case. However an asynchronous reset signal cannot be relied upon to always meet the setup time and it might not be detected until almost a whole clock cycle after becoming active which is why databooks say RESET should be low for at least 3T.

After the special reset is detected

CLRPC going high is no guarantee that the reset will be special but if not cleared by NRES CLRPC will stay high until the falling edge of T2 in the next M1 cycle. The patent shows CLRPC sampled on the rising edge of M1T2 at which time the type of reset is not in doubt and PC will be zeroed if CLRPC is set. However an opcode fetch from address zero must wait until the following M1 cycle as the incremented PC has already been placed on the address bus and M1 has gone low. Thus following the instruction when RESET is active there is an M1 cycle in which the opcode of the next instruction is fetched and the main if not only job of the CPU during this cycle is to zero PC.

The patent describes external circuitry with a multiplexer that zeroes the data bus to ensure the opcode is read as a NOP (although test results indicate the opcode is ignored anyway) and a 16-bit register that holds the last value of PC before it changes to zero. This is the address to which the CPU should jump after the special reset routines have finished and so the instruction here must not be executed before then. Of course if the special reset was generated at a pre-determined breakpoint this continuation address would be known beforehand.

To summarize the instruction in which the special reset pulse occurs is completed, then the opcode of the following instruction is fetched but appears to be treated as a NOP in a similar way to the halt state, then the opcode at address zero is fetched. No return address is pushed automatically onto the stack as the special reset is not an interrupt and if PC is not saved during the reset or the breakpoint specified in advance the CPU will not know the correct address to resume normal program execution.

Prefixed instructions and the special reset

Tests have shown that the special reset is accepted in the first or second M1 cycle of an instruction prefixed by CB, the only difference being that the reset takes effect 4T sooner when RESET is low during the second. Identical behaviour is assumed for the other prefixes DD, ED and FD. Thus the next M1 cycle after an accepted special reset pulse might not always be an opcode fetch of a new instruction. Prefixed instructions are followed by a disregarded opcode fetch in the same way as non-prefixed ones and two examples of program execution are shown below.

PC    Instruction  Comments

0012  RLC B        Special reset during fetch from 0012
0014  PUSH BC      Fetch from 0014, opcode ignored, 0000 -> PC
0000  xxx          Fetch from 0000, starts 12T after start of fetch from 0012

0012  RLC B        Special reset during fetch from 0013
0014  PUSH BC      Fetch from 0014, opcode ignored, 0000 -> PC
0000  xxx          Fetch from 0000, starts 8T after start of fetch from 0013

      xxx = don't care
      All addresses and numbers in instructions are in hexadecimal

Halt and the special reset

An interesting situation arises when there is a special reset pulse after a HALT instruction. The halt state can be exited by a maskable interrupt (if enabled), a non-maskable interrupt or either type of reset. Until one of these happens databooks say that "the CPU executes NOPs to maintain memory refresh" without giving any more detail. HALT needs to be executed only once to place the CPU in the halt state and if the HALT opcode is continually read thereafter this would have the same effect presumably as executing NOPs. If HALT were replaced by NOP after HALT has gone low would this be another way to exit the halt state?

The answer is no. When HALT is low PC has already been incremented and the opcode fetched is for the instruction after HALT. The halt state stops this instruction from being executed and PC from incrementing so this opcode is read again and again until an exit condition occurs. When an interrupt occurs during the halt state PC is pushed unchanged onto the stack as it is already the correct return address. This is no different from an interrupt when not halted as INT and NMI are sampled and accepted at the end of an instruction by which time PC has incremented. (N.B. What "The Undocumented Z80 Documented" says about HALT and PC is wrong.)

If a special reset pulse occurs when HALT is low the halt state is exited immediately and the opcode of the instruction after HALT will be fetched and executed with no delay. This is possible because special reset is sampled on the rising edge of M1T2 and the opcode is sampled on the rising edge of M1T3. (Tests show that HALT goes high after the falling edge of M1T2.) Once the instruction after HALT is completed there is an opcode fetch of the next instruction then a fetch from address zero as already described.

Apart from what is preserved it can be seen that there is another difference between a normal and a special reset during the halt state: the latter executes an instruction between the HALT and the actual reset. This could be used to save PC without the need for an external register. CALL pushes a return address but the two memory reads to get the address of the subroutine are a waste of time as it is never actually called. RST is a better choice as it is single-byte and faster. RST 18 was used during tests but any of the eight would do as the restart address is effectively redundant and RST 0 is perhaps the most appropriate.

Tests indicate that there is a significant difference between special resets when unhalted and halted. For the latter the halt state appears to prevent PC from incrementing at the end of the instruction after HALT, even though HALT goes high before the rising edge of M1T3 during the opcode fetch. PC holds the address of the last byte of the instruction after it finishes executing and RST pushes its own address onto the stack. When unhalted both addresses will be one more. Three examples from testing are shown below, with M cycle lengths.

0011  xxx          Not HALT
0012  HALT
0013  RST 18       Special reset during fetch from 0013, M1 = 5T, M2 = 3T, M3 = 3T * **
0018  xxx          Fetch from 0018, opcode ignored, 0000 -> PC, M1 = 4T
0000  xxx          Fetch from 0000, starts 15T after start of fetch from 0013

0011  xxx          Not HALT
0012  HALT
0013  PUSH AF      Special reset during fetch from 0013, M1 = 5T, M2 = 3T, M3 = 3T **
0013  PUSH AF      Fetch from 0013 again, opcode ignored, 0000 -> PC, M1 = 4T
0000  xxx          Fetch from 0000, starts 15T after start of first fetch from 0013

0011  xxx          Not HALT
0012  HALT
0013  LD (8000),A  Special reset during fetch from 0013, M1 = 4T, M2 = 3T, M3 = 3T, M4 = 3T **
0015  DB 80        Fetch from 0015, opcode ignored, 0000 -> PC, M1 = 4T ***
0000  xxx          Fetch from 0000, starts 17T after start of fetch from 0013

  * Address pushed onto stack = 0013
 ** HALT low at rising and falling edges of M1T1 and M1T2
*** High byte of address read as opcode but ignored

The state of HALT at the rising edge of CLK when RESET is low could be stored so that the special reset routines know whether or not PC should be incremented before resuming normal program execution. An alternative solution that would work when halted or unhalted would be to store the value of PC when RESET is low and replace all opcodes with NOP until there is a fetch from address zero. However memory cycles would have to be continually examined to ensure the special reset pulse does not occur immediately after a prefix fetch.

If the special reset pulse occurs when HALT is high during a HALT opcode fetch then PC is incremented at the end of the fetch and HALT goes low very briefly. If the special reset pulse occurs when HALT is low during a HALT fetch (two consecutive HALTs) then HALT goes high before the rising edge of M1T3, PC is not incremented at the end of the fetch and HALT goes low again very briefly. Examples of program execution in both cases are shown below.

0011  xxx          Not HALT
0012  HALT         Special reset during fetch from 0012
0013  xxx          Fetch from 0013, opcode ignored, 0000 -> PC *
0000  xxx          Fetch from 0000, starts 8T after start of fetch from 0012

0011  xxx          Not HALT
0012  HALT
0013  HALT         Special reset during first fetch from 0013 **
0013  HALT         Fetch from 0013 again, opcode ignored, 0000 -> PC *
0000  xxx          Fetch from 0000, starts 8T after start of first fetch from 0013

 * HALT low at rising edge of M1T1 only
** HALT low at rising and falling edges of M1T1 and M1T2

How the tests were done

Dave Stevenson's MTX Plus+ CPU board was used for testing the special reset. Some modifications were needed first, in particular creating a separate reset signal for the Z80 only. The onboard Altera MAX 7000 series CPLD contained all the necessary test logic and 64 bytes of Z80 machine code so that only one device needed to be programmed. The initial test program is shown below.

0000  JR NC,0002   interrupt vector table DW 0030
0002  LD A,I       or LD A,R
0004  NOP
0005  RLCA
0006  JR C,0028    jump if bit 7 of I or R set
0008  LD A,80      opcodes at 0008-000F zeroed after 2nd fetch from 0000
000A  LD I,A       or LD R,A
000C  NOP
000D  EI
000E  IM 2         or IM 1
0010  NOP          special reset generated at 001x (varied) after 1st fetch from 0000
0020  HALT         here if normal reset, generate interrupt, stop, INT low
0028  HALT         here if special reset, generate interrupt
0030  HALT         here if IM 2 interrupt accepted, stop, INT high
0038  HALT         here if IM 1 interrupt accepted, stop, INT high

There is a NOP at any address not listed up to 003F. The first two bytes of the program form the complete interrupt mode 2 vector table as zero is placed on the data bus during a maskable interrupt acknowledge cycle. 30 was chosen so that IM 1 and IM 2 tests end at different addresses and 30 00 is a harmless instruction as whatever the state of the carry flag the second instruction after a reset will be read from address 0002. Note that only A5-A0 were used for address decoding, the I register can have any value during IM 2 tests and any combination of I or R and IM 1 or IM 2 is permissible.

Each test began with a button press generating a 200 ms normal reset. Code at 0000-000F was then executed, followed by a short reset pulse (normal or special) shortly after address 0010. A special reset preserved I and R and the CPU executed the HALT at 0028. A normal reset zeroed I and R and the CPU executed the HALT at 0020 (opcodes from 0008-000F were zeroed after this second reset). A maskable interrupt was generated when the address reached 002x, accepted only if the reset was special. Thus the state of INT at the end of the test was a simple indication of the type of reset.

Opcodes were placed carefully to minimise the amount of logic required even though there was ample available. The CPLD has 128 macrocells with five combinatorial product terms per cell. (Unused terms can be borrowed from adjacent cells if required.) As it turned out only eight macrocells were needed to create 17 non-zero bytes with three to five product terms per data bit and 33 in total for D7-D0. Later tests utilised more logic as instructions were added in the range 0010-001F and the results of these were listed earlier.

In order to see more information Dave Stevenson's diagnostic card was connected. This has 7-segment LEDs that can latch and display the contents of the address and data buses. The CPLD output a signal that latched the final PC and various data values during opcode fetches when halted at the end of each test. The data bus is ignored by the CPU when in the halt state and therefore can be used by other devices. Initially one data value was displayed, then two and ultimately four. A counter was implemented with the refresh address as the low bits to display each data byte in turn for about one second.

The values displayed on the data LEDs included the last PC after the special reset before the fetch from address zero, the number of fetches from address zero (a reset count), the number of halt cycles completed, the number of T-states from the reset pulse to the fetch from address zero and the last 16 successive samples at the falling edge of CLK before the fetch from address zero of HALT and MREQ. The latter showed clearly the different types of M cycle. (It was necessary to also sample HALT on the rising edge of CLK to detect the very short pulses discussed earlier.)

As the tests were not about speed a 1 MHz CLK signal was output by the CPLD. Any signals sampled by the CPU on the rising edge of CLK were clocked using the falling edge in the CPLD and any signal from the CPU clocked on the falling edge was sampled by the CPLD on the rising edge. The state of MREQ, M1 and RFSH at the falling edge of CLK was used to distinguish each of the four T states during M1 cycles as shown below. (Using the rising edge of CLK gives ambiguous results.)

At falling edge of CLK   T state
   MREQ  M1  RFSH

    H    L    H            M1T1
    L    L    H            M1T2
    H    H    L            M1T3
    L    H    L            M1T4

Tests used a variety of different CPUs from Zilog, Mostek and SGS in NMOS and CMOS versions. A genuine Zilog CPU was used mainly and other brands only as a check. The special reset behaviour was the same no matter which CPU was tested. The only difference detected was that register B does not have the same value on power-up in the CMOS version compared to NMOS.

Conclusions

The Z80 special reset has been tested and works as described in the patent. A difference was detected in the program counter just before the special reset takes effect depending on whether the CPU was halted or unhalted. Normal reset pulses less than 3T long were also tested successfully.

Thanks

A very special thank you to Dave Stevenson for not only hosting this webpage and allowing his MTX Plus+ project to be derailed (or at least shunted onto a slow branch line) but also performing all the tests and reporting the results, often without being told what they were all about. The whole process took far longer than anticipated and throughout Dave was remarkably patient and good-humoured.

I have given the information above in good faith and as accurately as I can. Further study might show that it contains errors but I leave that to others!

Tony Brewer
December 2014

 

Note from Webmaster : I had hoped that this page would generate some comment / discussions, but that has not been the case, perhaps using the Disqus comment feature was not a very good move. I have now changed to a more generic html comment system, hopefully, this will encourage some participation. (If you are logged into Google+, your e-mail address will not be publically visible, but it will allow you to be notified if new comments are posted) 

HTML Comment Box is loading comments...

mailto: Webmaster

 Terms & Conditions