------------------------------------------------------------------------------- -- Project ELE8304 : Circuits intégrés à très grande échelle ------------------------------------------------------------------------------- -- File riscv_decode.vhd -- Authors Titouan Luard <luardtitouan@gmail.com> -- Yann Roberge <yann.roberge@polymtl.ca> -- Lab ELE8304-9 -- Date 2021-11-28 ------------------------------------------------------------------------------- -- Brief RISC-V Decode pipeline stage -- Breaks down instructions into their specific components, -- Reads from & Writes into the register file, -- Generate outputs needed for the Execute stage ------------------------------------------------------------------------------- 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 is port ( -- Entrées provenant de l'étage FETCH i_fetch_reg : in fetch_reg; -- Entrées provenant de l'étage WRITE-BACK i_wr_addr : in std_logic_vector(REG_WIDTH-1 downto 0); i_wr_data : in std_logic_vector(XLEN-1 downto 0); i_we : in std_logic; -- Entrée provenant de l'étage EXECUTE i_flush : in std_logic; -- Entrées externes au pipeline i_rstn : in std_logic; i_clk : in std_logic; -- Sorties rs1_data : out std_logic_vector(XLEN-1 downto 0); rs2_data : out std_logic_vector(XLEN-1 downto 0); o_decode_reg : out decode_reg); end entity riscv_decode; architecture beh of riscv_decode is -- Signaux internes Predecode signal opcode : std_logic_vector(OPCODE_WIDTH-1 downto 0); signal funct3 : std_logic_vector(2 downto 0); signal funct7 : std_logic_vector(6 downto 0); signal rs1_addr : std_logic_vector(REG_WIDTH-1 downto 0); signal rs2_addr : std_logic_vector(REG_WIDTH-1 downto 0); signal rd : std_logic_vector(REG_WIDTH-1 downto 0); -- opcode funct3 funct7 rs1 rs2 -- jump -- branch -- imm -- Signaux internes Decode -- alu_opcode -- shamt -- arith -- sign signal jump : std_logic; signal branch : std_logic; signal alu_opcode : std_logic_vector(ALUOP_WIDTH-1 downto 0); signal sign : std_logic; signal imm : std_logic_vector(XLEN-1 downto 0); alias instruction is i_fetch_reg.instruction; begin -- Predecode -- Décompose les signaux en fonction de leurs types (opcodes) opcode <= i_fetch_reg.instruction(OPCODE_WIDTH-1 downto 0); predecode: process (opcode) is begin case opcode is -- R-TYPE -- FIXME: Le code répété when OPCODE_JALR => funct7 <= instruction(31 downto 25); rs2_addr <= instruction(24 downto 20); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= instruction(11 downto 7); when OPCODE_ALU_R_TYPE => funct7 <= instruction(31 downto 25); rs2_addr <= instruction(24 downto 20); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= instruction(11 downto 7); -- I-TYPE -- FIXME: Le code répété when OPCODE_LW => funct7 <= (others => '0'); rs2_addr <= (others => '0'); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= instruction(11 downto 7); when OPCODE_ALU_I_TYPE => funct7 <= (others => '0'); rs2_addr <= (others => '0'); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= instruction(11 downto 7); -- S-TYPE when OPCODE_SW => funct7 <= (others => '0'); rs2_addr <= instruction(24 downto 20); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= (others => '0'); -- B-TYPE when OPCODE_BEQ => funct7 <= (others => '0'); rs2_addr <= instruction(24 downto 20); rs1_addr <= instruction(19 downto 15); funct3 <= instruction(14 downto 12); rd <= (others => '0'); -- U-TYPE when OPCODE_LUI => funct7 <= (others => '0'); rs2_addr <= (others => '0'); rs1_addr <= (others => '0'); funct3 <= (others => '0'); rd <= instruction(11 downto 7); -- J-TYPE when OPCODE_JAL => funct7 <= (others => '0'); rs2_addr <= (others => '0'); rs1_addr <= (others => '0'); funct3 <= (others => '0'); rd <= instruction(11 downto 7); -- Unsupported instructions when others => funct7 <= (others => '0'); rs2_addr <= (others => '0'); rs1_addr <= (others => '0'); funct3 <= (others => '0'); rd <= (others => '0'); end case; end process predecode; -- Gestion des valeurs immédiates immediate : process (opcode) begin case opcode is -- I-TYPE -- FIXME: Le code répété when OPCODE_LW => imm(31 downto 11) <= (others => instruction(31)); imm(10 downto 5) <= instruction(30 downto 25); imm(4 downto 1) <= instruction(24 downto 21); imm(0) <= instruction(20); when OPCODE_ALU_I_TYPE => imm(31 downto 11) <= (others => instruction(31)); imm(10 downto 5) <= instruction(30 downto 25); imm(4 downto 1) <= instruction(24 downto 21); imm(0) <= instruction(20); -- S-TYPE when OPCODE_SW => imm(31 downto 11) <= (others => instruction(31)); imm(10 downto 5) <= instruction(30 downto 25); imm(4 downto 1) <= instruction(11 downto 8); imm(0) <= instruction(7); -- B-TYPE when OPCODE_BEQ => imm(31 downto 12) <= (others => instruction(31)); imm(11) <= instruction(7); imm(10 downto 5) <= instruction(30 downto 25); imm(4 downto 1) <= instruction(11 downto 8); imm(0) <= '0'; -- U-TYPE when OPCODE_LUI => -- FIXME: Pourquoi pas avoir compacté les 2 lignes suivantes -- à la figure 3 de l'énoncé? imm(31) <= instruction(31); imm(30 downto 20) <= instruction(30 downto 20); imm(19 downto 12) <= instruction(19 downto 12); imm(11 downto 0) <= (others => '0'); -- J-TYPE when OPCODE_JAL => imm(31 downto 20) <= (others => instruction(31)); imm(19 downto 12) <= instruction(19 downto 12); imm(11) <= instruction(20); imm(10 downto 5) <= instruction(30 downto 25); imm(4 downto 1) <= instruction(24 downto 21); imm(0) <= '0'; -- R-TYPE -- Unsupported instructions when others => imm <= (others => '0'); end case; end process immediate; -- Instanciation du Register File register_file: entity work.riscv_rf port map ( i_clk => i_clk, i_rstn => i_rstn, i_we => i_we, i_addr_ra => rs1_addr, o_data_ra => rs1_data, i_addr_rb => rs2_addr, o_data_rb => rs2_data, i_addr_w => i_wr_addr, i_data_w => i_wr_data ); -- Decode -- Écrire le registre ID/EX -- DEBUG: o_decode_reg.shamt <= (others => '1'); o_decode_reg.arith <= '1'; o_decode_reg.sign <= '1'; o_decode_reg.jump <= '1'; o_decode_reg.branch <= '1'; o_decode_reg.pc <= (others => '1'); o_decode_reg.imm <= (others => '1'); -- Références: -- Écrire le registre pointé -- write_reg_file: -- process (i_clk) is -- begin -- -- if rising_edge(i_clk) then -- if i_rstn = '1' then -- if reg_file_wr_en = '1' then -- reg_file(to_integer(unsigned(i_addr_w))) <= i_data_w; -- else -- reg_file <= reg_file; -- end if; -- else -- reg_file <= (others => (others => '0')); -- end if; -- end if; -- end process write_reg_file; -- Transférer la valeur écrite vers un tampon -- transfer_write_buffers: -- process (i_clk) is -- begin -- if rising_edge(i_clk) then -- if i_rstn = '1' then -- write_buffer <= i_data_w; -- else -- write_buffer <= (others => '0'); -- end if; -- end if; -- end process transfer_write_buffers; end architecture beh;