`include "hvsync_generator.v" module example_bitmap_rom(addr, data); input [15:0] addr; output [15:0] data; reg [15:0] bitarray[0:255]; assign data = bitarray[addr & 15]; initial begin/*{w:16,h:16,bpw:16,count:1}*/ bitarray[8'h00] = 16'b11110000000; bitarray[8'h01] = 16'b100001000000; bitarray[8'h02] = 16'b1111111100000; bitarray[8'h03] = 16'b1111111100000; bitarray[8'h04] = 16'b11110000000; bitarray[8'h05] = 16'b11111111110000; bitarray[8'h06] = 16'b111100001111000; bitarray[8'h07] = 16'b1111101101111100; bitarray[8'h08] = 16'b1101100001101111; bitarray[8'h09] = 16'b1101111111100110; bitarray[8'h0a] = 16'b1001111111100000; bitarray[8'h0b] = 16'b1111111100000; bitarray[8'h0c] = 16'b1110011100000; bitarray[8'h0d] = 16'b1100001100000; bitarray[8'h0e] = 16'b1100001100000; bitarray[8'h0f] = 16'b11100001110000; end endmodule module sprite_scanline_renderer(clk, reset, hpos, vpos, rgb, rom_addr, rom_data); parameter NB = 5; parameter MB = 3; localparam N = 1<= 256 if (reset || vpos[8]) begin // wiggle sprites randomly once per frame if (vpos == 256 && hpos < N) begin sprite_xpos[move_index] <= sprite_xpos[move_index] + 8'(($random&3)-1); sprite_ypos[move_index] <= sprite_ypos[move_index] + 8'(($random&3)-1); end end else if (hpos < N*2) begin k <= 0; // select the sprites that will appear in this scanline case (hpos[0]) // compute Y offset of sprite relative to scanline 0: z <= 8'(vpos - sprite_ypos[i]); // sprite is active if Y offset is 0..15 1: begin if (z < 16) begin line_yofs[j] <= z; // save Y offset sprite_to_line[j] <= i; // save main array index line_active[j] <= 1; // mark sprite active j <= j + 1; // inc counter end i <= i + 1; // inc main array counter end endcase end else if (hpos < N*2+M*24) begin j <= 0; // divide hpos by 24 (8 setup + 16 render) if ((hpos[3:0] < 8) ^^ hpos[4]) begin // render sprites into write buffer case (hpos[3:0]) // grab index into main sprite array 0: i <= sprite_to_line[k]; // load scanline buffer offset to write 1: write_ofs <= {~vpos[0], sprite_xpos[i]}; // set ROM address and fetch bitmap 2: rom_addr <= {4'b0, sprite_attr[i][7:4], line_yofs[k]}; // fetch 0 if sprite is inactive 3: out_bitmap <= line_active[k] ? rom_data : 0; // load attribute for sprite 4: out_attr <= sprite_attr[i]; // disable sprite for next scanline 6: line_active[k] <= 0; // go to next sprite in 2ndary buffer 7: k <= k + 1; endcase end else begin // write color to scanline buffer if low bit == 1 if (out_bitmap[0]) scanline[write_ofs] <= out_attr[3:0]; // shift bits right out_bitmap <= out_bitmap >> 1; // increment to next scanline pixel write_ofs <= write_ofs + 1; end end else begin // clear counters i <= 0; end // read and clear buffer rgb <= scanline[read_bufidx]; scanline[read_bufidx] <= 0; end initial begin sprite_xpos[0] = 0; sprite_ypos[0] = 0; sprite_attr[0] = 1; end endmodule module test_scanline_render_top(clk, reset, hsync, vsync, rgb); input clk, reset; output hsync, vsync; output [3:0] rgb; wire display_on; wire [8:0] hpos; wire [8:0] vpos; hvsync_generator hvsync_gen( .clk(clk), .reset(reset), .hsync(hsync), .vsync(vsync), .display_on(display_on), .hpos(hpos), .vpos(vpos) ); wire [15:0] rom_addr; wire [15:0] rom_data; example_bitmap_rom bitmap_rom( .addr(rom_addr), .data(rom_data) ); sprite_scanline_renderer ssr( .clk(clk), .reset(reset), .hpos(hpos), .vpos(vpos), .rgb(rgb), .rom_addr(rom_addr), .rom_data(rom_data) ); endmodule