diff --git a/vhdl/risc_v.vhd b/vhdl/risc_v.vhd index f4b5632..fbce138 100644 --- a/vhdl/risc_v.vhd +++ b/vhdl/risc_v.vhd @@ -2,13 +2,18 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use std.env.all; + use work.risc_v_pkg.all; entity risc_v is port ( - reset_n_i : in std_logic; - clk_i : in std_logic + reset_n_i : in std_logic; + clk_i : in std_logic; + -- test out + reg_file_o : out t_reg_file; + dmem_o : out t_dmem ); end entity; @@ -18,7 +23,7 @@ architecture rtl of risc_v is signal s_reg_file : t_reg_file; - signal s_dmem : t_dmem; + signal s_dmem : t_dmem; signal s_instr : std_logic_vector(31 downto 0); signal s_imm : std_logic_vector(31 downto 0); @@ -26,14 +31,15 @@ architecture rtl of risc_v is signal s_src1_value : std_logic_vector(31 downto 0); signal s_src2_value : std_logic_vector(31 downto 0); signal s_ld_data : std_logic_vector(31 downto 0); + signal s_result : std_logic_vector(31 downto 0); + signal s_sltu_rslt : std_logic_vector(31 downto 0); + signal s_sltiu_rslt : std_logic_vector(31 downto 0); signal s_pc : unsigned(31 downto 0); signal s_next_pc : unsigned(31 downto 0); signal s_br_tgt_br : unsigned(31 downto 0); signal s_jalr_tgt_pc : unsigned(31 downto 0); - signal s_result : signed(31 downto 0); - signal s_taken_br : boolean; signal s_is_r_instr : boolean; signal s_is_i_instr : boolean; @@ -78,6 +84,8 @@ architecture rtl of risc_v is signal s_is_and : boolean; signal s_is_load : boolean; signal s_is_store : boolean; + signal s_src_sgn_eq : boolean; + signal s_imm_sgn_eq : boolean; alias a_opcode : std_logic_vector(6 downto 0) is s_instr(6 downto 0); alias a_rd : std_logic_vector(4 downto 0) is s_instr(11 downto 7); @@ -88,6 +96,11 @@ architecture rtl of risc_v is begin + + -- Test outs + reg_file_o <= s_reg_file; + dmem_o <= s_dmem; + -- prog counter next state logic s_next_pc <= 32x"0" when not reset_n_i else s_br_tgt_br when s_taken_br or s_is_jal else @@ -184,10 +197,44 @@ begin -- SB, SH, SW s_is_store <= s_is_s_instr; + -- Some subexpressions + s_src_sgn_eq <= s_src1_value(31) = s_src2_value(31); + s_imm_sgn_eq <= s_src1_value(31) = s_imm(31); + -- SLTU & SLTI (set if less than, unsigned) + s_sltu_rslt <= 31x"0" & to_std_logic(unsigned(s_src1_value) < unsigned(s_src2_value)); + s_sltiu_rslt <= 31x"0" & to_std_logic(unsigned(s_src1_value) < unsigned(s_imm)); -- ALU - s_result <= signed(s_src1_value) + signed(s_imm) when s_is_addi or s_is_load or s_is_store else - signed(s_src1_value) + signed(s_src2_value) when s_is_add else - 32x"0"; + s_result <= + s_src1_value and s_imm when s_is_andi else + s_src1_value or s_imm when s_is_ori else + s_src1_value xor s_imm when s_is_xori else + std_logic_vector(signed(s_src1_value) + signed(s_imm)) when s_is_addi or + s_is_load or + s_is_store else + shift_left(s_src1_value, s_imm(5 downto 0)) when s_is_slli else + shift_right(s_src1_value, s_imm(5 downto 0)) when s_is_srli else + s_src1_value and s_src2_value when s_is_and else + s_src1_value or s_src2_value when s_is_or else + s_src1_value xor s_src2_value when s_is_xor else + std_logic_vector(signed(s_src1_value) + signed(s_src2_value)) when s_is_add else + std_logic_vector(signed(s_src1_value) - signed(s_src2_value)) when s_is_sub else + shift_left(s_src1_value, s_src2_value(4 downto 0)) when s_is_sll else + shift_right(s_src1_value, s_src2_value(4 downto 0)) when s_is_srl else + s_sltu_rslt when s_is_sltu else + s_sltiu_rslt when s_is_sltiu else + s_imm(31 downto 12) & 12x"0" when s_is_lui else + std_logic_vector(s_pc + unsigned(s_imm)) when s_is_auipc else + std_logic_vector(s_pc + 4) when s_is_jal or + s_is_jalr else + s_sltu_rslt when s_is_slt and + s_src_sgn_eq else + 31x"0" & s_src1_value(31) when s_is_slt else + s_sltiu_rslt when s_is_slti and + s_imm_sgn_eq else + 31x"0" & s_src1_value(31) when s_is_slti else + shift_arith_right(s_src1_value, s_src2_value(4 downto 0)) when s_is_sra else + shift_arith_right(s_src1_value, s_imm(4 downto 0)) when s_is_srai else + 32x"0"; -- Branch logic s_taken_br <= s_src1_value = s_src2_value when s_is_beq else @@ -202,16 +249,14 @@ begin -- Register file process (clk_i) is + variable v_value : std_logic_vector(31 downto 0); begin if rising_edge(clk_i) then if reset_n_i = '0' then - s_reg_file <= (others => 32x"0"); + s_reg_file <= init_reg_file; elsif s_rd_valid and a_rd /= 5x"0" then - if s_is_load then - s_reg_file(to_integer(unsigned(a_rd))) <= std_logic_vector(s_ld_data); - else - s_reg_file(to_integer(unsigned(a_rd))) <= std_logic_vector(s_result); - end if; + v_value := std_logic_vector(s_ld_data) when s_is_load else s_result; + s_reg_file(to_integer(unsigned(a_rd))) <= v_value; end if; end if; end process; @@ -226,14 +271,15 @@ begin begin if rising_edge(clk_i) then if reset_n_i = '0' then - s_dmem <= (others => 32x"0"); + s_dmem <= init_dmem; elsif s_is_store then s_dmem(to_integer(unsigned(s_result(6 downto 2)))) <= std_logic_vector(s_src2_value); - end if; + end if; end if; end process; s_ld_data <= s_dmem(to_integer(unsigned(s_result(6 downto 2)))) when s_is_load else (others => '0'); + end architecture rtl; diff --git a/vhdl/risc_v_pkg.vhd b/vhdl/risc_v_pkg.vhd index 3c8db9a..14b396f 100644 --- a/vhdl/risc_v_pkg.vhd +++ b/vhdl/risc_v_pkg.vhd @@ -1,5 +1,8 @@ library ieee; use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use ieee.math_real.all; + package risc_v_pkg is @@ -10,7 +13,6 @@ package risc_v_pkg is subtype t_imem is t_slv_array(natural range 0 to 57)(31 downto 0); subtype t_dmem is t_reg_file; - -- Test program constant c_imem : t_imem := ( -- (I) ADDI x1, x0, 10101 @@ -130,5 +132,82 @@ package risc_v_pkg is -- (J) JAL x0, 0 b"00000000000000000000000001101111"); + function init_reg_file return t_reg_file; + function init_dmem return t_dmem; + + function shift_right (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector; + + function shift_left (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector; + + function shift_arith_right (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector; + + function to_std_logic (data : in boolean) return std_logic; + + procedure check_equal (a, b : in std_logic_vector; prefix : in string := ""); + end package risc_v_pkg; + + +package body risc_v_pkg is + + + function init_reg_file return t_reg_file is + variable v_reg_file : t_reg_file; + begin + for i in t_reg_file'range loop + v_reg_file(i) := std_logic_vector(to_unsigned(i, 32)); + end loop; + return v_reg_file; + end init_reg_file; + + function init_dmem return t_dmem is + variable v_dmem : t_dmem; + begin + for i in t_dmem'range loop + v_dmem(t_dmem'high-i) := std_logic_vector(to_unsigned(i, 32)); + end loop; + return v_dmem; + end init_dmem; + + function shift_right (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector is + begin + return std_logic_vector(shift_right(unsigned(data), + to_integer(unsigned(index)))); + end function shift_right; + + function shift_left (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector is + begin + return std_logic_vector(shift_left(unsigned(data), + to_integer(unsigned(index)))); + end function shift_left; + + function shift_arith_right (data : in std_logic_vector(31 downto 0); + index : in std_logic_vector) return std_logic_vector is + begin + return std_logic_vector(shift_right(signed(data), + to_integer(unsigned(index)))); + end function shift_arith_right; + + function to_std_logic (data : in boolean) return std_logic is + begin + if data then + return '1'; + else + return '0'; + end if; + end function to_std_logic; + + procedure check_equal (a, b : in std_logic_vector; prefix : in string := "") is + begin + assert a = b + report prefix & "expected 0x" & to_hstring(b) & ", got 0x" & to_hstring(a); + end procedure check_equal; + + +end package body risc_v_pkg; diff --git a/vhdl/tb_risc_v.vhd b/vhdl/tb_risc_v.vhd index fed8bfb..7e9b1bf 100644 --- a/vhdl/tb_risc_v.vhd +++ b/vhdl/tb_risc_v.vhd @@ -4,6 +4,8 @@ library ieee; use std.env.all; +use work.risc_v_pkg.all; + entity tb_risc_v is end entity tb_risc_v; @@ -12,8 +14,10 @@ end entity tb_risc_v; architecture sim of tb_risc_v is - signal s_clk : std_logic := '1'; - signal s_reset_n : std_logic := '0'; + signal s_clk : std_logic := '1'; + signal s_reset_n : std_logic := '0'; + signal s_reg_file : t_reg_file; + signal s_dmem : t_dmem; begin @@ -22,17 +26,42 @@ begin s_clk <= not s_clk after 5 ns; s_reset_n <= '1' after 20 ns; - DUT : entity work.risc_v port map ( - reset_n_i => s_reset_n, - clk_i => s_clk + reset_n_i => s_reset_n, + clk_i => s_clk, + reg_file_o => s_reg_file, + dmem_o => s_dmem ); - + -- Checker process is + variable v_expected : std_logic_vector(31 downto 0); begin - wait for 380 ns; + wait until s_reset_n = '1'; + -- until program is finished + wait for c_imem'length * 10 ns; + -- Check register file entries + for i in t_reg_file'range loop + case i is + when 0 => v_expected := 32x"0"; + when 1 => v_expected := 32x"15"; + when 2 => v_expected := 32x"7"; + when 3 => v_expected := x"FFFFFFFC"; + when 4 => v_expected := 32x"B4"; + when 31 => v_expected := 32x"1F"; + when others => v_expected := 32x"1"; + end case; + check_equal(s_reg_file(i), v_expected, "Reg. x" & to_string(i) & ": "); + end loop; + -- Check data memory entries + for i in t_dmem'range loop + case i is + when 2 => v_expected := 32x"15"; + when others => v_expected := std_logic_vector(to_unsigned(t_dmem'high-i, 32)); + end case; + check_equal(s_dmem(i), v_expected, "Dmem @" & to_string(i) & ": "); + end loop; stop(0); end process;