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

@@ -11,9 +11,7 @@ entity VerticalSpritePipeline is
--@ 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)
@@ -21,35 +19,44 @@ entity VerticalSpritePipeline is
--@ Clock enable signal (**Active high**)
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')
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';
@@ -57,106 +64,114 @@ architecture Rtl of VerticalSpritePipeline is
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
);
--@ 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);
--@ 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)
);
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 => S_CalculatingPipeline_Enable,
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 => 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;