From bbe0ff9b9e71f4a328ac92dd9d01297e4353a1ab Mon Sep 17 00:00:00 2001 From: MaxP Date: Sun, 20 Apr 2025 03:02:02 +0000 Subject: [PATCH] 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. --- libs/PriorityEncoders.vhd | 345 ++++++++++++++++++++++++++++++++++++++ src/CalcPipeline.vhd | 207 +++++++++++++++++++++++ src/Rom.vhd | 305 +++++++++++++++++++++++++++++++++ src/Scheduler.vhd | 144 ++++++++++++++++ 4 files changed, 1001 insertions(+) create mode 100644 libs/PriorityEncoders.vhd create mode 100644 src/CalcPipeline.vhd create mode 100644 src/Rom.vhd create mode 100644 src/Scheduler.vhd diff --git a/libs/PriorityEncoders.vhd b/libs/PriorityEncoders.vhd new file mode 100644 index 0000000..0af3b3c --- /dev/null +++ b/libs/PriorityEncoders.vhd @@ -0,0 +1,345 @@ +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (2 to 1 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 1-bit output code. +entity PriorityEncoder_2 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(1 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(0 downto 0) := (others => '0') + ); +end entity PriorityEncoder_2; + +architecture Combinatoric of PriorityEncoder_2 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(0 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; +begin + C_Code <= "0" when I_Select(1) = '1' else + "1" when I_Select(0) = '1' else + "-"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (4 to 2 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 2-bit output code. +entity PriorityEncoder_4 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(3 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(1 downto 0) := (others => '0') + ); +end entity PriorityEncoder_4; + +architecture Combinatoric of PriorityEncoder_4 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(1 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; +begin + C_Code <= "00" when I_Select(3) = '1' else + "01" when I_Select(2) = '1' else + "10" when I_Select(1) = '1' else + "11" when I_Select(0) = '1' else + "--"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (8 to 3 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 3-bit output code. +entity PriorityEncoder_8 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(7 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(2 downto 0) := (others => '0') + ); +end entity PriorityEncoder_8; + +architecture Combinatoric of PriorityEncoder_8 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(2 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; +begin + C_Code <= "000" when I_Select(7) = '1' else + "001" when I_Select(6) = '1' else + "010" when I_Select(5) = '1' else + "011" when I_Select(4) = '1' else + "100" when I_Select(3) = '1' else + "101" when I_Select(2) = '1' else + "110" when I_Select(1) = '1' else + "111" when I_Select(0) = '1' else + "---"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (16 to 4 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 4-bit output code. +entity PriorityEncoder_16 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(15 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(3 downto 0) := (others => '0') + ); +end entity PriorityEncoder_16; + +architecture Combinatoric of PriorityEncoder_16 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(3 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; +begin + C_Code <= "0000" when I_Select(15) = '1' else + "0001" when I_Select(14) = '1' else + "0010" when I_Select(13) = '1' else + "0011" when I_Select(12) = '1' else + "0100" when I_Select(11) = '1' else + "0101" when I_Select(10) = '1' else + "0110" when I_Select(9) = '1' else + "0111" when I_Select(8) = '1' else + "1000" when I_Select(7) = '1' else + "1001" when I_Select(6) = '1' else + "1010" when I_Select(5) = '1' else + "1011" when I_Select(4) = '1' else + "1100" when I_Select(3) = '1' else + "1101" when I_Select(2) = '1' else + "1110" when I_Select(1) = '1' else + "1111" when I_Select(0) = '1' else + "----"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (32 to 5 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 5-bit output code. +entity PriorityEncoder_32 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(31 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(4 downto 0) := (others => '0') + ); +end entity PriorityEncoder_32; + +architecture Combinatoric of PriorityEncoder_32 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(4 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; + +begin + C_Code <= "00000" when I_Select(31) = '1' else + "00001" when I_Select(30) = '1' else + "00010" when I_Select(29) = '1' else + "00011" when I_Select(28) = '1' else + "00100" when I_Select(27) = '1' else + "00101" when I_Select(26) = '1' else + "00110" when I_Select(25) = '1' else + "00111" when I_Select(24) = '1' else + "01000" when I_Select(23) = '1' else + "01001" when I_Select(22) = '1' else + "01010" when I_Select(21) = '1' else + "01011" when I_Select(20) = '1' else + "01100" when I_Select(19) = '1' else + "01101" when I_Select(18) = '1' else + "01110" when I_Select(17) = '1' else + "01111" when I_Select(16) = '1' else + "10000" when I_Select(15) = '1' else + "10001" when I_Select(14) = '1' else + "10010" when I_Select(13) = '1' else + "10011" when I_Select(12) = '1' else + "10100" when I_Select(11) = '1' else + "10101" when I_Select(10) = '1' else + "10110" when I_Select(9) = '1' else + "10111" when I_Select(8) = '1' else + "11000" when I_Select(7) = '1' else + "11001" when I_Select(6) = '1' else + "11010" when I_Select(5) = '1' else + "11011" when I_Select(4) = '1' else + "11100" when I_Select(3) = '1' else + "11101" when I_Select(2) = '1' else + "11110" when I_Select(1) = '1' else + "11111" when I_Select(0) = '1' else + "-----"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; + +--@ Priority Encoder (64 to 6 bits) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 6-bit output code. +entity PriorityEncoder_64 is + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(63 downto 0) := (others => '0'); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(5 downto 0) := (others => '0') + ); +end entity PriorityEncoder_64; + +architecture Combinatoric of PriorityEncoder_64 is + --@ Internal signal to hold the encoded output. + signal C_Code : std_logic_vector(5 downto 0); + + --@ Attribute to force the synthesis tool (XST, old Parser) to treat this as a combinatorial signal. + attribute PRIORITY_EXTRACT : string; + attribute PRIORITY_EXTRACT of C_Code : signal is "force"; + +begin + C_Code <= "000000" when I_Select(63) = '1' else + "000001" when I_Select(62) = '1' else + "000010" when I_Select(61) = '1' else + "000011" when I_Select(60) = '1' else + "000100" when I_Select(59) = '1' else + "000101" when I_Select(58) = '1' else + "000110" when I_Select(57) = '1' else + "000111" when I_Select(56) = '1' else + "001000" when I_Select(55) = '1' else + "001001" when I_Select(54) = '1' else + "001010" when I_Select(53) = '1' else + "001011" when I_Select(52) = '1' else + "001100" when I_Select(51) = '1' else + "001101" when I_Select(50) = '1' else + "001110" when I_Select(49) = '1' else + "001111" when I_Select(48) = '1' else + "010000" when I_Select(47) = '1' else + "010001" when I_Select(46) = '1' else + "010010" when I_Select(45) = '1' else + "010011" when I_Select(44) = '1' else + "010100" when I_Select(43) = '1' else + "010101" when I_Select(42) = '1' else + "010110" when I_Select(41) = '1' else + "010111" when I_Select(40) = '1' else + "011000" when I_Select(39) = '1' else + "011001" when I_Select(38) = '1' else + "011010" when I_Select(37) = '1' else + "011011" when I_Select(36) = '1' else + "011100" when I_Select(35) = '1' else + "011101" when I_Select(34) = '1' else + "011110" when I_Select(33) = '1' else + "011111" when I_Select(32) = '1' else + "100000" when I_Select(31) = '1' else + "100001" when I_Select(30) = '1' else + "100010" when I_Select(29) = '1' else + "100011" when I_Select(28) = '1' else + "100100" when I_Select(27) = '1' else + "100101" when I_Select(26) = '1' else + "100110" when I_Select(25) = '1' else + "100111" when I_Select(24) = '1' else + "101000" when I_Select(23) = '1' else + "101001" when I_Select(22) = '1' else + "101010" when I_Select(21) = '1' else + "101011" when I_Select(20) = '1' else + "101100" when I_Select(19) = '1' else + "101101" when I_Select(18) = '1' else + "101110" when I_Select(17) = '1' else + "101111" when I_Select(16) = '1' else + "110000" when I_Select(15) = '1' else + "110001" when I_Select(14) = '1' else + "110010" when I_Select(13) = '1' else + "110011" when I_Select(12) = '1' else + "110100" when I_Select(11) = '1' else + "110101" when I_Select(10) = '1' else + "110110" when I_Select(9) = '1' else + "110111" when I_Select(8) = '1' else + "111000" when I_Select(7) = '1' else + "111001" when I_Select(6) = '1' else + "111010" when I_Select(5) = '1' else + "111011" when I_Select(4) = '1' else + "111100" when I_Select(3) = '1' else + "111101" when I_Select(2) = '1' else + "111110" when I_Select(1) = '1' else + "111111" when I_Select(0) = '1' else + "------"; + + O_Code <= C_Code; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +--@ Priority Encoder (Generic) +--@ This is a combinatorial priority encoder that encodes the highest priority +--@ bit in the input vector to a 6-bit output code. +entity PriorityEncoder_G is + generic ( + --@ Code width with minimum 2 bits and maximum 6 bits. + G_CodeWidth : integer := 6 + ); + port ( + --@ Input vector to be encoded. + --@ The least significant bit has the highest priority. + I_Select : in std_logic_vector(2 ** G_CodeWidth - 1 downto 0); + --@ Output code. + --@ The output code is the index of the highest priority bit in the input vector. + O_Code : out std_logic_vector(G_CodeWidth - 1 downto 0) + ); +end entity PriorityEncoder_G; + +architecture Combinatoric of PriorityEncoder_G is + signal C_Select : std_logic_vector(63 downto 0) := (others => '-'); + signal C_Code : std_logic_vector(5 downto 0) := (others => '-'); +begin + + entity_inst : entity work.PriorityEncoder_64 + port map( + I_Select => C_Select, + O_Code => C_Code + ); + + C_Select(G_CodeWidth * 2 - 1 downto 0) <= I_Select; + O_Code <= C_Code(G_CodeWidth - 1 downto 0); +end architecture; diff --git a/src/CalcPipeline.vhd b/src/CalcPipeline.vhd new file mode 100644 index 0000000..948cfef --- /dev/null +++ b/src/CalcPipeline.vhd @@ -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; diff --git a/src/Rom.vhd b/src/Rom.vhd new file mode 100644 index 0000000..7934d46 --- /dev/null +++ b/src/Rom.vhd @@ -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; diff --git a/src/Scheduler.vhd b/src/Scheduler.vhd new file mode 100644 index 0000000..d776653 --- /dev/null +++ b/src/Scheduler.vhd @@ -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;