go-board-code/pong.v

182 lines
4.1 KiB
Verilog

module Pong(
input i_Clk,
input i_HSync,
input i_VSync,
input i_GameStart,
input i_Player1_Up,
input i_Player1_Down,
input i_Player2_Up,
input i_Player2_Down,
output reg o_HSync,
output reg o_VSync,
output [2:0] o_Red,
output [2:0] o_Green,
output [2:0] o_Blue
);
parameter TOTAL_COLUMNS = 800;
parameter TOTAL_ROWS = 525;
parameter ACTIVE_COLUMNS = 640;
parameter ACTIVE_ROWS = 480;
localparam SCREEN_WIDTH_CELLS = 40;
localparam SCREEN_HEIGHT_CELLS = 30;
localparam SCORE_LIMIT = 9;
localparam PADDLE_HEIGHT = 6;
localparam PADDLE_PLAYER1_X = 0;
localparam PADDLE_PLAYER2_X = SCREEN_WIDTH_CELLS - 1;
localparam STATE_IDLE = 0;
localparam STATE_RUNNING = 1;
localparam STATE_P1_WINNER = 2;
localparam STATE_P2_WINNER = 3;
localparam STATE_CLEANUP = 4;
reg [2:0] r_currentState = STATE_IDLE;
wire w_HSync, w_VSync;
wire [9:0] w_X, w_Y;
wire w_P1_DoDrawPaddle, w_P2_DoDrawPaddle;
wire [5:0] w_P1_PaddleY, w_P2_PaddleY;
wire w_DoDrawBall, w_DrawAny;
wire [5:0] w_BallX, w_BallY;
wire w_IsGameActive;
reg [3:0] r_P1_Score = 0;
reg [3:0] r_P2_Score = 0;
wire [5:0] w_CellX, w_CellY;
VGA_Current_Beam_Position #(
.TOTAL_COLUMNS(TOTAL_COLUMNS),
.TOTAL_ROWS(TOTAL_ROWS)
) CurrentPosition (
.i_Clk(i_Clk),
.i_HSync(i_HSync),
.i_VSync(i_VSync),
.o_HSync(w_HSync),
.o_VSync(w_VSync),
.o_X(w_X),
.o_Y(w_Y)
);
always @(posedge i_Clk) begin
o_HSync <= w_HSync;
o_VSync <= w_VSync;
end
// right shift 4
assign w_CellX = w_X[9:4];
assign w_CellY = w_Y[9:4];
// paddles
PongPaddle #(
.X_POS_CELLS(PADDLE_PLAYER1_X),
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS),
.PADDLE_HEIGHT_CELLS(PADDLE_HEIGHT)
) P1_Paddle (
.i_Clk(i_Clk),
.i_CellX(w_CellX),
.i_CellY(w_CellY),
.i_PaddleUp(i_Player1_Up),
.i_PaddleDown(i_Player1_Down),
.o_DoDrawPaddle(w_P1_DoDrawPaddle),
.o_PaddleY(w_P1_PaddleY)
);
PongPaddle #(
.X_POS_CELLS(PADDLE_PLAYER2_X),
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS),
.PADDLE_HEIGHT_CELLS(PADDLE_HEIGHT)
) P2_Paddle (
.i_Clk(i_Clk),
.i_CellX(w_CellX),
.i_CellY(w_CellY),
.i_PaddleUp(i_Player2_Up),
.i_PaddleDown(i_Player2_Down),
.o_DoDrawPaddle(w_P2_DoDrawPaddle),
.o_PaddleY(w_P2_PaddleY)
);
PongBall #(
.SCREEN_WIDTH_CELLS(SCREEN_WIDTH_CELLS),
.SCREEN_HEIGHT_CELLS(SCREEN_HEIGHT_CELLS)
) Ball (
.i_Clk(i_Clk),
.i_IsGameActive(w_IsGameActive),
.i_CellX(w_CellX),
.i_CellY(w_CellY),
.o_DoDrawBall(w_DoDrawBall),
.o_BallX(w_BallX),
.o_BallY(w_BallY)
);
always @(posedge i_Clk) begin
case (r_currentState)
STATE_IDLE:
begin
if (i_GameStart) begin
r_currentState <= STATE_RUNNING;
end
end
STATE_RUNNING:
begin
if (
w_BallX == 0 && (
w_BallY < w_P1_PaddleY ||
w_BallY > w_P1_PaddleY + PADDLE_HEIGHT
)
) begin
r_currentState <= STATE_P1_WINNER;
end else if (
w_BallX == SCREEN_WIDTH_CELLS - 1 && (
w_BallY < w_P2_PaddleY ||
w_BallY > w_P2_PaddleY + PADDLE_HEIGHT
)
) begin
r_currentState <= STATE_P2_WINNER;
end
end
STATE_P1_WINNER:
begin
if (r_P1_Score == SCORE_LIMIT - 1) begin
r_P1_Score <= 0;
end else begin
r_P1_Score <= r_P1_Score + 1;
r_currentState <= STATE_CLEANUP;
end
end
STATE_P2_WINNER:
begin
if (r_P2_Score == SCORE_LIMIT - 1) begin
r_P2_Score <= 0;
end else begin
r_P2_Score <= r_P2_Score + 1;
r_currentState <= STATE_CLEANUP;
end
end
STATE_CLEANUP:
begin
r_currentState <= STATE_IDLE;
end
endcase
end
assign w_IsGameActive = (r_currentState == STATE_RUNNING) ? 1 : 0;
assign w_DrawAny = w_DoDrawBall | w_P1_DoDrawPaddle | w_P2_DoDrawPaddle;
assign o_Red = w_DrawAny ? 7 : 0;
assign o_Green = w_DrawAny ? 7 : 0;
assign o_Blue = w_DrawAny ? 7 : 0;
endmodule