Adds priority encoders and pipeline-based modules

Implements various priority encoder components with combinatorial logic for encoding input vectors to output codes of varying widths.

Introduces pipeline-based modules for handling calculation, ROM data fetching, and scheduling operations with AXI-like handshaking interfaces.

Facilitates modular and reusable design for priority encoding and data processing tasks.
This commit is contained in:
2025-04-20 03:02:02 +00:00
commit bbe0ff9b9e
4 changed files with 1001 additions and 0 deletions

207
src/CalcPipeline.vhd Normal file
View File

@@ -0,0 +1,207 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity CalcPipeline is
generic (
--@ Width of the sprite index (Base address) register
G_Index_Width : integer := 5;
--@ Width of the sprite offset (Line address) register
G_Offset_Width : integer := 8;
--@ Width of the X position (Row) register
G_X_Width : integer := 10;
--@ Width of the pixel data from rom
G_Rom_Width : integer := 8;
--@ Width of the pixel data output
G_Pixel_Width : integer := 8
);
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 Start-OP @dir In Start calculation bus
--@ AXI like valid; (**Synchronous**, **Active high**)
I_OP_Valid : in std_logic;
--@ AXI like ready; (**Synchronous**, **Active high**)
O_OP_Ready : out std_logic;
--@ Index address
I_OP_Index : in std_logic_vector(G_Index_Width - 1 downto 0);
--@ Offset address
I_OP_Offset : in std_logic_vector(G_Offset_Width - 1 downto 0);
--@ X position of the request
I_OP_X_Request : in std_logic_vector(G_X_Width - 1 downto 0);
--@ X position of the sprite
I_OP_X_Sprite : in std_logic_vector(G_X_Width - 1 downto 0);
--@ @end
--@ @virtualbus Rom-Address @dir Out Request rom data bus
--@ AXI like valid; (**Synchronous**, **Active high**)
O_Rom_Valid : out std_logic;
--@ AXI like ready; (**Synchronous**, **Active high**)
I_Rom_Ready : in std_logic;
--@ Rom address
O_Rom_Address : out std_logic_vector(G_Index_Width + G_Offset_Width - 1 downto 0);
--@ @end
--@ @virtualbus Rom-Data @dir In Rom data bus
--@ AXI like valid; (**Synchronous**, **Active high**)
I_Rom_Valid : in std_logic;
--@ AXI like ready; (**Synchronous**, **Active high**)
O_Rom_Ready : out std_logic;
--@ Rom data
I_Rom_Data : in std_logic_vector(G_Rom_Width - 1 downto 0);
--@ @end
--@ @virtualbus Pixel-Data @dir Out Pixel data output bus
--@ AXI like valid; (**Synchronous**, **Active high**)
O_Pixel_Valid : out std_logic;
--@ AXI like ready; (**Synchronous**, **Active high**)
I_Pixel_Ready : in std_logic;
--@ Pixel data
O_Pixel_Data : out std_logic_vector(G_Pixel_Width - 1 downto 0)
--@ @end
);
end entity CalcPipeline;
architecture RTL of CalcPipeline is
signal R_Index : std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0');
signal R_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0');
signal R_X_Request : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
signal R_X_Sprite : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0');
signal C_Address : std_logic_vector(G_Index_Width + G_Offset_Width - 1 downto 0) := (others => '0');
signal R_Address : std_logic_vector(G_Index_Width + G_Offset_Width - 1 downto 0) := (others => '0');
signal I_I_Calculating_Ready : std_logic := '0';
signal O_I_Calculating_Valid : std_logic := '0';
signal I_O_Calculating_Ready : std_logic := '0';
signal O_O_Calculating_Valid : std_logic := '0';
signal C_X_Visible : std_logic := '0';
signal R_X_Visible : std_logic := '0';
signal I_RomRequest_Valid : std_logic := '0';
signal O_RomRequest_Ready : std_logic := '0';
begin
INST_I_Calculating : entity work.PipelineStage
generic map(
G_PipelineStages => 1,
G_D0_Width => G_Index_Width,
G_D1_Width => G_Offset_Width,
G_D2_Width => G_X_Width,
G_D3_Width => G_X_Width
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
I_RST => I_RST,
I_Valid => I_OP_Valid,
O_Ready => O_OP_Ready,
I_Data_0 => I_OP_Index,
I_Data_1 => I_OP_Offset,
I_Data_2 => I_OP_X_Request,
I_Data_3 => I_OP_X_Sprite,
O_Valid => O_I_Calculating_Valid,
I_Ready => I_I_Calculating_Ready,
O_Data_0 => R_Index,
O_Data_1 => R_Offset,
O_Data_2 => R_X_Request,
O_Data_3 => R_X_Sprite
);
process (R_Offset, R_Index, R_X_Request, R_X_Sprite)
variable V_Offset : unsigned(G_Offset_Width - 1 downto 0);
variable V_X_Request : unsigned(G_X_Width - 1 downto 0);
variable V_X_Sprite : unsigned(G_X_Width - 1 downto 0);
variable V_RelativeOffset : unsigned(G_X_Width - 1 downto 0);
variable V_CalculateOffset : unsigned(G_Offset_Width - 1 downto 0);
begin
V_Offset := unsigned(R_Offset);
V_X_Request := unsigned(R_X_Request);
V_X_Sprite := unsigned(R_X_Sprite);
V_RelativeOffset := V_X_Request - V_X_Sprite;
V_CalculateOffset := V_Offset + V_RelativeOffset(G_Offset_Width - 1 downto 0);
if V_CalculateOffset > 15 then
C_X_Visible <= '0';
else
C_X_Visible <= '1';
end if;
C_Address <= R_Index & std_logic_vector(V_CalculateOffset);
end process;
INST_O_Calculating : entity work.PipelineStage
generic map(
G_PipelineStages => 1,
G_D0_Width => G_Index_Width + G_Offset_Width,
G_D1_Width => 1
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
I_RST => I_RST,
I_Valid => O_I_Calculating_Valid,
O_Ready => I_I_Calculating_Ready,
I_Data_0 => C_Address,
I_Data_1(0) => C_X_Visible,
O_Valid => O_O_Calculating_Valid,
I_Ready => I_O_Calculating_Ready,
O_Data_0 => R_Address,
O_Data_1(0) => R_X_Visible
);
process (R_X_Visible, O_O_Calculating_Valid, O_RomRequest_Ready)
begin
if R_X_Visible = '0' then
I_RomRequest_Valid <= '0';
I_O_Calculating_Ready <= '1';
else
I_RomRequest_Valid <= O_O_Calculating_Valid;
I_O_Calculating_Ready <= O_RomRequest_Ready;
end if;
end process;
INST_RomRequest : entity work.PipelineStage
generic map(
G_PipelineStages => 1,
G_D0_Width => G_Index_Width + G_Offset_Width
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
I_RST => I_RST,
I_Valid => I_RomRequest_Valid,
O_Ready => O_RomRequest_Ready,
I_Data_0 => R_Address,
O_Valid => O_Rom_Valid,
I_Ready => I_Rom_Ready,
O_Data_0 => O_Rom_Address
);
I_ForwardPixelData : entity work.PipelineStage
generic map(
G_PipelineStages => 1,
G_D0_Width => G_Pixel_Width
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
I_RST => I_RST,
I_Valid => I_Rom_Valid,
O_Ready => O_Rom_Ready,
I_Data_0 => I_Rom_Data,
O_Valid => O_Pixel_Valid,
I_Ready => I_Pixel_Ready,
O_Data_0 => O_Pixel_Data
);
end architecture;

305
src/Rom.vhd Normal file
View File

@@ -0,0 +1,305 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.SpriteRom.all;
entity Rom is
generic (
--@ ROM Address Width
G_Address_Width : integer := 13;
--@ ROM Data Width
G_Data_Width : integer := 8;
--@ Port-0 In/Out Buffer Stages
G_P0_BufferStages : integer := 1;
--@ Port-0 Identifier Width
G_P0_ID_Width : integer := 4;
--@ Port-1 In/Out Buffer Stages
G_P1_BufferStages : integer := 1;
--@ Port-1 Identifier Width
G_P1_ID_Width : integer := 4;
--@ Implementation of the ROM: "Block" or "Distributed"
G_RomType : string := "Block"
);
port (
--@ Clock signal; (**Rising edge** triggered)
I_CLK : in std_logic := '0';
--@ Clock enable signal (**Active high**)
I_CE : in std_logic := '1';
--@ @virtualbus Address-Port-0 @dir in Address Port 0
I_P0_Address_Valid : in std_logic := '0';
O_P0_Address_Ready : out std_logic := '0';
I_P0_Address : in std_logic_vector(G_Address_Width - 1 downto 0) := (others => '0');
I_P0_ID : in std_logic_vector(G_P0_ID_Width - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus Address-Port-0 @dir in Address Port 0
I_P1_Address_Valid : in std_logic := '0';
O_P1_Address_Ready : out std_logic := '0';
I_P1_Address : in std_logic_vector(G_Address_Width - 1 downto 0) := (others => '0');
I_P1_ID : in std_logic_vector(G_P1_ID_Width - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus Data-Port-0 @dir out Data Port 0
O_P0_Data_Valid : out std_logic := '0';
I_P0_Data_Ready : in std_logic := '0';
O_P0_Data : out std_logic_vector(G_Data_Width - 1 downto 0) := (others => '0');
O_P0_ID : out std_logic_vector(G_P0_ID_Width - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus Data-Port-1 @dir out Data Port 1
O_P1_Data_Valid : out std_logic := '0';
I_P1_Data_Ready : in std_logic := '0';
O_P1_Data : out std_logic_vector(G_Data_Width - 1 downto 0) := (others => '0');
O_P1_ID : out std_logic_vector(G_P1_ID_Width - 1 downto 0) := (others => '0')
--@ @end
);
end entity Rom;
architecture Rtl of Rom is
signal Rom : T_Rom := K_SPRITE_ROM;
attribute ROM_STYLE : string;
attribute ROM_STYLE of Rom : signal is G_RomType;
signal S_P0_InBufferEnable : std_logic := '0';
signal S_P0_OutBufferEnable : std_logic := '0';
signal S_P0_Address_Valid : std_logic := '0';
signal R_P0_Address : std_logic_vector(G_Address_Width - 1 downto 0) := (others => '0');
signal R_P0_Address_ID : std_logic_vector(G_P0_ID_Width - 1 downto 0) := (others => '0');
signal R_P0_Data_Valid : std_logic := '0';
signal C_P0_Address_Ready : std_logic := '0';
signal S_P0_Data_Ready : std_logic := '0';
signal R_P0_Data : std_logic_vector(G_Data_Width - 1 downto 0) := (others => '0');
signal R_P0_Data_ID : std_logic_vector(G_P0_ID_Width - 1 downto 0) := (others => '0');
signal S_P1_InBufferEnable : std_logic := '0';
signal S_P1_OutBufferEnable : std_logic := '0';
signal S_P1_Address_Valid : std_logic := '0';
signal R_P1_Address : std_logic_vector(G_Address_Width - 1 downto 0) := (others => '0');
signal R_P1_Address_ID : std_logic_vector(G_P1_ID_Width - 1 downto 0) := (others => '0');
signal R_P1_Data_Valid : std_logic := '0';
signal C_P1_Address_Ready : std_logic := '0';
signal S_P1_Data_Ready : std_logic := '0';
signal R_P1_Data : std_logic_vector(G_Data_Width - 1 downto 0) := (others => '0');
signal R_P1_Data_ID : std_logic_vector(G_P1_ID_Width - 1 downto 0) := (others => '0');
begin
I_P0_InBufferCtrl : entity work.PipelineController
generic map(
G_PipelineStages => G_P0_BufferStages
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
O_Enable => S_P0_InBufferEnable,
I_Valid => I_P0_Address_Valid,
O_Ready => O_P0_Address_Ready,
O_Valid => S_P0_Address_Valid,
I_Ready => C_P0_Address_Ready
);
I_P0_InBuffer_Data : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P0_BufferStages,
G_Width => G_Address_Width,
G_RegisterBalancing => "forward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P0_InBufferEnable,
I_Data => I_P0_Address,
O_Data => R_P0_Address
);
I_P0_InBuffer_ID : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P0_BufferStages,
G_Width => G_P0_ID_Width,
G_RegisterBalancing => "forward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P0_InBufferEnable,
I_Data => I_P0_ID,
O_Data => R_P0_Address_ID
);
C_P0_Address_Ready <= not R_P0_Data_Valid;
P_P0_Flags : process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_CE = '1' then
if S_P0_Address_Valid = '1' and C_P0_Address_Ready = '1' then
R_P0_Data_Valid <= '1';
R_P0_Data_ID <= R_P0_Address_ID;
end if;
if S_P0_Data_Ready = '1' and R_P0_Data_Valid = '1' then
R_P0_Data_Valid <= '0';
end if;
end if;
end if;
end process;
P_P0_Read : process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_CE = '1' then
R_P0_Data <= Rom(to_integer(unsigned(R_P0_Address)));
end if;
end if;
end process;
I_P0_OutBufferCtrl : entity work.PipelineController
generic map(
G_PipelineStages => G_P0_BufferStages
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
O_Enable => S_P0_OutBufferEnable,
I_Valid => R_P0_Data_Valid,
O_Ready => S_P0_Data_Ready,
O_Valid => O_P0_Data_Valid,
I_Ready => I_P0_Data_Ready
);
I_P0_OutBuffer_Data : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P0_BufferStages,
G_Width => G_Data_Width,
G_RegisterBalancing => "backward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P0_OutBufferEnable,
I_Data => R_P0_Data,
O_Data => O_P0_Data
);
I_P0_OutBuffer_ID : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P0_BufferStages,
G_Width => G_P0_ID_Width,
G_RegisterBalancing => "backward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P0_OutBufferEnable,
I_Data => R_P0_Data_ID,
O_Data => O_P0_ID
);
-----------------------
I_P1_InBufferCtrl : entity work.PipelineController
generic map(
G_PipelineStages => G_P1_BufferStages
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
O_Enable => S_P1_InBufferEnable,
I_Valid => I_P1_Address_Valid,
O_Ready => O_P1_Address_Ready,
O_Valid => S_P1_Address_Valid,
I_Ready => C_P1_Address_Ready
);
I_P1_InBuffer_Data : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P1_BufferStages,
G_Width => G_Address_Width,
G_RegisterBalancing => "forward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P1_InBufferEnable,
I_Data => I_P1_Address,
O_Data => R_P1_Address
);
I_P1_InBuffer_ID : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P1_BufferStages,
G_Width => G_P1_ID_Width,
G_RegisterBalancing => "forward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P1_InBufferEnable,
I_Data => I_P1_ID,
O_Data => R_P1_Address_ID
);
C_P1_Address_Ready <= not R_P1_Data_Valid;
P_P1_Flags : process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_CE = '1' then
if S_P1_Address_Valid = '1' and C_P1_Address_Ready = '1' then
R_P1_Data_Valid <= '1';
R_P1_Data_ID <= R_P1_Address_ID;
end if;
if S_P1_Data_Ready = '1' and R_P1_Data_Valid = '1' then
R_P1_Data_Valid <= '0';
end if;
end if;
end if;
end process;
P_P1_Read : process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_CE = '1' then
R_P1_Data <= Rom(to_integer(unsigned(R_P1_Address)));
end if;
end if;
end process;
I_P1_OutBufferCtrl : entity work.PipelineController
generic map(
G_PipelineStages => G_P1_BufferStages
)
port map(
I_CLK => I_CLK,
I_CE => I_CE,
O_Enable => S_P1_OutBufferEnable,
I_Valid => R_P1_Data_Valid,
O_Ready => S_P1_Data_Ready,
O_Valid => O_P1_Data_Valid,
I_Ready => I_P1_Data_Ready
);
I_P1_OutBuffer : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P1_BufferStages,
G_Width => G_Data_Width,
G_RegisterBalancing => "backward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P1_OutBufferEnable,
I_Data => R_P1_Data,
O_Data => O_P1_Data
);
I_P1_OutBuffer_ID : entity work.PipelineRegister
generic map(
G_PipelineStages => G_P1_BufferStages,
G_Width => G_P1_ID_Width,
G_RegisterBalancing => "backward"
)
port map(
I_CLK => I_CLK,
I_Enable => S_P1_OutBufferEnable,
I_Data => R_P1_Data_ID,
O_Data => O_P1_ID
);
end architecture;

144
src/Scheduler.vhd Normal file
View File

@@ -0,0 +1,144 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity AXI_Handshaking_Scheduler_4 is
generic (
G_DataWidth : integer := 32
);
port (
--@ Clock signal; (**Rising edge** triggered)
I_CLK : in std_logic;
--@ Clock enable signal (**Active high**)
I_CE : in std_logic;
--@ Synchronous reset signal (**Active high**)
I_RST : in std_logic;
--@ @virtualbus P0 @dir in P0 interface
I_P0_Valid : in std_logic := '0';
O_P0_Ready : out std_logic := '0';
I_P0_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus P1 @dir in P1 interface
I_P1_Valid : in std_logic := '0';
O_P1_Ready : out std_logic := '0';
I_P1_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus P2 @dir in P2 interface
I_P2_Valid : in std_logic := '0';
O_P2_Ready : out std_logic := '0';
I_P2_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus P3 @dir in P3 interface
I_P3_Valid : in std_logic := '0';
O_P3_Ready : out std_logic := '0';
I_P3_Data : in std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
--@ @end
--@ @virtualbus Out @dir out Output interface
O_Out_Valid : out std_logic := '0';
I_Out_Ready : in std_logic := '0';
O_Out_Data : out std_logic_vector(G_DataWidth - 1 downto 0) := (others => '0');
O_Out_Address : out std_logic_vector(1 downto 0) := (others => '0')
--@ @end
);
end entity AXI_Handshaking_Scheduler_4;
architecture Rtl of AXI_Handshaking_Scheduler_4 is
signal R_Counter : unsigned(1 downto 0) := (others => '0');
signal C_Select : std_logic_vector(3 downto 0) := (others => '0');
signal C_Code : std_logic_vector(1 downto 0) := (others => '0');
signal C_CodeReverse : std_logic_vector(1 downto 0) := (others => '0');
begin
i_PriorityEncoder_4 : entity work.PriorityEncoder_4
port map(
I_Select => C_Select,
O_Code => C_Code
);
P_SelectMux : process (R_Counter, I_P0_Valid, I_P1_Valid, I_P2_Valid, I_P3_Valid)
begin
if R_Counter = "00" then
C_Select <= I_P0_Valid & I_P1_Valid & I_P2_Valid & I_P3_Valid;
elsif R_Counter = "01" then
C_Select <= I_P1_Valid & I_P2_Valid & I_P3_Valid & I_P0_Valid;
elsif R_Counter = "10" then
C_Select <= I_P2_Valid & I_P3_Valid & I_P0_Valid & I_P1_Valid;
elsif R_Counter = "11" then
C_Select <= I_P3_Valid & I_P0_Valid & I_P1_Valid & I_P2_Valid;
else
C_Select <= (others => '-');
end if;
end process;
P_CodeReverse : process (C_Code, R_Counter)
begin
C_CodeReverse <= std_logic_vector(unsigned(C_Code) + R_Counter);
end process;
P_OutMux : process (
C_CodeReverse, I_P0_Data, I_P1_Data, I_P2_Data, I_P3_Data,
I_P0_Valid, I_P1_Valid, I_P2_Valid, I_P3_Valid,
I_Out_Ready)
begin
O_Out_Valid <= '0';
O_P0_Ready <= '0';
O_P1_Ready <= '0';
O_P2_Ready <= '0';
O_P3_Ready <= '0';
O_Out_Data <= (others => '0');
O_Out_Address <= C_CodeReverse;
case C_CodeReverse is
when "00" =>
O_Out_Valid <= I_P0_Valid;
O_P0_Ready <= I_Out_Ready;
O_Out_Data <= I_P0_Data;
when "01" =>
O_Out_Valid <= I_P1_Valid;
O_P1_Ready <= I_Out_Ready;
O_Out_Data <= I_P1_Data;
when "10" =>
O_Out_Valid <= I_P2_Valid;
O_P2_Ready <= I_Out_Ready;
O_Out_Data <= I_P2_Data;
when "11" =>
O_Out_Valid <= I_P3_Valid;
O_P3_Ready <= I_Out_Ready;
O_Out_Data <= I_P3_Data;
when others =>
null;
end case;
end process;
P_Counter : process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_CE = '1' then
if I_RST = '1' then
R_Counter <= (others => '0');
else
if I_Out_Ready = '1' then
case C_CodeReverse is
when "00" =>
R_Counter <= "01";
when "01" =>
R_Counter <= "10";
when "10" =>
R_Counter <= "11";
when "11" =>
R_Counter <= "00";
when others =>
R_Counter <= "00";
end case;
end if;
end if;
end if;
end if;
end process P_Counter;
end architecture;