Files
emuz80go/interrupts_tests.go

52 lines
1.6 KiB
Go

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)
}
}