Skip to content
Snippets Groups Projects
riscv_decode.vhd 8.34 KiB
Newer Older
-------------------------------------------------------------------------------
-- 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;
  -- 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
    );
  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;