272 lines
5.2 KiB
Verilog
272 lines
5.2 KiB
Verilog
module game_controller #(
|
|
parameter SCREEN_WIDTH = 1024,
|
|
parameter SCREEN_HEIGHT = 768,
|
|
|
|
parameter BALL_START_X = SCREEN_WIDTH / 2,
|
|
parameter BALL_START_Y = SCREEN_HEIGHT / 6,
|
|
//parameter BALL_START_SPEED_VEC = 2'b11,
|
|
|
|
parameter POD_TOP = SCREEN_HEIGHT - 50,
|
|
parameter POD_WIDTH = SCREEN_WIDTH / 6,
|
|
parameter POD1_START_X = (SCREEN_WIDTH / 2 - POD_WIDTH) / 2,
|
|
parameter POD2_START_X = POD1_START_X + SCREEN_WIDTH / 2,
|
|
|
|
parameter WALL_HALF_WIDTH = 4,
|
|
parameter WALL_HEIGHT = SCREEN_HEIGHT / 3,
|
|
|
|
parameter SIMDIV = 2500,
|
|
|
|
parameter N_SCR_WIDTH = $clog2(SCREEN_WIDTH),
|
|
parameter N_SCR_HEIGHT = $clog2(SCREEN_HEIGHT),
|
|
parameter N_SIMDIV = $clog2(SIMDIV)
|
|
)(
|
|
input wire clk,
|
|
input wire rst,
|
|
input wire rst2,
|
|
|
|
input wire start,
|
|
input wire acknowledge,
|
|
|
|
output reg [N_SCR_WIDTH - 1:0] pod1x,
|
|
output reg [N_SCR_WIDTH - 1:0] pod2x,
|
|
|
|
output reg [N_SCR_WIDTH - 1:0] ballx,
|
|
output reg [N_SCR_HEIGHT - 1:0] bally,
|
|
|
|
input wire move_pod1_en,
|
|
input wire move_pod1_dir,
|
|
input wire move_pod2_en,
|
|
input wire move_pod2_dir,
|
|
|
|
output reg [7:0] score1,
|
|
output reg [7:0] score2,
|
|
input wire clear_score,
|
|
|
|
output reg hit,
|
|
output reg miss
|
|
);
|
|
|
|
reg [15:0] rnd;
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
rnd <= 16'hACE1;
|
|
end
|
|
else
|
|
begin
|
|
rnd <= { rnd[14:0], rnd[15] ^ rnd[13] ^ rnd[12] ^ rnd[10] };
|
|
end
|
|
end
|
|
|
|
// -----------
|
|
|
|
localparam GS_FROZEN = 0;
|
|
localparam GS_RUNNING = 1;
|
|
localparam GS_SCORING = 2;
|
|
localparam GS_GAME_OVER = 3;
|
|
|
|
wire restart = (next_game_state == GS_FROZEN) && (game_state == GS_GAME_OVER);
|
|
|
|
reg [1:0] next_game_state;
|
|
always @(*)
|
|
begin
|
|
case (game_state)
|
|
default : next_game_state <= start ? GS_RUNNING : GS_FROZEN;
|
|
GS_RUNNING : next_game_state <= (bally > SCREEN_HEIGHT - 5) ? GS_SCORING : GS_RUNNING;
|
|
GS_SCORING : next_game_state <= GS_GAME_OVER;
|
|
GS_GAME_OVER : next_game_state <= acknowledge ? GS_FROZEN : GS_GAME_OVER;
|
|
endcase
|
|
end
|
|
|
|
reg [1:0] game_state;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
game_state <= GS_FROZEN;
|
|
end
|
|
else
|
|
begin
|
|
game_state <= next_game_state;
|
|
end
|
|
end
|
|
|
|
wire game_running = (game_state == GS_RUNNING);
|
|
|
|
// -----------
|
|
|
|
reg speed_boost;
|
|
reg [2:0] speed_vec;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart)
|
|
begin
|
|
speed_boost <= 1'b0;
|
|
speed_vec <= rnd[15:14];
|
|
hit <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if (((ballx == (SCREEN_WIDTH - 1)) && (speed_vec[0] == 1'b1)) ||
|
|
((ballx == 0) && (speed_vec[0] == 1'b0)) ||
|
|
((bally > (SCREEN_HEIGHT - WALL_HEIGHT - 1)) &&
|
|
(((ballx == (SCREEN_WIDTH / 2 - 1)) && (speed_vec[0] == 1'b1)) || ((ballx == (SCREEN_WIDTH / 2)) && (speed_vec[0] == 1'b0)))))
|
|
begin
|
|
speed_vec[0] <= ~speed_vec[0];
|
|
end
|
|
|
|
if ((bally == 0) && (speed_vec[1] == 1'b0))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
end
|
|
|
|
hit <= 1'b0;
|
|
|
|
if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && (((ballx > pod1x) && (ballx < (pod1x + POD_WIDTH)))))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
|
|
speed_boost <= move_pod1_en;
|
|
|
|
hit <= 1'b1;
|
|
end
|
|
|
|
if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && ((ballx > pod2x) && (ballx < (pod2x + POD_WIDTH))))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
|
|
speed_boost <= move_pod2_en;
|
|
|
|
hit <= 1'b1;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
// -----------------
|
|
|
|
reg [N_SIMDIV - 1:0] sim_cntr;
|
|
reg [N_SIMDIV - 1:0] sim_cntr_max;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
sim_cntr <= 0;
|
|
sim_cntr_max <= SIMDIV - 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if (sim_cntr == sim_cntr_max)
|
|
begin
|
|
sim_cntr_max <= speed_boost ? ((SIMDIV / 2) - 1'b1) : (SIMDIV - 1'b1);
|
|
sim_cntr <= 0;
|
|
end
|
|
else
|
|
begin
|
|
sim_cntr <= sim_cntr + 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
wire sim_step = game_running && (sim_cntr == sim_cntr_max);
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart)
|
|
begin
|
|
ballx <= BALL_START_X + rnd[8:0] - 8'd255;
|
|
bally <= BALL_START_Y + rnd[13:9] - 5'd16;
|
|
end
|
|
else
|
|
begin
|
|
if (sim_step)
|
|
begin
|
|
ballx <= speed_vec[0] ? (ballx + 1'b1) : (ballx - 1'b1);
|
|
bally <= speed_vec[1] ? (bally + 1'b1) : (bally - 1'b1);
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart)
|
|
begin
|
|
pod1x <= POD1_START_X;
|
|
pod2x <= POD2_START_X;
|
|
end
|
|
else if (sim_step)
|
|
begin
|
|
if (move_pod1_en)
|
|
begin
|
|
if (move_pod1_dir && (pod1x < ((SCREEN_WIDTH / 2) - POD_WIDTH - WALL_HALF_WIDTH))) // jobbra mozgatás
|
|
begin
|
|
pod1x <= pod1x + 1'b1;
|
|
end
|
|
else if ((!move_pod1_dir) && (pod1x > 0)) // balra mozgatás
|
|
begin
|
|
pod1x <= pod1x - 1'b1;
|
|
end
|
|
end
|
|
|
|
if (move_pod2_en)
|
|
begin
|
|
if (move_pod2_dir && (pod2x < (SCREEN_WIDTH - POD_WIDTH))) // jobbra mozgatás
|
|
begin
|
|
pod2x <= pod2x + 1'b1;
|
|
end
|
|
else if ((!move_pod2_dir) && (pod2x > ((SCREEN_WIDTH / 2) + WALL_HALF_WIDTH))) // balra mozgatás
|
|
begin
|
|
pod2x <= pod2x - 1'b1;
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function [7:0] bcd_inc;
|
|
input [7:0] a;
|
|
begin
|
|
bcd_inc = (a[3:0] == 4'd9) ? { a[7:4] + 4'd1, 4'd0 } : a + 8'd1;
|
|
end
|
|
endfunction
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || clear_score)
|
|
begin
|
|
score1 <= 8'h00;
|
|
score2 <= 8'h00;
|
|
end
|
|
else if (game_state == GS_SCORING)
|
|
begin
|
|
if (ballx >= (SCREEN_WIDTH / 2))
|
|
begin
|
|
score1 <= bcd_inc(score1);
|
|
end
|
|
else
|
|
begin
|
|
score2 <= bcd_inc(score2);
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
miss <= 1'b0;
|
|
end
|
|
else if (game_state == GS_SCORING)
|
|
begin
|
|
miss <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
miss <= 1'b0;
|
|
end
|
|
end
|
|
|
|
endmodule
|