diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ppu_render_test.go | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/tests/ppu_render_test.go b/tests/ppu_render_test.go new file mode 100644 index 0000000..a6602b9 --- /dev/null +++ b/tests/ppu_render_test.go @@ -0,0 +1,160 @@ +package tests + +import ( + "testing" + + "crecher.net/gones/v2/cart" + "crecher.net/gones/v2/ppu" +) + +const ( + black = 0xFF000000 // palette entry $0F + white = 0xFFECEEEC // $30 + red = 0xFF982220 // $16 + blue = 0xFF4C9AEC // $21 +) + +// writes bytes through $2006/$2007 starting at addr, then points v back at 0 +func writeVRAM(p *ppu.PPU, addr uint16, data ...uint8) { + p.WriteRegister(0x2006, uint8(addr>>8)) + p.WriteRegister(0x2006, uint8(addr)) + for _, b := range data { + p.WriteRegister(0x2007, b) + } + p.WriteRegister(0x2006, 0) + p.WriteRegister(0x2006, 0) +} + +// ticks two full frames so scroll registers have been copied from t at least once +func runFrames(p *ppu.PPU) { + for i := 0; i < 2*341*262; i++ { + p.Tick() + } +} + +func pixel(p *ppu.PPU, x, y int) uint32 { + return p.Framebuffer()[y*ppu.ScreenWidth+x] +} + +// tile 1: row 0 is color 1 across, row 1 is color 2 across +// palette 0: backdrop black, 1 = white, 2 = red. palette 1 color 1 = blue +func newSceneWithTile1() *ppu.PPU { + p, _ := newTestPPU(cart.Horizontal) + writeVRAM(p, 0x0010, 0xFF, 0x00) + writeVRAM(p, 0x0018, 0x00, 0xFF) + writeVRAM(p, 0x3F00, 0x0F, 0x30, 0x16) + writeVRAM(p, 0x3F05, 0x21) + return p +} + +func TestBackgroundDrawsBackdropWhenDisabled(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x2000, 1) + runFrames(p) + if got := pixel(p, 0, 0); got != black { + t.Errorf("pixel(0,0) = %#08x, want %#08x", got, uint32(black)) + } +} + +func TestBackgroundTilePixels(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x2000, 1) + p.WriteRegister(0x2001, 0x0A) // background + left 8 pixels + runFrames(p) + + tests := []struct { + x, y int + want uint32 + }{ + {0, 0, white}, + {7, 0, white}, + {8, 0, black}, // next tile is tile 0, blank + {0, 1, red}, + {7, 1, red}, + {0, 2, black}, // rows 2-7 of tile 1 are empty + } + for _, tt := range tests { + if got := pixel(p, tt.x, tt.y); got != tt.want { + t.Errorf("pixel(%d,%d) = %#08x, want %#08x", tt.x, tt.y, got, tt.want) + } + } +} + +func TestBackgroundAttributeSelectsPalette(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x2000, 1, 1, 1, 1) + writeVRAM(p, 0x23C0, 0x01) // top-left 16x16 quadrant uses palette 1 + p.WriteRegister(0x2001, 0x0A) + runFrames(p) + + if got := pixel(p, 0, 0); got != blue { + t.Errorf("pixel(0,0) = %#08x, want %#08x", got, uint32(blue)) + } + if got := pixel(p, 15, 0); got != blue { + t.Errorf("pixel(15,0) = %#08x, want %#08x", got, uint32(blue)) + } + if got := pixel(p, 16, 0); got != white { + t.Errorf("pixel(16,0) = %#08x, want %#08x (next quadrant, palette 0)", got, uint32(white)) + } +} + +func TestBackgroundLeftClip(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x2000, 1, 1) + p.WriteRegister(0x2001, 0x08) // background on, left 8 pixels hidden + runFrames(p) + + if got := pixel(p, 0, 0); got != black { + t.Errorf("pixel(0,0) = %#08x, want %#08x (clipped)", got, uint32(black)) + } + if got := pixel(p, 8, 0); got != white { + t.Errorf("pixel(8,0) = %#08x, want %#08x", got, uint32(white)) + } +} + +func TestBackgroundFineXScroll(t *testing.T) { + p, _ := newTestPPU(cart.Horizontal) + writeVRAM(p, 0x0010, 0x01, 0x00) // only the rightmost pixel of row 0 is set + writeVRAM(p, 0x3F00, 0x0F, 0x30) + writeVRAM(p, 0x2000, 1) + p.WriteRegister(0x2005, 7) + p.WriteRegister(0x2005, 0) + p.WriteRegister(0x2001, 0x0A) + runFrames(p) + + if got := pixel(p, 0, 0); got != white { + t.Errorf("pixel(0,0) = %#08x, want %#08x", got, uint32(white)) + } + if got := pixel(p, 1, 0); got != black { + t.Errorf("pixel(1,0) = %#08x, want %#08x", got, uint32(black)) + } +} + +func TestBackgroundCoarseXScroll(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x2003, 1) // tile 1 in the 4th column + p.WriteRegister(0x2005, 24) // coarse x = 3 + p.WriteRegister(0x2005, 0) + p.WriteRegister(0x2001, 0x0A) + runFrames(p) + + if got := pixel(p, 0, 0); got != white { + t.Errorf("pixel(0,0) = %#08x, want %#08x", got, uint32(white)) + } + if got := pixel(p, 8, 0); got != black { + t.Errorf("pixel(8,0) = %#08x, want %#08x", got, uint32(black)) + } +} + +func TestBackgroundPatternTableSelect(t *testing.T) { + p := newSceneWithTile1() + writeVRAM(p, 0x1018, 0xFF) // tile 1 in the high pattern table, row 0 high plane only = color 2 + writeVRAM(p, 0x2000, 1) + p.WriteRegister(0x2000, 0x10) + p.WriteRegister(0x2001, 0x0A) + runFrames(p) + + if got := pixel(p, 0, 0); got != red { + t.Errorf("pixel(0,0) = %#08x, want %#08x", got, uint32(red)) + } +} |