package tests import ( "testing" "crecher.net/gones/v2/nes" ) func fillPage(n *nes.Console, page uint8) { for i := 0; i < 256; i++ { n.Write(uint16(page)<<8|uint16(i), uint8(i)) } } func TestOAMDMACopiesPage(t *testing.T) { n := newTestConsole(t) fillPage(n, 0x02) n.Write(0x4014, 0x02) for i := 0; i < 256; i++ { if n.PPU.OAM[i] != uint8(i) { t.Fatalf("OAM[%d] = %d, want %d", i, n.PPU.OAM[i], i) } } } func TestOAMDMAStartsAtOAMAddr(t *testing.T) { n := newTestConsole(t) fillPage(n, 0x03) n.Write(0x2003, 0x10) n.Write(0x4014, 0x03) // source byte 0 lands at OAM[0x10], and the copy wraps around for _, i := range []int{0, 1, 0xF0, 0xFF} { if got := n.PPU.OAM[(0x10+i)&0xFF]; got != uint8(i) { t.Errorf("OAM[0x%02X] = %d, want %d", (0x10+i)&0xFF, got, i) } } } // runs `lda ; sta $4014` from RAM and returns the cycles the sta step took func dmaStepCycles(t *testing.T, lda []uint8) int { t.Helper() n := newTestConsole(t) prog := append(lda, 0x8D, 0x14, 0x40) // sta $4014 for i, b := range prog { n.Write(0x0200+uint16(i), b) } n.Write(0x0000, 0x02) // for the zero page lda n.CPU.PC = 0x0200 n.Step() return n.Step() } func TestOAMDMAStallCycles(t *testing.T) { // reset leaves the cpu at 7 cycles // lda #imm (2): sta ends on cycle 13, odd -> 4 + 514 if got := dmaStepCycles(t, []uint8{0xA9, 0x02}); got != 518 { t.Errorf("odd start: sta step = %d cycles, want 518", got) } // lda zp (3): sta ends on cycle 14, even -> 4 + 513 if got := dmaStepCycles(t, []uint8{0xA5, 0x00}); got != 517 { t.Errorf("even start: sta step = %d cycles, want 517", got) } } func TestOAMDMAAdvancesCPUCycles(t *testing.T) { n := newTestConsole(t) for i, b := range []uint8{0xA9, 0x02, 0x8D, 0x14, 0x40} { n.Write(0x0200+uint16(i), b) } n.CPU.PC = 0x0200 n.Step() n.Step() if n.CPU.Cycles != 7+2+4+514 { t.Errorf("CPU.Cycles = %d, want %d", n.CPU.Cycles, 7+2+4+514) } }