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; flush_in : in std_ulogic; -- Results from icache i_in : in IcacheToFetch2Type; -- Output to decode f_out : out Fetch2ToDecode1Type ); end entity fetch2; architecture behaviour of fetch2 is -- The icache cannot stall, so we need to stash a cycle -- of output from it when we stall. type reg_internal_type is record stash : IcacheToFetch2Type; stash_valid : std_ulogic; stopped : std_ulogic; end record; signal r_int, rin_int : reg_internal_type; signal r, rin : Fetch2ToDecode1Type; begin regs : process(clk) begin if rising_edge(clk) then if (r /= rin) then report "fetch2 rst:" & std_ulogic'image(rst) & " S:" & std_ulogic'image(stall_in) & " F:" & std_ulogic'image(flush_in) & " T:" & std_ulogic'image(rin.stop_mark) & " V:" & std_ulogic'image(rin.valid) & " nia:" & to_hstring(rin.nia); end if; -- 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; -- Internal state is updated on every clock r_int <= rin_int; end if; end process; comb : process(all) variable v : Fetch2ToDecode1Type; variable v_int : reg_internal_type; variable v_i_in : IcacheToFetch2Type; begin v := r; v_int := r_int; -- If stalling, stash away the current input from the icache if stall_in = '1' and v_int.stash_valid = '0' then v_int.stash := i_in; v_int.stash_valid := '1'; end if; -- If unstalling, source input from the stash and invalidate it, -- otherwise source normally from the icache. -- v_i_in := i_in; if v_int.stash_valid = '1' and stall_in = '0' then v_i_in := v_int.stash; v_int.stash_valid := '0'; end if; v.valid := v_i_in.valid; v.stop_mark := v_i_in.stop_mark; v.nia := v_i_in.nia; v.insn := v_i_in.insn; -- Clear stash internal valid bit on flush. We still mark -- the stash itself as valid since we still want to override -- whatever comes form icache when unstalling, but we'll -- override it with something invalid. -- if flush_in = '1' then v_int.stash.valid := '0'; end if; -- If we are flushing or the instruction comes with a stop mark -- we tag it as invalid so it doesn't get decoded and executed if flush_in = '1' or v.stop_mark = '1' then v.valid := '0'; end if; -- Clear stash on reset if rst = '1' then v_int.stash_valid := '0'; end if; -- Update registers rin <= v; rin_int <= v_int; -- Update outputs f_out <= r; end process; end architecture behaviour;