z80 icon indicating copy to clipboard operation
z80 copied to clipboard

Incorrect halted CPU behaviour

Open simonowen opened this issue 2 years ago • 2 comments

The traditional way to implement HALT has been to keep PC on the same instruction and execute NOPs. PC is incremented as part of acknowledging the next interrupt to step over it. However, this has been shown to not match the real Z80 CPU behaviour, and it's possible to detect the difference in code.

The following article describes it, in the section "Halt and the special reset": http://www.primrosebank.net/computers/z80/z80_special_reset.htm

When HALT is executed it puts the CPU into a halted state (already implemented in your core). It also advances PC to point to the next instruction. During the halted state the opcode fetch runs on this new PC value but a NOP is executed instead, and PC isn't advanced. When an interrupt occurs the halted state is cleared and execution continues from the current point as normal.

It's possible to detect this behaviour with a HALT in the last byte before a contention boundary, such as 0x7FFF on the ZX Spectrum. The incorrect behaviour reads from 0x7FFF for each NOP executed at the HALT, which has more contention than the correct fetches from 0x8000. The difference in timing can be detected by measuring how much has R changed when the next interrupt is ackknowledged.

simonowen avatar Oct 25 '21 20:10 simonowen

I've made some test changes to give the behaviour described above in a halt_tweak branch. It may be incomplete but it was enough to pass the test I wrote to detect the difference in my emulator.

simonowen avatar Oct 25 '21 20:10 simonowen

What a nice catch! I'm playing with our new shiny transistor-level simulator, https://github.com/kosarev/z80/blob/c6ad460108c514df05f47e568b1ca0ea77e12705/tests/z80sim/z80sim.py, trying to understand what is supposed to happen in silicon on HALT. Clearly the address bus freezes, but otherwise it behaves like a normal fetch cycle. And then indeed it seemingly proceeds as if it was a NOP. So maybe let's commit what your branch does, and then I think I'd like to spend just a little bit more time looking into the actual hardware behaviour.

PC 0000, A 55, R 00, clk 0, abus 0000, dbus 00, m1 1, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 0, mreq 0
PC 0001, A 55, R 00, clk 1, abus 0000, dbus 00, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 00, clk 0, abus 0000, dbus 76, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 00, clk 1, abus 0000, dbus 76, m1 1, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 00, clk 0, abus 0000, dbus 76, m1 0, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0
PC 0001, A 55, R 01, clk 1, abus 0000, dbus 76, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 01, clk 0, abus 0000, dbus 76, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 01, clk 1, abus 0000, dbus 76, m1 0, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0

PC 0001, A 55, R 01, clk 0, abus 0001, dbus 76, m1 1, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 0, mreq 0
PC 0001, A 55, R 01, clk 1, abus 0001, dbus 76, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 01, clk 0, abus 0001, dbus c5, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 01, clk 1, abus 0001, dbus c5, m1 1, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 01, clk 0, abus 0001, dbus c5, m1 0, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0
PC 0001, A 55, R 02, clk 1, abus 0001, dbus c5, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 02, clk 0, abus 0001, dbus c5, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 02, clk 1, abus 0001, dbus c5, m1 0, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0

PC 0001, A 55, R 02, clk 0, abus 0001, dbus c5, m1 1, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 0, mreq 0
PC 0001, A 55, R 02, clk 1, abus 0001, dbus c5, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 02, clk 0, abus 0001, dbus c5, m1 1, t1 0, t2 1, t3 0, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 02, clk 1, abus 0001, dbus c5, m1 1, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 0, rd 1, mreq 1
PC 0001, A 55, R 02, clk 0, abus 0002, dbus c5, m1 0, t1 0, t2 0, t3 1, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0
PC 0001, A 55, R 03, clk 1, abus 0002, dbus c5, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 03, clk 0, abus 0002, dbus c5, m1 0, t1 0, t2 0, t3 0, t4 1, t5 0, t6 0, rfsh 1, rd 0, mreq 1
PC 0001, A 55, R 03, clk 1, abus 0002, dbus c5, m1 0, t1 1, t2 0, t3 0, t4 0, t5 0, t6 0, rfsh 1, rd 0, mreq 0

kosarev avatar Nov 06 '21 19:11 kosarev