mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-21 23:30:58 +00:00
116 lines
3.0 KiB
Verilog
116 lines
3.0 KiB
Verilog
|
|
`include "hvsync_generator.v"
|
|
|
|
/*
|
|
A bouncing ball using the "slipping counter" method, as
|
|
used in Pong, Computer Space, and other early arcade games.
|
|
*/
|
|
|
|
module ball_slip_counter_top(clk, reset, hsync, vsync, rgb);
|
|
|
|
input clk;
|
|
input reset;
|
|
output hsync, vsync;
|
|
output [2:0] rgb;
|
|
wire display_on;
|
|
wire [8:0] hpos;
|
|
wire [8:0] vpos;
|
|
|
|
// 9-bit ball timers
|
|
reg [8:0] ball_htimer;
|
|
reg [8:0] ball_vtimer;
|
|
|
|
// 4-bit motion codes
|
|
reg [3:0] ball_horiz_move;
|
|
reg [3:0] ball_vert_move;
|
|
|
|
// 4-bit stop codes
|
|
localparam ball_horiz_stop = 4'd11;
|
|
localparam ball_vert_stop = 4'd10;
|
|
|
|
// 5-bit constants to load into counters
|
|
localparam ball_horiz_prefix = 5'b01100; // 192
|
|
localparam ball_vert_prefix = 5'b01111; // 240
|
|
|
|
// reset ball; will be unset when video beam reaches center position
|
|
reg ball_reset;
|
|
|
|
// video sync generator
|
|
hvsync_generator hvsync_gen(
|
|
.clk(clk),
|
|
.reset(reset),
|
|
.hsync(hsync),
|
|
.vsync(vsync),
|
|
.display_on(display_on),
|
|
.hpos(hpos),
|
|
.vpos(vpos)
|
|
);
|
|
|
|
// update horizontal timer
|
|
always @(posedge clk or posedge ball_reset)
|
|
begin
|
|
if (ball_reset || &ball_htimer) begin
|
|
if (ball_reset || &ball_vtimer) // nudge ball in horiz. dir
|
|
ball_htimer <= {ball_horiz_prefix, ball_horiz_move};
|
|
else // reset timer but don't move ball horizontally
|
|
ball_htimer <= {ball_horiz_prefix, ball_horiz_stop};
|
|
end else
|
|
ball_htimer <= ball_htimer + 1;
|
|
end
|
|
|
|
// update vertical timer
|
|
always @(posedge hsync or posedge ball_reset)
|
|
begin
|
|
if (ball_reset || &ball_vtimer) // reset timer
|
|
ball_vtimer <= {ball_vert_prefix, ball_vert_move};
|
|
else
|
|
ball_vtimer <= ball_vtimer + 1;
|
|
end
|
|
|
|
// reset ball position
|
|
always @(posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
ball_reset <= 1;
|
|
else if (hpos == 128 && vpos == 128)
|
|
ball_reset <= 0; // un-reset when beam reaches center position
|
|
end
|
|
|
|
// collide with vertical and horizontal boundaries?
|
|
wire ball_vert_collide = ball_vgfx && vpos >= 240;
|
|
wire ball_horiz_collide = ball_hgfx && hpos >= 256 && vpos == 255;
|
|
|
|
// vertical bounce
|
|
always @(posedge ball_vert_collide or posedge reset)
|
|
begin
|
|
if (reset)
|
|
ball_vert_move <= 4'd9; // initial vertical velocity
|
|
else
|
|
ball_vert_move <= (4'd9 ^ 4'd11) ^ ball_vert_move; // change dir.
|
|
end
|
|
|
|
// horizontal bounce
|
|
always @(posedge ball_horiz_collide or posedge reset)
|
|
begin
|
|
if (reset)
|
|
ball_horiz_move <= 4'd10; // initial horizontal velocity
|
|
else
|
|
ball_horiz_move <= (4'd10 ^ 4'd12) ^ ball_horiz_move; // change dir.
|
|
end
|
|
|
|
// compute ball display
|
|
wire ball_hgfx = ball_htimer >= 508; // 512-508 = 4 pixel ball
|
|
wire ball_vgfx = ball_vtimer >= 508;
|
|
wire ball_gfx = ball_hgfx && ball_vgfx;
|
|
|
|
// compute grid display
|
|
wire grid_gfx = (((hpos&7)==0) && ((vpos&7)==0));
|
|
|
|
// combine into RGB signals
|
|
wire r = display_on && (ball_hgfx | ball_gfx);
|
|
wire g = display_on && (grid_gfx | ball_gfx);
|
|
wire b = display_on && (ball_vgfx | ball_gfx);
|
|
assign rgb = {b,g,r};
|
|
|
|
endmodule
|