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);

Yann Roberge
committed

Yann Roberge
committed
-- 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);

Yann Roberge
committed
-- 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

Yann Roberge
committed
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);

Yann Roberge
committed
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);
alias opcode is i_decode_reg.opcode;
alias jump is i_decode_reg.jump;
alias branch is i_decode_reg.branch;

Yann Roberge
committed
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:
if (jump = '1') or ((branch = '1') and (alu_result = ALL_ZEROES)) then

Yann Roberge
committed
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';

Yann Roberge
committed
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
-- 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

Yann Roberge
committed
pick_shamt:
process (all) is

Yann Roberge
committed
begin
case opcode is
when OPCODE_ALU_R_TYPE =>

Yann Roberge
committed
shamt <= rs2_data(SHAMT_WIDTH-1 downto 0);

Yann Roberge
committed
when OPCODE_ALU_I_TYPE =>
shamt <= imm(SHAMT_WIDTH-1 downto 0);
when others =>
shamt <= (others => '0');
end case;
end process pick_shamt;
alu_feeder_src1:
process (all) is
begin
-- Select src1
case opcode is
when OPCODE_JAL | OPCODE_JALR =>
alu_src1 <= pc;
when others =>

Yann Roberge
committed
alu_src1 <= rs1_data;
end case;
end process alu_feeder_src1;
alu_feeder_src2:
process (all) is

Yann Roberge
committed
begin
-- Select src2
case opcode is
when OPCODE_ALU_R_TYPE | OPCODE_BEQ =>
when OPCODE_ALU_I_TYPE | OPCODE_LUI | OPCODE_SW =>

Yann Roberge
committed
alu_src2 <= imm;
when OPCODE_JAL | OPCODE_JALR =>
alu_src2 <= std_logic_vector(to_unsigned(4, alu_src2'length));

Yann Roberge
committed
when others =>
alu_src2 <= (others => '0');
end case;
end process alu_feeder_src2;

Yann Roberge
committed
-- 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,
i_src1 => alu_src1,

Yann Roberge
committed
i_src2 => alu_src2,
o_res => alu_result
);
-- JAL & BEQ: IMM + PC
-- JALR: IMM + BASE
add_feeder:
process (all) is
begin
case opcode is
when OPCODE_JALR =>

Yann Roberge
committed
add_to_imm <= rs1_data;
-- JAL & BEQ
when others =>
add_to_imm <= pc;
end case;
end process add_feeder;
-- Ajustement du PC en cas de saut ou branchement

Yann Roberge
committed
-- Instanciate adder
dut: entity work.riscv_adder
generic map (
N => XLEN
)
port map (
i_a => imm,
i_b => add_to_imm,

Yann Roberge
committed
i_sign => SIGN_UNSIGNED,
i_sub => ARITH_ADD,
o_sum(XLEN) => dummy,
o_sum(XLEN-1 downto 0) => o_pc_target

Yann Roberge
committed
);

Yann Roberge
committed
-- 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;

Yann Roberge
committed
o_execute_reg.store_data <= rs2_data;
o_execute_reg.rd_addr <= i_decode_reg.rd_addr;

Yann Roberge
committed
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');

Yann Roberge
committed
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';