forked from cores/microwatt
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.6 KiB
VHDL
160 lines
3.6 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.common.all;
|
|
use work.wishbone_types.all;
|
|
|
|
entity fetch2 is
|
|
port(
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
|
|
stall_in : in std_ulogic;
|
|
stall_out : out std_ulogic;
|
|
|
|
flush_in : in std_ulogic;
|
|
|
|
-- instruction memory interface
|
|
wishbone_in : in wishbone_slave_out;
|
|
wishbone_out : out wishbone_master_out;
|
|
|
|
f_in : in Fetch1ToFetch2Type;
|
|
|
|
f_out : out Fetch2ToDecode1Type
|
|
);
|
|
end entity fetch2;
|
|
|
|
architecture behaviour of fetch2 is
|
|
type state_type is (IDLE, JUST_IDLE, WAIT_ACK, WAIT_ACK_THROWAWAY);
|
|
|
|
type reg_internal_type is record
|
|
state : state_type;
|
|
nia : std_ulogic_vector(63 downto 0);
|
|
w : wishbone_master_out;
|
|
-- Trivial 64B cache
|
|
cache : std_ulogic_vector(63 downto 0);
|
|
tag : std_ulogic_vector(60 downto 0);
|
|
tag_valid : std_ulogic;
|
|
end record;
|
|
|
|
function wishbone_fetch(nia : std_ulogic_vector(63 downto 0)) return wishbone_master_out is
|
|
variable w : wishbone_master_out;
|
|
begin
|
|
assert nia(2 downto 0) = "000";
|
|
|
|
w.adr := nia;
|
|
w.dat := (others => '0');
|
|
w.cyc := '1';
|
|
w.stb := '1';
|
|
w.sel := "11111111";
|
|
w.we := '0';
|
|
|
|
return w;
|
|
end;
|
|
|
|
signal r, rin : Fetch2ToDecode1Type;
|
|
signal r_int, rin_int : reg_internal_type;
|
|
begin
|
|
regs : process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
-- Output state remains unchanged on stall, unless we are flushing
|
|
if rst = '1' or flush_in = '1' or stall_in = '0' then
|
|
r <= rin;
|
|
end if;
|
|
r_int <= rin_int;
|
|
end if;
|
|
end process;
|
|
|
|
comb : process(all)
|
|
variable v : Fetch2ToDecode1Type;
|
|
variable v_int : reg_internal_type;
|
|
begin
|
|
v := r;
|
|
v_int := r_int;
|
|
|
|
v.valid := '0';
|
|
v.nia := f_in.nia;
|
|
|
|
case v_int.state is
|
|
when IDLE | JUST_IDLE =>
|
|
v_int.state := IDLE;
|
|
|
|
if (v_int.tag_valid = '1') and (v_int.tag = f_in.nia(63 downto 3)) then
|
|
v.valid := '1';
|
|
if f_in.nia(2) = '0' then
|
|
v.insn := v_int.cache(31 downto 0);
|
|
else
|
|
v.insn := v_int.cache(63 downto 32);
|
|
end if;
|
|
else
|
|
v_int.state := WAIT_ACK;
|
|
v_int.nia := f_in.nia;
|
|
v_int.w := wishbone_fetch(f_in.nia(63 downto 3) & "000");
|
|
end if;
|
|
|
|
when WAIT_ACK =>
|
|
if wishbone_in.ack = '1' then
|
|
v_int.state := IDLE;
|
|
v_int.w := wishbone_master_out_init;
|
|
v_int.cache := wishbone_in.dat;
|
|
v_int.tag := v_int.nia(63 downto 3);
|
|
v_int.tag_valid := '1';
|
|
|
|
v.valid := '1';
|
|
if v_int.nia(2) = '0' then
|
|
v.insn := v_int.cache(31 downto 0);
|
|
else
|
|
v.insn := v_int.cache(63 downto 32);
|
|
end if;
|
|
end if;
|
|
|
|
when WAIT_ACK_THROWAWAY =>
|
|
if wishbone_in.ack = '1' then
|
|
-- Should we put the returned data in the cache? We went to the
|
|
-- trouble of fetching it and it might be useful in the future
|
|
|
|
v_int.w := wishbone_master_out_init;
|
|
|
|
-- We need to stall fetch1 for one more cycle, so transition through JUST_IDLE
|
|
v_int.state := JUST_IDLE;
|
|
end if;
|
|
end case;
|
|
|
|
stall_out <= '0';
|
|
if v_int.state /= IDLE then
|
|
stall_out <= '1';
|
|
end if;
|
|
|
|
if flush_in = '1' then
|
|
v.valid := '0';
|
|
|
|
-- Throw away in flight data
|
|
if v_int.state = WAIT_ACK then
|
|
v_int.state := WAIT_ACK_THROWAWAY;
|
|
end if;
|
|
end if;
|
|
|
|
if rst = '1' then
|
|
v := Fetch2ToDecode1Init;
|
|
|
|
v_int.state := IDLE;
|
|
v_int.nia := (others => '0');
|
|
v_int.w := wishbone_master_out_init;
|
|
v_int.cache := (others => '0');
|
|
v_int.tag := (others => '0');
|
|
v_int.tag_valid := '0';
|
|
end if;
|
|
|
|
-- Update registers
|
|
rin_int <= v_int;
|
|
rin <= v;
|
|
|
|
-- Update outputs
|
|
f_out <= r;
|
|
wishbone_out <= r_int.w;
|
|
end process;
|
|
end architecture behaviour;
|