blob: d7da62493faab8bd779cf2a4c4e5748cf03b6341 [file]
`timescale 1ns / 1ps
module pong_graph(
input wire clk, reset,
input wire [1:0] btn1,
input wire [1:0] btn2,
input wire [9:0] pix_x, pix_y,
input wire graph_still,
output reg miss, hit_left, hit_right,
output wire graph_on,
output reg [2:0] graph_rgb,
output reg [7:0] left_score, right_score
);
// define constant value here
localparam MAX_X = 640;
localparam MAX_Y = 480;
localparam BALL_SIZE = 8;
localparam BAR_SIZE = 108;
localparam BAR_V = 4;
localparam BAR_LEFT_X = 40;
localparam BAR_RIGHT_X = 600;
localparam BAR_WIDTH = 6;
localparam V_X = 3;
localparam V_X_N = -3;
localparam V_Y = 3;
localparam V_Y_N = -3;
// all about ball
reg [9:0] ball_x, ball_y;
wire [9:0] ball_x_next, ball_y_next;
wire [9:0] ball_right, ball_left, ball_top, ball_bottom;
reg [9:0] x_delta, x_delta_next;
reg [9:0] y_delta, y_delta_next;
wire [2:0] ball_row, ball_col;
reg [7:0] ball_data;
// all about the output rgb
wire bar_on, ball_on;
wire [2:0] bar_rgb, ball_rgb;
// colors
assign bar_rgb = 3'b101; // purple
assign ball_rgb = 3'b100; // red
// bar right & left
reg [9:0] bar_right, bar_right_next;
reg [9:0] bar_left, bar_left_next;
wire [9:0] bar_right_top, bar_right_bottom;
wire [9:0] bar_left_top, bar_left_bottom;
// to judge wether added
reg added;
// refr_tick: 1-clock tick asserted at start of v-sync
// i.e., when the screen is refreshed (60 Hz)
assign refr_tick = (pix_y == 481) && (pix_x == 0);
// keep refreshing all the assistant values
assign ball_right = ball_x + 4;
assign ball_left = ball_x - 3;
assign ball_top = ball_y - 3;
assign ball_bottom = ball_y + 4;
assign ball_x_next = (graph_still) ? MAX_X / 2 :
(refr_tick) ? ball_x + x_delta : ball_x;
assign ball_y_next = (graph_still) ? MAX_Y / 2 :
(refr_tick) ? ball_y + y_delta : ball_y;
assign ball_row = pix_y[2:0] - ball_top[2:0];
assign ball_col = pix_x[2:0] - ball_left[2:0];
assign ball_bit = ball_data[ball_col];
assign ball_on = (ball_left <= pix_x) && (pix_x <= ball_right)
&& (ball_top <= pix_y) && (pix_y <= ball_bottom)
&& ball_bit;
assign bar_right_top = bar_right - BAR_SIZE / 2;
assign bar_right_bottom = bar_right + BAR_SIZE / 2;
assign bar_left_top = bar_left - BAR_SIZE / 2;
assign bar_left_bottom = bar_left + BAR_SIZE / 2;
assign bar_on = ((BAR_LEFT_X <= pix_x) && (pix_x <= BAR_LEFT_X + BAR_WIDTH)
&& (bar_right_top <= pix_y) && (pix_y <= bar_right_bottom))
|| ((BAR_RIGHT_X >= pix_x) && (pix_x >= BAR_RIGHT_X - BAR_WIDTH)
&& (bar_left_top <= pix_y) && (pix_y <= bar_left_bottom));
// provide the ball's data
always @*
case (ball_row)
3'h0: ball_data = 8'b00111100; // ****
3'h1: ball_data = 8'b01111110; // ******
3'h2: ball_data = 8'b11111111; // ********
3'h3: ball_data = 8'b11111111; // ********
3'h4: ball_data = 8'b11111111; // ********
3'h5: ball_data = 8'b11111111; // ********
3'h6: ball_data = 8'b01111110; // ******
3'h7: ball_data = 8'b00111100; // ****
endcase
// move ball and deal reset
always @(posedge clk, posedge reset)
begin
if (reset)
begin
bar_right <= 0;
bar_left <= 0;
ball_x <= 0;
ball_y <= 0;
x_delta <= V_X;
y_delta <= V_Y;
end
else
begin
bar_right <= bar_right_next;
bar_left <= bar_left_next;
ball_x <= ball_x_next;
ball_y <= ball_y_next;
x_delta <= x_delta_next;
y_delta <= y_delta_next;
end
end
// calc the position of bar
always @*
begin
bar_right_next = bar_right;
if (graph_still)
bar_right_next = MAX_Y / 2;
else if (refr_tick)
if (btn1[1] & (bar_right_bottom < (MAX_Y - 1 - BAR_V)))
bar_right_next = bar_right + BAR_V;
else if (btn1[0] & (bar_right_top > BAR_V))
bar_right_next = bar_right - BAR_V;
bar_left_next = bar_left;
if (graph_still)
bar_left_next = MAX_Y / 2;
else if (refr_tick)
if (btn2[1] & (bar_left_bottom < (MAX_Y - 1 - BAR_V)))
bar_left_next = bar_left + BAR_V;
else if (btn2[0] & (bar_left_top > BAR_V))
bar_left_next = bar_left - BAR_V;
end
// deal with the ball's movement
always @(posedge refr_tick, posedge reset)
if (reset) begin
hit_left = 1'b0;
hit_right = 1'b0;
miss = 1'b0;
x_delta_next = V_X;
y_delta_next = V_Y;
right_score = 8'b0;
left_score = 8'b0;
added = 0;
end else begin
hit_left = 1'b0;
hit_right = 1'b0;
miss = 1'b0;
x_delta_next = x_delta;
y_delta_next = y_delta;
if (graph_still)
begin
x_delta_next = V_X;
y_delta_next = V_Y;
hit_right = 1'b0;
hit_left = 1'b0;
miss = 1'b0;
right_score = 8'b0;
left_score = 8'b0;
added = 0;
end
else if (ball_top <= 5)
begin
y_delta_next = V_Y;
hit_right = 1'b0;
hit_left = 1'b0;
added = 0;
end
else if (ball_bottom >= MAX_Y - 5)
begin
y_delta_next = V_Y_N;
hit_right = 1'b0;
hit_left = 1'b0;
added = 0;
end
else if (BAR_LEFT_X <= ball_left && BAR_LEFT_X + BAR_WIDTH >= ball_left - 1
&& ball_top - bar_right + BAR_SIZE / 2 > 0 && bar_right - ball_top + BAR_SIZE / 2 > 0)
begin
hit_left = 1'b1;
hit_right = 1'b0;
x_delta_next = V_X;
if(added == 0)
begin
if(left_score[3:0] == 4'b1001)
begin
left_score[3:0] = 4'b0000;
left_score[7:4] = left_score[7:4] + 1;
end
else
left_score[3:0] = left_score[3:0] + 1;
end
added = 1;
end
else if (BAR_RIGHT_X >= ball_right && BAR_RIGHT_X - BAR_WIDTH <= ball_right + 1
&& ball_top - bar_left + BAR_SIZE / 2 > 0 && bar_left - ball_top + BAR_SIZE / 2 > 0)
begin
hit_right = 1'b1;
hit_left = 1'b0;
x_delta_next = V_X_N;
if(added == 0)
begin
if(right_score[3:0] == 4'h9)
begin
right_score[3:0] = 4'h0;
right_score[7:4] = right_score[7:4] + 1;
end
else
right_score[3:0] = right_score[3:0] + 1;
end
added = 1;
end
else if (ball_right >= MAX_X - 10 || ball_right <= 10)
begin
added = 0;
miss = 1'b1;
hit_right = 1'b0;
hit_left = 1'b0;
right_score = 8'b0;
left_score = 8'b0;
end
end
// assign rgb to the correct color
always @*
begin
if (bar_on)
graph_rgb = bar_rgb;
else if (ball_on)
graph_rgb = ball_rgb;
else
graph_rgb = 3'b000;
end
// decide wether need to display
assign graph_on = bar_on | ball_on;
endmodule