`timescale 1ns/1ps module vga #( parameter COLS = 1024, // oszlopok száma a képernyőn parameter ROWS = 768, // sorok száma a képernyőn 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, // színek (BGR) parameter COL_POD1 = 3'b001, parameter COL_POD2 = 3'b010, parameter COL_BALL = 3'b011, parameter COL_BG = 3'b000, // platformok tulajdonságai parameter POD_WIDTH = COLS / 6, parameter POD_HEIGHT = ROWS / 32, parameter POD_TOP = ROWS - 50, // középső fal tulajdonságai parameter WALL_HALF_WIDTH = 4, parameter WALL_HEIGHT = ROWS / 3, // bithosszok parameter N_COLS = $clog2(H_FULL), parameter N_ROWS = $clog2(V_FULL) )( input wire pclk, // pixel órajel (65MHz) input wire sclk, // lassú órajel (1MHz) 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'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