From 49be0b81a060432989364575b10348df0d1e7d0e Mon Sep 17 00:00:00 2001 From: MaxP Date: Mon, 21 Apr 2025 15:37:01 +0000 Subject: [PATCH] Add testbench and configuration files for SpriteChannel and YHitCheck modules Not functional yet --- libs/PriorityEncoders.vhd | 345 --------------------------- test/OPDecoder_tb.vhd | 221 +++++++++++++++++ test/RegisterFile_tb.vhd.bak | 176 ++++++++++++++ test/SpriteChannel/CalcPipeline.wcfg | 199 +++++++++++++++ test/SpriteChannel/Default.wcfg | 292 +++++++++++++++++++++++ test/SpriteChannel/Rom.wcfg | 55 +++++ test/SpriteChannel/Y_HitCheck.wcfg | 129 ++++++++++ test/SpriteChannel_tb.vhd | 194 +++++++++++++++ test/YHitCheck_tb.vhd | 165 +++++++++++++ 9 files changed, 1431 insertions(+), 345 deletions(-) delete mode 100644 libs/PriorityEncoders.vhd create mode 100644 test/OPDecoder_tb.vhd create mode 100644 test/RegisterFile_tb.vhd.bak create mode 100644 test/SpriteChannel/CalcPipeline.wcfg create mode 100644 test/SpriteChannel/Default.wcfg create mode 100644 test/SpriteChannel/Rom.wcfg create mode 100644 test/SpriteChannel/Y_HitCheck.wcfg create mode 100644 test/SpriteChannel_tb.vhd create mode 100644 test/YHitCheck_tb.vhd diff --git a/libs/PriorityEncoders.vhd b/libs/PriorityEncoders.vhd deleted file mode 100644 index 0af3b3c..0000000 --- a/libs/PriorityEncoders.vhd +++ /dev/null @@ -1,345 +0,0 @@ -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/test/OPDecoder_tb.vhd b/test/OPDecoder_tb.vhd new file mode 100644 index 0000000..a83bff9 --- /dev/null +++ b/test/OPDecoder_tb.vhd @@ -0,0 +1,221 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.OPCodes.all; +use std.env.stop; + +entity OPDecoder_tb is +end entity OPDecoder_tb; + +architecture bench of OPDecoder_tb is + -- Clock period + constant K_CLKPeriod : time := 10 ns; + -- Generics + constant G_OPCodeData_Width : integer := 10; + constant G_ROM_DataWidth : integer := 16; + constant G_Index_Width : integer := 6; + constant G_Offset_Width : integer := 4; + constant G_LineData_Width : integer := 16; + constant G_X_Width : integer := 10; + constant G_Y_Width : integer := 10; + constant G_Sprite_Height : integer := 16; + constant G_PipelineStages : integer := 2; + + -- Ports + signal I_CLK : std_logic; + signal I_CE : std_logic; + signal I_RST : std_logic; + signal I_OP_Valid : std_logic := '0'; + signal O_OP_Ready : std_logic := '0'; + signal I_OP_Code : std_logic_vector(3 downto 0) := (others => '0'); + signal I_OP_Data : std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0'); + signal O_Register_Index_WE : std_logic := '0'; + signal O_Register_Index : std_logic_vector(G_Index_Width - 1 downto 0) := (others => '0'); + signal O_Register_Offset_WE : std_logic := '0'; + signal O_Register_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0'); + signal O_Register_X_We : std_logic := '0'; + signal O_Register_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0'); + signal O_Register_Y_WE : std_logic := '0'; + signal O_Register_Y : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + signal O_Register_CachedLineData_WE : std_logic := '0'; + signal O_Register_CachedLineData : std_logic_vector(G_LineData_Width - 1 downto 0) := (others => '0'); + signal O_Register_CacheValid_WE : std_logic := '0'; + signal O_Register_CacheValid : std_logic := '0'; + signal I_YHitCheck_Ready : std_logic := '0'; + signal O_YHitCheck_Valid : std_logic := '0'; + signal O_YHitCheck_YToCheck : std_logic_vector(G_Y_Width - 1 downto 0) := (others => '0'); + signal O_YHitCheck_Ready : std_logic := '0'; + signal I_YHitCheck_Valid : std_logic := '0'; + signal I_YHitCheck_IsVisible : std_logic := '0'; + signal I_YHitCheck_Offset : std_logic_vector(G_Offset_Width - 1 downto 0) := (others => '0'); + signal O_Rom_Valid : std_logic := '0'; + signal I_Rom_Ready : std_logic := '0'; + signal I_Rom_Valid : std_logic := '0'; + signal O_Rom_Ready : std_logic := '0'; + signal I_Rom_Data : std_logic_vector(G_ROM_DataWidth - 1 downto 0) := (others => '0'); + signal O_CalcPipeline_Valid : std_logic := '0'; + signal I_CalcPipeline_Ready : std_logic := '0'; + signal O_CalcPipeline_X : std_logic_vector(G_X_Width - 1 downto 0) := (others => '0'); + + signal R1, R2 : std_logic := '0'; + + signal TestDone : boolean := false; +begin + + ClockProc : process + begin + while TestDone = false loop + I_CLK <= '0'; + wait for K_CLKPeriod / 2; + I_CLK <= '1'; + wait for K_CLKPeriod / 2; + end loop; + + I_CLK <= '0'; + stop(0); + wait; + end process; + + i_OPDecoder : entity work.OPDecoder + generic map( + G_OPCodeData_Width => G_OPCodeData_Width, + G_ROM_DataWidth => G_ROM_DataWidth, + G_Index_Width => G_Index_Width, + G_Offset_Width => G_Offset_Width, + G_LineData_Width => G_LineData_Width, + G_X_Width => G_X_Width, + G_Y_Width => G_Y_Width + ) + port map( + I_CLK => I_CLK, + I_CE => I_CE, + I_RST => I_RST, + I_OP_Valid => I_OP_Valid, + O_OP_Ready => O_OP_Ready, + I_OP_Code => I_OP_Code, + I_OP_Data => I_OP_Data, + O_Register_Index_WE => O_Register_Index_WE, + O_Register_Index => O_Register_Index, + O_Register_Offset_WE => O_Register_Offset_WE, + O_Register_Offset => O_Register_Offset, + O_Register_X_We => O_Register_X_We, + O_Register_X => O_Register_X, + O_Register_Y_WE => O_Register_Y_WE, + O_Register_Y => O_Register_Y, + O_Register_CachedLineData_WE => O_Register_CachedLineData_WE, + O_Register_CachedLineData => O_Register_CachedLineData, + O_Register_CacheValid_WE => O_Register_CacheValid_WE, + O_Register_CacheValid => O_Register_CacheValid, + I_YHitCheck_Ready => I_YHitCheck_Ready, + O_YHitCheck_Valid => O_YHitCheck_Valid, + O_YHitCheck_YToCheck => O_YHitCheck_YToCheck, + O_YHitCheck_Ready => O_YHitCheck_Ready, + I_YHitCheck_Valid => I_YHitCheck_Valid, + I_YHitCheck_IsVisible => I_YHitCheck_IsVisible, + I_YHitCheck_Offset => I_YHitCheck_Offset, + O_Rom_Valid => O_Rom_Valid, + I_Rom_Ready => I_Rom_Ready, + I_Rom_Valid => I_Rom_Valid, + O_Rom_Ready => O_Rom_Ready, + I_Rom_Data => I_Rom_Data, + O_HSpritePipeline_Valid => O_CalcPipeline_Valid, + I_HSpritePipeline_Ready => I_CalcPipeline_Ready, + O_HSpritePipeline_X_Request => O_CalcPipeline_X + ); + + I_CalcPipeline_Ready <= O_CalcPipeline_Valid; + + i_YHitCheck : entity work.VerticalSpritePipeline + generic map( + G_Y_Width => G_Y_Width, + G_Sprite_Height => G_Sprite_Height, + G_Offset_Width => G_Offset_Width, + G_PipelineStages => G_PipelineStages + ) + port map( + I_CLK => I_CLK, + I_CE => I_CE, + O_Ready => I_YHitCheck_Ready, + I_Valid => O_YHitCheck_Valid, + I_YToCheck => O_YHitCheck_YToCheck, + I_Y => "0000000000", + I_Ready => O_YHitCheck_Ready, + O_Valid => I_YHitCheck_Valid, + O_IsVisible => I_YHitCheck_IsVisible, + O_Offset => I_YHitCheck_Offset + ); + + StimulusProc : process + type T_OpTest is record + Code : std_logic_vector(3 downto 0); + Data : std_logic_vector(G_OPCodeData_Width - 1 downto 0); + Name : string(1 to 20); + end record; + + type T_OpTestArray is array (natural range <>) of T_OpTest; + + constant TestCases : T_OpTestArray := ( + 0 => (K_OP_NOP, (others => '0'), "NOP "), + 1 => (K_OP_SET_ID, std_logic_vector(to_unsigned(2, G_OPCodeData_Width)), "SET_ID "), + 2 => (K_OP_SET_X, std_logic_vector(to_unsigned(3, G_OPCodeData_Width)), "SET_X "), + 3 => (K_OP_SET_Y, std_logic_vector(to_unsigned(4, G_OPCodeData_Width)), "SET_Y "), + 4 => (K_OP_CLEAR_ALL, (others => '1'), "CLEAR_ALL "), + 6 => (K_OP_REQ_ROW_DATA, std_logic_vector(to_unsigned(5, G_OPCodeData_Width)), "REQ_ROW_DATA "), + 5 => (K_OP_NEWLINE, std_logic_vector(to_unsigned(1, G_Y_Width)), "NEWLINE ") + ); + + variable i : integer; + begin + -- Init + I_RST <= '1'; + I_CE <= '1'; + wait for K_CLKPeriod * 2; + I_RST <= '0'; + wait for K_CLKPeriod * 2; + + for i in TestCases'range loop + -- Warte auf Ready + wait until rising_edge(I_CLK); + while O_OP_Ready /= '1' loop + wait until rising_edge(I_CLK); + end loop; + + I_OP_Code <= TestCases(i).Code; + I_OP_Data <= TestCases(i).Data; + I_OP_Valid <= '1'; + + wait until rising_edge(I_CLK); + I_OP_Valid <= '0'; + + -- Einfach ein bisschen warten, bis Modul durch ist + -- wait for K_CLKPeriod * 5; + + report "Opcode-Test: " & TestCases(i).Name & " abgeschlossen." severity note; + end loop; + + report "Alle OPCodes getestet." severity note; + TestDone <= true; + wait; + end process; + + -- ROM Simulation: immer gültig, gibt X"FFFF" zurück + RomProcess : process (I_CLK) + begin + if rising_edge(I_CLK) then + if I_CE = '1' then + -- Standard: nichts tun + I_Rom_Valid <= '0'; + I_Rom_Data <= (others => '0'); + + -- Prüfen, ob Decoder Daten anfordert + if O_Rom_Valid = '1' then + I_Rom_Valid <= '1'; + I_Rom_Data <= (others => '1'); -- z.B. X"FFFF" + end if; + end if; + end if; + end process; + + -- ROM ist immer bereit + I_Rom_Ready <= '1'; +end architecture; diff --git a/test/RegisterFile_tb.vhd.bak b/test/RegisterFile_tb.vhd.bak new file mode 100644 index 0000000..2e682af --- /dev/null +++ b/test/RegisterFile_tb.vhd.bak @@ -0,0 +1,176 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.env.stop; + +entity SpriteChannel_RegisterFile_tb is +end; + +architecture bench of SpriteChannel_RegisterFile_tb is + -- Clock period + constant K_CLKPeriod : time := 10 ns; + + -- Generics + constant G_SpriteIDWidth : integer := 10; + constant G_SpriteLineWidth : integer := 16; + constant G_XWidth : integer := 10; + constant G_YWidth : integer := 10; + + -- Ports + signal I_CLK : std_logic; + signal I_CE : std_logic; + signal I_RST : std_logic; + signal I_SpriteID_WE : std_logic; + signal I_SpriteID : std_logic_vector(G_SpriteIDWidth - 1 downto 0); + signal I_X_WE : std_logic; + signal I_X : std_logic_vector(G_XWidth - 1 downto 0); + signal I_Y_WE : std_logic; + signal I_Y : std_logic_vector(G_YWidth - 1 downto 0); + signal I_SpriteLine_WE : std_logic; + signal I_SpriteLine : std_logic_vector(G_SpriteLineWidth - 1 downto 0); + signal I_SpriteLineValid_WE : std_logic; + signal I_SpriteLineValid : std_logic; + signal O_SpriteID : std_logic_vector(G_SpriteIDWidth - 1 downto 0); + signal O_X : std_logic_vector(G_XWidth - 1 downto 0); + signal O_Y : std_logic_vector(G_YWidth - 1 downto 0); + signal O_SpriteLine : std_logic_vector(G_SpriteLineWidth - 1 downto 0); + signal O_SpriteLineValid : std_logic; + + -- Test control signals + signal TestDone : boolean := false; + + type T_TestCase is record + SpriteID : integer; + X : integer; + Y : integer; + SpriteLine : integer; + SpriteLineValid : std_logic; + end record; + + type T_TestArray is array (natural range <>) of T_TestCase; + + constant TestValues : T_TestArray := ( + (SpriteID => 5, X => 100, Y => 200, SpriteLine => 1234, SpriteLineValid => '1'), + (SpriteID => 42, X => 10, Y => 20, SpriteLine => 65535, SpriteLineValid => '0'), + (SpriteID => 0, X => 0, Y => 0, SpriteLine => 0, SpriteLineValid => '1'), + (SpriteID => 1023, X => 1023, Y => 1023, SpriteLine => 1, SpriteLineValid => '1') + ); +begin + + ClockProc : process + begin + while TestDone = false loop + I_CLK <= '0'; + wait for K_CLKPeriod / 2; + I_CLK <= '1'; + wait for K_CLKPeriod / 2; + end loop; + + I_CLK <= '0'; + stop(0); + wait; + end process; + + SpriteChannel_RegisterFile_inst : entity work.RegisterFile + generic map( + G_SpriteAddrWidth => G_SpriteIDWidth, + G_LineData_Width => G_SpriteLineWidth, + G_X_Width => G_XWidth, + G_Y_Width => G_YWidth + ) + port map( + I_CLK => I_CLK, + I_CE => I_CE, + I_RST => I_RST, + I_SpriteAddr_WE => I_SpriteID_WE, + I_SpriteAddr => I_SpriteID, + I_X_We => I_X_WE, + I_X => I_X, + I_Y_WE => I_Y_WE, + I_Y => I_Y, + I_CachedLineData_WE => I_SpriteLine_WE, + I_CachedLineData => I_SpriteLine, + I_CacheValid_WE => I_SpriteLineValid_WE, + I_CacheValid => I_SpriteLineValid, + O_SpriteAddr => O_SpriteID, + O_X => O_X, + O_Y => O_Y, + O_CachedRowData => O_SpriteLine, + O_CacheValid => O_SpriteLineValid + ); + + StimulusProc : process + variable i : integer; + begin + -- Init + i := 0; + I_CE <= '1'; + I_RST <= '1'; + I_SpriteID_WE <= '0'; + I_SpriteID <= (others => '0'); + I_X_WE <= '0'; + I_X <= (others => '0'); + I_Y_WE <= '0'; + I_Y <= (others => '0'); + I_SpriteLine_WE <= '0'; + I_SpriteLine <= (others => '0'); + I_SpriteLineValid_WE <= '0'; + I_SpriteLineValid <= '0'; + wait for K_CLKPeriod * 2; + I_RST <= '0'; + wait for K_CLKPeriod * 2; + + for i in TestValues'range loop + -- WRITE phase + I_SpriteID <= std_logic_vector(to_unsigned(TestValues(i).SpriteID, G_SpriteIDWidth)); + I_SpriteID_WE <= '1'; + I_X <= std_logic_vector(to_unsigned(TestValues(i).X, G_XWidth)); + I_X_WE <= '1'; + I_Y <= std_logic_vector(to_unsigned(TestValues(i).Y, G_YWidth)); + I_Y_WE <= '1'; + I_SpriteLine <= std_logic_vector(to_unsigned(TestValues(i).SpriteLine, G_SpriteLineWidth)); + I_SpriteLine_WE <= '1'; + I_SpriteLineValid <= TestValues(i).SpriteLineValid; + I_SpriteLineValid_WE <= '1'; + + wait until rising_edge(I_CLK); + -- deactivate write signals + I_SpriteID_WE <= '0'; + I_X_WE <= '0'; + I_Y_WE <= '0'; + I_SpriteLine_WE <= '0'; + I_SpriteLineValid_WE <= '0'; + + wait for K_CLKPeriod; + + -- READ and CHECK + assert O_SpriteID = std_logic_vector(to_unsigned(TestValues(i).SpriteID, G_SpriteIDWidth)) + report "Fehler: SpriteID falsch bei Test " & integer'image(i) + severity error; + + assert O_X = std_logic_vector(to_unsigned(TestValues(i).X, G_XWidth)) + report "Fehler: X falsch bei Test " & integer'image(i) + severity error; + + assert O_Y = std_logic_vector(to_unsigned(TestValues(i).Y, G_YWidth)) + report "Fehler: Y falsch bei Test " & integer'image(i) + severity error; + + assert O_SpriteLine = std_logic_vector(to_unsigned(TestValues(i).SpriteLine, G_SpriteLineWidth)) + report "Fehler: SpriteLine falsch bei Test " & integer'image(i) + severity error; + + assert O_SpriteLineValid = TestValues(i).SpriteLineValid + report "Fehler: SpriteLineValid falsch bei Test " & integer'image(i) + severity error; + + report "Test " & integer'image(i) & " erfolgreich." severity note; + wait for K_CLKPeriod; + end loop; + + report "Alle Tests abgeschlossen." severity note; + TestDone <= true; + wait; + end process; +end; diff --git a/test/SpriteChannel/CalcPipeline.wcfg b/test/SpriteChannel/CalcPipeline.wcfg new file mode 100644 index 0000000..f9419bc --- /dev/null +++ b/test/SpriteChannel/CalcPipeline.wcfg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + i_clk + i_clk + + + i_ce + i_ce + + + i_rst + i_rst + + + Input_OP + label + + i_op_valid + i_op_valid + + + o_op_ready + o_op_ready + + + i_op_x_request[9:0] + i_op_x_request[9:0] + HEXRADIX + + + i_op_index[4:0] + i_op_index[4:0] + HEXRADIX + + + i_op_offset[7:0] + i_op_offset[7:0] + HEXRADIX + + + i_op_x_sprite[9:0] + i_op_x_sprite[9:0] + HEXRADIX + + + + o_rom_valid + o_rom_valid + + + i_rom_ready + i_rom_ready + + + o_rom_address[12:0] + o_rom_address[12:0] + HEXRADIX + + + i_rom_valid + i_rom_valid + + + o_rom_ready + o_rom_ready + + + i_rom_data[7:0] + i_rom_data[7:0] + HEXRADIX + + + o_pixel_valid + o_pixel_valid + + + i_pixel_ready + i_pixel_ready + + + o_pixel_data[7:0] + o_pixel_data[7:0] + HEXRADIX + + + k_pipelinestages + k_pipelinestages + + + r_index[4:0] + r_index[4:0] + HEXRADIX + + + r_offset[7:0] + r_offset[7:0] + HEXRADIX + + + r_x_request[9:0] + r_x_request[9:0] + HEXRADIX + + + r_x_sprite[9:0] + r_x_sprite[9:0] + HEXRADIX + + + r_address[12:0] + r_address[12:0] + + + r_x_visible + r_x_visible + + + c_address[12:0] + c_address[12:0] + HEXRADIX + + + s_calculatingpipeline_enable + s_calculatingpipeline_enable + + + i_calculatingpipeline_ready + i_calculatingpipeline_ready + + + o_calculatingpipeline_valid + o_calculatingpipeline_valid + + + o_romrequest_ready + o_romrequest_ready + + + i_romrequest_valid + i_romrequest_valid + + + r_data[0:0] + r_data[0:0] + HEXRADIX + + [0] + r_data[0] + HEXRADIX + + + + r_data[0:1] + r_data[0:1] + HEXRADIX + true + #ff0000 + + [0] + r_data[0] + HEXRADIX + true + #ff0000 + + + [1] + r_data[1] + HEXRADIX + true + #ff0000 + + + + o_enable + o_enable + + + r_valid[1:0] + r_valid[1:0] + + diff --git a/test/SpriteChannel/Default.wcfg b/test/SpriteChannel/Default.wcfg new file mode 100644 index 0000000..bb0fec4 --- /dev/null +++ b/test/SpriteChannel/Default.wcfg @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + i_clk + i_clk + + + i_ce + i_ce + true + #ffffff + + + i_rst + i_rst + true + #ffffff + + + i_op_valid + i_op_valid + true + #008080 + + + o_op_ready + o_op_ready + true + #008080 + + + i_op_code[3:0] + i_op_code[3:0] + true + #008080 + + + i_op_data[9:0] + i_op_data[9:0] + true + #008080 + + + r_index[4:0] + r_index[4:0] + true + #008080 + + + r_offset[7:0] + r_offset[7:0] + true + #008080 + + + r_x[9:0] + r_x[9:0] + true + #008080 + + + r_isvisible + r_isvisible + true + #008080 + + + oi_p0_address_valid + oi_p0_address_valid + true + #008080 + + + io_p0_address_ready + io_p0_address_ready + true + #008080 + + + oi_p0_address[12:0] + oi_p0_address[12:0] + UNSIGNEDDECRADIX + true + #008080 + + + io_p0_data_valid + io_p0_data_valid + true + #008080 + + + oi_p0_data_ready + oi_p0_data_ready + true + #008080 + + + io_p0_data[7:0] + io_p0_data[7:0] + HEXRADIX + true + #008080 + + + oi_register_index_we + oi_register_index_we + true + #008080 + + + oi_register_index[4:0] + oi_register_index[4:0] + true + #008080 + + + oi_register_offset_we + oi_register_offset_we + true + #008080 + + + oi_register_offset[7:0] + oi_register_offset[7:0] + true + #008080 + + + oi_register_x_we + oi_register_x_we + true + #008080 + + + oi_register_x[9:0] + oi_register_x[9:0] + true + #008080 + + + oi_register_y_we + oi_register_y_we + true + #008080 + + + oi_register_y[9:0] + oi_register_y[9:0] + true + #008080 + + + oi_isvisible_we + oi_isvisible_we + true + #008080 + + + oi_isvisible + oi_isvisible + true + #008080 + + + Intern + label + 128 128 255 + 230 230 230 + + + c_nextstate + c_nextstate + + + r_state + r_state + + + r_op_data[9:0] + r_op_data[9:0] + UNSIGNEDDECRADIX + + + YHitCheck + label + + o_yhitcheck_valid + o_yhitcheck_valid + true + #00ff00 + + + i_yhitcheck_ready + i_yhitcheck_ready + true + #00ff00 + + + o_yhitcheck_ytocheck[9:0] + o_yhitcheck_ytocheck[9:0] + true + #00ff00 + UNSIGNEDDECRADIX + + + r_y[9:0] + r_y[9:0] + true + #00ff00 + + + o_yhitcheck_ready + o_yhitcheck_ready + true + #ff0000 + + + i_yhitcheck_valid + i_yhitcheck_valid + true + #ff0000 + + + i_yhitcheck_isvisible + i_yhitcheck_isvisible + true + #ff0000 + + + i_yhitcheck_offset[7:0] + i_yhitcheck_offset[7:0] + true + #ff0000 + + + + oi_calcpipeline_valid + oi_calcpipeline_valid + true + #008080 + + + io_calcpipeline_ready + io_calcpipeline_ready + true + #008080 + + + oi_calcpipeline_x_request[9:0] + oi_calcpipeline_x_request[9:0] + true + #008080 + HEXRADIX + + + o_pixel_valid + o_pixel_valid + true + #ff0000 + + + i_pixel_ready + i_pixel_ready + true + #ff0000 + + + o_pixel_data[7:0] + o_pixel_data[7:0] + HEXRADIX + true + #ff0000 + + diff --git a/test/SpriteChannel/Rom.wcfg b/test/SpriteChannel/Rom.wcfg new file mode 100644 index 0000000..3f617bc --- /dev/null +++ b/test/SpriteChannel/Rom.wcfg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + i_clk + i_clk + + + i_p0_address_valid + i_p0_address_valid + + + o_p0_address_ready + o_p0_address_ready + + + i_p0_address[12:0] + i_p0_address[12:0] + UNSIGNEDDECRADIX + + + s_p0_address_valid + s_p0_address_valid + + + c_p0_address_ready + c_p0_address_ready + + + r_p0_address[12:0] + r_p0_address[12:0] + UNSIGNEDDECRADIX + + + r_p0_data[7:0] + r_p0_data[7:0] + HEXRADIX + + diff --git a/test/SpriteChannel/Y_HitCheck.wcfg b/test/SpriteChannel/Y_HitCheck.wcfg new file mode 100644 index 0000000..5227634 --- /dev/null +++ b/test/SpriteChannel/Y_HitCheck.wcfg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + i_clk + i_clk + + + State + label + + r_state + r_state + + + c_nextstate + c_nextstate + + + + OP Data + label + + c_op_data_we + c_op_data_we + + + r_op_data[9:0] + r_op_data[9:0] + + + + Y_HitCheck + label + + o_enable + o_enable + + + r_valid[3:0] + r_valid[3:0] + + + i_data[9:0] + i_data[9:0] + HEXRADIX + + + r_data[0:1] + r_data[0:1] + HEXRADIX + + + o_data[9:0] + o_data[9:0] + HEXRADIX + + + + O_YHitCheck + label + + i_yhitcheck_ready + i_yhitcheck_ready + + + o_yhitcheck_valid + o_yhitcheck_valid + + + o_yhitcheck_ytocheck[9:0] + o_yhitcheck_ytocheck[9:0] + HEXRADIX + + + + I_YHitCheck + label + + o_yhitcheck_ready + o_yhitcheck_ready + + + i_yhitcheck_valid + i_yhitcheck_valid + + + i_yhitcheck_isvisible + i_yhitcheck_isvisible + + + i_yhitcheck_offset[7:0] + i_yhitcheck_offset[7:0] + HEXRADIX + + + + Offset + label + + i_enable + i_enable + + + i_data[7:0] + i_data[7:0] + + + r_data[0:1] + r_data[0:1] + + + diff --git a/test/SpriteChannel_tb.vhd b/test/SpriteChannel_tb.vhd new file mode 100644 index 0000000..c926cfa --- /dev/null +++ b/test/SpriteChannel_tb.vhd @@ -0,0 +1,194 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.env.stop; +use work.OPCodes.all; + +entity SpriteChannel_tb is +end entity SpriteChannel_tb; + +architecture Testbench of SpriteChannel_tb is + function to_hex(v : std_logic_vector) return string is + variable h : string(1 to 8); -- Maximal 8 Hex-Zeichen + variable u : unsigned(v'range) := unsigned(v); + begin + for i in h'range loop + exit when i > (v'length + 3) / 4; + case to_integer(u((v'length - 1) - (i - 1) * 4 downto v'length - i * 4)) is + when 0 => h(i) := '0'; + when 1 => h(i) := '1'; + when 2 => h(i) := '2'; + when 3 => h(i) := '3'; + when 4 => h(i) := '4'; + when 5 => h(i) := '5'; + when 6 => h(i) := '6'; + when 7 => h(i) := '7'; + when 8 => h(i) := '8'; + when 9 => h(i) := '9'; + when 10 => h(i) := 'A'; + when 11 => h(i) := 'B'; + when 12 => h(i) := 'C'; + when 13 => h(i) := 'D'; + when 14 => h(i) := 'E'; + when 15 => h(i) := 'F'; + when others => h(i) := '?'; + end case; + end loop; + return h(1 to (v'length + 3) / 4); + end; + + -- Clock period + constant K_CLKPeriod : time := 10 ns; + -- Generics + constant G_OPCodeData_Width : integer := 10; + constant G_Index_Width : integer := 5; + constant G_Offset_Width : integer := 8; + constant G_X_Width : integer := 10; + constant G_Y_Width : integer := 10; + constant G_Sprite_Height : integer := 16; + constant G_Sprite_Width : integer := 16; + -- Ports + signal I_CLK : std_logic; + signal I_CE : std_logic := '1'; + signal I_RST : std_logic := '0'; + signal I_OP_Valid : std_logic := '0'; + signal O_OP_Ready : std_logic := '0'; + signal I_OP_Code : std_logic_vector(3 downto 0) := (others => '0'); + signal I_OP_Data : std_logic_vector(G_OPCodeData_Width - 1 downto 0) := (others => '0'); + signal O_Pixel_Valid : std_logic := '0'; + signal I_Pixel_Ready : std_logic := '0'; + signal O_Pixel_Data : std_logic_vector(7 downto 0) := (others => '0'); + + signal TestDone : boolean := false; + + -- Testdaten für Befehle + type T_Command is record + OP_Code : std_logic_vector(3 downto 0); + OP_Data : std_logic_vector(G_OPCodeData_Width - 1 downto 0); + end record; + + type T_CommandArray is array (natural range <>) of T_Command; + constant CommandSequence : T_CommandArray := ( + (OP_Code => K_OP_NEWLINE, OP_Data => "0000000100"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000000"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000001"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000010"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000011"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000100"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000101"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000110"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000000111"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001000"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001001"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001010"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001011"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001100"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001101"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001110"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000001111"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000010000"), + (OP_Code => K_OP_REQ_ROW_DATA, OP_Data => "0000010001") + + ); +begin + + ClockProc : process + begin + while TestDone = false loop + I_CLK <= '0'; + wait for K_CLKPeriod / 2; + I_CLK <= '1'; + wait for K_CLKPeriod / 2; + end loop; + + I_CLK <= '0'; + stop(0); + wait; + end process; + + StimulusProc : process + variable i : integer := 0; + begin + -- Initialisierung + I_RST <= '1'; + wait for K_CLKPeriod * 2; + I_RST <= '0'; + wait for K_CLKPeriod * 2; + + -- Befehle senden + for i in CommandSequence'range loop + -- Warten, bis das Modul bereit ist + wait until rising_edge(I_CLK); + while O_OP_Ready /= '1' loop + wait until rising_edge(I_CLK); + end loop; + + -- Befehl setzen + I_OP_Code <= CommandSequence(i).OP_Code; + I_OP_Data <= CommandSequence(i).OP_Data; + I_OP_Valid <= '1'; + + -- Einen Takt warten + wait until rising_edge(I_CLK); + I_OP_Valid <= '0'; + + -- Warten, bis der Befehl verarbeitet wurde + while O_OP_Ready /= '1' loop + wait until rising_edge(I_CLK); + end loop; + + -- Optional: Ergebnisse prüfen (falls relevant) + report "Befehl " & integer'image(i) & " erfolgreich gesendet." severity note; + end loop; + + wait for K_CLKPeriod * 10; + -- Test abgeschlossen + report "Alle Befehle erfolgreich gesendet." severity note; + TestDone <= true; + wait; + end process; + + AXIReceiverProc : process + variable V_PacketCount : integer := 0; + begin + -- Initialisierung + I_Pixel_Ready <= '1'; -- Signalisiert, dass Daten empfangen werden können + + while TestDone = false loop + -- Warten, bis gültige Daten anliegen + wait until rising_edge(I_CLK); + if O_Pixel_Valid = '1' then + report "Empfangenes Paket #" & integer'image(V_PacketCount) & + " (hex): " & to_hex(O_Pixel_Data) + severity note; + V_PacketCount := V_PacketCount + 1; + end if; + end loop; + + wait; + end process; + + i_SpriteChannel : entity work.SpriteChannel + generic map( + G_OPCodeData_Width => G_OPCodeData_Width, + G_Index_Width => G_Index_Width, + G_Offset_Width => G_Offset_Width, + G_X_Width => G_X_Width, + G_Y_Width => G_Y_Width, + G_Sprite_Height => G_Sprite_Height, + G_Sprite_Width => G_Sprite_Width + ) + port map( + I_CLK => I_CLK, + I_CE => I_CE, + I_RST => I_RST, + I_OP_Valid => I_OP_Valid, + O_OP_Ready => O_OP_Ready, + I_OP_Code => I_OP_Code, + I_OP_Data => I_OP_Data, + O_Pixel_Valid => O_Pixel_Valid, + I_Pixel_Ready => I_Pixel_Ready, + O_Pixel_Data => O_Pixel_Data + ); + +end architecture; diff --git a/test/YHitCheck_tb.vhd b/test/YHitCheck_tb.vhd new file mode 100644 index 0000000..f222121 --- /dev/null +++ b/test/YHitCheck_tb.vhd @@ -0,0 +1,165 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.env.stop; +use work.SpriteRom.all; + +entity YHitCheck_tb is +end; + +architecture bench of YHitCheck_tb is + -- Clock period + constant K_CLKPeriod : time := 10 ns; + -- Generics + constant G_YWidth : integer := 10; + constant G_SpriteHeight : integer := 16; + -- Ports + signal I_CLK : std_logic := '0'; + signal I_CE : std_logic; + signal O_Ready : std_logic; + signal I_Valid : std_logic; + signal I_YToCheck : std_logic_vector(G_YWidth - 1 downto 0); + signal I_Y : std_logic_vector(G_YWidth - 1 downto 0); + signal I_Ready : std_logic; + signal O_Valid : std_logic; + signal O_IsVisible : std_logic; + signal O_Offset : std_logic_vector(7 downto 0); + + type T_TestData is record + YToCheck : integer; + SpriteY : integer; + ExpectedVisible : std_logic; + ExpectedOffset : integer; -- NEU + end record; + + type T_TestArray is array (natural range <>) of T_TestData; + constant TestValues : T_TestArray := ( + (10, 10, '1', 0), + (25, 10, '1', K_SPRITE_ROW_OFFSETS(15)), + (26, 10, '0', 0), + (9, 10, '0', 0), + (15, 0, '1', K_SPRITE_ROW_OFFSETS(15)), + (31, 16, '1', K_SPRITE_ROW_OFFSETS(15)), + (32, 16, '0', 0), + (984, 459, '0', 0), + (360, 972, '0', 0), + (160, 434, '0', 0), + (996, 713, '0', 0), + (63, 184, '0', 0), + (700, 376, '0', 0), + (702, 69, '0', 0), + (583, 181, '0', 0), + (302, 974, '0', 0), + (985, 392, '0', 0), + (0, 0, '1', 0), + (15, 0, '1', K_SPRITE_ROW_OFFSETS(15)), + (16, 0, '0', 0), + (0, 1, '0', 0), + (1023, 1008, '1', K_SPRITE_ROW_OFFSETS(15)), + (1023, 1007, '0', 0), + (1007, 1007, '1', 0), + (1008, 1008, '1', 0), + (1009, 1008, '1', K_SPRITE_ROW_OFFSETS(1)), + (1023, 1008, '1', K_SPRITE_ROW_OFFSETS(15)) + ); + + signal TestDone : boolean := false; +begin + + ClockProc : process + begin + while TestDone = false loop + I_CLK <= '0'; + wait for K_CLKPeriod / 2; + I_CLK <= '1'; + wait for K_CLKPeriod / 2; + end loop; + + I_CLK <= '0'; + stop(0); + wait; + end process; + + SpriteChannel_YHitCheck_inst : entity work.VerticalSpritePipeline + generic map( + G_Y_Width => G_YWidth, + G_Sprite_Height => G_SpriteHeight + ) + port map( + I_CLK => I_CLK, + I_CE => I_CE, + O_Ready => O_Ready, + I_Valid => I_Valid, + I_YToCheck => I_YToCheck, + I_Y => I_Y, + I_Ready => I_Ready, + O_Valid => O_Valid, + O_IsVisible => O_IsVisible, + O_Offset => O_Offset + ); + + StimulusProc : process + variable i : integer := 0; + begin + -- Init + i := 0; + I_CE <= '1'; + I_Valid <= '0'; + I_Ready <= '1'; + I_Y <= (others => '0'); + I_YToCheck <= (others => '0'); + wait for K_CLKPeriod * 5; + + for i in TestValues'range loop + -- Warte auf Ready + wait until rising_edge(I_CLK); + while O_Ready /= '1' loop + wait until rising_edge(I_CLK); + end loop; + + -- Werte setzen + I_Y <= std_logic_vector(to_unsigned(TestValues(i).SpriteY, G_YWidth)); + I_YToCheck <= std_logic_vector(to_unsigned(TestValues(i).YToCheck, G_YWidth)); + I_Valid <= '1'; + + wait until rising_edge(I_CLK); + I_Valid <= '0'; + + -- Warte auf O_Valid + while O_Valid /= '1' loop + wait until rising_edge(I_CLK); + end loop; + + -- Ergebnis prüfen + if O_IsVisible /= TestValues(i).ExpectedVisible then + assert false + report "Fehler bei Test " & integer'image(i) & + ": SpriteY=" & integer'image(TestValues(i).SpriteY) & + " YToCheck=" & integer'image(TestValues(i).YToCheck) & + " Erwartet Sichtbarkeit=" & std_logic'image(TestValues(i).ExpectedVisible) & + " Tatsaechlich=" & std_logic'image(O_IsVisible) + severity error; + elsif O_IsVisible = '1' then + -- Nur prüfen, wenn sichtbar + if to_integer(unsigned(O_Offset)) /= TestValues(i).ExpectedOffset then + assert false + report "Fehler bei Test " & integer'image(i) & + ": Falscher Offset. Erwartet=" & integer'image(TestValues(i).ExpectedOffset) & + " Tatsaechlich=" & integer'image(to_integer(unsigned(O_Offset))) + severity error; + else + report "Test " & integer'image(i) & " erfolgreich." severity note; + end if; + else + -- Unsichtbarer Fall, Sichtbarkeit korrekt => Erfolg + report "Test " & integer'image(i) & " erfolgreich." severity note; + end if; + + wait for K_CLKPeriod * 2; + end loop; + + report "Alle Tests abgeschlossen." severity note; + TestDone <= true; + wait; + end process; +end;