318 lines
7.7 KiB
Verilog
318 lines
7.7 KiB
Verilog
`timescale 1ns/1ps
|
|
|
|
module vga #(
|
|
parameter COLS = 1024,
|
|
parameter ROWS = 768,
|
|
parameter H_FRONT_PORCH = 24,
|
|
parameter H_SYNC_PULSE = 136,
|
|
parameter H_BACK_PORCH = 160,
|
|
parameter V_FRONT_PORCH = 3,
|
|
parameter V_SYNC_PULSE = 6,
|
|
parameter V_BACK_PORCH = 29,
|
|
parameter H_SYNC_NEG = 1'b1,
|
|
parameter V_SYNC_NEG = 1'b1,
|
|
parameter OVERSCAN = 1,
|
|
|
|
parameter COL_POD1 = 3'b001,
|
|
parameter COL_POD2 = 3'b010,
|
|
parameter COL_BALL = 3'b011,
|
|
parameter COL_BG = 3'b000,
|
|
|
|
parameter POD_WIDTH = COLS / 6,
|
|
parameter POD_HEIGHT = ROWS / 32,
|
|
parameter POD_TOP = ROWS - 50,
|
|
|
|
parameter WALL_HALF_WIDTH = 4,
|
|
parameter WALL_HEIGHT = ROWS / 3,
|
|
|
|
parameter N_COLS = $clog2(H_FULL),
|
|
parameter N_ROWS = $clog2(V_FULL)
|
|
)(
|
|
input wire pclk, // pixel órajel
|
|
input wire sclk, // lassú órajel
|
|
input wire rst, // reset
|
|
|
|
output wire hsync, // vízszintes szinkron
|
|
output wire vsync, // függőleges szinkron
|
|
output wire [2:0] rgb, // színjelek
|
|
|
|
input wire [N_COLS - 1:0] pod1x, // első játékos helye
|
|
input wire [N_COLS - 1:0] pod2x, // második játékos helye
|
|
input wire [N_COLS - 1:0] ballx, // a labda X koordinátája
|
|
input wire [N_ROWS - 1:0] bally // a labda Y koordinátája
|
|
);
|
|
|
|
localparam H_FULL = COLS + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;
|
|
localparam V_FULL = ROWS + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;
|
|
|
|
localparam BALL_RADIUS = 12;
|
|
//localparam [0:25*25-1] BALL_GLYPH = {
|
|
// 25'b0000000000000000000000000,
|
|
// 25'b0000000001111111100000000,
|
|
// 25'b0000001111111111111000000,
|
|
// 25'b0000011111111111111100000,
|
|
// 25'b0000111111111111111110000,
|
|
// 25'b0001111111111111111111000,
|
|
// 25'b0011111111111111111111100,
|
|
// 25'b0011111111111111111111110,
|
|
// 25'b0111111111111111111111110,
|
|
// 25'b0111111111111111111111110,
|
|
// 25'b0111111111111111111111110,
|
|
// 25'b0111111111111111111111111,
|
|
// 25'b0111111111111111111111111,
|
|
// 25'b0111111111111111111111111,
|
|
// 25'b0111111111111111111111111,
|
|
// 25'b0111111111111111111111110,
|
|
// 25'b0111111111111111111111110,
|
|
// 25'b0011111111111111111111110,
|
|
// 25'b0011111111111111111111100,
|
|
// 25'b0001111111111111111111100,
|
|
// 25'b0000111111111111111111000,
|
|
// 25'b0000111111111111111110000,
|
|
// 25'b0000001111111111111100000,
|
|
// 25'b0000000111111111110000000,
|
|
// 25'b0000000000111110000000000
|
|
//};
|
|
|
|
localparam [0:25*25-1] BALL_GLYPH = {
|
|
25'b0000000000000000000000000,
|
|
25'b0000000001111111100000000,
|
|
25'b0000001111111111111000000,
|
|
25'b0000011100111111111100000,
|
|
25'b0000110000011111111110000,
|
|
25'b0001110000011111111111000,
|
|
25'b0011100000111111111111100,
|
|
25'b0011000001111111111111110,
|
|
25'b0111000011111111111111110,
|
|
25'b0110000011111111111111110,
|
|
25'b0110000111111111111111110,
|
|
25'b0111111111111111111111111,
|
|
25'b0111111111111111111111111,
|
|
25'b0111111111111111111111111,
|
|
25'b0111111111111111111111111,
|
|
25'b0111111111111111111111110,
|
|
25'b0111111111111111111111110,
|
|
25'b0011111111111111111111110,
|
|
25'b0011111111111111111111100,
|
|
25'b0001111111111111111111100,
|
|
25'b0000111111111111111111000,
|
|
25'b0000111111111111111110000,
|
|
25'b0000001111111111111100000,
|
|
25'b0000000111111111110000000,
|
|
25'b0000000000111110000000000
|
|
};
|
|
|
|
// -----------
|
|
|
|
reg [N_COLS - 1:0] col; // oszlopszámláló
|
|
reg [N_ROWS - 1:0] row; // sorszámláló
|
|
|
|
// oszlopszámláló
|
|
always @(posedge pclk)
|
|
begin
|
|
col <= (rst || (col == (H_FULL - 1))) ? 0 : (col + 1'b1);
|
|
end
|
|
|
|
wire row_ce = col == (H_FULL - 1); // oszlopszámláló engedélyezés
|
|
|
|
// sorszámláló
|
|
always @(posedge pclk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
row <= 0;
|
|
end
|
|
else if (row_ce)
|
|
begin
|
|
row <= (row == (V_FULL - 1)) ? 0 : (row + 1'b1);
|
|
end
|
|
end
|
|
|
|
wire new_frame = row_ce && (row == (V_FULL - 1));
|
|
|
|
// kijazolási állapotok
|
|
localparam VIS = 0; // látható terület
|
|
localparam NV_FP = 1; // nem látható, front porch
|
|
localparam NV_SYNC = 2; // nem látható, szinkronjel
|
|
localparam NV_BP = 3; // nem látható, back porch
|
|
|
|
reg [1:0] h_state; // vízszintes kirajzolási állapot
|
|
reg [1:0] v_state; // függőleges kirajzolási állapot
|
|
always @(posedge pclk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
h_state = VIS;
|
|
v_state = VIS;
|
|
end
|
|
else
|
|
begin
|
|
h_state <= next_h_state;
|
|
if (row_ce)
|
|
begin
|
|
v_state <= next_v_state;
|
|
end
|
|
end
|
|
end
|
|
|
|
reg [1:0] next_h_state; // következő vízszintes állapot
|
|
reg [1:0] next_v_state; // következő függőleges állapot
|
|
always @(*)
|
|
begin
|
|
case (h_state)
|
|
VIS : next_h_state <= (col == (COLS - 1)) ? NV_FP : VIS;
|
|
NV_FP : next_h_state <= (col == (COLS + H_FRONT_PORCH - 1)) ? NV_SYNC : NV_FP;
|
|
NV_SYNC : next_h_state <= (col == (COLS + H_FRONT_PORCH + H_SYNC_PULSE - 1)) ? NV_BP : NV_SYNC;
|
|
NV_BP : next_h_state <= (col == (H_FULL - 1)) ? VIS : NV_BP;
|
|
endcase
|
|
end
|
|
|
|
always @(*)
|
|
begin
|
|
case (v_state)
|
|
VIS : next_v_state <= (row == (ROWS - 1)) ? NV_FP : VIS;
|
|
NV_FP : next_v_state <= (row == (ROWS + V_FRONT_PORCH - 1)) ? NV_SYNC : NV_FP;
|
|
NV_SYNC : next_v_state <= (row == (ROWS + V_FRONT_PORCH + V_SYNC_PULSE - 1)) ? NV_BP : NV_SYNC;
|
|
NV_BP : next_v_state <= (row == (V_FULL - 1)) ? VIS : NV_BP;
|
|
endcase
|
|
end
|
|
|
|
// vízszintes overscan
|
|
reg h_ovs_visible;
|
|
always @(posedge pclk)
|
|
begin
|
|
h_ovs_visible <= (rst) ? 1'b0 : next_h_ovs_visible;
|
|
end
|
|
|
|
reg next_h_ovs_visible;
|
|
always @(*)
|
|
begin
|
|
case (h_ovs_visible)
|
|
1'b0 : next_h_ovs_visible <= (col == OVERSCAN) ? 1'b1 : 1'b0;
|
|
1'b1 : next_h_ovs_visible <= (col == (COLS - OVERSCAN - 1)) ? 1'b0 : 1'b1;
|
|
endcase
|
|
end
|
|
|
|
// függőleges overscan
|
|
reg v_ovs_visible;
|
|
always @(posedge pclk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
v_ovs_visible <= 1'b0;
|
|
end
|
|
else
|
|
begin if (row_ce)
|
|
v_ovs_visible <= next_v_ovs_visible;
|
|
end
|
|
end
|
|
|
|
reg next_v_ovs_visible;
|
|
always @(*)
|
|
begin
|
|
case (v_ovs_visible)
|
|
1'b0 : next_v_ovs_visible <= (row == OVERSCAN) ? 1'b1 : 1'b0;
|
|
1'b1 : next_v_ovs_visible <= (row == (ROWS - OVERSCAN - 1)) ? 1'b0 : 1'b1;
|
|
endcase
|
|
end
|
|
|
|
// szinkronjelek
|
|
assign hsync = H_SYNC_NEG ? (h_state != NV_SYNC) : (h_state == NV_SYNC);
|
|
assign vsync = V_SYNC_NEG ? (v_state != NV_SYNC) : (v_state == NV_SYNC);
|
|
|
|
// kijelzés
|
|
reg [N_COLS - 1:0] pod1x_;
|
|
reg [N_COLS - 1:0] pod2x_;
|
|
reg [N_COLS - 1:0] ballx_;
|
|
reg [N_ROWS - 1:0] bally_;
|
|
|
|
// bemeneti adatok átvétele
|
|
always @(posedge pclk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
pod1x_ <= 10;
|
|
pod2x_ <= 400;
|
|
ballx_ <= 200;
|
|
bally_ <= 200;
|
|
end
|
|
else if (new_frame)
|
|
begin
|
|
pod1x_ <= pod1x;
|
|
pod2x_ <= pod2x;
|
|
ballx_ <= ballx;
|
|
bally_ <= bally;
|
|
end
|
|
end
|
|
|
|
reg pod_area;
|
|
|
|
// ütők kirajzolási magasságának felismerése
|
|
always @(posedge pclk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
pod_area <= 1'b0;
|
|
end
|
|
else
|
|
begin if (row_ce)
|
|
pod_area <= next_pod_area;
|
|
end
|
|
end
|
|
|
|
reg next_pod_area;
|
|
always @(*)
|
|
begin
|
|
case (pod_area)
|
|
1'b0: next_pod_area <= (row == (POD_TOP - 1)) ? 1'b1 : 1'b0;
|
|
1'b1: next_pod_area <= (row == (POD_TOP + POD_HEIGHT - 1)) ? 1'b0 : 1'b1;
|
|
endcase
|
|
end
|
|
|
|
// teljes játéktér kirajzolása
|
|
reg [2:0] color;
|
|
always @(posedge pclk)
|
|
begin
|
|
// háttérszín
|
|
color <= COL_BG;
|
|
|
|
// labda kirajzolása
|
|
if ((col > ballx_ - BALL_RADIUS - 1) && (col < ballx_ + BALL_RADIUS + 1) &&
|
|
(row > bally_ - BALL_RADIUS - 1) && (row < bally_ + BALL_RADIUS + 1 ))
|
|
begin
|
|
reg [N_COLS:0] rbx;
|
|
reg [N_ROWS:0] rby;
|
|
rbx = col - (ballx_ - BALL_RADIUS);
|
|
rby = row - (bally_ - BALL_RADIUS);
|
|
color <= BALL_GLYPH[rby * 25 + rbx] ? COL_BALL : 3'b000;
|
|
end
|
|
|
|
// fal kirajzolása
|
|
if ((col > (COLS / 2) - WALL_HALF_WIDTH - 1) && (col < (COLS / 2) + WALL_HALF_WIDTH - 1) &&
|
|
(row > (ROWS - WALL_HEIGHT)))
|
|
begin
|
|
color <= 3'b111;
|
|
end
|
|
|
|
// ütők kirajzolása
|
|
if (pod_area)
|
|
begin
|
|
if ((col > pod1x_) && (col < pod1x_ + POD_WIDTH))
|
|
begin
|
|
color <= COL_POD1;
|
|
end
|
|
else if ((col > pod2x_) && (col < pod2x_ + POD_WIDTH))
|
|
begin
|
|
color <= COL_POD2;
|
|
end
|
|
end
|
|
end
|
|
|
|
//wire [2:0] color = (pod_area) ? COL_POD1 : COL_BG;
|
|
|
|
wire visible = h_ovs_visible && v_ovs_visible; // épp látható területen vagyunk?
|
|
|
|
assign rgb = visible ? color : 3'b000; // színinformáció kiadása
|
|
|
|
endmodule
|