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;
|
|
-- test out
|
|
reg_file_o : out t_reg_file;
|
|
dmem_o : out t_dmem
|
|
);
|
|
end entity;
|
|
|
|
|
|
|
|
architecture rtl of risc_v is
|
|
|
|
|
|
signal s_reg_file : t_reg_file;
|
|
signal s_dmem : t_dmem;
|
|
|
|
signal s_instr : std_logic_vector(31 downto 0);
|
|
signal s_imm : std_logic_vector(31 downto 0);
|
|
signal s_dec_bits : std_logic_vector(10 downto 0);
|
|
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_taken_br : boolean;
|
|
signal s_is_r_instr : boolean;
|
|
signal s_is_i_instr : boolean;
|
|
signal s_is_s_instr : boolean;
|
|
signal s_is_b_instr : boolean;
|
|
signal s_is_u_instr : boolean;
|
|
signal s_is_j_instr : boolean;
|
|
signal s_rd_valid : boolean;
|
|
signal s_funct3_valid : boolean;
|
|
signal s_rs1_valid : boolean;
|
|
signal s_rs2_valid : boolean;
|
|
signal s_funct7_valid : boolean;
|
|
signal s_imm_valid : boolean;
|
|
signal s_is_lui : boolean;
|
|
signal s_is_auipc : boolean;
|
|
signal s_is_jal : boolean;
|
|
signal s_is_jalr : boolean;
|
|
signal s_is_beq : boolean;
|
|
signal s_is_bne : boolean;
|
|
signal s_is_blt : boolean;
|
|
signal s_is_bge : boolean;
|
|
signal s_is_bltu : boolean;
|
|
signal s_is_bgeu : boolean;
|
|
signal s_is_addi : boolean;
|
|
signal s_is_slti : boolean;
|
|
signal s_is_sltiu : boolean;
|
|
signal s_is_xori : boolean;
|
|
signal s_is_ori : boolean;
|
|
signal s_is_andi : boolean;
|
|
signal s_is_slli : boolean;
|
|
signal s_is_srli : boolean;
|
|
signal s_is_srai : boolean;
|
|
signal s_is_add : boolean;
|
|
signal s_is_sub : boolean;
|
|
signal s_is_sll : boolean;
|
|
signal s_is_slt : boolean;
|
|
signal s_is_sltu : boolean;
|
|
signal s_is_xor : boolean;
|
|
signal s_is_srl : boolean;
|
|
signal s_is_sra : boolean;
|
|
signal s_is_or : boolean;
|
|
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);
|
|
alias a_funct3 : std_logic_vector(2 downto 0) is s_instr(14 downto 12);
|
|
alias a_rs1 : std_logic_vector(4 downto 0) is s_instr(19 downto 15);
|
|
alias a_rs2 : std_logic_vector(4 downto 0) is s_instr(24 downto 20);
|
|
alias a_funct7 : std_logic_vector(6 downto 0) is s_instr(31 downto 25);
|
|
|
|
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
|
|
s_jalr_tgt_pc when s_is_jalr else
|
|
s_pc + 4;
|
|
|
|
-- prog counter register
|
|
process (clk_i) is
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
s_pc <= s_next_pc;
|
|
end if;
|
|
end process;
|
|
|
|
-- Instruction memory
|
|
s_instr <= c_imem(to_integer(s_pc(31 downto 2)));
|
|
|
|
-- Decode
|
|
-- Decode instruction type
|
|
s_is_r_instr <= s_instr(6 downto 2) = "01011" or
|
|
s_instr(6 downto 2) = "01100" or
|
|
s_instr(6 downto 2) = "01110" or
|
|
s_instr(6 downto 2) = "10100";
|
|
s_is_i_instr <= std_match(s_instr(6 downto 2), "0000-") or
|
|
std_match(s_instr(6 downto 2), "001-0") or
|
|
s_instr(6 downto 2) = "11001";
|
|
s_is_s_instr <= std_match(s_instr(6 downto 2), "0100-");
|
|
s_is_b_instr <= s_instr(6 downto 2) = "11000";
|
|
s_is_u_instr <= std_match(s_instr(6 downto 2), "0-101");
|
|
s_is_j_instr <= s_instr(6 downto 2) = "11011";
|
|
|
|
-- Extract instruction fields
|
|
s_imm <= (31 downto 11 => s_instr(31),
|
|
10 downto 0 => s_instr(30 downto 20)) when s_is_i_instr else
|
|
(31 downto 11 => s_instr(31),
|
|
10 downto 5 => s_instr(30 downto 25),
|
|
4 downto 0 => s_instr(11 downto 7)) when s_is_s_instr else
|
|
(31 downto 12 => s_instr(31),
|
|
11 => s_instr(7),
|
|
10 downto 5 => s_instr(30 downto 25),
|
|
4 downto 1 => s_instr(11 downto 8),
|
|
0 => '0') when s_is_b_instr else
|
|
( 31 => s_instr(31),
|
|
30 downto 12 => s_instr(30 downto 12),
|
|
11 downto 0 => 12x"0") when s_is_u_instr else
|
|
(31 downto 20 => s_instr(31),
|
|
19 downto 12 => s_instr(19 downto 12),
|
|
11 => s_instr(20),
|
|
10 downto 1 => s_instr(30 downto 21),
|
|
0 => '0') when s_is_j_instr else
|
|
32x"0";
|
|
|
|
-- Calculate instruction fields valids
|
|
s_rd_valid <= s_is_r_instr or s_is_i_instr or s_is_u_instr or s_is_j_instr;
|
|
s_funct3_valid <= s_is_r_instr or s_is_i_instr or s_is_s_instr or s_is_b_instr;
|
|
s_rs1_valid <= s_funct3_valid;
|
|
s_rs2_valid <= s_is_r_instr or s_is_s_instr or s_is_b_instr;
|
|
s_funct7_valid <= s_is_r_instr;
|
|
s_imm_valid <= not s_is_r_instr;
|
|
|
|
-- Instruction code decoding
|
|
s_dec_bits <= (a_funct7(5), a_funct3, a_opcode);
|
|
s_is_lui <= std_match(s_dec_bits, b"-_---_0110111");
|
|
s_is_auipc <= std_match(s_dec_bits, b"-_---_0010111");
|
|
s_is_jal <= std_match(s_dec_bits, b"-_---_1101111");
|
|
s_is_jalr <= std_match(s_dec_bits, b"-_000_1100111");
|
|
s_is_beq <= std_match(s_dec_bits, b"-_000_1100011");
|
|
s_is_bne <= std_match(s_dec_bits, b"-_001_1100011");
|
|
s_is_blt <= std_match(s_dec_bits, b"-_100_1100011");
|
|
s_is_bge <= std_match(s_dec_bits, b"-_101_1100011");
|
|
s_is_bltu <= std_match(s_dec_bits, b"-_110_1100011");
|
|
s_is_bgeu <= std_match(s_dec_bits, b"-_111_1100011");
|
|
s_is_addi <= std_match(s_dec_bits, b"-_000_0010011");
|
|
s_is_slti <= std_match(s_dec_bits, b"-_010_0010011");
|
|
s_is_sltiu <= std_match(s_dec_bits, b"-_011_0010011");
|
|
s_is_xori <= std_match(s_dec_bits, b"-_100_0010011");
|
|
s_is_ori <= std_match(s_dec_bits, b"-_110_0010011");
|
|
s_is_andi <= std_match(s_dec_bits, b"-_111_0010011");
|
|
s_is_slli <= s_dec_bits = b"0_001_0010011";
|
|
s_is_srli <= s_dec_bits = b"0_101_0010011";
|
|
s_is_srai <= s_dec_bits = b"1_101_0010011";
|
|
s_is_add <= s_dec_bits = b"0_000_0110011";
|
|
s_is_sub <= s_dec_bits = b"1_000_0110011";
|
|
s_is_sll <= s_dec_bits = b"0_001_0110011";
|
|
s_is_slt <= s_dec_bits = b"0_010_0110011";
|
|
s_is_sltu <= s_dec_bits = b"0_011_0110011";
|
|
s_is_xor <= s_dec_bits = b"0_100_0110011";
|
|
s_is_srl <= s_dec_bits = b"0_101_0110011";
|
|
s_is_sra <= s_dec_bits = b"1_101_0110011";
|
|
s_is_or <= s_dec_bits = b"0_110_0110011";
|
|
s_is_and <= s_dec_bits = b"0_111_0110011";
|
|
-- LB, LH, LW, LBU, LHU
|
|
s_is_load <= a_opcode = "0000011";
|
|
-- 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 <=
|
|
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
|
|
s_src1_value /= s_src2_value when s_is_bne else
|
|
signed(s_src1_value) < signed(s_src2_value) when s_is_blt else
|
|
signed(s_src1_value) >= signed(s_src2_value) when s_is_bge else
|
|
unsigned(s_src1_value) < unsigned(s_src2_value) when s_is_bltu else
|
|
unsigned(s_src1_value) >= unsigned(s_src2_value) when s_is_bgeu else
|
|
false;
|
|
s_br_tgt_br <= s_pc + unsigned(s_imm);
|
|
s_jalr_tgt_pc <= unsigned(s_src1_value) + unsigned(s_imm);
|
|
|
|
-- 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 <= init_reg_file;
|
|
elsif s_rd_valid and a_rd /= 5x"0" then
|
|
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;
|
|
|
|
s_src1_value <= s_reg_file(to_integer(unsigned(a_rs1))) when s_rs1_valid else
|
|
(others => '0');
|
|
s_src2_value <= s_reg_file(to_integer(unsigned(a_rs2))) when s_rs2_valid else
|
|
(others => '0');
|
|
|
|
-- Data memory
|
|
process (clk_i) is
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if reset_n_i = '0' then
|
|
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 process;
|
|
|
|
s_ld_data <= s_dmem(to_integer(unsigned(s_result(6 downto 2)))) when s_is_load else
|
|
(others => '0');
|
|
|
|
|
|
end architecture rtl;
|