first public release

This commit is contained in:
2025-09-25 15:29:49 +03:00
parent 6f90fda7a7
commit 24702e4419
41 changed files with 34202 additions and 0 deletions

51
interrupts_tests.go Normal file
View File

@@ -0,0 +1,51 @@
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)
}
}