You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

285 lines
12 KiB

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;