MMU: Remove software-loaded dTLB mode
[microwatt.git] / fetch1.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4
5 library work;
6 use work.common.all;
7
8 entity fetch1 is
9 generic(
10 RESET_ADDRESS : std_logic_vector(63 downto 0) := (others => '0')
11 );
12 port(
13 clk : in std_ulogic;
14 rst : in std_ulogic;
15
16 -- Control inputs:
17 stall_in : in std_ulogic;
18 flush_in : in std_ulogic;
19 stop_in : in std_ulogic;
20
21 -- redirect from execution unit
22 e_in : in Execute1ToFetch1Type;
23
24 -- Request to icache
25 i_out : out Fetch1ToIcacheType
26 );
27 end entity fetch1;
28
29 architecture behaviour of fetch1 is
30 type stop_state_t is (RUNNING, STOPPED, RESTARTING);
31 type reg_internal_t is record
32 stop_state: stop_state_t;
33 end record;
34 signal r, r_next : Fetch1ToIcacheType;
35 signal r_int, r_next_int : reg_internal_t;
36 begin
37
38 regs : process(clk)
39 begin
40 if rising_edge(clk) then
41 if r /= r_next then
42 report "fetch1 rst:" & std_ulogic'image(rst) &
43 " R:" & std_ulogic'image(e_in.redirect) &
44 " S:" & std_ulogic'image(stall_in) &
45 " T:" & std_ulogic'image(stop_in) &
46 " nia:" & to_hstring(r_next.nia) &
47 " SM:" & std_ulogic'image(r_next.stop_mark);
48 end if;
49 r <= r_next;
50 r_int <= r_next_int;
51 end if;
52 end process;
53
54 comb : process(all)
55 variable v : Fetch1ToIcacheType;
56 variable v_int : reg_internal_t;
57 variable increment : boolean;
58 begin
59 v := r;
60 v_int := r_int;
61
62 if rst = '1' then
63 v.nia := RESET_ADDRESS;
64 v_int.stop_state := RUNNING;
65 elsif e_in.redirect = '1' then
66 v.nia := e_in.redirect_nia;
67 elsif stall_in = '0' then
68
69 -- For debug stop/step to work properly we need a little bit of
70 -- trickery here. If we just stop incrementing and send stop marks
71 -- when stop_in is set, then we'll increment on the cycle it clears
72 -- and end up never executing the instruction we were stopped on.
73 --
74 -- Avoid this along with the opposite issue when stepping (stop is
75 -- cleared for only one cycle) is handled by the state machine below
76 --
77 -- By default, increment addresses
78 increment := true;
79 case v_int.stop_state is
80 when RUNNING =>
81 -- If we are running and stop_in is set, then stop incrementing,
82 -- we are now stopped.
83 if stop_in = '1' then
84 increment := false;
85 v_int.stop_state := STOPPED;
86 end if;
87 when STOPPED =>
88 -- When stopped, never increment. If stop is cleared, go to state
89 -- "restarting" but still don't increment that cycle. stop_in is
90 -- now 0 so we'll send the NIA down without a stop mark.
91 increment := false;
92 if stop_in = '0' then
93 v_int.stop_state := RESTARTING;
94 end if;
95 when RESTARTING =>
96 -- We have just sent the NIA down, we can start incrementing again.
97 -- If stop_in is still not set, go back to running normally.
98 -- If stop_in is set again (that was a one-cycle "step"), go
99 -- back to "stopped" state which means we'll stop incrementing
100 -- on the next cycle. This ensures we increment the PC once after
101 -- sending one instruction without a stop mark. Since stop_in is
102 -- now set, the new PC will be sent with a stop mark and thus not
103 -- executed.
104 if stop_in = '0' then
105 v_int.stop_state := RUNNING;
106 else
107 v_int.stop_state := STOPPED;
108 end if;
109 end case;
110
111 if increment then
112 v.nia := std_logic_vector(unsigned(v.nia) + 4);
113 end if;
114 end if;
115
116 v.req := not rst;
117 v.stop_mark := stop_in;
118
119 r_next <= v;
120 r_next_int <= v_int;
121
122 -- Update outputs to the icache
123 i_out <= r;
124
125 end process;
126
127 end architecture behaviour;