328 lines
7.5 KiB
Coq
328 lines
7.5 KiB
Coq
module Arkanoid
|
|
|
|
#(
|
|
// Parameters
|
|
parameter SCREEN_WIDTH = 640, // Horizontal screen resolution (in pixels)
|
|
parameter SCREEN_HEIGHT = 480, // Vertical screen resolution (in pixels)
|
|
|
|
parameter CELL_SIZE = 20, // 1 cell has size of 20x20 pixels.
|
|
|
|
parameter BALL_SIZE = 1, // Game ball is a square of side 1 cell
|
|
parameter BALL_SPEED = 2, // Number of cells per second
|
|
|
|
parameter PLATFORM_WIDTH = 8, // Game platform width
|
|
parameter PLATFORM_SPEED = 1, // Number of cells per second
|
|
|
|
parameter [3:0] BK_COLOR_R = 4'b1111, // Red background
|
|
parameter [3:0] BK_COLOR_G = 4'b0000,
|
|
parameter [3:0] BK_COLOR_B = 4'b0000,
|
|
|
|
parameter [3:0] STABLE_COLOR_R = 4'b0011, // ??? color :)
|
|
parameter [3:0] STABLE_COLOR_G = 4'b1100,
|
|
parameter [3:0] STABLE_COLOR_B = 4'b0110,
|
|
|
|
parameter [3:0] BALL_COLOR_R = 4'b0000, // Blue ball
|
|
parameter [3:0] BALL_COLOR_G = 4'b0000,
|
|
parameter [3:0] BALL_COLOR_B = 4'b1111,
|
|
|
|
parameter [3:0] PLATFORM_COLOR_R = 4'b1111, // Red platforms
|
|
parameter [3:0] PLATFORM_COLOR_G = 4'b0000,
|
|
parameter [3:0] PLATFORM_COLOR_B = 4'b0000
|
|
)
|
|
|
|
(
|
|
// Input Ports
|
|
input clk50MHz, // 50 MHz clock on DE1
|
|
input button1, button2, button3, button4, // 4 buttons on DE1 (left<->right for 2 players)
|
|
|
|
// Output Ports
|
|
output h_sync,
|
|
output v_sync,
|
|
output [3:0] red, green, blue, // Current pixel color (4096 colors = 12 bit)
|
|
output [6:0] num1, num2, num3, num4, // Digital LED's on DE1
|
|
output [7:0] led
|
|
);
|
|
|
|
//////////////////////////////////////
|
|
// **** BEGIN OF MODULE HEADER **** //
|
|
//////////////////////////////////////
|
|
|
|
// Output registers
|
|
reg [3:0] red_, green_, blue_;
|
|
reg [6:0] num1_, num2_, num3_, num4_;
|
|
reg [7:0] led_;
|
|
|
|
localparam FIELD_WIDTH = SCREEN_WIDTH/CELL_SIZE; // Horizontal screen resolution (in cells)
|
|
localparam FIELD_HEIGHT = SCREEN_HEIGHT/CELL_SIZE; // Vertical screen resolution (in cells)
|
|
|
|
// VGA Module
|
|
localparam line = 799;
|
|
localparam frame = 524;
|
|
|
|
// 25 MHz clock
|
|
reg clk25MHz_;
|
|
wire clk25MHz;
|
|
|
|
// 2D array of cells, stores game field state
|
|
reg [1:0] field[0:FIELD_HEIGHT-1][0:FIELD_WIDTH-1];
|
|
|
|
// Possible cell values: (no comments)
|
|
localparam [1:0] EMPTY_CELL = 2'b00;
|
|
localparam [1:0] STABLE_CELL = 2'b11;
|
|
localparam [1:0] BALL_CELL = 2'b01;
|
|
localparam [1:0] PLATFORM_CELL = 2'b10;
|
|
|
|
// ATTENTION!!!
|
|
// All definitions below are in cells only.
|
|
//
|
|
|
|
// Informaton about game ball
|
|
integer ball_position_x; // Current coordinates
|
|
integer ball_position_y;
|
|
reg ball_state; // Current state (0 - stopped, 1 - moving)
|
|
reg [1:0] ball_direction; // Current moving direction
|
|
|
|
// Possible ball directions:
|
|
localparam [1:0] LEFT_UP = 2'b00;
|
|
localparam [1:0] RIGHT_UP = 2'b01;
|
|
localparam [1:0] LEFT_DOWN = 2'b10;
|
|
localparam [1:0] RIGHT_DOWN = 2'b11;
|
|
|
|
// Information about game platforms
|
|
integer platform1_position; // Current position (X axis, left border coordinate)
|
|
integer platform2_position;
|
|
|
|
// VGA variables
|
|
integer h_counter; // Horizontal pixel counter
|
|
integer v_counter; // Vertical pixel counter
|
|
integer h_cell; // Horizontal cell counter
|
|
integer v_cell; // Vertical cell counter
|
|
reg [1:0] current_cell; // Current cell value
|
|
|
|
// Loops variables
|
|
integer i, j;
|
|
|
|
// Last buttons state
|
|
reg button1_state;
|
|
reg button2_state;
|
|
reg button3_state;
|
|
reg button4_state;
|
|
|
|
|
|
////////////////////////////////////
|
|
// **** END OF MODULE HEADER **** //
|
|
////////////////////////////////////
|
|
|
|
// Initialization of all module variables
|
|
initial
|
|
begin
|
|
|
|
// Place ball to the center of the screen
|
|
ball_position_x = FIELD_WIDTH/2;
|
|
ball_position_y = FIELD_HEIGHT/2;
|
|
ball_state = 0;
|
|
|
|
// Place platforms at the center of the borders
|
|
platform1_position = (FIELD_WIDTH-PLATFORM_WIDTH)/2; // central position
|
|
platform2_position = platform1_position;
|
|
|
|
button1_state = 1'b0;
|
|
button2_state = 1'b0;
|
|
button3_state = 1'b0;
|
|
button4_state = 1'b0;
|
|
|
|
h_counter = 0;
|
|
v_counter = 0;
|
|
|
|
for (i = 0; i < FIELD_HEIGHT; i = i + 1)
|
|
for (j = 0; j< FIELD_WIDTH; j = j + 1)
|
|
field[i][j] = EMPTY_CELL;
|
|
|
|
field[ball_position_y][ball_position_x] = BALL_CELL;
|
|
|
|
// Print platforms
|
|
|
|
num1_ = 7'b0000000;
|
|
num2_ = 7'b0000000;
|
|
num3_ = 7'b0000000;
|
|
num4_ = 7'b0000000;
|
|
|
|
end
|
|
|
|
// Frequency divider (50 MHz to 25 MHz, needed for VGA)
|
|
always @ (posedge clk50MHz)
|
|
begin
|
|
clk25MHz_ = ~clk25MHz_;
|
|
end
|
|
|
|
// VGA sync
|
|
always @ (posedge clk25MHz)
|
|
begin
|
|
if(h_counter == line)
|
|
h_counter <= 0;
|
|
else
|
|
h_counter <= (h_counter + 1);
|
|
end
|
|
|
|
always @ (posedge clk25MHz)
|
|
begin
|
|
if (v_counter == frame)
|
|
v_counter <= 0;
|
|
else if (h_counter == line)
|
|
v_counter <= (v_counter + 1);
|
|
end
|
|
|
|
|
|
|
|
always @ (posedge clk25MHz)
|
|
begin
|
|
|
|
if (button1 != button1_state)
|
|
begin
|
|
if (button1 == 1'b1)
|
|
begin
|
|
led_[7] = 1'b1;
|
|
led_[6] = 1'b1;
|
|
if (platform1_position > 0)
|
|
platform1_position = platform1_position - 1;
|
|
end
|
|
else
|
|
begin
|
|
led_[7] = 1'b0;
|
|
led_[6] = 1'b0;
|
|
end
|
|
button1_state = button1;
|
|
end
|
|
|
|
if (button2 != button2_state)
|
|
begin
|
|
if (button2 == 1'b1)
|
|
begin
|
|
led_[5] = 1'b1;
|
|
led_[4] = 1'b1;
|
|
if (platform1_position < FIELD_WIDTH-PLATFORM_WIDTH-1)
|
|
platform1_position = platform1_position + 1;
|
|
end
|
|
else
|
|
begin
|
|
led_[5] = 1'b0;
|
|
led_[4] = 1'b0;
|
|
end
|
|
button2_state = button2;
|
|
end
|
|
|
|
if (button3 != button3_state)
|
|
begin
|
|
if (button3 == 1'b1)
|
|
begin
|
|
led_[3] = 1'b1;
|
|
led_[2] = 1'b1;
|
|
if (platform2_position > 0)
|
|
platform2_position = platform2_position - 1;
|
|
end
|
|
else
|
|
begin
|
|
led_[3] = 1'b0;
|
|
led_[2] = 1'b0;
|
|
end
|
|
button3_state = button3;
|
|
end
|
|
|
|
if (button4 != button4_state)
|
|
begin
|
|
if (button4 == 1'b1)
|
|
begin
|
|
led_[1] = 1'b1;
|
|
led_[0] = 1'b1;
|
|
if (platform2_position < FIELD_WIDTH-PLATFORM_WIDTH-1)
|
|
platform2_position = platform2_position + 1;
|
|
end
|
|
else
|
|
begin
|
|
led_[1] = 1'b0;
|
|
led_[0] = 1'b0;
|
|
end
|
|
button4_state = button4;
|
|
end
|
|
|
|
|
|
for (i = 0; i < FIELD_WIDTH; i = i + 1)
|
|
begin
|
|
if ((i >= platform2_position) && (i <= platform2_position+PLATFORM_WIDTH))
|
|
field[0][i] = PLATFORM_CELL;
|
|
else
|
|
field[0][i] = EMPTY_CELL;
|
|
|
|
if ((i >= platform1_position) && (i <= platform1_position+PLATFORM_WIDTH))
|
|
field[FIELD_HEIGHT-1][i] = PLATFORM_CELL;
|
|
else
|
|
field[FIELD_HEIGHT-1][i] = EMPTY_CELL;
|
|
end
|
|
|
|
|
|
// VGA output
|
|
h_cell = (h_counter-143)/CELL_SIZE;
|
|
v_cell = (v_counter-34)/CELL_SIZE;
|
|
if ((v_counter > 34) && (v_counter < 514) && (h_counter > 143) && (h_counter < 783))
|
|
begin
|
|
|
|
current_cell = field[v_cell][h_cell];
|
|
|
|
case(current_cell)
|
|
|
|
EMPTY_CELL:
|
|
begin
|
|
red_ = BK_COLOR_R;
|
|
green_ = BK_COLOR_G;
|
|
blue_ = BK_COLOR_B;
|
|
end
|
|
|
|
STABLE_CELL:
|
|
begin
|
|
red_ = STABLE_COLOR_R;
|
|
green_ = STABLE_COLOR_G;
|
|
blue_ = STABLE_COLOR_B;
|
|
end
|
|
|
|
BALL_CELL:
|
|
begin
|
|
red_ = BALL_COLOR_R;
|
|
green_ = BALL_COLOR_G;
|
|
blue_ = BALL_COLOR_B;
|
|
end
|
|
|
|
PLATFORM_CELL:
|
|
begin
|
|
red_ = PLATFORM_COLOR_R;
|
|
green_ = PLATFORM_COLOR_G;
|
|
blue_ = PLATFORM_COLOR_B;
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
else
|
|
begin
|
|
red_ = 4'b0000;
|
|
green_ = 4'b0000;
|
|
blue_ = 4'b0000;
|
|
end
|
|
|
|
end
|
|
|
|
assign clk25MHz = clk25MHz_;
|
|
|
|
assign h_sync = ~((h_counter > 0) && (h_counter < 95));
|
|
assign v_sync = ~((v_counter == 0) || (v_counter == 1));
|
|
|
|
assign red = red_;
|
|
assign green = green_;
|
|
assign blue = blue_;
|
|
|
|
assign led = led_;
|
|
assign num1 = num1_;
|
|
assign num2 = num2_;
|
|
assign num3 = num3_;
|
|
assign num4 = num4_;
|
|
|
|
endmodule
|