2018-10-01 16:30:47 +00:00
|
|
|
|
2018-02-15 18:31:32 +00:00
|
|
|
`ifndef SPRITE_RENDERER_H
|
|
|
|
`define SPRITE_RENDERER_H
|
2017-11-21 21:36:38 +00:00
|
|
|
|
2018-02-15 18:31:32 +00:00
|
|
|
`include "hvsync_generator.v"
|
|
|
|
`include "sprite_bitmap.v"
|
2017-11-21 21:36:38 +00:00
|
|
|
|
2018-10-01 16:30:47 +00:00
|
|
|
/*
|
|
|
|
Displays a 16x16 sprite (8 bits mirrored left/right).
|
|
|
|
*/
|
|
|
|
|
2018-02-09 22:23:14 +00:00
|
|
|
module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
|
2017-11-21 21:36:38 +00:00
|
|
|
gfx, in_progress);
|
|
|
|
|
2018-02-19 00:19:20 +00:00
|
|
|
input clk;
|
|
|
|
input vstart; // start drawing (top border)
|
|
|
|
input load; // ok to load sprite data?
|
|
|
|
input hstart; // start drawing scanline (left border)
|
2021-06-28 20:36:47 +00:00
|
|
|
output reg [3:0] rom_addr; // select ROM address
|
2018-02-19 00:19:20 +00:00
|
|
|
input [7:0] rom_bits; // input bits from ROM
|
2021-06-28 20:36:47 +00:00
|
|
|
output reg gfx; // output pixel
|
2018-02-19 00:19:20 +00:00
|
|
|
output in_progress; // 0 if waiting for vstart
|
2018-02-15 18:31:32 +00:00
|
|
|
|
2018-02-19 00:19:20 +00:00
|
|
|
reg [2:0] state; // current state #
|
|
|
|
reg [3:0] ycount; // number of scanlines drawn so far
|
|
|
|
reg [3:0] xcount; // number of horiz. pixels in this line
|
2017-11-21 21:36:38 +00:00
|
|
|
|
2018-02-19 00:19:20 +00:00
|
|
|
reg [7:0] outbits; // register to store bits from ROM
|
2017-11-21 21:36:38 +00:00
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// states for state machine
|
2018-02-09 22:23:14 +00:00
|
|
|
localparam WAIT_FOR_VSTART = 0;
|
|
|
|
localparam WAIT_FOR_LOAD = 1;
|
|
|
|
localparam LOAD1_SETUP = 2;
|
|
|
|
localparam LOAD1_FETCH = 3;
|
|
|
|
localparam WAIT_FOR_HSTART = 4;
|
|
|
|
localparam DRAW = 5;
|
2018-09-16 23:45:32 +00:00
|
|
|
|
|
|
|
// assign in_progress output bit
|
|
|
|
assign in_progress = state != WAIT_FOR_VSTART;
|
|
|
|
|
2017-11-21 21:36:38 +00:00
|
|
|
always @(posedge clk)
|
|
|
|
begin
|
2018-02-09 22:23:14 +00:00
|
|
|
case (state)
|
|
|
|
WAIT_FOR_VSTART: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
ycount <= 0; // initialize vertical count
|
|
|
|
gfx <= 0; // default pixel value (off)
|
|
|
|
// wait for vstart, then next state
|
|
|
|
if (vstart)
|
|
|
|
state <= WAIT_FOR_LOAD;
|
2018-02-09 22:23:14 +00:00
|
|
|
end
|
|
|
|
WAIT_FOR_LOAD: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
xcount <= 0; // initialize horiz. count
|
2018-02-09 22:23:14 +00:00
|
|
|
gfx <= 0;
|
2018-02-19 00:19:20 +00:00
|
|
|
// wait for load, then next state
|
|
|
|
if (load)
|
|
|
|
state <= LOAD1_SETUP;
|
2018-02-09 22:23:14 +00:00
|
|
|
end
|
|
|
|
LOAD1_SETUP: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
rom_addr <= ycount; // load ROM address
|
2018-02-09 22:23:14 +00:00
|
|
|
state <= LOAD1_FETCH;
|
|
|
|
end
|
|
|
|
LOAD1_FETCH: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
outbits <= rom_bits; // latch bits from ROM
|
2018-02-09 22:23:14 +00:00
|
|
|
state <= WAIT_FOR_HSTART;
|
|
|
|
end
|
|
|
|
WAIT_FOR_HSTART: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
// wait for hstart, then start drawing
|
|
|
|
if (hstart)
|
|
|
|
state <= DRAW;
|
2018-02-09 22:23:14 +00:00
|
|
|
end
|
|
|
|
DRAW: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
// get pixel, mirroring graphics left/right
|
2018-02-09 22:23:14 +00:00
|
|
|
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
|
2017-11-21 21:36:38 +00:00
|
|
|
xcount <= xcount + 1;
|
2018-02-19 00:19:20 +00:00
|
|
|
// finished drawing horizontal slice?
|
2017-11-21 21:36:38 +00:00
|
|
|
if (xcount == 15) begin // pre-increment value
|
2018-02-09 22:23:14 +00:00
|
|
|
ycount <= ycount + 1;
|
2018-02-19 00:19:20 +00:00
|
|
|
// finished drawing sprite?
|
2018-02-09 22:23:14 +00:00
|
|
|
if (ycount == 15) // pre-increment value
|
|
|
|
state <= WAIT_FOR_VSTART; // done drawing sprite
|
|
|
|
else
|
|
|
|
state <= WAIT_FOR_LOAD; // done drawing this scanline
|
2017-11-21 21:36:38 +00:00
|
|
|
end
|
|
|
|
end
|
2018-02-19 00:19:20 +00:00
|
|
|
// unknown state -- reset
|
2018-02-09 22:23:14 +00:00
|
|
|
default: begin
|
2018-02-19 00:19:20 +00:00
|
|
|
state <= WAIT_FOR_VSTART;
|
2018-02-09 22:23:14 +00:00
|
|
|
end
|
|
|
|
endcase
|
2017-11-21 21:36:38 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
/// TEST MODULE
|
2018-02-09 22:23:14 +00:00
|
|
|
|
2018-07-22 12:31:42 +00:00
|
|
|
module sprite_render_test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
2017-11-21 21:36:38 +00:00
|
|
|
|
|
|
|
input clk;
|
|
|
|
input hpaddle, vpaddle;
|
|
|
|
output hsync, vsync;
|
|
|
|
output [2:0] rgb;
|
|
|
|
wire display_on;
|
|
|
|
wire [8:0] hpos;
|
|
|
|
wire [8:0] vpos;
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// player position
|
2017-11-21 21:36:38 +00:00
|
|
|
reg [7:0] player_x;
|
|
|
|
reg [7:0] player_y;
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// paddle position
|
2017-11-21 21:36:38 +00:00
|
|
|
reg [7:0] paddle_x;
|
|
|
|
reg [7:0] paddle_y;
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// video sync generator
|
2017-11-21 21:36:38 +00:00
|
|
|
hvsync_generator hvsync_gen(
|
|
|
|
.clk(clk),
|
2017-11-29 01:48:27 +00:00
|
|
|
.reset(0),
|
2017-11-21 21:36:38 +00:00
|
|
|
.hsync(hsync),
|
|
|
|
.vsync(vsync),
|
|
|
|
.display_on(display_on),
|
|
|
|
.hpos(hpos),
|
|
|
|
.vpos(vpos)
|
|
|
|
);
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// car bitmap ROM and associated wires
|
2018-02-19 00:19:20 +00:00
|
|
|
wire [3:0] car_sprite_addr;
|
2017-11-21 21:36:38 +00:00
|
|
|
wire [7:0] car_sprite_bits;
|
|
|
|
|
|
|
|
car_bitmap car(
|
2018-02-19 00:19:20 +00:00
|
|
|
.yofs(car_sprite_addr),
|
2017-11-21 21:36:38 +00:00
|
|
|
.bits(car_sprite_bits));
|
2018-02-15 18:31:32 +00:00
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// convert player X/Y to 9 bits and compare to CRT hpos/vpos
|
|
|
|
wire vstart = {1'b0,player_y} == vpos;
|
|
|
|
wire hstart = {1'b0,player_x} == hpos;
|
2017-11-21 21:36:38 +00:00
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
wire car_gfx; // car sprite video signal
|
|
|
|
wire in_progress; // 1 = rendering taking place on scanline
|
|
|
|
|
|
|
|
// sprite renderer module
|
2017-11-21 21:36:38 +00:00
|
|
|
sprite_renderer renderer(
|
|
|
|
.clk(clk),
|
|
|
|
.vstart(vstart),
|
|
|
|
.load(hsync),
|
|
|
|
.hstart(hstart),
|
2018-02-19 00:19:20 +00:00
|
|
|
.rom_addr(car_sprite_addr),
|
2017-11-21 21:36:38 +00:00
|
|
|
.rom_bits(car_sprite_bits),
|
|
|
|
.gfx(car_gfx),
|
2018-02-19 00:19:20 +00:00
|
|
|
.in_progress(in_progress));
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// measure paddle position
|
2018-02-19 00:19:20 +00:00
|
|
|
always @(posedge hpaddle)
|
|
|
|
paddle_x <= vpos[7:0];
|
|
|
|
|
|
|
|
always @(posedge vpaddle)
|
|
|
|
paddle_y <= vpos[7:0];
|
|
|
|
|
2017-11-21 21:36:38 +00:00
|
|
|
always @(posedge vsync)
|
|
|
|
begin
|
|
|
|
player_x <= paddle_x;
|
|
|
|
player_y <= paddle_y;
|
|
|
|
end
|
|
|
|
|
2018-09-16 23:45:32 +00:00
|
|
|
// video RGB output
|
2017-11-21 21:36:38 +00:00
|
|
|
wire r = display_on && car_gfx;
|
|
|
|
wire g = display_on && car_gfx;
|
2018-02-19 00:19:20 +00:00
|
|
|
wire b = display_on && in_progress;
|
2017-11-21 21:36:38 +00:00
|
|
|
assign rgb = {b,g,r};
|
|
|
|
|
|
|
|
endmodule
|
2018-02-15 18:31:32 +00:00
|
|
|
|
|
|
|
`endif
|