commit d1d0f6b409b636da0d147cb44ab258b4bd810913 Author: Epagris Date: Tue Nov 4 22:47:49 2025 +0100 init diff --git a/ball2.png b/ball2.png new file mode 100644 index 0000000..1ed9a7d Binary files /dev/null and b/ball2.png differ diff --git a/beep.v b/beep.v new file mode 100644 index 0000000..dbf3069 --- /dev/null +++ b/beep.v @@ -0,0 +1,103 @@ +module beep #( + parameter HIT_PERIOD = 1, + parameter HIT_LEN = 150, + parameter MISS_PERIOD = 3, + parameter MISS_LEN = 1400, + parameter HALF_MS_DIV = 500 +)( + input wire clk, + input wire rst, + + input wire hit, + input wire miss, + + output reg beep +); + +reg [8:0] cntr; +always @(posedge clk) +begin + if (rst) + begin + cntr <= 9'd0; + end + else + begin + if (cntr != (HALF_MS_DIV - 1)) + begin + cntr <= cntr + 9'd1; + end + else + begin + cntr <= 9'd0; + end + end +end + +wire tc = (cntr == (HALF_MS_DIV - 1)); + +reg [3:0] period; +reg [3:0] subperiod_cntr; +always @(posedge clk) +begin + if (rst || (!sound_playing)) + begin + beep <= 1'b0; + subperiod_cntr <= 4'd0; + end + else if (sound_playing && tc) + begin + if (subperiod_cntr != period) + begin + subperiod_cntr <= subperiod_cntr + 4'd1; + end + else + begin + subperiod_cntr <= 4'd0; + beep <= ~beep; + end + end + +end + +reg sound_playing; +reg [10:0] len; + +always @(posedge clk) +begin + if (rst) + begin + sound_playing <= 1'b0; + len <= 11'd0; + period <= 4'd0; + end + else if ((!sound_playing) && (hit || miss)) + begin + if (hit) + begin + period <= HIT_PERIOD; + len <= HIT_LEN; + end + else if (miss) + begin + period <= MISS_PERIOD; + len <= MISS_LEN; + end + + sound_playing <= 1'b1; + end + else if (sound_playing && tc) + begin + if (len != 10'd0) + begin + len <= len - 10'd1; + end + else + begin + sound_playing <= 1'b0; + end + end +end + + +endmodule diff --git a/cdc.v b/cdc.v new file mode 100644 index 0000000..158912c --- /dev/null +++ b/cdc.v @@ -0,0 +1,27 @@ +`timescale 1ns / 1ps + +module cdc ( + input tclk, // target domain's clock + input rst, + + input sin, // input data from the source domain + output tout // output data to the target domain +); + +reg [1:0] pipe; +always @(posedge tclk) +begin + if (rst) + begin + pipe <= 0; + end + else + begin + pipe[0] <= sin; + pipe[1] <= pipe[0]; + end +end + +assign tout = pipe[1]; + +endmodule diff --git a/clk_gen.v b/clk_gen.v new file mode 100644 index 0000000..152aa87 --- /dev/null +++ b/clk_gen.v @@ -0,0 +1,349 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: clk_gen.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 23.1std.1 Build 993 05/14/2024 SC Lite Edition +// ************************************************************ + + +//Copyright (C) 2024 Intel Corporation. All rights reserved. +//Your use of Intel Corporation's design tools, logic functions +//and other software and tools, and any partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Intel Program License +//Subscription Agreement, the Intel Quartus Prime License Agreement, +//the Intel FPGA IP License Agreement, or other applicable license +//agreement, including, without limitation, that your use is for +//the sole purpose of programming logic devices manufactured by +//Intel and sold by Intel or its authorized distributors. Please +//refer to the applicable agreement for further details, at +//https://fpgasoftware.intel.com/eula. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module clk_gen ( + areset, + inclk0, + c0, + c1, + locked); + + input areset; + input inclk0; + output c0; + output c1; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [4:0] sub_wire0; + wire sub_wire3; + wire [0:0] sub_wire6 = 1'h0; + wire [1:1] sub_wire2 = sub_wire0[1:1]; + wire [0:0] sub_wire1 = sub_wire0[0:0]; + wire c0 = sub_wire1; + wire c1 = sub_wire2; + wire locked = sub_wire3; + wire sub_wire4 = inclk0; + wire [1:0] sub_wire5 = {sub_wire6, sub_wire4}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire5), + .clk (sub_wire0), + .locked (sub_wire3), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 10, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 13, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 50, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 1, + altpll_component.clk1_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 20000, + altpll_component.intended_device_family = "Cyclone IV E", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=clk_gen", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "65.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "1.000000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "1" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "65.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "1.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "clk_gen.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "10" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "13" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "1" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clk_gen_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/game_controller.v b/game_controller.v new file mode 100644 index 0000000..19284b0 --- /dev/null +++ b/game_controller.v @@ -0,0 +1,271 @@ +module game_controller #( + parameter SCREEN_WIDTH = 1024, + parameter SCREEN_HEIGHT = 768, + + parameter BALL_START_X = SCREEN_WIDTH / 2, + parameter BALL_START_Y = SCREEN_HEIGHT / 6, + //parameter BALL_START_SPEED_VEC = 2'b11, + + parameter POD_TOP = SCREEN_HEIGHT - 50, + parameter POD_WIDTH = SCREEN_WIDTH / 6, + parameter POD1_START_X = (SCREEN_WIDTH / 2 - POD_WIDTH) / 2, + parameter POD2_START_X = POD1_START_X + SCREEN_WIDTH / 2, + + parameter WALL_HALF_WIDTH = 4, + parameter WALL_HEIGHT = SCREEN_HEIGHT / 3, + + parameter SIMDIV = 2500, + + parameter N_SCR_WIDTH = $clog2(SCREEN_WIDTH), + parameter N_SCR_HEIGHT = $clog2(SCREEN_HEIGHT), + parameter N_SIMDIV = $clog2(SIMDIV) +)( + input wire clk, + input wire rst, + input wire rst2, + + input wire start, + input wire acknowledge, + + output reg [N_SCR_WIDTH - 1:0] pod1x, + output reg [N_SCR_WIDTH - 1:0] pod2x, + + output reg [N_SCR_WIDTH - 1:0] ballx, + output reg [N_SCR_HEIGHT - 1:0] bally, + + input wire move_pod1_en, + input wire move_pod1_dir, + input wire move_pod2_en, + input wire move_pod2_dir, + + output reg [7:0] score1, + output reg [7:0] score2, + input wire clear_score, + + output reg hit, + output reg miss +); + +reg [15:0] rnd; + +always @(posedge clk) +begin + if (rst) + begin + rnd <= 16'hACE1; + end + else + begin + rnd <= { rnd[14:0], rnd[15] ^ rnd[13] ^ rnd[12] ^ rnd[10] }; + end +end + +// ----------- + +localparam GS_FROZEN = 0; +localparam GS_RUNNING = 1; +localparam GS_SCORING = 2; +localparam GS_GAME_OVER = 3; + +wire restart = (next_game_state == GS_FROZEN) && (game_state == GS_GAME_OVER); + +reg [1:0] next_game_state; +always @(*) +begin + case (game_state) + default : next_game_state <= start ? GS_RUNNING : GS_FROZEN; + GS_RUNNING : next_game_state <= (bally > 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