6

The Z80 user manual (um0080.pdf) is basically useless for finding out many details about NMI. The diagram is broken and there's no mention that it's edge-triggered rather than level-triggered like INT is (it's mentioned in the pin description, thanks Thomas Jager for the correction). The product specification (ps0178.pdf) at least has a usable diagram, and mentions that it is "asynchronous", which I assume also implies edge-triggered (empirically it's provably edge-triggered), yet it also mentions that to ensure it is recognized before the next instruction is executed, the falling edge should occur "no latter than the raising edge of the clock cycle preceding the last state of any instruction cycle".

I'm not sure how to interpret the text. One interpretation is that the falling edge must occur no later than the raising edge of the next-to-last cycle before the instruction ends. But most importantly, I'm interested in how it's implemented at the gate level, in order to be able to predict how it will behave in the presence of very short high or low pulses.

Does anyone know the details of the implementation? Like, is it a flip-flop controlled by the CPU CLK line, or one using the NMI line itself as a clock? And how/when is this flip-flop reset? Is there a flip-flop at all?

9
  • 2
    The pin description for NMI in um00800.pdf starts with "Nonmaskable Interrupt (input, negative edge-triggered)". Commented Oct 22 at 0:48
  • 2
    I don't have full schematics to back this up, but it seems that (based on the existing die-based simulators) the NMI input immediately triggers an asynchronous latch (the NMI is recorded even if no further clock steps are made in the simulator). As far as I can tell, this latch output serves as an internal level-sensitive NMI, until it's cleared at the start of the NMI processing. The NMI edge detection also seems to only be re-enabled at the end of NMI processing, so a second NMI pulse arriving quickly after a first (during NMI processing) will not cause a second NMI to be registered. Commented Oct 22 at 2:57
  • 1
    @Raffzahn I took a look at the 1978 paper you mention but all I found was that there is an NMI F/F. It answers what happens when BUSRQ and NMI come at the same time, which is nice, but it doesn't give any more insight, and doesn't tell when the F/F is reset. The die simulations you mention don't answer the question - one doesn't let you trigger NMI, and the other has the problem I mentioned to Thomas. A better source would be Z80 Explorer, by Goran Devic, but I haven't been able to compile it yet, and I'm not sure if I would be able to understand that part. Commented Oct 22 at 9:21
  • 2
    As the call of the NMI service routine needs to be synchronized to instruction cycles, it is obvious that the internal interrupt signal needs to be active at some time related to the clock. But that does not mean that the NMI pin is sampled by the clock. Commented Oct 22 at 9:58
  • 1
    @PedroGimeno NMI needing to be asserted before the last rising edge of the instruction (though not 2 full cycles before, it's the rising edge preceding the last state, not preceding the last full cycle) is about it needing to be asserted before the decision is made whether to do an instruction next or handle the NMI. This is the same time that the level-sensitive IRQ is sampled. Being an asynchronous signal, NMI is not sampled using the clock. The internal latched NMI is however used in sync with instruction execution, as is IRQ. Commented Oct 22 at 12:13

1 Answer 1

6

I've found that the author of "Z80 Explorer", Goran Devic, has written a Z80 module for FPGA, presumably based on the extensive analysis of the die that he made. This file deals with interrupts.

I haven't checked much of the rest of files but I think it's safe to assume the following, specifically related to the NMI:

  • nreset is the /RESET line.
  • nmi is the negation of the /NMI line.
  • setM1 is a flag that indicates that this is the last cycle in the instruction (as it has to, well, set M1 on the next cycle).
  • ctl_no_ints is a signal that tells whether interrupts are disabled for this opcode. Interrupts are disabled for CB, DD, ED or FD prefixes, even if M1 will be active in the next byte (*)

Now, here's what I gather from it. Ignoring the /RESET line, which just resets both registers:

  • nmi_armed is clocked by the /NMI line (and by the line that resets it), not by the system clock. It's set with an /NMI falling edge, and reset when the flag that tracks whether the interrupt needs servicing is set. So it seems to be a sort of async-to-sync bridge that holds the fact that NMI was requested until the CPU is ready to read it.
  • in_nmi_ALTERA_SYNTHESIZED seems to be the register that tracks whether the NMI needs servicing. It's clocked by the system clock and copied from nmi_armed on the last clock of an instruction, provided interrupts are possible. This means that it will be reset on the last cycle of the 11-cycle NMI processing, which sets setM1 again.

Here are the parts of the code that are relevant to NMI, with the nreset signal eliminated for clarity, simplified to get rid of the confusingly named wires:

input wire  setM1;
input wire  ctl_no_ints;
input wire  nmi;
output wire in_nmi;

reg nmi_armed;
reg in_nmi_ALTERA_SYNTHESIZED;


always @(posedge nmi or posedge in_nmi_ALTERA_SYNTHESIZED)
begin
    nmi_armed <= ~in_nmi_ALTERA_SYNTHESIZED;
end


always @(posedge clk)
begin
    if (setM1 & ~ctl_no_ints)
    begin
        in_nmi_ALTERA_SYNTHESIZED <= nmi_armed;
    end
end

assign  in_nmi = in_nmi_ALTERA_SYNTHESIZED;

(*) According to the code, DI and EI also set ctl_no_ints, which would mean they also prevent an NMI from executing in the next instruction. I don't think this is right - in the die simulation, EI seems to disable IFF1 until the falling edge of M1T2 of the next instruction, in which it is set again, and that seems to be the way it prevents a maskable interrupt after EI, yet NMI can happen right after either DI or EI.

Update:

In the "Z80 Remix" die-level simulation, nmi_armed is node #57 while in_nmi appears to be node #78 or #1070, not sure which as I haven't seen them differ and I can't read dies. #57 is about halfway between the _nmi and the _halt pins (easy to find by ticking and unticking "NMI" without stepping the clock, and checking what's changed), while #78 and #1070 are both immediately below the _halt pin.

There's an inconsistency between the die version and the Verilog version, in that in the die version, nmi_armed is cleared 2 half-clocks after node #78 goes on, while in the Verilog version it should be cleared pretty much immediately. I don't know the reason for this discrepancy, but it doesn't affect the outcome much.

As mentioned above, there's another inconsistency in that in the die simulation, an NMI can occur right after DI or EI, while in the Verilog version can't.

Yet another inconsistency is that in the Verilog version, there's a synchronous int_armed register that holds the negation of the /INT state until the CPU acknowledges it, while in the die simulation, activating /INT at any clock other than the last will skip the interrupt.

I don't know the reason for these discrepancies, but it would appear that the Verilog version is not too precise in these details. These inconsistencies diminish the confidence in the Verilog version and thus in the accuracy of this answer, although the die simulation seems to support the general findings.

1
  • 1
    Very nice answer and great detective work Commented Oct 24 at 16:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .