forked from Jbalkind/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetch1.vhdl
169 lines (151 loc) · 5.21 KB
/
fetch1.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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;
-- redirect from decode1
d_in : in Decode1ToFetch1Type;
-- Request to icache
i_out : out Fetch1ToIcacheType;
-- outputs to logger
log_out : out std_ulogic_vector(42 downto 0)
);
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;
mode_32bit: std_ulogic;
end record;
signal r, r_next : Fetch1ToIcacheType;
signal r_int, r_next_int : reg_internal_t;
signal log_nia : std_ulogic_vector(42 downto 0);
begin
regs : process(clk)
begin
if rising_edge(clk) then
log_nia <= r.nia(63) & r.nia(43 downto 2);
if r /= r_next then
report "fetch1 rst:" & std_ulogic'image(rst) &
" IR:" & std_ulogic'image(r_next.virt_mode) &
" P:" & std_ulogic'image(r_next.priv_mode) &
" E:" & std_ulogic'image(r_next.big_endian) &
" 32:" & std_ulogic'image(r_next_int.mode_32bit) &
" R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_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;
log_out <= log_nia;
comb : process(all)
variable v : Fetch1ToIcacheType;
variable v_int : reg_internal_t;
variable increment : boolean;
begin
v := r;
v_int := r_int;
v.sequential := '0';
if rst = '1' then
if alt_reset_in = '1' then
v.nia := ALT_RESET_ADDRESS;
else
v.nia := RESET_ADDRESS;
end if;
v.virt_mode := '0';
v.priv_mode := '1';
v.big_endian := '0';
v_int.stop_state := RUNNING;
v_int.mode_32bit := '0';
elsif e_in.redirect = '1' then
v.nia := e_in.redirect_nia(63 downto 2) & "00";
if e_in.mode_32bit = '1' then
v.nia(63 downto 32) := (others => '0');
end if;
v.virt_mode := e_in.virt_mode;
v.priv_mode := e_in.priv_mode;
v.big_endian := e_in.big_endian;
v_int.mode_32bit := e_in.mode_32bit;
elsif d_in.redirect = '1' then
v.nia := d_in.redirect_nia(63 downto 2) & "00";
if r_int.mode_32bit = '1' then
v.nia(63 downto 32) := (others => '0');
end if;
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
if r_int.mode_32bit = '0' then
v.nia := std_ulogic_vector(unsigned(r.nia) + 4);
else
v.nia := x"00000000" & std_ulogic_vector(unsigned(r.nia(31 downto 0)) + 4);
end if;
v.sequential := '1';
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;