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
This commit is contained in:
2025-04-22 11:38:13 +00:00
parent 49be0b81a0
commit b25727997c

View File

@@ -7,156 +7,171 @@ use work.SpriteRom.all;
entity VerticalSpritePipeline is entity VerticalSpritePipeline is
generic ( generic (
--@ Width of the Y position (Line) register --@ Width of the Y position (Line) register
G_Y_Width : integer := 10; G_Y_Width : integer := 10;
--@ The height of the sprite in pixels --@ The height of the sprite in pixels
G_Sprite_Height : integer := 16; G_Sprite_Height : integer := 16;
--@ Width of the sprite offset (Line address) register --@ Width of the sprite offset (Line address) register
G_Offset_Width : integer := 8; 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
);
port ( port (
--@ Clock signal; (**Rising edge** triggered) --@ Clock signal; (**Rising edge** triggered)
I_CLK : in std_logic := '0'; I_CLK : in std_logic := '0';
--@ Clock enable signal (**Active high**) --@ 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 --@ @virtualbus VSpritePipeline-OP @dir In Vertical sprite pipeline operation interfacee
--@ Indicates if the pipeline is ready to accept data. (**Active high**) --@ AXI like ready; (**Synchronous**, **Active high**)
O_Ready : out std_logic := '0'; O_VSpritePipeline_OP_Ready : out std_logic := '0';
--@ Indicates if the pipeline is valid. (**Active high**) --@ AXI like valid; (**Synchronous**, **Active high**)
I_Valid : in std_logic := '0'; I_VSpritePipeline_OP_Valid : in std_logic := '0';
--@ The line to check if the sprite is in the line visible. --@ 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. --@ 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 --@ @end
--@ @virtualbus YHitCheck-Output-Interface @dir out YHitCheck Output Interface --@ @virtualbus VSpritePipeline-Result @dir Out Vertical sprite pipeline result interface
--@ Indicates if the pipeline is ready to deliver data. (**Active high**) --@ AXI like ready; (**Synchronous**, **Active high**)
I_Ready : in std_logic := '0'; I_VSpritePipeline_Ready : in std_logic := '0';
--@ Indicates if `O_IsVisible` is valid. (**Active high**) --@ AXI like valid; (**Synchronous**, **Active high**)
O_Valid : out std_logic := '0'; O_VSpritePipeline_Valid : out std_logic := '0';
--@ Indicates if the sprite is visible in the line. --@ 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. --@ The calculated offset address of the sprite.
O_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0') O_VSpritePipeline_Offset : out std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0')
--@ @end --@ @end
); );
end entity VerticalSpritePipeline; end entity VerticalSpritePipeline;
architecture Rtl of VerticalSpritePipeline is architecture Rtl of VerticalSpritePipeline is
--@ Line to check if the sprite is in the line visible --@ (Stage 0) 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'); signal R0_Y_Request : 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 --@ (Stage 1) Line to check if the sprite is in the line visible
signal R_SpriteY : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); 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 --@ Calculated visibility signal
signal C_IsVisible : std_logic := '0'; signal C_IsVisible : std_logic := '0';
--@ The calculated offset address of the sprite --@ 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 --@ Pipeline enable signal
signal S_CalculatingPipeline_Enable : std_logic := '0'; signal O_VSpritePipeline_Ctrl_Enable : std_logic := '0';
begin begin
INST_VSpritePipeline_Ctrl : entity work.PipelineController
--@ Pipeline controller for the calculating pipeline
I_CalculatingPipelineCtrl : entity work.PipelineController
generic map( generic map(
G_PipelineStages => G_PipelineStages * 2 G_PipelineStages => 3
) )
port map( port map(
I_CLK => I_CLK, I_CLK => I_CLK,
I_CE => I_CE, I_CE => I_CE,
O_Enable => S_CalculatingPipeline_Enable, O_Enable => O_VSpritePipeline_Ctrl_Enable,
I_Valid => I_Valid, I_Valid => I_VSpritePipeline_OP_Valid,
O_Ready => O_Ready, O_Ready => O_VSpritePipeline_OP_Ready,
O_Valid => O_Valid, O_Valid => O_VSpritePipeline_Valid,
I_Ready => I_Ready I_Ready => I_VSpritePipeline_Ready
); );
--@ Input register for the Y position of the sprite INST0_VSpritePipeline_Y_Sprite : entity work.PipelineRegister
I_Y_InputRegister : entity work.PipelineRegister
generic map( generic map(
G_PipelineStages => G_PipelineStages, G_Width => G_Y_Width
G_Width => G_Y_Width, )
G_RegisterBalancing => "forward"
)
port map( port map(
I_CLK => I_CLK, I_CLK => I_CLK,
I_Enable => S_CalculatingPipeline_Enable, I_Enable => O_VSpritePipeline_Ctrl_Enable,
I_Data => I_Y, I_Data => I_VSpritePipeline_OP_Y_Sprite,
O_Data => R_SpriteY O_Data => R0_Y_Sprite
); );
--@ Input register for the line to check if the sprite is in the line visible INST0_VSpritePipeline_Y_Request : entity work.PipelineRegister
I_YToCheck_InputRegister : entity work.PipelineRegister
generic map( generic map(
G_PipelineStages => G_PipelineStages, G_Width => G_Y_Width
G_Width => G_Y_Width, )
G_RegisterBalancing => "forward"
)
port map( port map(
I_CLK => I_CLK, I_CLK => I_CLK,
I_Enable => S_CalculatingPipeline_Enable, I_Enable => O_VSpritePipeline_Ctrl_Enable,
I_Data => I_YToCheck, I_Data => I_VSpritePipeline_OP_Y_Request,
O_Data => R_YToCheck 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. INST_VSpritePipeline_Y_Bottom_Sprite : entity work.PipelineRegister
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
generic map( generic map(
G_PipelineStages => G_PipelineStages, G_Width => G_Y_Width
G_Width => 1, )
G_RegisterBalancing => "backward" 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( port map(
I_CLK => I_CLK, I_CLK => I_CLK,
I_Enable => S_CalculatingPipeline_Enable, I_Enable => O_VSpritePipeline_Ctrl_Enable,
I_Data(0) => C_IsVisible, I_Data(0) => C_IsVisible,
O_Data(0) => O_IsVisible O_Data(0) => O_VSpritePipeline_IsVisible
); );
--@ Output register for the offset of the sprite INST_Offset_OutputRegister : entity work.PipelineRegister
I_Offset_OutputRegister : entity work.PipelineRegister
generic map( generic map(
G_PipelineStages => G_PipelineStages, G_Width => G_Offset_Width
G_Width => G_Offset_Width, )
G_RegisterBalancing => "backward"
)
port map( port map(
I_CLK => I_CLK, I_CLK => I_CLK,
I_Enable => S_CalculatingPipeline_Enable, I_Enable => O_VSpritePipeline_Ctrl_Enable,
I_Data => C_Offset, I_Data => C_Offset,
O_Data => O_Offset O_Data => O_VSpritePipeline_Offset
); );
end architecture; end architecture;