From d1d0f6b409b636da0d147cb44ab258b4bd810913 Mon Sep 17 00:00:00 2001 From: Epagris Date: Tue, 4 Nov 2025 22:47:49 +0100 Subject: [PATCH] init --- ball2.png | Bin 0 -> 511 bytes beep.v | 103 ++++++++++++++ cdc.v | 27 ++++ clk_gen.v | 349 ++++++++++++++++++++++++++++++++++++++++++++++ game_controller.v | 271 +++++++++++++++++++++++++++++++++++ key_matcher.v | 114 +++++++++++++++ pp_top.v | 238 +++++++++++++++++++++++++++++++ ps2_host.v | 108 ++++++++++++++ sseg_disp.v | 105 ++++++++++++++ vga.v | 317 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1632 insertions(+) create mode 100644 ball2.png create mode 100644 beep.v create mode 100644 cdc.v create mode 100644 clk_gen.v create mode 100644 game_controller.v create mode 100644 key_matcher.v create mode 100644 pp_top.v create mode 100644 ps2_host.v create mode 100644 sseg_disp.v create mode 100644 vga.v diff --git a/ball2.png b/ball2.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed9a7d175c098be5a6f496fe5a890eac06d4697 GIT binary patch literal 511 zcmVP000>X1^@s6#OZ}&00004b3#c}2nYxW zd3KE`-ns$Ps821TCKve ztk+1h*>rq(TlglFOeV2jue}jfRUg6~i{FG2i3GOW?IY6b^;~!G2|`3D6bepczu!ZW zB;NqLJDtuiQm@y22Z#uqb6hSL2h7Twi=XpAQU~&1P3*I2;B7$g=F5!m=#;3WP!-EEWqVvfJ%m{%Zfz zx~@A%yztc_ILC zI-St%c2O)A5sgM62*NFtF@{Vg165TqpU SCREEN_HEIGHT - 5) ? GS_SCORING : GS_RUNNING; + GS_SCORING : next_game_state <= GS_GAME_OVER; + GS_GAME_OVER : next_game_state <= acknowledge ? GS_FROZEN : GS_GAME_OVER; + endcase +end + +reg [1:0] game_state; +always @(posedge clk) +begin + if (rst) + begin + game_state <= GS_FROZEN; + end + else + begin + game_state <= next_game_state; + end +end + +wire game_running = (game_state == GS_RUNNING); + +// ----------- + +reg speed_boost; +reg [2:0] speed_vec; +always @(posedge clk) +begin + if (rst || restart) + begin + speed_boost <= 1'b0; + speed_vec <= rnd[15:14]; + hit <= 1'b0; + end + else + begin + if (((ballx == (SCREEN_WIDTH - 1)) && (speed_vec[0] == 1'b1)) || + ((ballx == 0) && (speed_vec[0] == 1'b0)) || + ((bally > (SCREEN_HEIGHT - WALL_HEIGHT - 1)) && + (((ballx == (SCREEN_WIDTH / 2 - 1)) && (speed_vec[0] == 1'b1)) || ((ballx == (SCREEN_WIDTH / 2)) && (speed_vec[0] == 1'b0))))) + begin + speed_vec[0] <= ~speed_vec[0]; + end + + if ((bally == 0) && (speed_vec[1] == 1'b0)) + begin + speed_vec[1] <= ~speed_vec[1]; + end + + hit <= 1'b0; + + if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && (((ballx > pod1x) && (ballx < (pod1x + POD_WIDTH))))) + begin + speed_vec[1] <= ~speed_vec[1]; + + speed_boost <= move_pod1_en; + + hit <= 1'b1; + end + + if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && ((ballx > pod2x) && (ballx < (pod2x + POD_WIDTH)))) + begin + speed_vec[1] <= ~speed_vec[1]; + + speed_boost <= move_pod2_en; + + hit <= 1'b1; + end + + end +end + +// ----------------- + +reg [N_SIMDIV - 1:0] sim_cntr; +reg [N_SIMDIV - 1:0] sim_cntr_max; +always @(posedge clk) +begin + if (rst) + begin + sim_cntr <= 0; + sim_cntr_max <= SIMDIV - 1'b1; + end + else + begin + if (sim_cntr == sim_cntr_max) + begin + sim_cntr_max <= speed_boost ? ((SIMDIV / 2) - 1'b1) : (SIMDIV - 1'b1); + sim_cntr <= 0; + end + else + begin + sim_cntr <= sim_cntr + 1'b1; + end + end +end + +wire sim_step = game_running && (sim_cntr == sim_cntr_max); + +always @(posedge clk) +begin + if (rst || restart) + begin + ballx <= BALL_START_X + rnd[8:0] - 8'd255; + bally <= BALL_START_Y + rnd[13:9] - 5'd16; + end + else + begin + if (sim_step) + begin + ballx <= speed_vec[0] ? (ballx + 1'b1) : (ballx - 1'b1); + bally <= speed_vec[1] ? (bally + 1'b1) : (bally - 1'b1); + end + end +end + +always @(posedge clk) +begin + if (rst || restart) + begin + pod1x <= POD1_START_X; + pod2x <= POD2_START_X; + end + else if (sim_step) + begin + if (move_pod1_en) + begin + if (move_pod1_dir && (pod1x < ((SCREEN_WIDTH / 2) - POD_WIDTH - WALL_HALF_WIDTH))) // jobbra mozgatás + begin + pod1x <= pod1x + 1'b1; + end + else if ((!move_pod1_dir) && (pod1x > 0)) // balra mozgatás + begin + pod1x <= pod1x - 1'b1; + end + end + + if (move_pod2_en) + begin + if (move_pod2_dir && (pod2x < (SCREEN_WIDTH - POD_WIDTH))) // jobbra mozgatás + begin + pod2x <= pod2x + 1'b1; + end + else if ((!move_pod2_dir) && (pod2x > ((SCREEN_WIDTH / 2) + WALL_HALF_WIDTH))) // balra mozgatás + begin + pod2x <= pod2x - 1'b1; + end + end + + end +end + +function [7:0] bcd_inc; + input [7:0] a; + begin + bcd_inc = (a[3:0] == 4'd9) ? { a[7:4] + 4'd1, 4'd0 } : a + 8'd1; + end +endfunction + +always @(posedge clk) +begin + if (rst || clear_score) + begin + score1 <= 8'h00; + score2 <= 8'h00; + end + else if (game_state == GS_SCORING) + begin + if (ballx >= (SCREEN_WIDTH / 2)) + begin + score1 <= bcd_inc(score1); + end + else + begin + score2 <= bcd_inc(score2); + end + end +end + +always @(posedge clk) +begin + if (rst) + begin + miss <= 1'b0; + end + else if (game_state == GS_SCORING) + begin + miss <= 1'b1; + end + else + begin + miss <= 1'b0; + end +end + +endmodule diff --git a/key_matcher.v b/key_matcher.v new file mode 100644 index 0000000..5d34e49 --- /dev/null +++ b/key_matcher.v @@ -0,0 +1,114 @@ +module key_matcher( + input wire clk, + input wire rst, + + input wire [7:0] scan_code, + input wire sc_valid, + + output reg [6:0] key_states +); + +// --------------- + +localparam SC_A = 8'h1C; +localparam SC_D = 8'h23; +localparam SC_N4 = 8'h6B; +localparam SC_N6 = 8'h74; +localparam SC_N = 8'h31; +localparam SC_M = 8'h3A; +localparam SC_ESC = 8'h76; + +localparam SC_REL = 8'hF0; + +// ------------- + +reg [15:0] shr; +always @(posedge clk) +begin + if (rst) + begin + shr <= 16'b0; + end + else if (sc_valid) + begin + shr <= { shr[7:0], scan_code }; + end +end + +wire [7:0] b0 = shr[7:0]; +wire [7:0] b1 = shr[15:8]; + +always @(posedge clk) +begin + if (rst) + begin + key_states <= 6'b0; + end + else + begin + if ((b0 == SC_A) && (b1 != SC_REL)) + begin + key_states[0] <= 1'b1; + end + else if ((b0 == SC_A) && (b1 == SC_REL)) + begin + key_states[0] <= 1'b0; + end + + else if ((b0 == SC_D) && (b1 != SC_REL)) + begin + key_states[1] <= 1'b1; + end + else if ((b0 == SC_D) && (b1 == SC_REL)) + begin + key_states[1] <= 1'b0; + end + + else if ((b0 == SC_N4) && (b1 != SC_REL)) + begin + key_states[2] <= 1'b1; + end + else if ((b0 == SC_N4) && (b1 == SC_REL)) + begin + key_states[2] <= 1'b0; + end + + else if ((b0 == SC_N6) && (b1 != SC_REL)) + begin + key_states[3] <= 1'b1; + end + else if ((b0 == SC_N6) && (b1 == SC_REL)) + begin + key_states[3] <= 1'b0; + end + + else if ((b0 == SC_N) && (b1 != SC_REL)) + begin + key_states[4] <= 1'b1; + end + else if ((b0 == SC_N) && (b1 == SC_REL)) + begin + key_states[4] <= 1'b0; + end + + else if ((b0 == SC_M) && (b1 != SC_REL)) + begin + key_states[5] <= 1'b1; + end + else if ((b0 == SC_M) && (b1 == SC_REL)) + begin + key_states[5] <= 1'b0; + end + + else if ((b0 == SC_ESC) && (b1 != SC_REL)) + begin + key_states[6] <= 1'b1; + end + else if ((b0 == SC_ESC) && (b1 == SC_REL)) + begin + key_states[6] <= 1'b0; + end + end +end + +endmodule diff --git a/pp_top.v b/pp_top.v new file mode 100644 index 0000000..9495cac --- /dev/null +++ b/pp_top.v @@ -0,0 +1,238 @@ +module pp_top( + input wire clk, + input wire rst_n, + + output wire [4:0] vga_sigs, + + output wire [3:0] leds_n, + input wire [3:0] btns_n, + output wire [7:0] segs_n, + output wire [3:0] digs_n, + input wire ps2_ck, + input wire ps2_dat, + output wire beep_n +); + +// bemenetek-kimenetek ponált-negált átalakítása +wire rst = ~rst_n; +wire [3:0] btns = ~btns_n; +assign leds_n = ~leds; + +// 65MHz és 1MHz órajelgenerátor +wire clk65M; +wire clk1M; +wire locked; + +reg srst; + +clk_gen main_clk_gen( + .areset(rst), + .inclk0(clk), + .c0(clk65M), + .c1(clk1M), + .locked(locked) +); + +// ----------- + +wire [7:0] data; +wire valid; +ps2_host ps2( + .clk(clk1M), + .rst(srst), + + .ps2_ck(ps2_ck), + .ps2_dat(ps2_dat), + + .data(data), + .valid(valid), + .ack(1'b1) +); + +//always @(posedge clk1M) +//begin +// if (rst) +// begin +// d <= 16'b0; +// end +// else if (valid) +// begin +// d <= { d[7:0], data }; +// end +//end + +// ----------- + +wire [6:0] ks; +key_matcher km( + .clk(clk1M), + .rst(rst), + + .scan_code(data), + .sc_valid(valid), + .key_states(ks) +); + +// ----------- + +// Játéklogika +wire [9:0] ballx; +wire [9:0] bally; +wire [9:0] pod1x; +wire [9:0] pod2x; +wire [7:0] score1; +wire [7:0] score2; +wire hit; +wire miss; + +game_controller game ( + .clk(clk1M), + .rst(srst), + + .start(ks[4]), + .acknowledge(ks[5]), + + .pod1x(pod1x), + .pod2x(pod2x), + .ballx(ballx), + .bally(bally), + + .move_pod1_en(ks[0] ^ ks[1]), + .move_pod1_dir(ks[1]), + .move_pod2_en(ks[2] ^ ks[3]), + .move_pod2_dir(ks[3]), + + .score1(score1), + .score2(score2), + .clear_score(ks[6]), + + .hit(hit), + .miss(miss) +); + +wire beep; +assign beep_n = ~beep; + +beep beeper( + .clk(clk1M), + .rst(srst), + + .hit(hit), + .miss(miss), + .beep(beep) +); + +// VGA renderer +wire hsync; +wire vsync; +wire [2:0] rgb; +vga /* #( + .COLS(800), + .ROWS(600), + .H_FRONT_PORCH(40), + .H_SYNC_PULSE(128), + .H_BACK_PORCH(88), + .V_FRONT_PORCH(1), + .V_SYNC_PULSE(4), + .V_BACK_PORCH(23), + .H_SYNC_NEG(0), + .V_SYNC_NEG(0) +) */ vga ( + .pclk(clk65M), + .sclk(clk1M), + .rst(srst), + + .hsync(hsync), + .vsync(vsync), + .rgb(rgb), + + .pod1x(pod1x), + .pod2x(pod2x), + .ballx(ballx), + .bally(bally) +); + +assign vga_sigs = { hsync, vsync, rgb }; + +// ----------- + +wire [3:0] d0; +wire [3:0] d1; +wire [3:0] d2; +wire [3:0] d3; + +assign { d3, d2, d1, d0 } = { score1, score2 }; + +//reg [15:0] d; +//assign { d3, d2, d1, d0 } = d; + +sseg_disp disp( + .clk(clk1M), + .rst(srst), + + .d0(d0), + .d1(d1), + .d2(d2), + .d3(d3), + + .dps(4'b0100), + + .segs_n(segs_n), + .digs_n(digs_n) +); + + +// ----------- + +reg [19:0] cntr; +always @(posedge clk1M, posedge rst) +begin + if (rst) + begin + cntr <= 0; + end + else + begin + cntr <= cntr + 1; + end +end + +wire tc = &cntr; + +reg reset_issued; +always @(posedge clk1M, posedge rst) +begin + if (rst) + begin + reset_issued <= 1'b0; + srst <= 1'b0; + end + else if (tc && !reset_issued) + begin + srst <= 1'b1; + reset_issued <= 1'b1; + end + else + begin + srst <= 1'b0; + end +end + +// ----------- + +//always @(posedge clk1M) +//begin +// if (rst) +// begin +// ld0 <= 0; +// end +// else if (tc) +// begin +// ld0 <= ~ld0; +// end +//end + + +wire [3:0] leds = ks[3:0]; + +endmodule \ No newline at end of file diff --git a/ps2_host.v b/ps2_host.v new file mode 100644 index 0000000..9fab8d7 --- /dev/null +++ b/ps2_host.v @@ -0,0 +1,108 @@ +module ps2_host ( + input wire clk, + input wire rst, + + input wire ps2_ck, + input wire ps2_dat, + + output reg [7:0] data, + output reg valid, + input wire ack +); + +reg prev_ps2_ck; +always @(posedge clk) +begin + if (rst) + begin + prev_ps2_ck <= 1'b1; + end + else + begin + prev_ps2_ck <= ps2_ck; + end +end + +wire ck_fallen = !prev_ps2_ck && !ps2_ck; +wire ck_risen = prev_ps2_ck && ps2_ck; + +reg ck_state, prev_ck_state; +always @(posedge clk) +begin + if (rst) + begin + ck_state <= 1'b1; + prev_ck_state <= 1'b1; + end + else + begin + if (ck_state && ck_fallen) + begin + ck_state <= 1'b0; + end + else if (!ck_state && ck_risen) + begin + ck_state <= 1'b1; + end + + prev_ck_state <= ck_state; + end +end + +wire ck_falling = prev_ck_state && !ck_state; + +reg [3:0] cntr; +always @(posedge clk) +begin + if (rst) + begin + cntr <= 4'b0; + end + else if (ck_falling) + begin + cntr <= cntr + 4'b1; + end + else if (cntr == 4'd11) + begin + cntr <= 4'b0; + end +end + +reg [10:0] shr; +always @(posedge clk) +begin + if (rst) + begin + shr <= 11'b0; + end + else if (ck_falling) + begin + shr <= { ps2_dat, shr[10:1] }; + end +end + +always @(posedge clk) +begin + if (rst) + begin + data <= 8'b0; + valid <= 1'b0; + end + else + begin + if (valid && ack) + begin + valid <= 1'b0; + end + + if (cntr == 4'd11) + begin + data <= shr[8:1]; + valid <= 1'b1; + end + end +end + + + +endmodule diff --git a/sseg_disp.v b/sseg_disp.v new file mode 100644 index 0000000..77f93e3 --- /dev/null +++ b/sseg_disp.v @@ -0,0 +1,105 @@ +module sseg_disp #( + parameter TMUX_DIV = 100, + parameter N_TMUX_DIV = $clog2(TMUX_DIV) +)( + input wire clk, + input wire rst, + + input wire [3:0] d0, + input wire [3:0] d1, + input wire [3:0] d2, + input wire [3:0] d3, + + input wire [3:0] dps, + + output reg [8:0] segs_n, + output wire [3:0] digs_n +); + + +reg [N_TMUX_DIV - 1:0] cntr; +always @(posedge clk) +begin + if (rst) + begin + cntr <= 0; + end + else + begin + if (cntr == (TMUX_DIV - 1)) + begin + cntr <= 0; + end + else + begin + cntr <= cntr + 1; + end + end +end + +wire dig_step = cntr == (TMUX_DIV - 1); + +reg [3:0] dig_sel; +always @(posedge clk) +begin + if (rst) + begin + dig_sel <= 4'b0001; + end + else + begin if (dig_step) + dig_sel <= { dig_sel[2:0], dig_sel[3] }; + end +end + +assign digs_n = ~dig_sel; + +reg [1:0] dig_cntr; +always @(posedge clk) +begin + if (rst) + begin + dig_cntr <= 2'b0; + end + else + begin if (dig_step) + dig_cntr <= dig_cntr + 2'b1; + end +end + +reg [3:0] data; +always @(*) +begin + case (dig_cntr) + default : data <= d0; + 2'd1 : data <= d1; + 2'd2 : data <= d2; + 2'd3 : data <= d3; + endcase +end + +wire [7:0] dp_n = dps[dig_cntr] ? 8'h7F : 8'hFF; + +always @(*) +begin + case (data) + 4'h0 : segs_n <= 8'hc0 & dp_n; + 4'h1 : segs_n <= 8'hf9 & dp_n; + 4'h2 : segs_n <= 8'ha4 & dp_n; + 4'h3 : segs_n <= 8'hb0 & dp_n; + 4'h4 : segs_n <= 8'h99 & dp_n; + 4'h5 : segs_n <= 8'h92 & dp_n; + 4'h6 : segs_n <= 8'h82 & dp_n; + 4'h7 : segs_n <= 8'hf8 & dp_n; + 4'h8 : segs_n <= 8'h80 & dp_n; + 4'h9 : segs_n <= 8'h90 & dp_n; + 4'ha : segs_n <= 8'h88 & dp_n; + 4'hb : segs_n <= 8'h83 & dp_n; + 4'hc : segs_n <= 8'hc6 & dp_n; + 4'hd : segs_n <= 8'ha1 & dp_n; + 4'he : segs_n <= 8'h86 & dp_n; + 4'hf : segs_n <= 8'h8e & dp_n; + endcase +end + +endmodule diff --git a/vga.v b/vga.v new file mode 100644 index 0000000..7f965c3 --- /dev/null +++ b/vga.v @@ -0,0 +1,317 @@ +`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