1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-02-01 14:22:14 +00:00
Files
antonblanchard.microwatt/fetch1.vhdl
Benjamin Herrenschmidt 6853d22203 core: Add alternate reset address
An external signal can control whether the core will start
executing at the standard or the alternate reset address.

This will be used when litedram is initialized by microwatt
itself, to route the reset to the built-in init code secondary
block RAM.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2020-05-08 11:41:06 +10:00

134 lines
3.7 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.common.all;
entity fetch1 is
generic(
RESET_ADDRESS : std_logic_vector(63 downto 0) := (others => '0');
ALT_RESET_ADDRESS : std_logic_vector(63 downto 0) := (others => '0')
);
port(
clk : in std_ulogic;
rst : in std_ulogic;
-- Control inputs:
stall_in : in std_ulogic;
flush_in : in std_ulogic;
stop_in : in std_ulogic;
alt_reset_in : in std_ulogic;
-- redirect from execution unit
e_in : in Execute1ToFetch1Type;
-- Request to icache
i_out : out Fetch1ToIcacheType
);
end entity fetch1;
architecture behaviour of fetch1 is
type stop_state_t is (RUNNING, STOPPED, RESTARTING);
type reg_internal_t is record
stop_state: stop_state_t;
end record;
signal r, r_next : Fetch1ToIcacheType;
signal r_int, r_next_int : reg_internal_t;
begin
regs : process(clk)
begin
if rising_edge(clk) then
if r /= r_next then
report "fetch1 rst:" & std_ulogic'image(rst) &
" R:" & std_ulogic'image(e_in.redirect) &
" S:" & std_ulogic'image(stall_in) &
" T:" & std_ulogic'image(stop_in) &
" nia:" & to_hstring(r_next.nia) &
" SM:" & std_ulogic'image(r_next.stop_mark);
end if;
r <= r_next;
r_int <= r_next_int;
end if;
end process;
comb : process(all)
variable v : Fetch1ToIcacheType;
variable v_int : reg_internal_t;
variable increment : boolean;
begin
v := r;
v_int := r_int;
if rst = '1' then
if alt_reset_in = '1' then
v.nia := ALT_RESET_ADDRESS;
else
v.nia := RESET_ADDRESS;
end if;
v_int.stop_state := RUNNING;
elsif e_in.redirect = '1' then
v.nia := e_in.redirect_nia;
elsif stall_in = '0' then
-- For debug stop/step to work properly we need a little bit of
-- trickery here. If we just stop incrementing and send stop marks
-- when stop_in is set, then we'll increment on the cycle it clears
-- and end up never executing the instruction we were stopped on.
--
-- Avoid this along with the opposite issue when stepping (stop is
-- cleared for only one cycle) is handled by the state machine below
--
-- By default, increment addresses
increment := true;
case v_int.stop_state is
when RUNNING =>
-- If we are running and stop_in is set, then stop incrementing,
-- we are now stopped.
if stop_in = '1' then
increment := false;
v_int.stop_state := STOPPED;
end if;
when STOPPED =>
-- When stopped, never increment. If stop is cleared, go to state
-- "restarting" but still don't increment that cycle. stop_in is
-- now 0 so we'll send the NIA down without a stop mark.
increment := false;
if stop_in = '0' then
v_int.stop_state := RESTARTING;
end if;
when RESTARTING =>
-- We have just sent the NIA down, we can start incrementing again.
-- If stop_in is still not set, go back to running normally.
-- If stop_in is set again (that was a one-cycle "step"), go
-- back to "stopped" state which means we'll stop incrementing
-- on the next cycle. This ensures we increment the PC once after
-- sending one instruction without a stop mark. Since stop_in is
-- now set, the new PC will be sent with a stop mark and thus not
-- executed.
if stop_in = '0' then
v_int.stop_state := RUNNING;
else
v_int.stop_state := STOPPED;
end if;
end case;
if increment then
v.nia := std_logic_vector(unsigned(v.nia) + 4);
end if;
end if;
v.req := not rst;
v.stop_mark := stop_in;
r_next <= v;
r_next_int <= v_int;
-- Update outputs to the icache
i_out <= r;
end process;
end architecture behaviour;