Fix an issue in flash controller when BOOT_CLOCKS is false
[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 ALT_RESET_ADDRESS : std_logic_vector(63 downto 0) := (others => '0')
12 );
13 port(
14 clk : in std_ulogic;
15 rst : in std_ulogic;
16
17 -- Control inputs:
18 stall_in : in std_ulogic;
19 flush_in : in std_ulogic;
20 stop_in : in std_ulogic;
21 alt_reset_in : in std_ulogic;
22
23 -- redirect from execution unit
24 e_in : in Execute1ToFetch1Type;
25
26 -- redirect from decode1
27 d_in : in Decode1ToFetch1Type;
28
29 -- Request to icache
30 i_out : out Fetch1ToIcacheType;
31
32 -- outputs to logger
33 log_out : out std_ulogic_vector(42 downto 0)
34 );
35 end entity fetch1;
36
37 architecture behaviour of fetch1 is
38 type stop_state_t is (RUNNING, STOPPED, RESTARTING);
39 type reg_internal_t is record
40 stop_state: stop_state_t;
41 mode_32bit: std_ulogic;
42 end record;
43 signal r, r_next : Fetch1ToIcacheType;
44 signal r_int, r_next_int : reg_internal_t;
45 signal log_nia : std_ulogic_vector(42 downto 0);
46 begin
47
48 regs : process(clk)
49 begin
50 if rising_edge(clk) then
51 log_nia <= r.nia(63) & r.nia(43 downto 2);
52 if r /= r_next then
53 report "fetch1 rst:" & std_ulogic'image(rst) &
54 " IR:" & std_ulogic'image(r_next.virt_mode) &
55 " P:" & std_ulogic'image(r_next.priv_mode) &
56 " E:" & std_ulogic'image(r_next.big_endian) &
57 " 32:" & std_ulogic'image(r_next_int.mode_32bit) &
58 " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) &
59 " S:" & std_ulogic'image(stall_in) &
60 " T:" & std_ulogic'image(stop_in) &
61 " nia:" & to_hstring(r_next.nia) &
62 " SM:" & std_ulogic'image(r_next.stop_mark);
63 end if;
64 r <= r_next;
65 r_int <= r_next_int;
66 end if;
67 end process;
68 log_out <= log_nia;
69
70 comb : process(all)
71 variable v : Fetch1ToIcacheType;
72 variable v_int : reg_internal_t;
73 variable increment : boolean;
74 begin
75 v := r;
76 v_int := r_int;
77 v.sequential := '0';
78
79 if rst = '1' then
80 if alt_reset_in = '1' then
81 v.nia := ALT_RESET_ADDRESS;
82 else
83 v.nia := RESET_ADDRESS;
84 end if;
85 v.virt_mode := '0';
86 v.priv_mode := '1';
87 v.big_endian := '0';
88 v_int.stop_state := RUNNING;
89 v_int.mode_32bit := '0';
90 elsif e_in.redirect = '1' then
91 v.nia := e_in.redirect_nia(63 downto 2) & "00";
92 if e_in.mode_32bit = '1' then
93 v.nia(63 downto 32) := (others => '0');
94 end if;
95 v.virt_mode := e_in.virt_mode;
96 v.priv_mode := e_in.priv_mode;
97 v.big_endian := e_in.big_endian;
98 v_int.mode_32bit := e_in.mode_32bit;
99 elsif d_in.redirect = '1' then
100 v.nia := d_in.redirect_nia(63 downto 2) & "00";
101 if r_int.mode_32bit = '1' then
102 v.nia(63 downto 32) := (others => '0');
103 end if;
104 elsif stall_in = '0' then
105
106 -- For debug stop/step to work properly we need a little bit of
107 -- trickery here. If we just stop incrementing and send stop marks
108 -- when stop_in is set, then we'll increment on the cycle it clears
109 -- and end up never executing the instruction we were stopped on.
110 --
111 -- Avoid this along with the opposite issue when stepping (stop is
112 -- cleared for only one cycle) is handled by the state machine below
113 --
114 -- By default, increment addresses
115 increment := true;
116 case v_int.stop_state is
117 when RUNNING =>
118 -- If we are running and stop_in is set, then stop incrementing,
119 -- we are now stopped.
120 if stop_in = '1' then
121 increment := false;
122 v_int.stop_state := STOPPED;
123 end if;
124 when STOPPED =>
125 -- When stopped, never increment. If stop is cleared, go to state
126 -- "restarting" but still don't increment that cycle. stop_in is
127 -- now 0 so we'll send the NIA down without a stop mark.
128 increment := false;
129 if stop_in = '0' then
130 v_int.stop_state := RESTARTING;
131 end if;
132 when RESTARTING =>
133 -- We have just sent the NIA down, we can start incrementing again.
134 -- If stop_in is still not set, go back to running normally.
135 -- If stop_in is set again (that was a one-cycle "step"), go
136 -- back to "stopped" state which means we'll stop incrementing
137 -- on the next cycle. This ensures we increment the PC once after
138 -- sending one instruction without a stop mark. Since stop_in is
139 -- now set, the new PC will be sent with a stop mark and thus not
140 -- executed.
141 if stop_in = '0' then
142 v_int.stop_state := RUNNING;
143 else
144 v_int.stop_state := STOPPED;
145 end if;
146 end case;
147
148 if increment then
149 if r_int.mode_32bit = '0' then
150 v.nia := std_ulogic_vector(unsigned(r.nia) + 4);
151 else
152 v.nia := x"00000000" & std_ulogic_vector(unsigned(r.nia(31 downto 0)) + 4);
153 end if;
154 v.sequential := '1';
155 end if;
156 end if;
157
158 v.req := not rst;
159 v.stop_mark := stop_in;
160
161 r_next <= v;
162 r_next_int <= v_int;
163
164 -- Update outputs to the icache
165 i_out <= r;
166
167 end process;
168
169 end architecture behaviour;