mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-25 20:11:34 +00:00
This enables back-to-back execution of integer instructions where the first instruction writes a GPR and the second reads the same GPR. This is done with a set of multiplexers at the start of execute1 which enable any of the three input operands to be taken from the output of execute1 (i.e. r.e.write_data) rather than the input from decode2 (i.e. e_in.read_data[123]). This also requires changes to the hazard detection and handling. Decode2 generates a signal indicating that the GPR being written is available for bypass, which is true for instructions that are executed in execute1 (rather than loadstore1/dcache). The gpr_hazard module stores this "bypassable" bit, and if the same GPR needs to be read by a subsequent instruction, it outputs a "use_bypass" signal rather than generating a stall. The use_bypass signal is then latched at the output of decode2 and passed down to execute1 to control the input multiplexer. At the moment there is no bypass on the inputs to loadstore1, but that is OK because all load and store instructions are marked as single-issue. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
99 lines
3.0 KiB
VHDL
99 lines
3.0 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
entity gpr_hazard is
|
|
generic (
|
|
PIPELINE_DEPTH : natural := 2
|
|
);
|
|
port(
|
|
clk : in std_ulogic;
|
|
stall_in : in std_ulogic;
|
|
|
|
gpr_write_valid_in : in std_ulogic;
|
|
gpr_write_in : in std_ulogic_vector(5 downto 0);
|
|
bypass_avail : in std_ulogic;
|
|
gpr_read_valid_in : in std_ulogic;
|
|
gpr_read_in : in std_ulogic_vector(5 downto 0);
|
|
|
|
stall_out : out std_ulogic;
|
|
use_bypass : out std_ulogic
|
|
);
|
|
end entity gpr_hazard;
|
|
architecture behaviour of gpr_hazard is
|
|
type pipeline_entry_type is record
|
|
valid : std_ulogic;
|
|
bypass : std_ulogic;
|
|
gpr : std_ulogic_vector(5 downto 0);
|
|
end record;
|
|
constant pipeline_entry_init : pipeline_entry_type := (valid => '0', bypass => '0', gpr => (others => '0'));
|
|
|
|
type pipeline_t is array(0 to PIPELINE_DEPTH-1) of pipeline_entry_type;
|
|
constant pipeline_t_init : pipeline_t := (others => pipeline_entry_init);
|
|
|
|
signal r, rin : pipeline_t := pipeline_t_init;
|
|
begin
|
|
gpr_hazard0: process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
r <= rin;
|
|
end if;
|
|
end process;
|
|
|
|
gpr_hazard1: process(all)
|
|
variable v : pipeline_t;
|
|
begin
|
|
v := r;
|
|
|
|
stall_out <= '0';
|
|
use_bypass <= '0';
|
|
if gpr_read_valid_in = '1' then
|
|
if r(0).valid = '1' and r(0).gpr = gpr_read_in then
|
|
if r(0).bypass = '1' and stall_in = '0' then
|
|
use_bypass <= '1';
|
|
else
|
|
stall_out <= '1';
|
|
end if;
|
|
end if;
|
|
loop_0: for i in 1 to PIPELINE_DEPTH-1 loop
|
|
if r(i).valid = '1' and r(i).gpr = gpr_read_in then
|
|
if r(i).bypass = '1' then
|
|
use_bypass <= '1';
|
|
else
|
|
stall_out <= '1';
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
|
|
if stall_in = '0' then
|
|
v(0).valid := gpr_write_valid_in;
|
|
v(0).bypass := bypass_avail;
|
|
v(0).gpr := gpr_write_in;
|
|
loop_1: for i in 1 to PIPELINE_DEPTH-1 loop
|
|
-- propagate to next slot
|
|
v(i).valid := r(i-1).valid;
|
|
v(i).bypass := r(i-1).bypass;
|
|
v(i).gpr := r(i-1).gpr;
|
|
end loop;
|
|
|
|
else
|
|
-- stage 0 stalled, so stage 1 becomes empty
|
|
loop_1b: for i in 1 to PIPELINE_DEPTH-1 loop
|
|
-- propagate to next slot
|
|
if i = 1 then
|
|
v(i).valid := '0';
|
|
else
|
|
v(i).valid := r(i-1).valid;
|
|
v(i).bypass := r(i-1).bypass;
|
|
v(i).gpr := r(i-1).gpr;
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
|
|
-- update registers
|
|
rin <= v;
|
|
|
|
end process;
|
|
end;
|