aboutsummaryrefslogtreecommitdiff
path: root/cpu/nestest_test.go
diff options
context:
space:
mode:
authorcrecher <crecher@crecher.net>2026-10-12 04:07:09 +0200
committercrecher <crecher@crecher.net>2026-10-12 04:07:09 +0200
commit8b0292cccf768efdd5295fe0b662488cbc671079 (patch)
treef2896047a2328d8aea9a7f7815a6cf8d9c0636ea /cpu/nestest_test.go
parent7775f9ad5407f2be4b03c300d1db4c745fda2f69 (diff)
downloadgones-8b0292cccf768efdd5295fe0b662488cbc671079.tar.gz
gones-8b0292cccf768efdd5295fe0b662488cbc671079.zip
added cart package, more tests, tests are now at ./tests and added .gitignore
Diffstat (limited to 'cpu/nestest_test.go')
-rw-r--r--cpu/nestest_test.go139
1 files changed, 0 insertions, 139 deletions
diff --git a/cpu/nestest_test.go b/cpu/nestest_test.go
deleted file mode 100644
index 4786c5b..0000000
--- a/cpu/nestest_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package cpu
-
-import (
- "bufio"
- "os"
- "regexp"
- "strconv"
- "testing"
-)
-
-type nestestBus struct {
- ram [0x0800]uint8
- prg []uint8
-}
-
-func (b *nestestBus) Read(addr uint16) uint8 {
- switch {
- case addr < 0x2000:
- return b.ram[addr%0x0800]
- case addr >= 0x8000:
- return b.prg[int(addr-0x8000)%len(b.prg)]
- default:
- return 0
- }
-}
-
-func (b *nestestBus) Write(addr uint16, v uint8) {
- if addr < 0x2000 {
- b.ram[addr%0x0800] = v
- }
-}
-
-func loadNestestPRG(path string) ([]uint8, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, err
- }
- prgBanks := int(data[4])
- prgSize := prgBanks * 16 * 1024
- hasTrainer := data[6]&0x04 != 0
- offset := 16
- if hasTrainer {
- offset += 512
- }
- return data[offset : offset+prgSize], nil
-}
-
-type cpuState struct {
- pc uint16
- a, x, y, p, sp uint8
- cyc uint64
-}
-
-var nestestLogRE = regexp.MustCompile(
- `^([0-9A-F]{4}).*A:([0-9A-F]{2}) X:([0-9A-F]{2}) Y:([0-9A-F]{2}) P:([0-9A-F]{2}) SP:([0-9A-F]{2}).*CYC:\s*(\d+)`)
-
-func loadNestestLog(path string) ([]cpuState, error) {
- f, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- var lines []cpuState
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- m := nestestLogRE.FindStringSubmatch(scanner.Text())
- if m == nil {
- continue
- }
- parseHex8 := func(s string) uint8 {
- v, _ := strconv.ParseUint(s, 16, 8)
- return uint8(v)
- }
- pc, _ := strconv.ParseUint(m[1], 16, 16)
- cyc, _ := strconv.ParseUint(m[7], 10, 64)
- lines = append(lines, cpuState{
- pc: uint16(pc),
- a: parseHex8(m[2]),
- x: parseHex8(m[3]),
- y: parseHex8(m[4]),
- p: parseHex8(m[5]),
- sp: parseHex8(m[6]),
- cyc: cyc,
- })
- }
- return lines, scanner.Err()
-}
-
-// TestNestest runs nestest.nes and diffs the state against a known good log before each instruction
-func TestNestest(t *testing.T) {
- const romPath = "testdata/nestest.nes"
- const logPath = "testdata/nestest.log"
-
- if _, err := os.Stat(romPath); err != nil {
- t.Skip("testdata/nestest.nes not present; add it and testdata/nestest.log to run this test")
- }
-
- prg, err := loadNestestPRG(romPath)
- if err != nil {
- t.Fatalf("loading ROM: %v", err)
- }
- want, err := loadNestestLog(logPath)
- if err != nil {
- t.Fatalf("loading log: %v", err)
- }
- if len(want) == 0 {
- t.Fatal("no log lines parsed")
- }
-
- bus := &nestestBus{prg: prg}
- c := NewCPU(bus)
- c.PC = 0xC000
- c.SP = 0xFD
- c.Status = 0x24
- c.Cycles = want[0].cyc
-
- for i, w := range want {
- got := cpuState{c.PC, c.A, c.X, c.Y, c.Status, c.SP, c.Cycles}
- if got != w {
- t.Fatalf("line %d: got %+v, want %+v", i+1, got, w)
- }
-
- stopped := func() (panicked bool) {
- defer func() {
- if r := recover(); r != nil {
- t.Logf("stopped at line %d: %v", i+1, r)
- panicked = true
- }
- }()
- c.Step()
- return false
- }()
- if stopped {
- t.Logf("matched %d instructions before stopping", i+1)
- return
- }
- }
-}