From b25727997cae9a47f9467e66e9c6b28fb90bd981 Mon Sep 17 00:00:00 2001 From: MaxP Date: Tue, 22 Apr 2025 11:38:13 +0000 Subject: [PATCH] Refactors vertical sprite pipeline for modularity Reorganizes pipeline logic into distinct stages for clarity Replaces monolithic process with modular components Introduces AXI-like interface for better integration Improves readability and maintainability by renaming signals Updates visibility and offset calculations to use pipeline registers --- src/VerticalSpritePipeline.vhd | 227 ++++++++++++++++++--------------- 1 file changed, 121 insertions(+), 106 deletions(-) diff --git a/src/VerticalSpritePipeline.vhd b/src/VerticalSpritePipeline.vhd index ae1965f..1954001 100644 --- a/src/VerticalSpritePipeline.vhd +++ b/src/VerticalSpritePipeline.vhd @@ -7,156 +7,171 @@ use work.SpriteRom.all; entity VerticalSpritePipeline is generic ( --@ Width of the Y position (Line) register - G_Y_Width : integer := 10; + G_Y_Width : integer := 10; --@ The height of the sprite in pixels G_Sprite_Height : integer := 16; --@ Width of the sprite offset (Line address) register - G_Offset_Width : integer := 8; - --@ The pipeline stages for the calculating pipeline (multiply by 2 for the the latency of the pipeline) - G_PipelineStages : integer := 2 - ); + G_Offset_Width : integer := 8 + ); port ( --@ Clock signal; (**Rising edge** triggered) I_CLK : in std_logic := '0'; --@ Clock enable signal (**Active high**) - I_CE : in std_logic := '1'; + I_CE : in std_logic := '1'; - --@ @virtualbus YHitCheck-Input-Interface @dir in YHitCheck Input Interface - --@ Indicates if the pipeline is ready to accept data. (**Active high**) - O_Ready : out std_logic := '0'; - --@ Indicates if the pipeline is valid. (**Active high**) - I_Valid : in std_logic := '0'; + --@ @virtualbus VSpritePipeline-OP @dir In Vertical sprite pipeline operation interfacee + --@ AXI like ready; (**Synchronous**, **Active high**) + O_VSpritePipeline_OP_Ready : out std_logic := '0'; + --@ AXI like valid; (**Synchronous**, **Active high**) + I_VSpritePipeline_OP_Valid : in std_logic := '0'; --@ The line to check if the sprite is in the line visible. - I_YToCheck : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + I_VSpritePipeline_OP_Y_Request : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); --@ The sprite Y position to check if the sprite is in the line visible. - I_Y : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + I_VSpritePipeline_OP_Y_Sprite : in std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); --@ @end - --@ @virtualbus YHitCheck-Output-Interface @dir out YHitCheck Output Interface - --@ Indicates if the pipeline is ready to deliver data. (**Active high**) - I_Ready : in std_logic := '0'; - --@ Indicates if `O_IsVisible` is valid. (**Active high**) - O_Valid : out std_logic := '0'; + --@ @virtualbus VSpritePipeline-Result @dir Out Vertical sprite pipeline result interface + --@ AXI like ready; (**Synchronous**, **Active high**) + I_VSpritePipeline_Ready : in std_logic := '0'; + --@ AXI like valid; (**Synchronous**, **Active high**) + O_VSpritePipeline_Valid : out std_logic := '0'; --@ Indicates if the sprite is visible in the line. - O_IsVisible : out std_logic := '0'; + O_VSpritePipeline_IsVisible : out std_logic := '0'; --@ The calculated offset address of the sprite. - O_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0') - --@ @end - ); + O_VSpritePipeline_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0') + --@ @end + ); end entity VerticalSpritePipeline; architecture Rtl of VerticalSpritePipeline is - --@ Line to check if the sprite is in the line visible - signal R_YToCheck : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); - --@ The sprite Y position to check if the sprite is in the line visible - signal R_SpriteY : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + --@ (Stage 0) Line to check if the sprite is in the line visible + signal R0_Y_Request : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + --@ (Stage 1) Line to check if the sprite is in the line visible + signal R1_Y_Request : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + --@ (Stage 0) The sprite Y position to check if the sprite is in the line visible + signal R0_Y_Sprite : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + --@ (Stage 1) The sprite Y position to check if the sprite is in the line visible + signal R1_Y_Sprite : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + + --@ The bottom Y position of the sprite + signal C_Y_Bottom_Sprite : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + --@ (Stage 1) The bottom Y position of the sprite + signal R1_Y_Bottom_Sprite : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); --@ Calculated visibility signal - signal C_IsVisible : std_logic := '0'; + signal C_IsVisible : std_logic := '0'; --@ The calculated offset address of the sprite - signal C_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0'); + signal C_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0'); --@ Pipeline enable signal - signal S_CalculatingPipeline_Enable : std_logic := '0'; + signal O_VSpritePipeline_Ctrl_Enable : std_logic := '0'; begin - - --@ Pipeline controller for the calculating pipeline - I_CalculatingPipelineCtrl : entity work.PipelineController + INST_VSpritePipeline_Ctrl : entity work.PipelineController generic map( - G_PipelineStages => G_PipelineStages * 2 - ) + G_PipelineStages => 3 + ) port map( I_CLK => I_CLK, I_CE => I_CE, - O_Enable => S_CalculatingPipeline_Enable, - I_Valid => I_Valid, - O_Ready => O_Ready, - O_Valid => O_Valid, - I_Ready => I_Ready - ); + O_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Valid => I_VSpritePipeline_OP_Valid, + O_Ready => O_VSpritePipeline_OP_Ready, + O_Valid => O_VSpritePipeline_Valid, + I_Ready => I_VSpritePipeline_Ready + ); - --@ Input register for the Y position of the sprite - I_Y_InputRegister : entity work.PipelineRegister + INST0_VSpritePipeline_Y_Sprite : entity work.PipelineRegister generic map( - G_PipelineStages => G_PipelineStages, - G_Width => G_Y_Width, - G_RegisterBalancing => "forward" - ) + G_Width => G_Y_Width + ) port map( I_CLK => I_CLK, - I_Enable => S_CalculatingPipeline_Enable, - I_Data => I_Y, - O_Data => R_SpriteY - ); + I_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Data => I_VSpritePipeline_OP_Y_Sprite, + O_Data => R0_Y_Sprite + ); - --@ Input register for the line to check if the sprite is in the line visible - I_YToCheck_InputRegister : entity work.PipelineRegister + INST0_VSpritePipeline_Y_Request : entity work.PipelineRegister generic map( - G_PipelineStages => G_PipelineStages, - G_Width => G_Y_Width, - G_RegisterBalancing => "forward" - ) + G_Width => G_Y_Width + ) port map( I_CLK => I_CLK, - I_Enable => S_CalculatingPipeline_Enable, - I_Data => I_YToCheck, - O_Data => R_YToCheck + I_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Data => I_VSpritePipeline_OP_Y_Request, + O_Data => R0_Y_Request + ); + + --@ Calculate the bottom Y position of the sprite + C_Y_Bottom_Sprite <= std_logic_vector( + unsigned(R0_Y_Sprite) + to_unsigned(G_Sprite_Height - 1, G_Y_Width) ); - --@ Combinatory process to calculate the visibility and offset of the sprite. - P_CalculateVisibility : process (R_SpriteY, R_YToCheck) - variable V_SpriteY : unsigned(R_SpriteY'range); - variable V_YToCheck : unsigned(R_YToCheck'range); - variable V_SpriteYBottom : unsigned(R_SpriteY'range); - variable V_OffsetLine : integer; - variable V_Offset : unsigned(C_Offset'range); - begin - V_SpriteY := unsigned(R_SpriteY); - V_YToCheck := unsigned(R_YToCheck); - V_SpriteYBottom := V_SpriteY + to_unsigned(G_Sprite_Height - 1, R_SpriteY'length); - - if V_YToCheck >= V_SpriteY and V_YToCheck <= V_SpriteYBottom then - C_IsVisible <= '1'; - else - C_IsVisible <= '0'; - end if; - - V_OffsetLine := to_integer(V_YToCheck - V_SpriteY); - -- pragma translate_off - if V_OffsetLine < 0 or V_OffsetLine >= K_SPRITE_ROW_OFFSETS'length then - V_OffsetLine := 0; - end if; - -- pragma translate_on - - V_Offset := to_unsigned(K_SPRITE_ROW_OFFSETS(V_OffsetLine), C_Offset'length); - C_Offset <= std_logic_vector(V_Offset); - end process; - - --@ Output register for the visibility of the sprite - I_IsVisible_OutputRegister : entity work.PipelineRegister + INST_VSpritePipeline_Y_Bottom_Sprite : entity work.PipelineRegister generic map( - G_PipelineStages => G_PipelineStages, - G_Width => 1, - G_RegisterBalancing => "backward" - ) + G_Width => G_Y_Width + ) + port map( + I_CLK => I_CLK, + I_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Data => C_Y_Bottom_Sprite, + O_Data => R1_Y_Bottom_Sprite + ); + + INST1_VSpritePipeline_Y_Sprite : entity work.PipelineRegister + generic map( + G_Width => G_Y_Width + ) + port map( + I_CLK => I_CLK, + I_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Data => R0_Y_Sprite, + O_Data => R1_Y_Sprite + ); + + INST1_VSpritePipeline_Y_Request : entity work.PipelineRegister + generic map( + G_Width => G_Y_Width + ) + port map( + I_CLK => I_CLK, + I_Enable => O_VSpritePipeline_Ctrl_Enable, + I_Data => R0_Y_Request, + O_Data => R1_Y_Request + ); + + --@ Calculate the visibility of the sprite + C_IsVisible <= '1' when ( + (unsigned(R1_Y_Request) >= unsigned(R1_Y_Sprite)) and + (unsigned(R1_Y_Request) <= unsigned(R1_Y_Bottom_Sprite)) + ) else '0'; + + --@ Calculate the offset address of the sprite + C_Offset <= std_logic_vector( + to_unsigned( + K_SPRITE_ROW_OFFSETS(to_integer(unsigned(R1_Y_Request) - unsigned(R1_Y_Sprite))), + C_Offset'length) + ); + + INST_IsVisible_OutputRegister : entity work.PipelineRegister + generic map( + G_Width => 1 + ) port map( I_CLK => I_CLK, - I_Enable => S_CalculatingPipeline_Enable, + I_Enable => O_VSpritePipeline_Ctrl_Enable, I_Data(0) => C_IsVisible, - O_Data(0) => O_IsVisible - ); + O_Data(0) => O_VSpritePipeline_IsVisible + ); - --@ Output register for the offset of the sprite - I_Offset_OutputRegister : entity work.PipelineRegister + INST_Offset_OutputRegister : entity work.PipelineRegister generic map( - G_PipelineStages => G_PipelineStages, - G_Width => G_Offset_Width, - G_RegisterBalancing => "backward" - ) + G_Width => G_Offset_Width + ) port map( I_CLK => I_CLK, - I_Enable => S_CalculatingPipeline_Enable, + I_Enable => O_VSpritePipeline_Ctrl_Enable, I_Data => C_Offset, - O_Data => O_Offset - ); + O_Data => O_VSpritePipeline_Offset + ); end architecture;