Skip to content
Snippets Groups Projects
riscv_execute.vhd 6.6 KiB
Newer Older
-------------------------------------------------------------------------------
-- Project  ELE8304 : Circuits intégrés à très grande échelle
-------------------------------------------------------------------------------
-- File     riscv_execute.vhd
-- Authors  Titouan Luard <luardtitouan@gmail.com> 
--          Yann Roberge <yann.roberge@polymtl.ca> 
-- Lab      GRM - Polytechnique Montreal
-- Date     2021-12-04
-------------------------------------------------------------------------------
-- Brief    Execute stage of the pipeline
-------------------------------------------------------------------------------
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_execute is
  port (
    -- Entrées de l'étage Decode
    i_decode_reg : in decode_reg;

    i_rs1_data : in std_logic_vector(XLEN-1 downto 0);
    i_rs2_data : in std_logic_vector(XLEN-1 downto 0);
    -- Entrées de l'étage Write Back (forwarding)
    i_write_back_reg : in write_back_reg;

    -- Sorties
    o_pc_transfer : out std_logic;
    o_pc_target   : out std_logic_vector(XLEN-1 downto 0);

    o_stall : out std_logic;
    o_flush : out std_logic;

    -- Entrées externes au pipeline
    i_rstn : in std_logic;
    i_clk  : in std_logic;

    -- Sorties registrées
    o_execute_reg : out execute_reg);
end entity riscv_execute;

architecture beh of riscv_execute is

  signal rs1_data : std_logic_vector(XLEN-1 downto 0);
  signal rs2_data : std_logic_vector(XLEN-1 downto 0);

  signal alu_src1 : std_logic_vector(XLEN-1 downto 0);
  signal alu_src2 : std_logic_vector(XLEN-1 downto 0);

  signal shamt : std_logic_vector(SHAMT_WIDTH-1 downto 0);

  signal add_to_imm : std_logic_vector(XLEN-1 downto 0);

  -- Sorties
  signal alu_result : std_logic_vector(XLEN-1 downto 0);
Yann Roberge's avatar
Yann Roberge committed
  --signal store_data : std_logic;

  alias opcode is i_decode_reg.opcode;
  alias jump   is i_decode_reg.jump;
  alias branch is i_decode_reg.branch;
  alias imm    is i_decode_reg.imm;
  alias pc     is i_decode_reg.pc;

  constant ALL_ZEROES : std_logic_vector(XLEN-1 downto 0) := (others => '0');

  signal dummy : std_logic; -- doesn't do anything
begin

  -- PC transfer
  -- transfert si jump ou si la condition du BEQ est vraie  
  -- flush la pipeline dans ce même cas
  -- toute la gestion de conflit se fait ici
  -- ie. branch prediction
  pc_transfer:
  begin
    if (jump = '1') or ((branch = '1') and (alu_result = ALL_ZEROES)) then
      o_flush <= '1';
      o_pc_transfer <= '1';
    elsif opcode = OPCODE_LW then
      o_flush <= '1';
      o_pc_transfer <= '0';
    else
      o_flush <= '0';
      o_pc_transfer <= '0';
    end if;
  end process pc_transfer;

  -- Résoudre le conflit de données en cas de LW
  o_stall <= '1' when opcode = OPCODE_LW else '0';

  -- Résolution des conflits de données par forwarding
  -- Si un des registres lues au RF à l'étage décode a été modifié entre-temps
  -- par les étages Execute et Memory, alors on utilise la donnée écrite par
  -- Execute ou la donnée chargée par Memory à la place de la donnée lue au RF
  resolve_data_conflicts:
  process (all) is
  begin
    -- FIXME: les lignes trop longues
    if i_decode_reg.rs1_addr = o_execute_reg.rd_addr then
      rs1_data <= o_execute_reg.alu_result;
    elsif (i_decode_reg.rs1_addr = i_write_back_reg.wr_addr) and i_write_back_reg.we = '1' then
      rs1_data <= i_write_back_reg.wr_data;
    else
      rs1_data <= i_rs1_data;
    end if;

    if i_decode_reg.rs2_addr = o_execute_reg.rd_addr then
      rs2_data <= o_execute_reg.alu_result;
    elsif (i_decode_reg.rs2_addr = i_write_back_reg.wr_addr) and i_write_back_reg.we = '1' then
      rs2_data <= i_write_back_reg.wr_data;
    else
      rs2_data <= i_rs2_data;
    end if;

  end process resolve_data_conflicts;

  -- Résolution des opérations arithmétiques et logiques

  -- Shamt: encoded in IMM for I-TYPE, else encoded in RS2
        shamt <= rs2_data(SHAMT_WIDTH-1 downto 0);
      when OPCODE_ALU_I_TYPE =>
        shamt <= imm(SHAMT_WIDTH-1 downto 0);
      when others =>
        shamt <= (others => '0');
    end case;
  end process pick_shamt;

  begin
    -- Select src1
    case opcode is
      when OPCODE_JAL | OPCODE_JALR =>
        alu_src1 <= pc;
      when others =>
    end case;
  end process alu_feeder_src1;

  alu_feeder_src2:
  begin
    -- Select src2
    case opcode is
      when OPCODE_ALU_R_TYPE | OPCODE_BEQ =>
        alu_src2 <= i_rs2_data;
Yann Roberge's avatar
Yann Roberge committed
      when OPCODE_ALU_I_TYPE | OPCODE_LUI | OPCODE_SW =>
      when OPCODE_JAL | OPCODE_JALR =>
        alu_src2 <= std_logic_vector(to_unsigned(4, alu_src2'length));
      when others =>
        alu_src2 <= (others => '0');
    end case;

  -- Instanciate alu
  alu: entity work.riscv_alu
  port map (
    i_arith   => i_decode_reg.arith,
    i_sign    => i_decode_reg.sign,
    i_opcode  => i_decode_reg.alu_opcode,
    i_shamt   => shamt,

  -- JAL & BEQ: IMM + PC
  -- JALR: IMM + BASE
  add_feeder:
  process (all) is
  begin
    case opcode is
      when OPCODE_JALR =>
      -- JAL & BEQ
      when others =>
        add_to_imm <= pc;
    end case;
  end process add_feeder;

  -- Ajustement du PC en cas de saut ou branchement
  -- Instanciate adder
  dut: entity work.riscv_adder
  generic map (
    N => XLEN
  )
  port map (
    i_a    => imm,
    o_sum(XLEN) => dummy,
    o_sum(XLEN-1 downto 0) => o_pc_target

  -- Écriture du registre execute
  -- same as decode register write thingy without flush input
  write_reg_ex_me:
  process (i_clk) is
  begin
    if rising_edge(i_clk) then
      if i_rstn = '1' then
        o_execute_reg.opcode <= opcode;

        o_execute_reg.alu_result <= alu_result;
        o_execute_reg.rd_addr    <= i_decode_reg.rd_addr;
      else
        o_execute_reg.opcode <= (others => '0');

        o_execute_reg.alu_result <= (others => '0');
        o_execute_reg.store_data <= (others => '0');
        o_execute_reg.rd_addr    <= (others => '0');
      end if;
    end if;
  end process write_reg_ex_me;

  -- DEBUG
  --o_pc_target <= (others => '1');
  --o_execute_reg.alu_result <= (others => '1');
  --o_execute_reg.store_data <= '1';

end architecture beh;