Skip to content

Commit

Permalink
test IM 0 interrupt, and fix bugs for it
Browse files Browse the repository at this point in the history
  • Loading branch information
koron committed Apr 20, 2024
1 parent 6e642da commit 1b1ef98
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
17 changes: 13 additions & 4 deletions cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,34 @@ type im0data struct {
start uint16
end uint16
data []uint8

base Memory
}

func newIm0data(pc uint16, d []uint8) *im0data {
func newIm0data(pc uint16, d []uint8, base Memory) *im0data {
return &im0data{
start: pc,
end: pc + uint16(len(d)-1),
data: d,
base: base,
}
}

func (im0 *im0data) Get(addr uint16) uint8 {
if addr < im0.start || addr > im0.end {
return 0
// delegate to base Memory for out of range.
return im0.base.Get(addr)
}
return im0.data[addr-im0.start]
}

func (im0 *im0data) Set(addr uint16, value uint8) {
// invalid opepration, nothing to do.
if addr >= im0.start && addr <= im0.end {
// invalid opepration, nothing to do.
return
}
// delegate to base Memory for out of range.
im0.base.Set(addr, value)
}

func (cpu *CPU) failf(msg string, args ...interface{}) {
Expand Down Expand Up @@ -252,7 +261,7 @@ func (cpu *CPU) tryInterrupt() bool {
}
cpu.HALT = false
savedMemory := cpu.Memory
cpu.Memory = newIm0data(cpu.PC, d)
cpu.Memory = newIm0data(cpu.PC, d, savedMemory)
cpu.executeOne()
cpu.Memory = savedMemory
return true
Expand Down
84 changes: 84 additions & 0 deletions cpu_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package z80

import (
"context"
"fmt"
"testing"
"time"

"github.com/google/go-cmp/cmp"
)
Expand Down Expand Up @@ -106,3 +109,84 @@ type tReg struct {
Label string
Code int
}

type tINT struct {
data []uint8
reti bool
}

func (tint *tINT) CheckINT() []uint8 {
v := tint.data
if v != nil {
tint.data = nil
tint.reti = false
}
return v
}

func (tint *tINT) ReturnINT() {
tint.reti = true
}

func testIM0(t *testing.T, n uint8) {
var (
addr uint16 = uint16(n) * 8
code uint8 = 0xC7 + n*0x08
)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

tint := &tINT{}
cpu := &CPU{
States: States{SPR: SPR{PC: 0x0100}, IM: 1},
Memory: MapMemory{}.
// HALT
Put(0x0000, 0x76).
// RETI
Put(addr, 0xed, 0x4d).
// IM 0 ; HALT ; HALT (for return)
Put(0x0100,
0xed, 0x46,
0x76,
0x76,
),
IO: &tForbiddenIO{},
INT: tint,
}

// Start the program and HALT at 0x0101
if err := cpu.Run(ctx); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cpu.PC != 0x0102 {
t.Fatalf("unexpected PC: want=%04X got=%04X", 0x102, cpu.PC)
}
if cpu.IM != 0 {
t.Fatalf("unexpected interrupt mode: want=0 got=%d", cpu.IM)
}

// Interrupt with IM 0
tint.data = []uint8{code}
cpu.Step()
if cpu.PC != addr {
t.Fatalf("RST 38H not work: want=%04X got=%04X", addr, cpu.PC)
}

if err := cpu.Run(ctx); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cpu.PC != 0x0103 {
t.Fatalf("unexpected PC: want=%04X got=%04X", 0x103, cpu.PC)
}
if !tint.reti {
t.Fatalf("RETI is not processed, unexpectedly")
}
}

func TestInterruptIM0(t *testing.T) {
for i := 0; i < 8; i++ {
t.Run(fmt.Sprintf("RST %02XH", i*8), func(t *testing.T) {
testIM0(t, uint8(i))
})
}
}

0 comments on commit 1b1ef98

Please sign in to comment.