1 |
2 |
alfik |
/*
|
2 |
|
|
* This file is subject to the terms and conditions of the BSD License. See
|
3 |
|
|
* the file "LICENSE" in the main directory of this archive for more details.
|
4 |
|
|
*
|
5 |
|
|
* Copyright (C) 2014 Aleksander Osman
|
6 |
|
|
*/
|
7 |
|
|
|
8 |
|
|
`include "defines.v"
|
9 |
|
|
|
10 |
|
|
module pipeline_if(
|
11 |
|
|
input clk,
|
12 |
|
|
input rst_n,
|
13 |
|
|
|
14 |
|
|
//
|
15 |
|
|
input config_kernel_mode,
|
16 |
|
|
input [5:0] entryhi_asid,
|
17 |
|
|
|
18 |
|
|
//
|
19 |
|
|
input micro_flush_do,
|
20 |
|
|
|
21 |
|
|
//
|
22 |
|
|
input exception_start,
|
23 |
|
|
input [31:0] exception_start_pc,
|
24 |
|
|
|
25 |
|
|
//
|
26 |
|
|
input mem_stall,
|
27 |
|
|
|
28 |
|
|
//
|
29 |
|
|
output if_exc_address_error,
|
30 |
|
|
output if_exc_tlb_inv,
|
31 |
|
|
output if_exc_tlb_miss,
|
32 |
|
|
output if_ready,
|
33 |
|
|
output [31:0] if_instr,
|
34 |
|
|
output reg [31:0] if_pc,
|
35 |
|
|
|
36 |
|
|
//
|
37 |
|
|
input branch_start,
|
38 |
|
|
input [31:0] branch_address,
|
39 |
|
|
|
40 |
|
|
//
|
41 |
|
|
output [8:0] fetch_cache_read_address,
|
42 |
|
|
input [53:0] fetch_cache_q,
|
43 |
|
|
|
44 |
|
|
output [8:0] fetch_cache_write_address,
|
45 |
|
|
output fetch_cache_write_enable,
|
46 |
|
|
output [53:0] fetch_cache_data,
|
47 |
|
|
|
48 |
|
|
//
|
49 |
|
|
output tlb_ram_fetch_start,
|
50 |
|
|
output [19:0] tlb_ram_fetch_vpn,
|
51 |
|
|
input tlb_ram_fetch_hit,
|
52 |
|
|
input [49:0] tlb_ram_fetch_result,
|
53 |
|
|
input tlb_ram_fetch_missed,
|
54 |
|
|
|
55 |
|
|
//
|
56 |
|
|
output [31:0] ram_instr_address,
|
57 |
|
|
output ram_instr_req,
|
58 |
|
|
input ram_instr_ack,
|
59 |
|
|
|
60 |
|
|
//
|
61 |
|
|
input [31:0] ram_result_address,
|
62 |
|
|
input ram_result_valid,
|
63 |
|
|
input ram_result_is_read_instr,
|
64 |
|
|
input [2:0] ram_result_burstcount,
|
65 |
|
|
input [31:0] ram_result
|
66 |
|
|
); /* verilator public_module */
|
67 |
|
|
|
68 |
|
|
//------------------------------------------------------------------------------
|
69 |
|
|
//------------------------------------------------------------------------------
|
70 |
|
|
//------------------------------------------------------------------------------
|
71 |
|
|
|
72 |
|
|
reg [31:0] branch_pc;
|
73 |
|
|
always @(posedge clk or negedge rst_n) begin
|
74 |
|
|
if(rst_n == 1'b0) branch_pc <= 32'h0;
|
75 |
|
|
else if(branch_start) branch_pc <= branch_address;
|
76 |
|
|
end
|
77 |
|
|
|
78 |
|
|
reg branch_waiting;
|
79 |
|
|
always @(posedge clk or negedge rst_n) begin
|
80 |
|
|
if(rst_n == 1'b0) branch_waiting <= `FALSE;
|
81 |
|
|
else if(if_ready || exception_start) branch_waiting <= `FALSE;
|
82 |
|
|
else if(branch_start && ~(if_ready)) branch_waiting <= `TRUE;
|
83 |
|
|
end
|
84 |
|
|
|
85 |
|
|
reg [31:0] exc_start_pc;
|
86 |
|
|
always @(posedge clk or negedge rst_n) begin
|
87 |
|
|
if(rst_n == 1'b0) exc_start_pc <= 32'hBFC00000;
|
88 |
|
|
else if(exception_start) exc_start_pc <= exception_start_pc;
|
89 |
|
|
end
|
90 |
|
|
|
91 |
|
|
reg exc_waiting;
|
92 |
|
|
always @(posedge clk or negedge rst_n) begin
|
93 |
|
|
if(rst_n == 1'b0) exc_waiting <= `TRUE;
|
94 |
|
|
else if(exception_start) exc_waiting <= `TRUE;
|
95 |
|
|
else if(fetch_state == FETCH_IDLE) exc_waiting <= `FALSE;
|
96 |
|
|
end
|
97 |
|
|
|
98 |
|
|
wire [31:0] if_pc_next = (exc_waiting)? exc_start_pc : (branch_start)? branch_address : (branch_waiting)? branch_pc : if_pc + 32'd4;
|
99 |
|
|
|
100 |
|
|
wire if_pc_update = if_ready || (exc_waiting && fetch_state == FETCH_IDLE);
|
101 |
|
|
|
102 |
|
|
always @(posedge clk or negedge rst_n) begin
|
103 |
|
|
if(rst_n == 1'b0) if_pc <= 32'h0;
|
104 |
|
|
else if(if_pc_update) if_pc <= if_pc_next;
|
105 |
|
|
end
|
106 |
|
|
|
107 |
|
|
reg if_pc_updated;
|
108 |
|
|
always @(posedge clk or negedge rst_n) begin
|
109 |
|
|
if(rst_n == 1'b0) if_pc_updated <= `FALSE;
|
110 |
|
|
else if_pc_updated <= if_pc_update;
|
111 |
|
|
end
|
112 |
|
|
|
113 |
|
|
//------------------------------------------------------------------------------
|
114 |
|
|
|
115 |
|
|
reg [19:0] if_pc_vpn_last;
|
116 |
|
|
always @(posedge clk or negedge rst_n) begin
|
117 |
|
|
if(rst_n == 1'b0) if_pc_vpn_last <= 20'd0;
|
118 |
|
|
else if_pc_vpn_last <= if_pc[31:12];
|
119 |
|
|
end
|
120 |
|
|
|
121 |
|
|
reg if_pc_vpn_changed;
|
122 |
|
|
always @(posedge clk or negedge rst_n) begin
|
123 |
|
|
if(rst_n == 1'b0) if_pc_vpn_changed <= `FALSE;
|
124 |
|
|
else if(fetch_state == FETCH_IDLE) if_pc_vpn_changed <= `FALSE;
|
125 |
|
|
else if(if_pc[31:12] != if_pc_vpn_last) if_pc_vpn_changed <= `TRUE;
|
126 |
|
|
end
|
127 |
|
|
|
128 |
|
|
wire if_pc_vpn_change = if_pc[31:12] != if_pc_vpn_last || if_pc_vpn_changed;
|
129 |
|
|
|
130 |
|
|
//------------------------------------------------------------------------------
|
131 |
|
|
//------------------------------------------------------------------------------
|
132 |
|
|
//------------------------------------------------------------------------------
|
133 |
|
|
|
134 |
|
|
wire tlb_use_at_idle = fetch_state == FETCH_IDLE && (if_pc[31] == 1'b0 || if_pc[31:30] == 2'b11);
|
135 |
|
|
|
136 |
|
|
wire [19:0] pfn_at_idle =
|
137 |
|
|
(~(tlb_use_at_idle))? { 3'b0, if_pc[28:12] } :
|
138 |
|
|
(micro_check_matched)? micro_check_result[39:20] :
|
139 |
|
|
tlb_ram_fetch_result[39:20];
|
140 |
|
|
|
141 |
|
|
reg [19:0] pfn_reg;
|
142 |
|
|
always @(posedge clk or negedge rst_n) begin
|
143 |
|
|
if(rst_n == 1'b0) pfn_reg <= 20'd0;
|
144 |
|
|
else if(fetch_state == FETCH_IDLE) pfn_reg <= pfn_at_idle;
|
145 |
|
|
else if(fetch_tlb_tlb_ok_cache_bad) pfn_reg <= tlb_ram_fetch_result[39:20];
|
146 |
|
|
end
|
147 |
|
|
|
148 |
|
|
wire n_at_idle =
|
149 |
|
|
(~(tlb_use_at_idle))? if_pc[31:29] == 3'b101 :
|
150 |
|
|
(micro_check_matched)? micro_check_result[46] :
|
151 |
|
|
tlb_ram_fetch_result[46];
|
152 |
|
|
|
153 |
|
|
reg n_reg;
|
154 |
|
|
always @(posedge clk or negedge rst_n) begin
|
155 |
|
|
if(rst_n == 1'b0) n_reg <= `FALSE;
|
156 |
|
|
else if(fetch_state == FETCH_IDLE) n_reg <= n_at_idle;
|
157 |
|
|
else if(fetch_tlb_tlb_ok_cache_bad) n_reg <= tlb_ram_fetch_result[46];
|
158 |
|
|
end
|
159 |
|
|
|
160 |
|
|
reg [53:0] fetch_cache_q_reg;
|
161 |
|
|
always @(posedge clk or negedge rst_n) begin
|
162 |
|
|
if(rst_n == 1'b0) fetch_cache_q_reg <= 54'd0;
|
163 |
|
|
else if(fetch_state == FETCH_IDLE) fetch_cache_q_reg <= fetch_cache_q;
|
164 |
|
|
end
|
165 |
|
|
|
166 |
|
|
//------------------------------------------------------------------------------
|
167 |
|
|
|
168 |
|
|
localparam [1:0] FETCH_IDLE = 2'd0;
|
169 |
|
|
localparam [1:0] FETCH_TLB = 2'd1;
|
170 |
|
|
localparam [1:0] FETCH_RESULT = 2'd2;
|
171 |
|
|
localparam [1:0] FETCH_STOPPED = 2'd3;
|
172 |
|
|
|
173 |
|
|
reg [1:0] fetch_state;
|
174 |
|
|
always @(posedge clk or negedge rst_n) begin
|
175 |
|
|
if(rst_n == 1'b0) fetch_state <= FETCH_STOPPED;
|
176 |
|
|
|
177 |
|
|
else if(fetch_state == FETCH_STOPPED && exc_waiting) fetch_state <= FETCH_IDLE;
|
178 |
|
|
|
179 |
|
|
else if(fetch_idle_exc_address_error) fetch_state <= FETCH_STOPPED;
|
180 |
|
|
else if(fetch_idle_tlb_bad_exc_inv) fetch_state <= FETCH_STOPPED;
|
181 |
|
|
else if(fetch_idle_tlb_ok_cache_bad) fetch_state <= FETCH_RESULT;
|
182 |
|
|
else if(fetch_idle_tlb_wait) fetch_state <= FETCH_TLB;
|
183 |
|
|
|
184 |
|
|
else if(fetch_tlb_tlb_ok_cache_ok) fetch_state <= FETCH_IDLE;
|
185 |
|
|
else if(fetch_tlb_tlb_bad_exc_inv || fetch_tlb_tlb_bad_exc_miss) fetch_state <= FETCH_STOPPED;
|
186 |
|
|
else if(fetch_tlb_tlb_ok_cache_bad) fetch_state <= FETCH_RESULT;
|
187 |
|
|
|
188 |
|
|
else if(fetch_result_finished) fetch_state <= FETCH_IDLE;
|
189 |
|
|
end
|
190 |
|
|
|
191 |
|
|
assign if_ready = ~(mem_stall) && ~(exc_waiting) && (
|
192 |
|
|
fetch_idle_tlb_ok_cache_ok ||
|
193 |
|
|
fetch_tlb_tlb_ok_cache_ok ||
|
194 |
|
|
(ram_result_valid && ram_result_is_read_instr && ram_result_address[31:2] == { pfn_reg, if_pc[11:2] } && if_pc[1:0] == 2'b00 && ~(if_pc_vpn_change))
|
195 |
|
|
);
|
196 |
|
|
|
197 |
|
|
assign if_instr =
|
198 |
|
|
(fetch_idle_tlb_ok_cache_ok)? fetch_cache_q[31:0] :
|
199 |
|
|
(fetch_state == FETCH_TLB)? fetch_cache_q_reg[31:0] :
|
200 |
|
|
ram_result;
|
201 |
|
|
|
202 |
|
|
assign ram_instr_req = fetch_idle_tlb_ok_cache_bad || fetch_tlb_tlb_ok_cache_bad || (fetch_state == FETCH_RESULT && ~(was_ram_ack) && ~(ram_instr_ack));
|
203 |
|
|
assign ram_instr_address = (fetch_state == FETCH_IDLE)? { pfn_at_idle, if_pc[11:0] } : { pfn_reg, if_pc[11:0] };
|
204 |
|
|
|
205 |
|
|
assign if_exc_address_error = ~(exc_waiting) && (fetch_idle_exc_address_error || exception_reg == 2'd1);
|
206 |
|
|
assign if_exc_tlb_inv = ~(exc_waiting) && (fetch_idle_tlb_bad_exc_inv || fetch_tlb_tlb_bad_exc_inv || (fetch_tlb_tlb_bad_exc_miss && if_pc[31] == 1'b1) || exception_reg == 2'd2);
|
207 |
|
|
assign if_exc_tlb_miss = ~(exc_waiting) && ((fetch_tlb_tlb_bad_exc_miss && if_pc[31] == 1'b0) || exception_reg == 2'd3);
|
208 |
|
|
|
209 |
|
|
reg [1:0] exception_reg;
|
210 |
|
|
always @(posedge clk or negedge rst_n) begin
|
211 |
|
|
if(rst_n == 1'b0) exception_reg <= 2'd0;
|
212 |
|
|
else if(exception_start || exc_waiting) exception_reg <= 2'd0;
|
213 |
|
|
else if(if_exc_address_error) exception_reg <= 2'd1;
|
214 |
|
|
else if(if_exc_tlb_inv) exception_reg <= 2'd2;
|
215 |
|
|
else if(if_exc_tlb_miss) exception_reg <= 2'd3;
|
216 |
|
|
end
|
217 |
|
|
|
218 |
|
|
//------------------------------------------------------------------------------
|
219 |
|
|
|
220 |
|
|
assign tlb_ram_fetch_start = if_pc_updated || (fetch_state == FETCH_IDLE && (~(tlb_ram_fetch_active) || tlb_ram_fetch_hit || tlb_ram_fetch_missed)) || (fetch_state == FETCH_TLB && ~(tlb_ram_fetch_active));
|
221 |
|
|
assign tlb_ram_fetch_vpn = if_pc[31:12];
|
222 |
|
|
|
223 |
|
|
reg tlb_ram_fetch_active;
|
224 |
|
|
always @(posedge clk or negedge rst_n) begin
|
225 |
|
|
if(rst_n == 1'b0) tlb_ram_fetch_active <= `FALSE;
|
226 |
|
|
else if(tlb_ram_fetch_start) tlb_ram_fetch_active <= `TRUE;
|
227 |
|
|
else if(tlb_ram_fetch_hit || tlb_ram_fetch_missed) tlb_ram_fetch_active <= `FALSE;
|
228 |
|
|
end
|
229 |
|
|
|
230 |
|
|
//------------------------------------------------------------------------------ state IDLE
|
231 |
|
|
|
232 |
|
|
wire fetch_idle_no_addr_exc = if_pc[1:0] == 2'b00 && (config_kernel_mode || if_pc[31] == 1'b0);
|
233 |
|
|
wire fetch_idle_exc_address_error = fetch_state == FETCH_IDLE && ~(fetch_idle_no_addr_exc) && ~(exc_waiting);
|
234 |
|
|
|
235 |
|
|
wire fetch_idle_tlb_ok_cache_ok = fetch_state == FETCH_IDLE && ~(exc_waiting) && fetch_cache_q[53] && ~(n_at_idle) && fetch_idle_no_addr_exc && (
|
236 |
|
|
(~(tlb_use_at_idle) && fetch_cache_q[52:32] == { pfn_at_idle, if_pc[11] }) || //tlb not in use
|
237 |
|
|
(tlb_use_at_idle && micro_check_matched && micro_check_result[48] && fetch_cache_q[52:32] == {micro_check_result[39:20], if_pc[11]}) //tlb in micro
|
238 |
|
|
);
|
239 |
|
|
|
240 |
|
|
wire fetch_idle_tlb_bad_exc_inv = fetch_state == FETCH_IDLE && ~(exc_waiting) && tlb_use_at_idle && fetch_idle_no_addr_exc && (
|
241 |
|
|
(micro_check_matched && ~(micro_check_result[48])) //tlb in micro
|
242 |
|
|
);
|
243 |
|
|
|
244 |
|
|
wire fetch_idle_tlb_ok_cache_bad = fetch_state == FETCH_IDLE && ~(exc_waiting) && fetch_idle_no_addr_exc && (
|
245 |
|
|
(~(tlb_use_at_idle) && (~(fetch_cache_q[53]) || n_at_idle || fetch_cache_q[52:32] != { pfn_at_idle, if_pc[11] })) || //tlb not in use
|
246 |
|
|
(tlb_use_at_idle && micro_check_matched && micro_check_result[48] && (~(fetch_cache_q[53]) || n_at_idle || fetch_cache_q[52:32] != {micro_check_result[39:20], if_pc[11]})) //tlb in micro
|
247 |
|
|
);
|
248 |
|
|
|
249 |
|
|
wire fetch_idle_tlb_wait = fetch_state == FETCH_IDLE && ~(exc_waiting) && fetch_idle_no_addr_exc && tlb_use_at_idle && ~(micro_check_matched);
|
250 |
|
|
|
251 |
|
|
//------------------------------------------------------------------------------ state TLB
|
252 |
|
|
|
253 |
|
|
wire fetch_tlb_tlb_ok_cache_ok = fetch_state == FETCH_TLB && tlb_ram_fetch_hit && tlb_ram_fetch_result[48] && fetch_cache_q_reg[53] && fetch_cache_q_reg[52:32] == { tlb_ram_fetch_result[39:20], if_pc[11] };
|
254 |
|
|
|
255 |
|
|
wire fetch_tlb_tlb_bad_exc_inv = fetch_state == FETCH_TLB && tlb_ram_fetch_hit && ~(tlb_ram_fetch_result[48]);
|
256 |
|
|
wire fetch_tlb_tlb_bad_exc_miss = fetch_state == FETCH_TLB && ~(tlb_ram_fetch_hit) && tlb_ram_fetch_missed;
|
257 |
|
|
|
258 |
|
|
wire fetch_tlb_tlb_ok_cache_bad = fetch_state == FETCH_TLB && tlb_ram_fetch_hit && tlb_ram_fetch_result[48] && (~(fetch_cache_q_reg[53]) || fetch_cache_q_reg[52:32] != { tlb_ram_fetch_result[39:20], if_pc[11] });
|
259 |
|
|
|
260 |
|
|
//------------------------------------------------------------------------------ state RESULT
|
261 |
|
|
|
262 |
|
|
reg was_ram_ack;
|
263 |
|
|
always @(posedge clk or negedge rst_n) begin
|
264 |
|
|
if(rst_n == 1'b0) was_ram_ack <= `FALSE;
|
265 |
|
|
else if(fetch_state != FETCH_RESULT) was_ram_ack <= `FALSE;
|
266 |
|
|
else if(ram_instr_ack) was_ram_ack <= `TRUE;
|
267 |
|
|
end
|
268 |
|
|
|
269 |
|
|
reg is_ram_stalled;
|
270 |
|
|
always @(posedge clk or negedge rst_n) begin
|
271 |
|
|
if(rst_n == 1'b0) is_ram_stalled <= `FALSE;
|
272 |
|
|
else if(mem_stall && ram_result_valid && ram_result_is_read_instr && ram_result_burstcount == 3'd1) is_ram_stalled <= `TRUE;
|
273 |
|
|
else if(~(mem_stall)) is_ram_stalled <= `FALSE;
|
274 |
|
|
end
|
275 |
|
|
|
276 |
|
|
wire fetch_result_finished = ~(mem_stall) && fetch_state == FETCH_RESULT && ((ram_result_valid && ram_result_is_read_instr && ram_result_burstcount == 3'd1) || is_ram_stalled);
|
277 |
|
|
|
278 |
|
|
//------------------------------------------------------------------------------ cache
|
279 |
|
|
//------------------------------------------------------------------------------
|
280 |
|
|
//------------------------------------------------------------------------------
|
281 |
|
|
|
282 |
|
|
assign fetch_cache_read_address = (if_pc_update)? if_pc_next[10:2] : if_pc[10:2];
|
283 |
|
|
|
284 |
|
|
assign fetch_cache_write_address = ram_result_address[10:2];
|
285 |
|
|
|
286 |
|
|
assign fetch_cache_write_enable = (~(n_reg) && ram_result_valid && ram_result_is_read_instr);
|
287 |
|
|
|
288 |
|
|
/*
|
289 |
|
|
[53] valid
|
290 |
|
|
[52:32] tag
|
291 |
|
|
[31:0] data
|
292 |
|
|
*/
|
293 |
|
|
assign fetch_cache_data = { 1'b1, ram_result_address[31:11], ram_result }; //load
|
294 |
|
|
|
295 |
|
|
//------------------------------------------------------------------------------ micro
|
296 |
|
|
//------------------------------------------------------------------------------
|
297 |
|
|
//------------------------------------------------------------------------------
|
298 |
|
|
|
299 |
|
|
/*
|
300 |
|
|
[19:0] vpn
|
301 |
|
|
[39:20] pfn
|
302 |
|
|
[45:40] asid
|
303 |
|
|
[46] n noncachable
|
304 |
|
|
[47] d dirty = write-enable
|
305 |
|
|
[48] v valid
|
306 |
|
|
[49] g global
|
307 |
|
|
*/
|
308 |
|
|
|
309 |
|
|
//input micro_check_matched,
|
310 |
|
|
//input [49:0] micro_check_result,
|
311 |
|
|
|
312 |
|
|
wire micro_check_do = tlb_use_at_idle;
|
313 |
|
|
wire [19:0] micro_check_vpn = if_pc[31:12];
|
314 |
|
|
wire [5:0] micro_check_asid = entryhi_asid;
|
315 |
|
|
|
316 |
|
|
wire micro_write_do = tlb_ram_fetch_hit && fetch_state == FETCH_TLB;
|
317 |
|
|
|
318 |
|
|
wire [49:0] micro_write_value = tlb_ram_fetch_result;
|
319 |
|
|
|
320 |
|
|
wire micro_check_matched;
|
321 |
|
|
wire [49:0] micro_check_result;
|
322 |
|
|
|
323 |
|
|
memory_instr_tlb_micro memory_instr_tlb_micro_inst(
|
324 |
|
|
.clk (clk),
|
325 |
|
|
.rst_n (rst_n),
|
326 |
|
|
|
327 |
|
|
//
|
328 |
|
|
.micro_flush_do (micro_flush_do), //input
|
329 |
|
|
|
330 |
|
|
//
|
331 |
|
|
.micro_write_do (micro_write_do), //input
|
332 |
|
|
.micro_write_value (micro_write_value), //input [49:0]
|
333 |
|
|
|
334 |
|
|
//
|
335 |
|
|
.micro_check_do (micro_check_do), //input
|
336 |
|
|
.micro_check_vpn (micro_check_vpn), //input [19:0]
|
337 |
|
|
.micro_check_asid (micro_check_asid), //input [5:0]
|
338 |
|
|
.micro_check_matched(micro_check_matched), //output
|
339 |
|
|
.micro_check_result (micro_check_result) //output [49:0]
|
340 |
|
|
);
|
341 |
|
|
|
342 |
|
|
//------------------------------------------------------------------------------
|
343 |
|
|
// synthesis translate_off
|
344 |
|
|
wire _unused_ok = &{ 1'b0, ram_result_address[1:0], micro_check_result[49], micro_check_result[47], micro_check_result[45:40], micro_check_result[19:0], 1'b0 };
|
345 |
|
|
// synthesis translate_on
|
346 |
|
|
//------------------------------------------------------------------------------
|
347 |
|
|
|
348 |
|
|
endmodule
|