Files
SpriteChannel/test/OPDecoder_tb.vhd
2025-04-22 15:23:15 +00:00

222 lines
11 KiB
VHDL

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_OPDecoder_Valid => I_OP_Valid,
O_OPDecoder_Ready => O_OP_Ready,
I_OPDecoder_Code => I_OP_Code,
I_OPDecoder_Data => I_OP_Data,
O_RFile_Wr_Index_WE => O_Register_Index_WE,
O_RFile_Wr_Index => O_Register_Index,
O_RFile_Wr_Offset_WE => O_Register_Offset_WE,
O_RFile_Wr_Offset => O_Register_Offset,
O_RFile_Wr_X_We => O_Register_X_We,
O_RFile_Wr_X => O_Register_X,
O_RFile_Wr_Y_WE => O_Register_Y_WE,
O_RFile_Wr_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_VSpritePipeline_Ready => I_YHitCheck_Ready,
O_VSpritePipeline_Valid => O_YHitCheck_Valid,
O_VSpritePipeline_YToCheck => O_YHitCheck_YToCheck,
O_VSpritePipeline_Ready => O_YHitCheck_Ready,
I_VSpritePipeline_Valid => I_YHitCheck_Valid,
I_VSpritePipeline_IsVisible => I_YHitCheck_IsVisible,
I_VSpritePipeline_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_VSpritePipeline_OP_Ready => I_YHitCheck_Ready,
I_VSpritePipeline_OP_Valid => O_YHitCheck_Valid,
I_VSpritePipeline_OP_Y_Request => O_YHitCheck_YToCheck,
I_VSpritePipeline_OP_Y_Sprite => "0000000000",
I_VSpritePipeline_Ready => O_YHitCheck_Ready,
O_VSpritePipeline_Valid => I_YHitCheck_Valid,
O_VSpritePipeline_IsVisible => I_YHitCheck_IsVisible,
O_VSpritePipeline_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;