package z80 import "testing" // EI delay: interrupt must not fire on the instruction immediately following EI. func TestEI_Delay_BeforeInterruptAccept(t *testing.T) { cpu, mem, io := testCPU() // Program: EI; NOP; NOP (we'll be in IM1 so accept RST 38h) loadProgram(cpu, mem, 0x0000, 0xFB, 0x00, 0x00) // FB=EI cpu.IM = 1 io.interrupt = true // interrupt line is asserted // EI executes; IFF1 set; interrupts checked before enabling => no service yet mustStep(t, cpu) // EI pc1 := cpu.PC mustStep(t, cpu) // NOP immediately after EI - still should not take INT if cpu.PC != pc1+1 { t.Fatalf("Interrupt fired too soon after EI; PC=%04X expected %04X", cpu.PC, pc1+1) } // Next step: now IFF1 is enabled and INT should be taken mustStep(t, cpu) if cpu.PC != 0x0038 { t.Fatalf("IM1 should vector to 0038h, PC=%04X", cpu.PC) } } // HALT exits on interrupt; cycles of the interrupt path are counted. func TestHALT_Interrupted_ExitsAndVectors(t *testing.T) { cpu, mem, io := testCPU() cpu.IM = 1 cpu.IFF1, cpu.IFF2 = true, true io.interrupt = true // interrupt line is asserted loadProgram(cpu, mem, 0x0000, 0x76) // HALT mustStep(t, cpu) // enter HALT if !cpu.HALT { t.Fatalf("CPU should be halted") } // Next step processes the interrupt and clears HALT c := mustStep(t, cpu) if cpu.HALT { t.Fatalf("CPU should exit HALT on interrupt") } if cpu.PC != 0x0038 { t.Fatalf("IM1 vector expected 0038h, got %04X", cpu.PC) } // Cycle count should match IM1 path (13) if c != 13 { t.Fatalf("Interrupt from HALT cycles got %d want 13", c) } }