From 3eab104f2178e4167b8063551da2ab47f15beb0f Mon Sep 17 00:00:00 2001 From: Max P Date: Sun, 27 Apr 2025 19:51:46 +0000 Subject: [PATCH] Move on to hdlbuild style. --- .devcontainer/devcontainer.json | 13 +- .gitignore | 6 +- .gitmodules | 6 - build | 1 - project.yml | 272 ++++++++++++++++ src/Controller.vhd | 162 ++++++++++ src/SPU.ucf | 17 + src/SPU.vhd | 216 +++++++++++++ src/SpriceProcessingUnit.vhd | 0 src/X_Y_Generator.vhd | 90 ++++++ tests/SPU_tb.vhd | 44 +++ tests/SPU_tb.wcfg | 541 ++++++++++++++++++++++++++++++++ 12 files changed, 1356 insertions(+), 12 deletions(-) delete mode 100644 .gitmodules delete mode 160000 build create mode 100644 project.yml create mode 100644 src/Controller.vhd create mode 100644 src/SPU.ucf create mode 100644 src/SPU.vhd create mode 100644 src/SpriceProcessingUnit.vhd create mode 100644 src/X_Y_Generator.vhd create mode 100644 tests/SPU_tb.vhd create mode 100644 tests/SPU_tb.wcfg diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a84eb92..7f86103 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,12 +4,14 @@ "runArgs": [ "--privileged", "--cap-add=SYS_ADMIN", - "--shm-size=2g" + "--shm-size=2g", + "-v", + "/run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent" ], "customizations": { "vscode": { "extensions": [ - "p2l2.vhdl-by-hgb", + "/home/xilinx/vsxirepo/vhdl-by-hgb.vsix", "eamodio.gitlens" ], "settings": { @@ -21,5 +23,8 @@ "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "features": {}, - "forwardPorts": [10000] -} + "forwardPorts": [ + 10000 + ], + "postStartCommand": "git config --global user.signingkey 87C8A5DD5C14DF55DBE1DB4199AC216D447E61C0 && git config --global gpg.format openpgp && git config --global commit.gpgsign true && git config --global tag.forceSignAnnotated true && sudo apt update && sudo apt upgrade -y" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2baa0a9..7394369 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ +.hdlbuild_deps/ +.working/ +reports/ +output/ .locale/ -.history/ \ No newline at end of file +vhdl_ls.toml \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index a417451..0000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "build"] - path = build - url = https://git.0xmax42.io/maxp/Xilinx-ISE-Build.git -[submodule "libs/SpriteChannel"] - path = libs/SpriteChannel - url = https://git.0xmax42.io/maxp/SpriteChannel.git diff --git a/build b/build deleted file mode 160000 index 54949f4..0000000 --- a/build +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 54949f43c0a900256c15d5d964c6b1da95d27473 diff --git a/project.yml b/project.yml new file mode 100644 index 0000000..27ab5cc --- /dev/null +++ b/project.yml @@ -0,0 +1,272 @@ +name: SPU +topmodule: SPU +target_device: xc3s1200e-4-fg320 +xilinx_path: /opt/Xilinx/14.7/ISE_DS/ISE + +constraints: src/SPU.ucf + +sources: + vhdl: + - path: src/*.vhd + library: work + +testbenches: + vhdl: + - path: tests/*.vhd + library: work + +dependencies: + - git: "https://git.0xmax42.io/HDL/VGA.git" + rev: "main" + - git: "https://git.0xmax42.io/HDL/Pipeline-AXI-Handshake.git" + rev: "main" + - git: "https://git.0xmax42.io/HDL/Asynchronous-FIFO-AXI-Handshake.git" + rev: "main" + +build: + build_dir: working + report_dir: reports + copy_target_dir: output + +# Tool Optionen +tool_options: + common: + - "-intstyle" + - "xflow" + + ngdbuild: [] + + map: + - "-detail" + - "-timing" + - "-ol" + - "high" + + par: [] + + bitgen: + - "-g" + - "StartupClk:JtagClk" + + trace: + - "-v" + - "3" + - "-n" + - "3" + + fuse: + - "-incremental" + + isim: + - "-gui" + + xst: + # Optimization goal: prioritize speed or area. + # Values: Speed | Area + - "-opt_mode Speed" + + # Optimization level: more aggressive optimizations at level 2. + # Values: 1 | 2 + - "-opt_level 2" + + # Use the new XST parser (recommended for modern designs). + # Values: yes | no + - "-use_new_parser yes" + + # Preserve design hierarchy or allow flattening for optimization. + # Values: Yes | No | Soft + - "-keep_hierarchy No" + + # Determines how hierarchy is preserved in the netlist. + # Values: As_Optimized | Rebuilt + - "-netlist_hierarchy As_Optimized" + + # Global optimization strategy for nets. + # Values: AllClockNets | Offset_In_Before | Offset_Out_After | Inpad_To_Outpad | Max_Delay + - "-glob_opt AllClockNets" + + ## Misc ## + + # Enable reading of IP cores. + # Values: YES | NO + - "-read_cores YES" + + # Do not write timing constraints into synthesis report. + # Values: YES | NO + - "-write_timing_constraints NO" + + # Analyze paths across different clock domains. + # Values: YES | NO + - "-cross_clock_analysis NO" + + # Character used to separate hierarchy levels in instance names. + # Default: / + - "-hierarchy_separator /" + + # Delimiters used for bus signals. + # Values: <> | [] | () | {} + - "-bus_delimiter <>" + + # Maintain original case of identifiers. + # Values: Maintain | Upper | Lower + - "-case Maintain" + + # Target maximum utilization ratio for slices. + # Values: 1–100 + - "-slice_utilization_ratio 100" + + # Target maximum utilization ratio for BRAMs. + # Values: 1–100 + - "-bram_utilization_ratio 100" + + # Use Verilog 2001 syntax features. + # Values: YES | NO + - "-verilog2001 YES" + + #### HDL Options #### + + ## FSM ## + + # Extract FSMs (Finite State Machines) from HDL code. + # Values: YES | NO + - "-fsm_extract YES" + + # Encoding strategy for FSMs. + # Values: Auto | Gray | One-Hot | Johnson | Compact | Sequential | Speed1 | User + - "-fsm_encoding Auto" + + # Add safe logic for undefined FSM states. + # Values: Yes | No + - "-safe_implementation No" + + # Structure used to implement FSMs. + # Values: LUT | BRAM + - "-fsm_style LUT" + + ## RAM/ROM ## + + # Extract RAM inference from HDL. + # Values: Yes | No + - "-ram_extract Yes" + + # Style used to implement RAM. + # Values: Auto | Block | Distributed + - "-ram_style Auto" + + # Extract ROM inference from HDL. + # Values: Yes | No + - "-rom_extract Yes" + + # Style used for implementing ROM. + # Values: Auto | Distributed | Block + - "-rom_style Auto" + + # Enable or disable automatic BRAM packing. + # Values: YES | NO + - "-auto_bram_packing NO" + + ## MUX/Decoder/Shift Register ## + + # Extract multiplexers where possible. + # Values: Yes | No | Force + - "-mux_extract Yes" + + # Style used for implementing MUX logic. + # Values: Auto | MUXCY | MUXF + - "-mux_style Auto" + + # Extract decoder logic from behavioral code. + # Values: YES | NO + - "-decoder_extract YES" + + # Extract and optimize priority encoder structures. + # Values: Yes | No | Force + - "-priority_extract Yes" + + # Extract shift register logic. + # Values: YES | NO + - "-shreg_extract YES" + + # Extract simple shift operations into dedicated hardware. + # Values: YES | NO + - "-shift_extract YES" + + ## Multiplier ## + + # Style for implementing multipliers. + # Values: Auto | LUT | Pipe_LUT | Pipe_Block | Block + - "-mult_style Auto" + + ## Misc ## + + # Collapse XOR trees where beneficial. + # Values: YES | NO + - "-xor_collapse YES" + + # Share resources like adders or multipliers between logic blocks. + # Values: YES | NO | Force + - "-resource_sharing YES" + + # Convert asynchronous resets to synchronous where possible. + # Values: YES | NO + - "-async_to_sync NO" + + #### Xilinx Specific Options #### + + ## Optimization ## + + # Enable removal of logically equivalent registers. + # Values: YES | NO + - "-equivalent_register_removal YES" + + # Duplicate registers to reduce fanout or improve timing. + # Values: YES | NO + - "-register_duplication YES" + + # Move registers across logic to balance timing. + # Values: Yes | No | Forward | Backward + - "-register_balancing No" + + # Use clock enable signals where possible. + # Values: Auto | Yes | No + - "-use_clock_enable Yes" + + # Use synchronous set (preset) signals when available. + # Values: Auto | Yes | No + - "-use_sync_set Yes" + + # Use synchronous reset signals where possible. + # Values: Auto | Yes | No + - "-use_sync_reset Yes" + + ## I/O ## + + # Insert IO buffers for top-level ports. + # Values: YES | NO + - "-iobuf YES" + + # Placement strategy for IOB registers (Auto = let tools decide). + # Values: Auto | YES | NO + - "-iob Auto" + + ## Misc ## + + # Maximum allowed fanout for a net. + # Values: integer (e.g., 500) + - "-max_fanout 500" + + # Maximum number of BUFGs (global buffers) to use. + # Values: 0–32 (device-dependent) + - "-bufg 24" + + # Enable logic packing into slices. + # Values: YES | NO + - "-slice_packing YES" + + # Try to reduce the number of primitive instances used. + # Values: YES | NO + - "-optimize_primitives NO" + + # Margin in percent beyond the target slice utilization. + # Values: 0–100 + - "-slice_utilization_ratio_maxmargin 5" \ No newline at end of file diff --git a/src/Controller.vhd b/src/Controller.vhd new file mode 100644 index 0000000..20df144 --- /dev/null +++ b/src/Controller.vhd @@ -0,0 +1,162 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; +use work.OPCodes.all; + +entity Controller is + generic ( + --@ Width of the X position (Row) register + G_X_Width : integer := 10; + --@ Width of the Y position (Line) register + G_Y_Width : integer := 10; + --@ Data width of the operation data. + G_OPCodeData_Width : integer := 10 + ); + port + ( + --@ Clock; (**Rising edge** triggered) + I_CLK : in std_logic; + --@ Clock Enable; (**Synchronous**, **Active high**) + I_CE : in std_logic; + --@ Reset; (**Synchronous**, **Active high**) + I_RST : in std_logic; + + --@ @virtualbus Y @dir Out Output of the Y positions, with priority over X + I_Y_Valid : in std_logic; + O_Y_Ready : out std_logic; + I_Y : in std_logic_vector(G_Y_Width - 1 downto 0); + --@ @end + --@ @virtualbus X @dir Out Output of the X positions + I_X_Valid : in std_logic; + O_X_Ready : out std_logic; + I_X : in std_logic_vector(G_X_Width - 1 downto 0); + --@ @end + + O_VGA_RST : out std_logic; + + --@ @virtualbus Decoder-OP @dir out Operation Read Interface + --@ AXI like valid; (**Synchronous**, **Active high**) + O_OPDecoder_Valid : out std_logic := '0'; + --@ AXI like ready; (**Synchronous**, **Active high**) + I_OPDecoder_Ready : in std_logic := '0'; + --@ Operation code for the sprite channel + O_OPDecoder_Code : out std_logic_vector(3 downto 0) := (others => '0'); + --@ Operation data for the sprite channel + O_OPDecoder_Data : out std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0') + --@ @end + + ); +end entity Controller; + +architecture RTL of Controller is + --@ Type for the state machine + type T_State is ( + S_None, + S_Idle, + S_NewLine, + S_RequestPixel + ); + --@ Current state of the state machine + signal R_State : T_State := S_None; + --@ Next state of the state machine + signal C_NextState : T_State := S_None; + + signal R_ResetCounter : unsigned(15 downto 0) := to_unsigned(1, 16); + signal C_ResetCounter : unsigned(15 downto 0) := (others => '0'); + + signal R_Y : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + signal C_O_Y_Ready : std_logic := '0'; + signal R_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0'); + signal C_O_X_Ready : std_logic := '0'; +begin + + O_Y_Ready <= C_O_Y_Ready; + O_X_Ready <= C_O_X_Ready; + + P_XY_Register : process (I_CLK) + begin + if rising_edge(I_CLK) then + if I_RST = '1' then + R_Y <= (others => '0'); + R_X <= (others => '0'); + elsif I_CE = '1' then + if I_Y_Valid = '1' and C_O_Y_Ready = '1' then + R_Y <= I_Y; + end if; + if I_X_Valid = '1' and C_O_X_Ready = '1' then + R_X <= I_X; + end if; + end if; + end if; + end process; + + P_FSM_StateForwarding : process (I_CLK) + begin + if rising_edge(I_CLK) then + if I_RST = '1' then + R_State <= S_None; + R_ResetCounter <= to_unsigned(1, 16); + elsif I_CE = '1' then + R_State <= C_NextState; + R_ResetCounter <= C_ResetCounter; + end if; + end if; + end process; + + P_FSM : process (R_State, R_ResetCounter, I_Y_Valid, I_X_Valid, R_Y, I_OPDecoder_Ready, R_X) + begin + C_NextState <= R_State; + C_ResetCounter <= (others => '0'); + O_VGA_RST <= '0'; + C_O_Y_Ready <= '0'; + C_O_X_Ready <= '0'; + O_OPDecoder_Valid <= '0'; + O_OPDecoder_Code <= (others => '0'); + O_OPDecoder_Data <= (others => '0'); + + case R_State is + when S_None => + C_ResetCounter <= R_ResetCounter + 1; + if R_ResetCounter = 0 then + + C_NextState <= S_Idle; + else + O_VGA_RST <= '1'; + end if; + + when S_Idle => + if I_Y_Valid = '1' then + C_O_Y_Ready <= '1'; + + C_NextState <= S_NewLine; + elsif I_X_Valid = '1' then + C_O_X_Ready <= '1'; + + C_NextState <= S_RequestPixel; + end if; + + when S_NewLine => + O_OPDecoder_Valid <= '1'; + O_OPDecoder_Code <= K_OP_NEWLINE; + O_OPDecoder_Data <= R_Y; + + if I_OPDecoder_Ready = '1' then + C_NextState <= S_Idle; + end if; + + when S_RequestPixel => + O_OPDecoder_Valid <= '1'; + O_OPDecoder_Code <= K_OP_REQ_ROW_DATA; + O_OPDecoder_Data <= R_X; + + if I_OPDecoder_Ready = '1' then + C_NextState <= S_Idle; + end if; + + when others => + null; + end case; + end process; + +end architecture; diff --git a/src/SPU.ucf b/src/SPU.ucf new file mode 100644 index 0000000..3183464 --- /dev/null +++ b/src/SPU.ucf @@ -0,0 +1,17 @@ +# TEMPERATURE = 50 C; + +NET I_CLK LOC = B8; +NET I_CLK TNM_NET = CLOCK; +TIMESPEC TS_CLOCK = PERIOD CLOCK 50 MHz HIGH 50 %; + +NET O_HSync LOC = T4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_VSync LOC = U3 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; + +NET O_Red<0> LOC = R9 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Red<1> LOC = T8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Red<2> LOC = R8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Green<0> LOC = N8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Green<1> LOC = P8 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Green<2> LOC = P6 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Blue<0> LOC = U5 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; +NET O_Blue<1> LOC = U4 | IOSTANDARD = LVCMOS25 | SLEW = FAST | DRIVE = 12; \ No newline at end of file diff --git a/src/SPU.vhd b/src/SPU.vhd new file mode 100644 index 0000000..8276f2a --- /dev/null +++ b/src/SPU.vhd @@ -0,0 +1,216 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; +library UNISIM; +use UNISIM.vcomponents.all; + +entity SPU is + port ( + --@ Clock; (**Rising edge** triggered) + I_CLK : in std_logic; + + --@ @virtualbus VGA-Timing-Signals @dir out VGA timing signals + --@ Horizontal Sync signal; **Active low** + O_HSync : out std_logic; + --@ Vertical Sync signal; **Active low** + O_VSync : out std_logic; + --@ @end + + --@ VGA Red Channel + O_Red : out std_logic_vector(2 downto 0); + --@ VGA Green Channel + O_Green : out std_logic_vector(2 downto 0); + --@ VGA Blue Channel + O_Blue : out std_logic_vector(1 downto 0) + --@ @end + + ); +end entity SPU; + +architecture RTL of SPU is + + signal CLK_FB : std_logic; + signal CLK_Pixel : std_logic; + signal CLK_100 : std_logic; + + signal C_O_HSync : std_logic := '0'; + signal C_O_VSync : std_logic := '0'; + + signal S_CE : std_logic := '1'; + signal C_VGA_RST : std_logic := '0'; + signal O_VGA_PixelReady : std_logic := '0'; + signal I_VGA_PixelValid : std_logic := '0'; + signal I_VGA_PixelData : std_logic_vector(7 downto 0) := (others => '0'); + + + signal O_XYGen_Y_Valid : std_logic := '0'; + signal I_XYGen_Y_Ready : std_logic := '0'; + signal O_XYGen_Y : std_logic_vector(9 downto 0) := (others => '0'); + + signal O_XYGen_X_Valid : std_logic := '0'; + signal I_XYGen_X_Ready : std_logic := '0'; + signal O_XYGen_X : std_logic_vector(9 downto 0) := (others => '0'); + + signal O_OPDecoder_Valid : std_logic := '0'; + signal I_OPDecoder_Ready : std_logic := '0'; + signal O_OPDecoder_Code : std_logic_vector(3 downto 0) := (others => '0'); + signal O_OPDecoder_Data : std_logic_vector(9 downto 0) := (others => '0'); + + signal I_Rom_Address_Valid : std_logic := '0'; + signal O_Rom_Address_Ready : std_logic := '0'; + signal O_Rom_Address : std_logic_vector(12 downto 0) := (others => '0'); + + signal O_Rom_Data_Valid : std_logic := '0'; + signal I_Rom_Data_Ready : std_logic := '0'; + signal O_Rom_Data : std_logic_vector(7 downto 0) := (others => '0'); + + signal O_Pixel_Data : std_logic_vector(7 downto 0) := (others => '0'); + signal O_Pixel_Valid : std_logic := '0'; + signal I_Pixel_Ready : std_logic := '0'; +begin + + ClockManager : DCM_SP + generic map( + CLKDV_DIVIDE => 2.0, + CLKFX_DIVIDE => 10, + CLKFX_MULTIPLY => 30, + CLKIN_DIVIDE_BY_2 => false, + CLKIN_PERIOD => 10.0, + CLKOUT_PHASE_SHIFT => "NONE", + CLK_FEEDBACK => "1X", + DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", + DFS_FREQUENCY_MODE => "LOW", + DLL_FREQUENCY_MODE => "LOW", + DUTY_CYCLE_CORRECTION => true, + FACTORY_JF => X"C080", + PHASE_SHIFT => 0, + STARTUP_WAIT => false) + port map + ( + CLK0 => CLK_FB, + CLKDV => CLK_Pixel, + CLKFB => CLK_FB, + CLKIN => I_CLK, + CLK2X => CLK_100 + ); + + O_HSync <= C_O_HSync; + O_VSync <= C_O_VSync; + + process (CLK_Pixel) + begin + if rising_edge(CLK_Pixel) then + if (C_O_HSync or C_O_VSync) = '0' then + --O_Red <= (others => '0'); + --O_Green <= (others => '0'); + --O_Blue <= (others => '0'); + elsif O_VGA_PixelReady = '1' and I_VGA_PixelValid = '1' then + O_Red <= I_VGA_PixelData(7 downto 5); + O_Green <= I_VGA_PixelData(4 downto 2); + O_Blue <= I_VGA_PixelData(1 downto 0); + end if; + end if; + end process; + + i_AsyncFIFO : entity work.AsyncFIFO + generic map( + G_Width => 8, + G_Depth => 4, + G_RamTypeFifo => "Block" + ) + port map( + I_Write_CLK => I_CLK, + I_Write_CE => '1', + I_Write_Data => O_Pixel_Data, + I_Write_Valid => O_Pixel_Valid, + O_Write_Ready => I_Pixel_Ready, + I_Read_CLK => CLK_Pixel, + I_Read_CE => '1', + O_Read_Data => I_VGA_PixelData, + I_Read_Ready => O_VGA_PixelReady, + O_Read_Valid => I_VGA_PixelValid + ); + + + INST_VGATimingGenerator : entity work.VGATimingGenerator + port map ( + I_CLK => CLK_Pixel, + I_CE => S_CE, + I_RST => C_VGA_RST, + O_PixelReady => O_VGA_PixelReady, + O_HSync => C_O_HSync, + O_VSync => C_O_VSync + ); + + INST_XY_Generator : entity work.XY_Generator + port map ( + I_CLK => I_CLK, + I_CE => S_CE, + I_RST => C_VGA_RST, + O_Y_Valid => O_XYGen_Y_Valid, + I_Y_Ready => I_XYGen_Y_Ready, + O_Y => O_XYGen_Y, + O_X_Valid => O_XYGen_X_Valid, + I_X_Ready => I_XYGen_X_Ready, + O_X => O_XYGen_X + ); + + INST_Controller : entity work.Controller + port map( + I_CLK => I_CLK, + I_CE => S_CE, + I_RST => '0', + I_Y_Valid => O_XYGen_Y_Valid, + O_Y_Ready => I_XYGen_Y_Ready, + I_Y => O_XYGen_Y, + I_X_Valid => O_XYGen_X_Valid, + O_X_Ready => I_XYGen_X_Ready, + I_X => O_XYGen_X, + O_VGA_RST => C_VGA_RST, + O_OPDecoder_Valid => O_OPDecoder_Valid, + I_OPDecoder_Ready => I_OPDecoder_Ready, + O_OPDecoder_Code => O_OPDecoder_Code, + O_OPDecoder_Data => O_OPDecoder_Data + ); + + INST_SpriteChannel : entity work.SpriteChannel + port map( + I_CLK => I_CLK, + I_CE => S_CE, + I_RST => '0', + I_OP_Valid => O_OPDecoder_Valid, + O_OP_Ready => I_OPDecoder_Ready, + I_OP_Code => O_OPDecoder_Code, + I_OP_Data => O_OPDecoder_Data, + + O_Rom_Address_Valid => I_Rom_Address_Valid, + I_Rom_Address_Ready => O_Rom_Address_Ready, + O_Rom_Address => O_Rom_Address, + + I_Rom_Data_Valid => O_Rom_Data_Valid, + O_Rom_Data_Ready => I_Rom_Data_Ready, + I_Rom_Data => O_Rom_Data, + + O_Pixel_Valid => O_Pixel_Valid, + I_Pixel_Ready => I_Pixel_Ready, + O_Pixel_Data => O_Pixel_Data + ); + + + INST_Rom : entity work.Rom + port map( + I_CLK => I_CLK, + I_CE => S_CE, + I_P0_Address_Valid => I_Rom_Address_Valid, + O_P0_Address_Ready => O_Rom_Address_Ready, + I_P0_Address => O_Rom_Address, + I_P0_ID => open, + O_P0_Data_Valid => O_Rom_Data_Valid, + I_P0_Data_Ready => I_Rom_Data_Ready, + O_P0_Data => O_Rom_Data, + O_P0_ID => open + ); + + +end architecture; diff --git a/src/SpriceProcessingUnit.vhd b/src/SpriceProcessingUnit.vhd new file mode 100644 index 0000000..e69de29 diff --git a/src/X_Y_Generator.vhd b/src/X_Y_Generator.vhd new file mode 100644 index 0000000..d216b28 --- /dev/null +++ b/src/X_Y_Generator.vhd @@ -0,0 +1,90 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +entity XY_Generator is + generic ( + G_X : integer := 640; + G_Y : integer := 480; + --@ Width of the X position (Row) register + G_X_Width : integer := 10; + --@ Width of the Y position (Line) register + G_Y_Width : integer := 10 + ); + port ( + --@ Clock; (**Rising edge** triggered) + I_CLK : in std_logic; + --@ Clock Enable; (**Synchronous**, **Active high**) + I_CE : in std_logic; + --@ Reset; (**Synchronous**, **Active high**) + I_RST : in std_logic; + + --@ @virtualbus Y @dir Out Output of the Y positions, with priority over X + O_Y_Valid : out std_logic; + I_Y_Ready : in std_logic; + O_Y : out std_logic_vector(G_Y_Width - 1 downto 0); + --@ @end + --@ @virtualbus Y @dir Out Output of the X positions + O_X_Valid : out std_logic; + I_X_Ready : in std_logic; + O_X : out std_logic_vector(G_X_Width - 1 downto 0) + --@ @end + + ); + +end entity XY_Generator; + +architecture RTL of XY_Generator is + signal R_X_Counter : unsigned(G_X_Width - 1 downto 0) := (others => '0'); + signal R_Y_Counter : unsigned(G_Y_Width - 1 downto 0) := (others => '0'); + + signal R_Y_Valid : std_logic := '1'; + signal R_X_Valid : std_logic := '1'; + signal C_X_Valid : std_logic := '0'; +begin + + C_X_Valid <= R_X_Valid and not R_Y_Valid; + + process (I_CLK) + begin + if rising_edge(I_CLK) then + if I_RST = '1' then + R_X_Counter <= (others => '0'); + R_Y_Counter <= (others => '0'); + R_Y_Valid <= '1'; + R_X_Valid <= '1'; + elsif I_CE = '1' then + if R_Y_Valid = '1' or R_X_Valid = '1' then + if I_Y_Ready = '1' then + R_Y_Valid <= '0'; + elsif I_X_Ready = '1' then + R_X_Valid <= '0'; + end if; + else + if R_X_Counter = (G_X - 1) then + R_X_Counter <= (others => '0'); + R_X_Valid <= '1'; + + if R_Y_Counter = (G_Y - 1) then + R_Y_Counter <= (others => '0'); + R_Y_Valid <= '1'; + else + R_Y_Counter <= R_Y_Counter + 1; + R_Y_Valid <= '1'; + end if; + else + R_X_Counter <= R_X_Counter + 1; + R_X_Valid <= '1'; + end if; + end if; + end if; + end if; + end process; + + O_X <= std_logic_vector(R_X_Counter); + O_Y <= std_logic_vector(R_Y_Counter); + O_Y_Valid <= R_Y_Valid; + O_X_Valid <= C_X_Valid; + +end architecture; diff --git a/tests/SPU_tb.vhd b/tests/SPU_tb.vhd new file mode 100644 index 0000000..21f2056 --- /dev/null +++ b/tests/SPU_tb.vhd @@ -0,0 +1,44 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +entity SPU_tb is +end entity SPU_tb; + +architecture RTL of SPU_tb is + -- Clock period + constant K_CLKPeriod : time := 20 ns; + signal I_CLK : std_logic; + signal O_HSync : std_logic; + signal O_VSync : std_logic; + signal O_Red : std_logic_vector(2 downto 0); + signal O_Green : std_logic_vector(2 downto 0); + signal O_Blue : std_logic_vector(1 downto 0); + +begin + + ClockProc : process + begin + while true loop + I_CLK <= '0'; + wait for K_CLKPeriod / 2; + I_CLK <= '1'; + wait for K_CLKPeriod / 2; + end loop; + + wait; + end process; + + i_SPU : entity work.SPU + port map( + I_CLK => I_CLK, + O_HSync => O_HSync, + O_VSync => O_VSync, + O_Red => O_Red, + O_Green => O_Green, + O_Blue => O_Blue + ); + + +end architecture; diff --git a/tests/SPU_tb.wcfg b/tests/SPU_tb.wcfg new file mode 100644 index 0000000..4607aa7 --- /dev/null +++ b/tests/SPU_tb.wcfg @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + i_clk + i_clk + + + clk_pixel + clk_pixel + + + TB + label + + o_hsync + o_hsync + + + o_vsync + o_vsync + + + O_RGB + label + HEXRADIX + + [2] + o_red[2] + + + [1] + o_red[1] + + + [0] + o_red[0] + + + [2] + o_green[2] + + + [1] + o_green[1] + + + [0] + o_green[0] + + + [1] + o_blue[1] + + + [0] + o_blue[0] + + + + o_vga_pixelready + o_vga_pixelready + + + + UUT + label + + c_vga_rst + c_vga_rst + + + o_vga_pixelready + o_vga_pixelready + + + o_pixel_valid + o_pixel_valid + + + o_pixel_data[7:0] + o_pixel_data[7:0] + HEXRADIX + + + o_xygen_y_valid + o_xygen_y_valid + + + i_xygen_y_ready + i_xygen_y_ready + + + o_xygen_y[9:0] + o_xygen_y[9:0] + UNSIGNEDDECRADIX + + + o_xygen_x_valid + o_xygen_x_valid + + + i_xygen_x_ready + i_xygen_x_ready + + + o_xygen_x[9:0] + o_xygen_x[9:0] + UNSIGNEDDECRADIX + + + o_opdecoder_valid + o_opdecoder_valid + + + i_opdecoder_ready + i_opdecoder_ready + + + o_opdecoder_code[3:0] + o_opdecoder_code[3:0] + HEXRADIX + + + o_opdecoder_data[9:0] + o_opdecoder_data[9:0] + UNSIGNEDDECRADIX + + + i_rom_address_valid + i_rom_address_valid + + + o_rom_address_ready + o_rom_address_ready + + + o_rom_address[12:0] + o_rom_address[12:0] + UNSIGNEDDECRADIX + + + o_rom_data_valid + o_rom_data_valid + + + i_rom_data_ready + i_rom_data_ready + + + o_rom_data[7:0] + o_rom_data[7:0] + HEXRADIX + + + + R_File + label + + r_isvisible + r_isvisible + + + + VSpritePipeline + label + + o_vspritepipeline_op_ready + o_vspritepipeline_op_ready + + + i_vspritepipeline_op_valid + i_vspritepipeline_op_valid + + + i_vspritepipeline_op_y_request[9:0] + i_vspritepipeline_op_y_request[9:0] + UNSIGNEDDECRADIX + + + i_vspritepipeline_op_y_sprite[9:0] + i_vspritepipeline_op_y_sprite[9:0] + UNSIGNEDDECRADIX + + + i_vspritepipeline_ready + i_vspritepipeline_ready + + + o_vspritepipeline_valid + o_vspritepipeline_valid + + + o_vspritepipeline_isvisible + o_vspritepipeline_isvisible + + + o_vspritepipeline_offset[7:0] + o_vspritepipeline_offset[7:0] + UNSIGNEDDECRADIX + + + r0_y_request[9:0] + r0_y_request[9:0] + UNSIGNEDDECRADIX + + + r1_y_request[9:0] + r1_y_request[9:0] + UNSIGNEDDECRADIX + + + r0_y_sprite[9:0] + r0_y_sprite[9:0] + UNSIGNEDDECRADIX + + + r1_y_sprite[9:0] + r1_y_sprite[9:0] + UNSIGNEDDECRADIX + + + c_y_bottom_sprite[9:0] + c_y_bottom_sprite[9:0] + UNSIGNEDDECRADIX + + + r1_y_bottom_sprite[9:0] + r1_y_bottom_sprite[9:0] + UNSIGNEDDECRADIX + + + c_isvisible + c_isvisible + + + c_offset[7:0] + c_offset[7:0] + UNSIGNEDDECRADIX + + + o_vspritepipeline_ctrl_enable + o_vspritepipeline_ctrl_enable + + + + AsyncFIFO + label + + i_write_clk + i_write_clk + + + i_write_ce + i_write_ce + + + i_write_data[7:0] + i_write_data[7:0] + HEXRADIX + + + i_write_valid + i_write_valid + + + o_write_ready + o_write_ready + + + i_read_ce + i_read_ce + + + s_fifo[31:0] + s_fifo[31:0] + HEXRADIX + + [31] + s_fifo[31] + HEXRADIX + + + [30] + s_fifo[30] + HEXRADIX + + + [29] + s_fifo[29] + HEXRADIX + + + [28] + s_fifo[28] + HEXRADIX + + + [27] + s_fifo[27] + HEXRADIX + + + [26] + s_fifo[26] + HEXRADIX + + + [25] + s_fifo[25] + HEXRADIX + + + [24] + s_fifo[24] + HEXRADIX + + + [23] + s_fifo[23] + HEXRADIX + + + [22] + s_fifo[22] + HEXRADIX + + + [21] + s_fifo[21] + HEXRADIX + + + [20] + s_fifo[20] + HEXRADIX + + + [19] + s_fifo[19] + HEXRADIX + + + [18] + s_fifo[18] + HEXRADIX + + + [17] + s_fifo[17] + HEXRADIX + + + [16] + s_fifo[16] + HEXRADIX + + + [15] + s_fifo[15] + HEXRADIX + + + [14] + s_fifo[14] + HEXRADIX + + + [13] + s_fifo[13] + HEXRADIX + + + [12] + s_fifo[12] + HEXRADIX + + + [11] + s_fifo[11] + HEXRADIX + + + [10] + s_fifo[10] + HEXRADIX + + + [9] + s_fifo[9] + HEXRADIX + + + [8] + s_fifo[8] + HEXRADIX + + + [7] + s_fifo[7] + HEXRADIX + + + [6] + s_fifo[6] + HEXRADIX + + + [5] + s_fifo[5] + HEXRADIX + + + [4] + s_fifo[4] + HEXRADIX + + + [3] + s_fifo[3] + HEXRADIX + + + [2] + s_fifo[2] + HEXRADIX + + + [1] + s_fifo[1] + HEXRADIX + + + [0] + s_fifo[0] + HEXRADIX + + + + r_write_pointer[4:0] + r_write_pointer[4:0] + + + r_write_pointersync[4:0] + r_write_pointersync[4:0] + + + r_write_lapointer[4:0] + r_write_lapointer[4:0] + + + c_write_ready + c_write_ready + + + c_write_pointerenable + c_write_pointerenable + + + Read + label + + i_read_clk + i_read_clk + + + o_read_data[7:0] + o_read_data[7:0] + HEXRADIX + + + i_read_ready + i_read_ready + + + o_read_valid + o_read_valid + + + r_read_pointer[4:0] + r_read_pointer[4:0] + + + c_read_valid + c_read_valid + + + c_read_pointerenable + c_read_pointerenable + + + GrayCounter + label + + i_countenable + i_countenable + + + o_lavalue[4:0] + o_lavalue[4:0] + + + o_value[4:0] + o_value[4:0] + + + r_countervalue[4:0] + r_countervalue[4:0] + + + r_grayvalue[4:0] + r_grayvalue[4:0] + + + r_lookaheadvalue[4:0] + r_lookaheadvalue[4:0] + + + + +