package Tiler_Test; import Connectable::*; import GetPut::*; import ClientServer::*; import Assert::*; import StmtFSM::*; import LFSR::*; import Probe::*; import Testing::*; import Tiler::*; import VRAM::*; interface Test; method Action start(); method Bool done(); endinterface (* synthesize *) module mkTestPixelcoordToTileSubcoord(Test); let testflags <- mkTestFlags(); Reg#(Bool) run <- mkReg(False); Reg#(Bool) finished <- mkReg(False); function Action check_pxc_to_tsc(PixelCoord screen_pixel, TilePixelCount pixels_per_tile, TileCount num_tiles, ExtendedPixelCoord scroll_offset, TileCoord want_tile, TilePixelCoord want_subtile); return action let got = pixelcoord_to_tilesubcoord(screen_pixel, pixels_per_tile, num_tiles, scroll_offset); let want = TileSubcoord{tile: want_tile, pixel: want_subtile}; if (testflags.verbose) $display("pixelcoord_to_tilesubcoord(", screen_pixel, ", ", pixels_per_tile, ", ", num_tiles, ", ", scroll_offset, ") = ", fshow(got), ", want ", fshow(want)); dynamicAssert(got == want, "wrong output from pixelcoord_to_tilesubcoord"); endaction; endfunction rule test (run && !finished); // Basic conversion with 32x8px tiles check_pxc_to_tsc(0, 8, 32, 0, 0, 0); check_pxc_to_tsc(5, 8, 32, 0, 0, 5); check_pxc_to_tsc(7, 8, 32, 0, 0, 7); check_pxc_to_tsc(8, 8, 32, 0, 1, 0); check_pxc_to_tsc(9, 8, 32, 0, 1, 1); // 32x16px tiles check_pxc_to_tsc(9, 16, 32, 0, 0, 9); check_pxc_to_tsc(15, 16, 32, 0, 0, 15); check_pxc_to_tsc(16, 16, 32, 0, 1, 0); // Tile wraparound at 32x8 check_pxc_to_tsc(255, 8, 32, 0, 31, 7); check_pxc_to_tsc(256, 8, 32, 0, 0, 0); check_pxc_to_tsc(511, 8, 32, 0, 31, 7); check_pxc_to_tsc(512, 8, 32, 0, 0, 0); // Tile wraparound at 64x8 check_pxc_to_tsc(256, 8, 64, 0, 32, 0); check_pxc_to_tsc(511, 8, 64, 0, 63, 7); check_pxc_to_tsc(512, 8, 64, 0, 0, 0); // Scroll offset check_pxc_to_tsc(0, 8, 32, 42, 5, 2); check_pxc_to_tsc(1, 8, 32, 42, 5, 3); check_pxc_to_tsc(5, 8, 32, 42, 5, 7); check_pxc_to_tsc(6, 8, 32, 42, 6, 0); check_pxc_to_tsc(6, 8, 32, 41, 5, 7); // Scroll offset vs. wraparound check_pxc_to_tsc(255, 8, 32, 2, 0, 1); check_pxc_to_tsc(0, 8, 32, 3072, 0, 0); check_pxc_to_tsc(0, 8, 32, 3071, 31, 7); finished <= True; endrule method Action start() if (!run); run <= True; endmethod method done = finished._read; endmodule (* synthesize *) module mkTestPaletteExpander(Test); let testflags <- mkTestFlags(); let cycles <- mkCycleCounter(); let dut <- mkPaletteExpander(); let got_probe <- mkProbe(); let got_done_probe <- mkProbe(); (* no_implicit_conditions,fire_when_enabled *) rule probe_done; got_done_probe <= dut.done; endrule function Action check_pixel(PaletteIndex want); return action let got <- dut.pixel(); got_probe <= got; if (testflags.verbose) $display("PaletteExpander.pixel() = %0d, want %0d", got, want); dynamicAssert(got == want, "wrong PaletteExpander output"); let got_done = dut.done(); let want_done = False; if (testflags.verbose) $display("PaletteExpander.done() = ", fshow(got_done), ", want ", fshow(want_done)); dynamicAssert(got_done == want_done, "wrong PaletteExpander done()"); dynamicAssert(cycles == 1, "output took more than 1 cycle"); cycles.reset(); endaction; endfunction let fsm <- mkFSM(par seq dut.expand('h8e, 8, Bpp1); dut.expand('ha4, 4, Bpp2); dut.expand('h6c, 2, Bpp4); dut.expand('h4d, 1, Bpp8); dut.expand('h8e, 5, Bpp1); dut.expand('ha4, 3, Bpp2); dut.expand('h6c, 1, Bpp4); endseq seq cycles.reset(); // 0x8e, 1bpp check_pixel(1); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); check_pixel(1); check_pixel(1); check_pixel(0); // 0xa4, 2bpp check_pixel(2); check_pixel(2); check_pixel(1); check_pixel(0); // 0x6c, 4bpp check_pixel(6); check_pixel(12); // 0x4d, 8bpp check_pixel('h4d); // 0x8d, 1bpp, first 5 only check_pixel(1); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); // 0xa4, 2bpp, first 3 only check_pixel(2); check_pixel(2); check_pixel(1); // 0x6c, 4bpp, first only check_pixel(6); action dynamicAssert(dut.done, "PaletteExpander not done after processing all requests"); dynamicAssert(cycles == 1, "done flag took too long to assert"); endaction endseq endpar); method start = fsm.start; method done = fsm.done; endmodule (* synthesize *) module mkTestTileRenderer(Test); let testflags <- mkTestFlags(); let cycles <- mkCycleCounter(); let vram <- mkVRAM(4); let dut <- mkTileRenderer(); mkConnection(dut.vram, vram.tile1); let got_probe <- mkProbe(); let want_probe <- mkProbe(); let done_probe <- mkProbe(); (* no_implicit_conditions,fire_when_enabled *) rule set_done_probe; done_probe <= dut.done(); endrule function Action check_pixel(PaletteIndex want); return action let got <- dut.tiles.response.get(); got_probe <= got; want_probe <= want; if (testflags.verbose) $display("TileRenderer.get() = %02x, want %02x", got, want); dynamicAssert(got == want, "wrong pixel rendered"); endaction; endfunction Reg#(VRAMAddr) i <- mkReg(0); LFSR#(Bit#(8)) rnd <- mkLFSR_8(); let populate_vram = seq for (i <= 0; i < 32; i <= i+1) action let val = rnd.value(); if (testflags.verbose) $display("VRAM.write(%0d, 0x%02x) (%0d, %08b)", i, val, val, val); vram.cpu.request.put(VRAMRequest{ addr: i, data: tagged Valid rnd.value }); rnd.next(); endaction endseq; let test_basic_render = seq dut.tiles.request.put(TileRequest{ tile_row_addr: 1, start_col: 0, end_col: 7, bpp: Bpp1, flip: False }); check_pixel(1); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); check_pixel(1); check_pixel(1); check_pixel(0); dut.tiles.request.put(TileRequest{ tile_row_addr: 0, start_col: 0, end_col: 7, bpp: Bpp1, flip: False }); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 0, end_col: 7, bpp: Bpp2, flip: False }); check_pixel(1); check_pixel(0); check_pixel(1); check_pixel(3); check_pixel(2); check_pixel(2); check_pixel(3); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 0, end_col: 7, bpp: Bpp4, flip: False }); check_pixel(4); check_pixel(7); check_pixel(10); check_pixel(13); check_pixel(13); check_pixel(8); check_pixel(6); check_pixel(12); dut.tiles.request.put(TileRequest{ tile_row_addr: 4, start_col: 0, end_col: 7, bpp: Bpp8, flip: False }); check_pixel('hd8); check_pixel('h6c); check_pixel('h36); check_pixel('h1b); check_pixel('h83); check_pixel('hcf); check_pixel('he9); check_pixel('hfa); endseq; let test_stalled_consumer = par seq dut.tiles.request.put(TileRequest{ tile_row_addr: 12, start_col: 0, end_col: 7, bpp: Bpp8, flip: False }); dut.tiles.request.put(TileRequest{ tile_row_addr: 4, start_col: 0, end_col: 7, bpp: Bpp8, flip: False }); endseq seq check_pixel('h7d); check_pixel('hb0); check_pixel('h58); check_pixel('h2c); repeat (10) noAction; check_pixel('h16); check_pixel('h0b); check_pixel('h8b); check_pixel('hcb); repeat (5) noAction; check_pixel('hd8); check_pixel('h6c); check_pixel('h36); repeat (5) noAction; check_pixel('h1b); check_pixel('h83); check_pixel('hcf); check_pixel('he9); check_pixel('hfa); endseq endpar; let test_scrolled_start = seq dut.tiles.request.put(TileRequest{ tile_row_addr: 1, start_col: 3, end_col: 7, bpp: Bpp1, flip: False }); check_pixel(0); check_pixel(1); check_pixel(1); check_pixel(1); check_pixel(0); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 1, end_col: 7, bpp: Bpp4, flip: False }); check_pixel(7); check_pixel(10); check_pixel(13); check_pixel(13); check_pixel(8); check_pixel(6); check_pixel(12); dut.tiles.request.put(TileRequest{ tile_row_addr: 4, start_col: 3, end_col: 7, bpp: Bpp2, flip: False }); check_pixel(0); check_pixel(1); check_pixel(2); check_pixel(3); check_pixel(0); dut.tiles.request.put(TileRequest{ tile_row_addr: 12, start_col: 3, end_col: 7, bpp: Bpp8, flip: False }); check_pixel('h2c); check_pixel('h16); check_pixel('h0b); check_pixel('h8b); check_pixel('hcb); endseq; let test_scrolled_end = seq dut.tiles.request.put(TileRequest{ tile_row_addr: 1, start_col: 0, end_col: 5, bpp: Bpp1, flip: False }); check_pixel(1); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 0, end_col: 4, bpp: Bpp4, flip: False }); check_pixel(4); check_pixel(7); check_pixel(10); check_pixel(13); check_pixel(13); dut.tiles.request.put(TileRequest{ tile_row_addr: 4, start_col: 0, end_col: 4, bpp: Bpp2, flip: False }); check_pixel(3); check_pixel(1); check_pixel(2); check_pixel(0); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 12, start_col: 0, end_col: 4, bpp: Bpp8, flip: False }); check_pixel('h7d); check_pixel('hb0); check_pixel('h58); check_pixel('h2c); check_pixel('h16); endseq; let test_flipped_tile = seq dut.tiles.request.put(TileRequest{ tile_row_addr: 1, start_col: 0, end_col: 7, bpp: Bpp1, flip: True }); check_pixel(0); check_pixel(1); check_pixel(1); check_pixel(1); check_pixel(0); check_pixel(0); check_pixel(0); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 0, end_col: 7, bpp: Bpp2, flip: True }); check_pixel(1); check_pixel(3); check_pixel(2); check_pixel(2); check_pixel(3); check_pixel(1); check_pixel(0); check_pixel(1); dut.tiles.request.put(TileRequest{ tile_row_addr: 2, start_col: 1, end_col: 5, bpp: Bpp2, flip: True }); // pixels in VRAM order: 1 0 1 3 2 2 3 1 // unflipped slice : _ 0 1 3 2 2 _ _ // flipped pixels : 1 3 2 2 3 1 0 1 // flipped slice : _ 3 2 2 3 1 _ _ check_pixel(3); check_pixel(2); check_pixel(2); check_pixel(3); check_pixel(1); endseq; let fsm <- mkFSM(seq populate_vram; test_basic_render; test_stalled_consumer; test_scrolled_start; test_scrolled_end; test_flipped_tile; repeat (10) noAction; endseq); method start = fsm.start; method done = fsm.done; endmodule module mkTB(); let test_pxc_to_tsc <- mkTestPixelcoordToTileSubcoord(); let test_palette_expander <- mkTestPaletteExpander(); let test_tile_renderer <- mkTestTileRenderer(); Reg#(Scanline) line <- mkReg(0); runTest(2000, mkTest("Tiler", seq mkTest("Tiler/PixelcoordToTilesubcoord", seq test_pxc_to_tsc.start(); await(test_pxc_to_tsc.done); endseq); mkTest("Tiler/PaletteExpander", seq test_palette_expander.start(); await(test_palette_expander.done); endseq); mkTest("Tiler/TileRenderer", seq test_tile_renderer.start(); await(test_tile_renderer.done); endseq); endseq)); endmodule endpackage