222 lines
10 KiB
VHDL
222 lines
10 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_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;
|