package tests import ( "bufio" "os" "regexp" "strconv" "testing" "crecher.net/gones/v2/cart" "crecher.net/gones/v2/nes" ) 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 := nes.New(c).CPU 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() } }