aboutsummaryrefslogtreecommitdiff
path: root/tests/nestest_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'tests/nestest_test.go')
-rw-r--r--tests/nestest_test.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/tests/nestest_test.go b/tests/nestest_test.go
new file mode 100644
index 0000000..de98156
--- /dev/null
+++ b/tests/nestest_test.go
@@ -0,0 +1,111 @@
+package tests
+
+import (
+ "bufio"
+ "os"
+ "regexp"
+ "strconv"
+ "testing"
+
+ "crecher.net/gones/v2/cart"
+ "crecher.net/gones/v2/cpu"
+)
+
+type nestestBus struct {
+ ram [0x0800]uint8
+ cart cart.Mapper
+}
+
+func (b *nestestBus) Read(addr uint16) uint8 {
+ switch {
+ case addr < 0x2000:
+ return b.ram[addr%0x0800]
+ case addr >= 0x4020:
+ return b.cart.CPURead(addr)
+ default:
+ return 0
+ }
+}
+
+func (b *nestestBus) Write(addr uint16, v uint8) {
+ switch {
+ case addr < 0x2000:
+ b.ram[addr%0x0800] = v
+ case addr >= 0x4020:
+ b.cart.CPUWrite(addr, v)
+ }
+}
+
+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()
+
+ parseHex8 := func(s string) uint8 {
+ v, _ := strconv.ParseUint(s, 16, 8)
+ return uint8(v)
+ }
+
+ var lines []cpuState
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ m := nestestLogRE.FindStringSubmatch(scanner.Text())
+ if m == nil {
+ continue
+ }
+ 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()
+}
+
+func TestNestest(t *testing.T) {
+ const romPath = "testdata/nestest.nes"
+ const logPath = "testdata/nestest.log"
+
+ c, err := cart.Load(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")
+ }
+
+ core := cpu.NewCPU(&nestestBus{cart: c.Mapper})
+ core.PC = 0xC000
+ core.SP = 0xFD
+ core.Status = 0x24
+ core.Cycles = want[0].cyc
+
+ for i, w := range want {
+ got := cpuState{core.PC, core.A, core.X, core.Y, core.Status, core.SP, core.Cycles}
+ if got != w {
+ t.Fatalf("line %d: got %+v, want %+v", i+1, got, w)
+ }
+ core.Step()
+ }
+}