------------------------------------------------------------------------------- -- Project ELE8304 : Circuits intégrés à très grande échelle ------------------------------------------------------------------------------- -- File riscv_decode_tb.vhd -- Authors Titouan Luard <luardtitouan@gmail.com> -- Yann Roberge <yann.roberge@polymtl.ca> -- Lab ELE8304-9 -- Date 2021-11-28 ------------------------------------------------------------------------------- -- Brief RISC-V Register file -- ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; library work; use work.riscv_pkg.all; entity riscv_decode_tb is end riscv_decode_tb; architecture tb of riscv_decode_tb is -- Entrées/Sorties du DUT signal instruction : std_logic_vector(XLEN-1 downto 0); signal pc_i : std_logic_vector(XLEN-1 downto 0); signal wr_addr : std_logic_vector(REG_WIDTH-1 downto 0); signal wr_data : std_logic_vector(XLEN-1 downto 0); signal we : std_logic; signal flush : std_logic; signal rstn : std_logic; signal clk : std_logic; signal rs1_data : std_logic_vector(XLEN-1 downto 0); signal rs2_data : std_logic_vector(XLEN-1 downto 0); signal shamt : std_logic_vector(SHAMT_WIDTH-1 downto 0); signal arith : std_logic; signal sign : std_logic; signal jump : std_logic; signal branch : std_logic; signal pc_o : std_logic_vector(XLEN-1 downto 0); signal imm : std_logic_vector(XLEN-1 downto 0); -- Write to a register, no checking of what's coming out -- TODO: Adapter procedure write_reg ( signal wr_addr : out std_logic_vector(REG_WIDTH-1 downto 0); signal wr_data : out std_logic_vector(XLEN-1 downto 0); signal we : out std_logic; constant test_wr_addr : in std_logic_vector(REG_WIDTH-1 downto 0); constant test_wr_data : in std_logic_vector(XLEN-1 downto 0); constant period : in time) is begin wr_addr <= test_wr_addr; wr_data <= test_wr_data; we <= '1'; wait for period; report "Wrote " & to_string(wr_data) & " to reg " & to_string(wr_addr); end procedure write_reg; -- Procédure pour un vecteur de test -- TODO: Adapter procedure test_vector ( signal instruction : out std_logic_vector(XLEN-1 downto 0); signal pc_i : out std_logic_vector(XLEN-1 downto 0); signal wr_addr : out std_logic_vector(REG_WIDTH-1 downto 0); signal wr_data : out std_logic_vector(XLEN-1 downto 0); signal we : out std_logic; signal flush : out std_logic; signal rs1_data : in std_logic_vector(XLEN-1 downto 0); signal rs2_data : in std_logic_vector(XLEN-1 downto 0); signal shamt : in std_logic_vector(SHAMT_WIDTH-1 downto 0); signal arith : in std_logic; signal sign : in std_logic; signal jump : in std_logic; signal branch : in std_logic; signal pc_o : in std_logic_vector(XLEN-1 downto 0); signal imm : in std_logic_vector(XLEN-1 downto 0); constant test_instruction : in std_logic_vector(XLEN-1 downto 0); constant test_pc_i : in std_logic_vector(XLEN-1 downto 0); constant test_wr_addr : in std_logic_vector(REG_WIDTH-1 downto 0); constant test_wr_data : in std_logic_vector(XLEN-1 downto 0); constant test_we : in std_logic; constant test_flush : in std_logic; constant expected_rs1_data : in std_logic_vector(XLEN-1 downto 0); constant expected_rs2_data : in std_logic_vector(XLEN-1 downto 0); constant expected_shamt : in std_logic_vector(SHAMT_WIDTH-1 downto 0); constant expected_arith : in std_logic; constant expected_sign : in std_logic; constant expected_jump : in std_logic; constant expected_branch : in std_logic; constant expected_pc_o : in std_logic_vector(XLEN-1 downto 0); constant expected_imm : in std_logic_vector(XLEN-1 downto 0); constant period : in time) is begin -- Set test signals instruction <= test_instruction; pc_i <= test_pc_i; wr_addr <= test_wr_addr; wr_data <= test_wr_data; we <= test_we; flush <= test_flush; -- Wait a cycle wait for period; -- Assert all outputs are what we expect assert rs1_data = expected_rs1_data report "RS1_DATA DIFFERS FROM EXPECTED" severity error; assert rs2_data = expected_rs2_data report "RS2_DATA DIFFERS FROM EXPECTED" severity error; assert shamt = expected_shamt report "SHAMT DIFFERS FROM EXPECTED" severity error; assert arith = expected_arith report "ARITH DIFFERS FROM EXPECTED" severity error; assert sign = expected_sign report "SIGN DIFFERS FROM EXPECTED" severity error; assert jump = expected_jump report "JUMP DIFFERS FROM EXPECTED" severity error; assert branch = expected_branch report "BRANCH DIFFERS FROM EXPECTED" severity error; assert pc_o = expected_pc_o report "PC_O DIFFERS FROM EXPECTED" severity error; assert imm = expected_imm report "IMM DIFFERS FROM EXPECTED" severity error; end procedure test_vector; constant PERIOD : time := 10 ns; -- Used to set the expected IMM as a function of intruction and its type signal inst : std_logic_vector(XLEN-1 downto 0); signal i_imm : std_logic_vector(XLEN-1 downto 0); signal s_imm : std_logic_vector(XLEN-1 downto 0); signal b_imm : std_logic_vector(XLEN-1 downto 0); signal u_imm : std_logic_vector(XLEN-1 downto 0); signal j_imm : std_logic_vector(XLEN-1 downto 0); begin -- Instanciation du DUT dut: entity work.riscv_decode port map ( i_instruction => instruction, i_pc => pc_i, i_wr_addr => wr_addr, i_wr_data => wr_data, i_we => we, i_flush => flush, i_rstn => rstn, i_clk => clk, o_rs1_data => rs1_data, o_rs2_data => rs2_data, o_shamt => shamt, o_arith => arith, o_sign => sign, o_jump => jump, o_branch => branch, o_pc => pc_o, o_imm => imm ); -- Drive clock drive_clk : process is begin clk <= '0'; wait for PERIOD/2; clk <= '1'; wait for PERIOD/2; end process drive_clk; -- Set expected IMM as a function of the instruction type set_imm : process (inst) is begin i_imm <= (others => '0'); s_imm <= (others => '0'); b_imm <= (others => '0'); u_imm <= (others => '0'); j_imm(31 downto 20) <= (others => inst(31)); j_imm(19 downto 0) <= inst(19 downto 12) & inst(20) & inst(30 downto 25) & inst(24 downto 21) & '0'; end process set_imm; -- Main TB process p_main : process is constant DUMMY_DATA : std_logic_vector(XLEN-1 downto 0) := (3 downto 0 => "1010", others => '1'); constant DUMMY_REG_ADDR : std_logic_vector(REG_WIDTH-1 downto 0) := (others => '1'); constant DUMMY_DEST_REG : std_logic_vector(REG_WIDTH-1 downto 0) := (1 downto 0 => "11", others => '0'); constant EXAMPLE_PC : std_logic_vector(XLEN-1 downto 0) := (3 downto 0 => "1010", others => '1'); begin -- Tests des cas représentatif report "BEGIN SIMULATION"; instruction <= (others => '-'); pc_i <= (others => '-'); wr_data <= (others => '-'); we <= '-'; flush <= '0'; rstn <= '0'; inst <= (others => '-'); wait for PERIOD; rstn <= '1'; wait for 2*PERIOD; -- Write all registers report "Write all registers except 0x00"; for i in 1 to 2**(REG_WIDTH)-1 loop write_reg( wr_addr => wr_addr, wr_data => wr_data, we => we, test_wr_addr => std_logic_vector(to_unsigned(i, wr_addr'length)), test_wr_data => std_logic_vector(to_unsigned(i + 3, wr_data'length)), period => PERIOD ); end loop; -- Read back all registers report "Read back all registers"; -- ADDI 0 to reg[0] specifically, check result test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "000000000000" & std_logic_vector(to_unsigned(0, REG_WIDTH)) & FUNCT3_ADD & DUMMY_REG_ADDR & OPCODE_ALU_I_TYPE, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => (others => '0'), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '-', expected_sign => '-', expected_jump => '-', expected_branch => '-', expected_pc_o => EXAMPLE_PC, expected_imm => (others => '0'), period => PERIOD ); for i in 1 to 2**(REG_WIDTH)-2 loop -- ADDI 0 to reg[i], check result test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "000000000000" & std_logic_vector(to_unsigned(i, REG_WIDTH)) & FUNCT3_ADD & DUMMY_REG_ADDR & OPCODE_ALU_I_TYPE, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => std_logic_vector(to_unsigned(i+3, rs1_data'length)), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '-', expected_sign => '-', expected_jump => '-', expected_branch => '-', expected_pc_o => EXAMPLE_PC, expected_imm => (others => '0'), period => PERIOD ); end loop; report "Test every instruction in supported ISA"; -- LUI: registre 0x03 <- pattern 0101 répété sur 20 bits test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "11110000111100001111" & DUMMY_REG_ADDR & OPCODE_LUI, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => (others => '-'), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '0', expected_sign => '0', expected_jump => '0', expected_branch => '0', expected_pc_o => EXAMPLE_PC, expected_imm => (XLEN-1 downto 12 => "11110000111100001111", others => '0'), period => PERIOD ); -- JAL inst <= "11110000111100001111" & DUMMY_DEST_REG & OPCODE_JAL; test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "11110000111100001111" & DUMMY_DEST_REG & OPCODE_JAL, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => (others => '-'), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '0', expected_sign => '0', expected_jump => '1', expected_branch => '0', expected_pc_o => EXAMPLE_PC, expected_imm => j_imm, period => PERIOD ); -- JALR test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "111100001111" & DUMMY_REG_ADDR & FUNCT3_JALR & DUMMY_DEST_REG & OPCODE_JALR, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => (others => '-'), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '0', expected_sign => '0', expected_jump => '1', expected_branch => '0', expected_pc_o => EXAMPLE_PC, expected_imm => (others => '0'), period => PERIOD ); -- BEQ test_vector( instruction, pc_i, wr_addr, wr_data, we, flush, rs1_data, rs2_data, shamt, arith, sign, jump, branch, pc_o, imm, test_instruction => "111100001111" & DUMMY_REG_ADDR & FUNCT3_JALR & DUMMY_DEST_REG & OPCODE_JALR, test_pc_i => EXAMPLE_PC, test_wr_addr => (others => '-'), test_wr_data => (others => '-'), test_we => '0', test_flush => '0', expected_rs1_data => (others => '-'), expected_rs2_data => (others => '-'), expected_shamt => (others => '-'), expected_arith => '0', expected_sign => '0', expected_jump => '1', expected_branch => '0', expected_pc_o => EXAMPLE_PC, expected_imm => (others => '0'), period => PERIOD ); -- LW -- SW -- ADDI -- SLTI -- SLTUI -- XORI -- ORI -- ANDI -- SLLI -- SRLI -- SRAI -- ADD -- SUB -- SLL -- SLT -- SLTU -- XOR -- SRL -- SRA -- OR -- AND -- Flush pipeline -- Reset entire stage report "Reset"; rstn <= '0'; wait for PERIOD; rstn <= '1'; wait for PERIOD; report "SIMULATION DONE"; wait; end process p_main; end architecture tb;