Merge pull request #130 from antonblanchard/build-fix
[microwatt.git] / control.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3
4 library work;
5 use work.common.all;
6
7 entity control is
8 generic (
9 PIPELINE_DEPTH : natural := 2
10 );
11 port (
12 clk : in std_ulogic;
13 rst : in std_ulogic;
14
15 complete_in : in std_ulogic;
16 valid_in : in std_ulogic;
17 flush_in : in std_ulogic;
18 stall_in : in std_ulogic;
19 sgl_pipe_in : in std_ulogic;
20 stop_mark_in : in std_ulogic;
21
22 gpr_write_valid_in : in std_ulogic;
23 gpr_write_in : in gspr_index_t;
24
25 gpr_a_read_valid_in : in std_ulogic;
26 gpr_a_read_in : in gspr_index_t;
27
28 gpr_b_read_valid_in : in std_ulogic;
29 gpr_b_read_in : in gspr_index_t;
30
31 gpr_c_read_valid_in : in std_ulogic;
32 gpr_c_read_in : in gpr_index_t;
33
34 cr_read_in : in std_ulogic;
35 cr_write_in : in std_ulogic;
36
37 valid_out : out std_ulogic;
38 stall_out : out std_ulogic;
39 stopped_out : out std_ulogic
40 );
41 end entity control;
42
43 architecture rtl of control is
44 type state_type is (IDLE, WAIT_FOR_PREV_TO_COMPLETE, WAIT_FOR_CURR_TO_COMPLETE);
45
46 type reg_internal_type is record
47 state : state_type;
48 outstanding : integer range -1 to PIPELINE_DEPTH+2;
49 end record;
50 constant reg_internal_init : reg_internal_type := (state => IDLE, outstanding => 0);
51
52 signal r_int, rin_int : reg_internal_type := reg_internal_init;
53
54 signal stall_a_out : std_ulogic;
55 signal stall_b_out : std_ulogic;
56 signal stall_c_out : std_ulogic;
57 signal cr_stall_out : std_ulogic;
58
59 signal gpr_write_valid : std_ulogic := '0';
60 signal cr_write_valid : std_ulogic := '0';
61
62 signal gpr_c_read_in_fmt : std_ulogic_vector(5 downto 0);
63 begin
64 gpr_hazard0: entity work.gpr_hazard
65 generic map (
66 PIPELINE_DEPTH => PIPELINE_DEPTH
67 )
68 port map (
69 clk => clk,
70 stall_in => stall_in,
71
72 gpr_write_valid_in => gpr_write_valid,
73 gpr_write_in => gpr_write_in,
74 gpr_read_valid_in => gpr_a_read_valid_in,
75 gpr_read_in => gpr_a_read_in,
76
77 stall_out => stall_a_out
78 );
79
80 gpr_hazard1: entity work.gpr_hazard
81 generic map (
82 PIPELINE_DEPTH => PIPELINE_DEPTH
83 )
84 port map (
85 clk => clk,
86 stall_in => stall_in,
87
88 gpr_write_valid_in => gpr_write_valid,
89 gpr_write_in => gpr_write_in,
90 gpr_read_valid_in => gpr_b_read_valid_in,
91 gpr_read_in => gpr_b_read_in,
92
93 stall_out => stall_b_out
94 );
95
96 gpr_c_read_in_fmt <= "0" & gpr_c_read_in;
97
98 gpr_hazard2: entity work.gpr_hazard
99 generic map (
100 PIPELINE_DEPTH => PIPELINE_DEPTH
101 )
102 port map (
103 clk => clk,
104 stall_in => stall_in,
105
106 gpr_write_valid_in => gpr_write_valid,
107 gpr_write_in => gpr_write_in,
108 gpr_read_valid_in => gpr_c_read_valid_in,
109 gpr_read_in => gpr_c_read_in_fmt,
110
111 stall_out => stall_c_out
112 );
113
114 cr_hazard0: entity work.cr_hazard
115 generic map (
116 PIPELINE_DEPTH => PIPELINE_DEPTH
117 )
118 port map (
119 clk => clk,
120 stall_in => stall_in,
121
122 cr_read_in => cr_read_in,
123 cr_write_in => cr_write_valid,
124
125 stall_out => cr_stall_out
126 );
127
128 control0: process(clk)
129 begin
130 if rising_edge(clk) then
131 assert r_int.outstanding >= 0 and r_int.outstanding <= (PIPELINE_DEPTH+1) report "Outstanding bad " & integer'image(r_int.outstanding) severity failure;
132 r_int <= rin_int;
133 end if;
134 end process;
135
136 control1 : process(all)
137 variable v_int : reg_internal_type;
138 variable valid_tmp : std_ulogic;
139 variable stall_tmp : std_ulogic;
140 begin
141 v_int := r_int;
142
143 -- asynchronous
144 valid_tmp := valid_in and not flush_in and not stall_in;
145 stall_tmp := stall_in;
146
147 if complete_in = '1' then
148 v_int.outstanding := r_int.outstanding - 1;
149 end if;
150
151 -- Handle debugger stop
152 stopped_out <= '0';
153 if stop_mark_in = '1' and v_int.outstanding = 0 then
154 stopped_out <= '1';
155 end if;
156
157 -- state machine to handle instructions that must be single
158 -- through the pipeline.
159 case r_int.state is
160 when IDLE =>
161 if valid_tmp = '1' then
162 if (sgl_pipe_in = '1') then
163 if v_int.outstanding /= 0 then
164 v_int.state := WAIT_FOR_PREV_TO_COMPLETE;
165 stall_tmp := '1';
166 else
167 -- send insn out and wait on it to complete
168 v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
169 end if;
170 else
171 -- let it go out if there are no GPR hazards
172 stall_tmp := stall_a_out or stall_b_out or stall_c_out or cr_stall_out;
173 end if;
174 end if;
175
176 when WAIT_FOR_PREV_TO_COMPLETE =>
177 if v_int.outstanding = 0 then
178 -- send insn out and wait on it to complete
179 v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
180 else
181 stall_tmp := '1';
182 end if;
183
184 when WAIT_FOR_CURR_TO_COMPLETE =>
185 if v_int.outstanding = 0 then
186 v_int.state := IDLE;
187 -- XXX Don't replicate this
188 if valid_tmp = '1' then
189 if (sgl_pipe_in = '1') then
190 if v_int.outstanding /= 0 then
191 v_int.state := WAIT_FOR_PREV_TO_COMPLETE;
192 stall_tmp := '1';
193 else
194 -- send insn out and wait on it to complete
195 v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
196 end if;
197 else
198 -- let it go out if there are no GPR hazards
199 stall_tmp := stall_a_out or stall_b_out or stall_c_out or cr_stall_out;
200 end if;
201 end if;
202 else
203 stall_tmp := '1';
204 end if;
205 end case;
206
207 if stall_tmp = '1' then
208 valid_tmp := '0';
209 end if;
210
211 if valid_tmp = '1' then
212 v_int.outstanding := v_int.outstanding + 1;
213 gpr_write_valid <= gpr_write_valid_in;
214 cr_write_valid <= cr_write_in;
215 else
216 gpr_write_valid <= '0';
217 cr_write_valid <= '0';
218 end if;
219
220 if rst = '1' then
221 v_int.state := IDLE;
222 v_int.outstanding := 0;
223 stall_tmp := '0';
224 end if;
225
226 -- update outputs
227 valid_out <= valid_tmp;
228 stall_out <= stall_tmp;
229
230 -- update registers
231 rin_int <= v_int;
232 end process;
233 end;