Skip to content
Snippets Groups Projects
riscv_decode_tb.vhd 10.5 KiB
Newer Older
-------------------------------------------------------------------------------
-- 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(REG_WIDTH-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 addr_w  : out std_logic_vector(REG_WIDTH-1 downto 0);
    signal data_w  : out std_logic_vector(XLEN-1 downto 0);
    signal we      : out std_logic;

    constant test_addr_w  : in std_logic_vector(REG_WIDTH-1 downto 0);
    constant test_data_w  : in std_logic_vector(XLEN-1 downto 0);

    constant period : in time) is
  begin
      addr_w <= test_addr_w;
      data_w <= test_data_w;
      we     <= '1';
      wait for period;

      report "Wrote " & to_string(data_w) & " to reg " & to_string(addr_w);

  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(REG_WIDTH-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);

    signal test_instruction : in std_logic_vector(XLEN-1 downto 0);
    signal test_pc_i        : in std_logic_vector(XLEN-1 downto 0);
    signal test_wr_addr     : in std_logic_vector(REG_WIDTH-1 downto 0);
    signal test_wr_data     : in std_logic_vector(REG_WIDTH-1 downto 0);
    signal test_we          : in std_logic;
    signal 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;

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;

  -- Main TB process
  p_main : process is
    constant DUMMY_DATA : std_logic_vector(XLEN-1 downto 0) := (3 downto 0 => "1010", others => '1');
    constant EXAMPLE_PC : std_logic_vector(XLEN-1 downto 0) := (3 downto 0 => "1010", others => '1');
    -- Tests des cas représentatif
    report "BEGIN SIMULATION";
    instruction <= (others => '-');
    pc_i        <= (others => '-');
    wr_data     <= (others => '-');
    we          <= '-';
    flush <= '0';
    rstn <= '0';
    wait for PERIOD;
    rstn <= '1';
    wait for 2*PERIOD;

    -- Write all registers
    -- TODO: Adapter mais le laisser faire la même chose
    report "Write all registers except 0x00";
    for i in 1 to 2**(REG_WIDTH)-1 loop
      write_reg(
        addr_w  => addr_w,
        data_w  => data_w,
        we      => we,

        test_addr_w  => std_logic_vector(to_unsigned(i, addr_w)),
        test_data_w  => std_logic_vector(to_unsigned(i + 3, data_w)),

        period => PERIOD
      );
    end loop;

    -- Read back all registers
    -- TODO: Adapter mais le laisser faire la même chose
    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 & 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    => (others => '-'),
      expected_sign     => (others => '-'),
      expected_jump     => (others => '-'),
      expected_branch   => (others => '-'),
      expected_pc_o     => EXAMPLE_PC,
      expected_imm      => (others => '0'),
      PERIOD
    );

    for i in 1 to 2**(REG_WIDTH)-2 loop
      -- ADDI 0 to reg[i], check result
        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 & 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    => (others => '-'),
        expected_sign     => (others => '-'),
        expected_jump     => (others => '-'),
        expected_branch   => (others => '-'),
        expected_pc_o     => EXAMPLE_PC,
        expected_imm      => (others => '0'),
        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" & "00011" & 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    => (others => '-'),
      expected_sign     => (others => '-'),
      expected_jump     => (others => '-'),
      expected_branch   => (others => '-'),
      expected_pc_o     => EXAMPLE_PC,
      expected_imm      => (XLEN-1 downto 12 => "11110000111100001111", others => '0'),
      PERIOD
    );

    -- JAL

    -- JALR

    -- BEQ

    -- 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;