-
Notifications
You must be signed in to change notification settings - Fork 8
NMI during EI Anomaly
These are my notes from 20th October 2018 on a interesting case where Visual Z80 diverges from reality.
I've discovered another interrupt related failure that I'd like to share. It happens when EI is immediately followed by an NMI, and the result is IFF2 ends up at 0 rather than 1. This means later, when the NMI returns, that interrupts are incorrectly disabled.
Here's a small test program that shows the issue:
; Main program
0000 : 31 80 00 : LD SP, 0x0080
0003 : ED 56 : IM 1
0005 : 3E 00 : LD A, 0x00
0007 : ED 47 : LD I, A
0009 : FB : EI // NMI arrives during the EI
000A : 00 : NOP
000B : 00 : NOP
000C : ED 57 : LD A, I // P flag == IFF2
000E : 18 FE : JR -2 // INT arrives later, and is not taken
; INT handler
0038 : FB : EI
0039 : C9 : RET
; NMI handler
0066 : ED 45 : RETN
Here's a link to a Visual Z80 session that shows this running. You need to run it for 125 cycles (250 half cycles).
These are some relevant nodes that are included in the simulation:
- node 135 seems to indicate an NMI is active and is used to force IFF1=0
- node 181 is part of the IFF1 latch
- node 206 is part of the IFF2 latch
- node 207 is /CLK.T1.M1.PLA97(EI/DI) which is used to load IFF1/IFF2 with node 248
- node 248 is bit 3 of the instruction register (1 for EI and 0 for DI.)
I've done some investigation and it seems the problem occurs in the first half of cycle 41.
If you stop the simulation on cycle 41 (look for 207 being 1), then search for node 206 and shift-click it, you get the list of channel-connected nodes:
- (nodes: 206,248,vcc,181,vss)
Something is probably not right if both vcc and vss are in this list at the same time.
What's happening is there are several paths enabled that results in an ambiguous node state.
- VCC ->248 (IR bit 3) ->181 (IFF1) (enabled by 207)
- VCC ->248 (IR bit 3) ->206 (IFF2) (enabled by 207)
- 181->GND (enabled by 135)
In ChipSim this conflict is resolved as a low and you end up with:
- IFF1 = 0 (because of the NMI)
- IFF2 = 0 (because of the the conflict, which is incorrect)
It seems like something is not right with the timing here, and I can't see how this is really meant to work. What we should end up with is:
- IFF1 = 0 (because of the NMI)
- IFF2 = 1 (because of the EI)
I tried the same In Pavel's simulator and the conflict does occur in the same cycle, but it seems to be resolved as a high. I'm not sure why that is.
I think this issue must be one of:
- A design oversight in the Z80 which just happens to works in practice
- A polygon capture error
- A trap
After further investigation, I have traced all of the logic around IFF1 and IFF2: https://raw.githack.com/hoglet67/Z80Decoder/master/docs/Z80/z80_iff/z80_iff.pdf
My conclusion is that this is (1)
Looking at the size of the three transistor in the path, then node 248 would likely resolve as high. Node 181 might be ambiguous, but that does not matter.
What's most important is that Node 248 is seen as high (so the effect of the EI is not lost).
It's less important if Node 181 is also wrongly seen as high in this particular cycle. This is because node 135 (NMI acknowledge) is active for 10 cycles, so there are plenty of subsequent non-conflicting cycles where IFF1 will correctly be set to zero.
So probably this is a mostly a simulation fidelity issue: we need a VDD trumps VSS rule if both appear in the list of connected nodes.
Of course, that might break other things....
It does seem to work though....