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