package tests import ( "testing" "crecher.net/gones/v2/cart" "crecher.net/gones/v2/nes" ) func newTestConsole(t *testing.T) *nes.Console { t.Helper() c, err := cart.Load("testdata/nestest.nes") if err != nil { t.Fatal(err) } return nes.New(c) } func strobe(n *nes.Console) { n.Write(0x4016, 1) n.Write(0x4016, 0) } func readBits(n *nes.Console, addr uint16, count int) []uint8 { bits := make([]uint8, count) for i := range bits { bits[i] = n.Read(addr) & 1 } return bits } func equalBits(a, b []uint8) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } func TestControllerReadsButtonsInOrder(t *testing.T) { n := newTestConsole(t) n.SetButtons(0, nes.ButtonA|nes.ButtonStart|nes.ButtonRight) strobe(n) // +---------------------- A // | +------------------- B // | | +---------------- Select // | | | +------------- Start // | | | | +---------- Up // | | | | | +------- Down // | | | | | | +---- Left // | | | | | | | +- Right // | | | | | | | | want := []uint8{1, 0, 0, 1, 0, 0, 0, 1} if got := readBits(n, 0x4016, 8); !equalBits(got, want) { t.Errorf("bits = %v, want %v", got, want) } } func TestControllerReturnsOneAfterEightReads(t *testing.T) { n := newTestConsole(t) strobe(n) readBits(n, 0x4016, 8) if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 1, 1}) { t.Errorf("bits after 8 reads = %v, want [1 1 1]", got) } } func TestControllerStrobeHighKeepsReturningA(t *testing.T) { n := newTestConsole(t) n.SetButtons(0, nes.ButtonA) n.Write(0x4016, 1) if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 1, 1}) { t.Errorf("bits = %v, want [1 1 1]", got) } n.SetButtons(0, nes.ButtonB) if got := readBits(n, 0x4016, 2); !equalBits(got, []uint8{0, 0}) { t.Errorf("bits after releasing A = %v, want [0 0]", got) } } func TestControllerLatchesOnStrobe(t *testing.T) { n := newTestConsole(t) n.SetButtons(0, nes.ButtonA) strobe(n) n.SetButtons(0, 0) // released after the latch, the readout should not change want := []uint8{1, 0, 0, 0, 0, 0, 0, 0} if got := readBits(n, 0x4016, 8); !equalBits(got, want) { t.Errorf("bits = %v, want %v", got, want) } } func TestControllerPortsAreIndependentWithSharedStrobe(t *testing.T) { n := newTestConsole(t) n.SetButtons(0, nes.ButtonA) n.SetButtons(1, nes.ButtonSelect) strobe(n) if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 0, 0}) { t.Errorf("port 1 bits = %v, want [1 0 0]", got) } if got := readBits(n, 0x4017, 3); !equalBits(got, []uint8{0, 0, 1}) { t.Errorf("port 2 bits = %v, want [0 0 1]", got) } } func TestControllerReadHasOpenBusBit6(t *testing.T) { n := newTestConsole(t) strobe(n) if got := n.Read(0x4016); got != 0x40 { t.Errorf("$4016 with nothing pressed = %#02x, want 0x40", got) } }