convert numbers to python format
[sv2nmigen.git] / examples / load_store_unit.sv
1 // Copyright 2018 ETH Zurich and University of Bologna.
2 // Copyright and related rights are licensed under the Solderpad Hardware
3 // License, Version 0.51 (the "License"); you may not use this file except in
4 // compliance with the License. You may obtain a copy of the License at
5 // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
6 // or agreed to in writing, software, hardware and materials distributed under
7 // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // specific language governing permissions and limitations under the License.
10 //
11 // Author: Florian Zaruba, ETH Zurich
12 // Date: 19.04.2017
13 // Description: Load Store Unit, handles address calculation and memory interface signals
14
15 //import ariane_pkg::*;
16
17 module load_store_unit #(
18 parameter int ASID_WIDTH = 1
19 // parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
20 )(
21 input logic clk_i,
22 input logic rst_ni,
23 input logic flush_i,
24 output logic no_st_pending_o,
25 input logic amo_valid_commit_i,
26
27
28 //input fu_data_t fu_data_i,
29 output logic lsu_ready_o, // FU is ready e.g. not busy
30 input logic lsu_valid_i, // Input is valid
31
32 output logic [TRANS_ID_BITS-1:0] load_trans_id_o, // ID of scoreboard entry at which to write back
33 output logic [63:0] load_result_o,
34 output logic load_valid_o,
35 //output exception_t load_exception_o, // to WB, signal exception status LD exception
36
37 output logic [TRANS_ID_BITS-1:0] store_trans_id_o, // ID of scoreboard entry at which to write back
38 output logic [63:0] store_result_o,
39 output logic store_valid_o,
40 //output exception_t store_exception_o, // to WB, signal exception status ST exception
41
42 input logic commit_i, // commit the pending store
43 output logic commit_ready_o, // commit queue is ready to accept another commit request
44
45 input logic enable_translation_i, // enable virtual memory translation
46 input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
47
48 // icache translation requests
49 //input icache_areq_o_t icache_areq_i,
50 //output icache_areq_i_t icache_areq_o,
51
52 //input riscv::priv_lvl_t priv_lvl_i, // From CSR register file
53 //input riscv::priv_lvl_t ld_st_priv_lvl_i, // From CSR register file
54 input logic sum_i, // From CSR register file
55 input logic mxr_i, // From CSR register file
56 input logic [43:0] satp_ppn_i, // From CSR register file
57 input logic [ASID_WIDTH-1:0] asid_i, // From CSR register file
58 input logic flush_tlb_i,
59 // Performance counters
60 output logic itlb_miss_o,
61 output logic dtlb_miss_o
62
63 // interface to dcache
64 //input dcache_req_o_t [2:0] dcache_req_ports_i,
65 //output dcache_req_i_t [2:0] dcache_req_ports_o,
66 // AMO interface
67 //output amo_req_t amo_req_o,
68 //input amo_resp_t amo_resp_i
69 );
70 #docstring_begin
71 // data is misaligned
72 logic data_misaligned;
73 // --------------------------------------
74 // 1st register stage - (stall registers)
75 // --------------------------------------
76 // those are the signals which are always correct
77 // e.g.: they keep the value in the stall case
78 lsu_ctrl_t lsu_ctrl;
79
80 logic pop_st;
81 logic pop_ld;
82
83 // ------------------------------
84 // Address Generation Unit (AGU)
85 // ------------------------------
86 // virtual address as calculated by the AGU in the first cycle
87 logic [63:0] vaddr_i;
88 logic [7:0] be_i;
89
90 assign vaddr_i = $unsigned($signed(fu_data_i.imm) + $signed(fu_data_i.operand_a));
91
92 logic st_valid_i;
93 logic ld_valid_i;
94 logic ld_translation_req;
95 logic st_translation_req;
96 logic [63:0] ld_vaddr;
97 logic [63:0] st_vaddr;
98 logic translation_req;
99 logic translation_valid;
100 logic [63:0] mmu_vaddr;
101 logic [63:0] mmu_paddr;
102 exception_t mmu_exception;
103 logic dtlb_hit;
104
105 logic ld_valid;
106 logic [TRANS_ID_BITS-1:0] ld_trans_id;
107 logic [63:0] ld_result;
108 logic st_valid;
109 logic [TRANS_ID_BITS-1:0] st_trans_id;
110 logic [63:0] st_result;
111
112 logic [11:0] page_offset;
113 logic page_offset_matches;
114
115 exception_t misaligned_exception;
116 exception_t ld_ex;
117 exception_t st_ex;
118
119 // -------------------
120 // MMU e.g.: TLBs/PTW
121 // -------------------
122 mmu #(
123 .INSTR_TLB_ENTRIES ( 16 ),
124 .DATA_TLB_ENTRIES ( 16 ),
125 .ASID_WIDTH ( ASID_WIDTH ),
126 .ArianeCfg ( ArianeCfg )
127 ) i_mmu (
128 // misaligned bypass
129 .misaligned_ex_i ( misaligned_exception ),
130 .lsu_is_store_i ( st_translation_req ),
131 .lsu_req_i ( translation_req ),
132 .lsu_vaddr_i ( mmu_vaddr ),
133 .lsu_valid_o ( translation_valid ),
134 .lsu_paddr_o ( mmu_paddr ),
135 .lsu_exception_o ( mmu_exception ),
136 .lsu_dtlb_hit_o ( dtlb_hit ), // send in the same cycle as the request
137 // connecting PTW to D$ IF
138 .req_port_i ( dcache_req_ports_i [0] ),
139 .req_port_o ( dcache_req_ports_o [0] ),
140 // icache address translation requests
141 .icache_areq_i ( icache_areq_i ),
142 .icache_areq_o ( icache_areq_o ),
143 .*
144 );
145 // ------------------
146 // Store Unit
147 // ------------------
148 store_unit i_store_unit (
149 .clk_i,
150 .rst_ni,
151 .flush_i,
152 .no_st_pending_o,
153
154 .valid_i ( st_valid_i ),
155 .lsu_ctrl_i ( lsu_ctrl ),
156 .pop_st_o ( pop_st ),
157 .commit_i,
158 .commit_ready_o,
159 .amo_valid_commit_i,
160
161 .valid_o ( st_valid ),
162 .trans_id_o ( st_trans_id ),
163 .result_o ( st_result ),
164 .ex_o ( st_ex ),
165 // MMU port
166 .translation_req_o ( st_translation_req ),
167 .vaddr_o ( st_vaddr ),
168 .paddr_i ( mmu_paddr ),
169 .ex_i ( mmu_exception ),
170 .dtlb_hit_i ( dtlb_hit ),
171 // Load Unit
172 .page_offset_i ( page_offset ),
173 .page_offset_matches_o ( page_offset_matches ),
174 // AMOs
175 .amo_req_o,
176 .amo_resp_i,
177 // to memory arbiter
178 .req_port_i ( dcache_req_ports_i [2] ),
179 .req_port_o ( dcache_req_ports_o [2] )
180 );
181
182 // ------------------
183 // Load Unit
184 // ------------------
185 load_unit i_load_unit (
186 .valid_i ( ld_valid_i ),
187 .lsu_ctrl_i ( lsu_ctrl ),
188 .pop_ld_o ( pop_ld ),
189
190 .valid_o ( ld_valid ),
191 .trans_id_o ( ld_trans_id ),
192 .result_o ( ld_result ),
193 .ex_o ( ld_ex ),
194 // MMU port
195 .translation_req_o ( ld_translation_req ),
196 .vaddr_o ( ld_vaddr ),
197 .paddr_i ( mmu_paddr ),
198 .ex_i ( mmu_exception ),
199 .dtlb_hit_i ( dtlb_hit ),
200 // to store unit
201 .page_offset_o ( page_offset ),
202 .page_offset_matches_i ( page_offset_matches ),
203 // to memory arbiter
204 .req_port_i ( dcache_req_ports_i [1] ),
205 .req_port_o ( dcache_req_ports_o [1] ),
206 .*
207 );
208
209 // ----------------------------
210 // Output Pipeline Register
211 // ----------------------------
212 shift_reg #(
213 .dtype ( logic[$bits(ld_valid) + $bits(ld_trans_id) + $bits(ld_result) + $bits(ld_ex) - 1: 0]),
214 .Depth ( NR_LOAD_PIPE_REGS )
215 ) i_pipe_reg_load (
216 .clk_i,
217 .rst_ni,
218 .d_i ( {ld_valid, ld_trans_id, ld_result, ld_ex} ),
219 .d_o ( {load_valid_o, load_trans_id_o, load_result_o, load_exception_o} )
220 );
221
222 shift_reg #(
223 .dtype ( logic[$bits(st_valid) + $bits(st_trans_id) + $bits(st_result) + $bits(st_ex) - 1: 0]),
224 .Depth ( NR_STORE_PIPE_REGS )
225 ) i_pipe_reg_store (
226 .clk_i,
227 .rst_ni,
228 .d_i ( {st_valid, st_trans_id, st_result, st_ex} ),
229 .d_o ( {store_valid_o, store_trans_id_o, store_result_o, store_exception_o} )
230 );
231
232 // determine whether this is a load or store
233 always_comb begin : which_op
234
235 ld_valid_i = 1'b0;
236 st_valid_i = 1'b0;
237
238 translation_req = 1'b0;
239 mmu_vaddr = 64'b0;
240
241 // check the operator to activate the right functional unit accordingly
242 unique case (lsu_ctrl.fu)
243 // all loads go here
244 LOAD: begin
245 ld_valid_i = lsu_ctrl.valid;
246 translation_req = ld_translation_req;
247 mmu_vaddr = ld_vaddr;
248 end
249 // all stores go here
250 STORE: begin
251 st_valid_i = lsu_ctrl.valid;
252 translation_req = st_translation_req;
253 mmu_vaddr = st_vaddr;
254 end
255 // not relevant for the LSU
256 default: ;
257 endcase
258 end
259
260
261 // ---------------
262 // Byte Enable
263 // ---------------
264 // we can generate the byte enable from the virtual address since the last
265 // 12 bit are the same anyway
266 // and we can always generate the byte enable from the address at hand
267 assign be_i = be_gen(vaddr_i[2:0], extract_transfer_size(fu_data_i.operator));
268
269 // ------------------------
270 // Misaligned Exception
271 // ------------------------
272 // we can detect a misaligned exception immediately
273 // the misaligned exception is passed to the functional unit via the MMU, which in case
274 // can augment the exception if other memory related exceptions like a page fault or access errors
275 always_comb begin : data_misaligned_detection
276
277 misaligned_exception = {
278 64'b0,
279 64'b0,
280 1'b0
281 };
282
283 data_misaligned = 1'b0;
284
285 if (lsu_ctrl.valid) begin
286 case (lsu_ctrl.operator)
287 // double word
288 LD, SD, FLD, FSD,
289 AMO_LRD, AMO_SCD,
290 AMO_SWAPD, AMO_ADDD, AMO_ANDD, AMO_ORD,
291 AMO_XORD, AMO_MAXD, AMO_MAXDU, AMO_MIND,
292 AMO_MINDU: begin
293 if (lsu_ctrl.vaddr[2:0] != 3'b000) begin
294 data_misaligned = 1'b1;
295 end
296 end
297 // word
298 LW, LWU, SW, FLW, FSW,
299 AMO_LRW, AMO_SCW,
300 AMO_SWAPW, AMO_ADDW, AMO_ANDW, AMO_ORW,
301 AMO_XORW, AMO_MAXW, AMO_MAXWU, AMO_MINW,
302 AMO_MINWU: begin
303 if (lsu_ctrl.vaddr[1:0] != 2'b00) begin
304 data_misaligned = 1'b1;
305 end
306 end
307 // half word
308 LH, LHU, SH, FLH, FSH: begin
309 if (lsu_ctrl.vaddr[0] != 1'b0) begin
310 data_misaligned = 1'b1;
311 end
312 end
313 // byte -> is always aligned
314 default:;
315 endcase
316 end
317
318 if (data_misaligned) begin
319
320 if (lsu_ctrl.fu == LOAD) begin
321 misaligned_exception = {
322 riscv::LD_ADDR_MISALIGNED,
323 lsu_ctrl.vaddr,
324 1'b1
325 };
326
327 end else if (lsu_ctrl.fu == STORE) begin
328 misaligned_exception = {
329 riscv::ST_ADDR_MISALIGNED,
330 lsu_ctrl.vaddr,
331 1'b1
332 };
333 end
334 end
335
336 // we work with SV39, so if VM is enabled, check that all bits [63:38] are equal
337 if (en_ld_st_translation_i && !((&lsu_ctrl.vaddr[63:38]) == 1'b1 || (|lsu_ctrl.vaddr[63:38]) == 1'b0)) begin
338
339 if (lsu_ctrl.fu == LOAD) begin
340 misaligned_exception = {
341 riscv::LD_ACCESS_FAULT,
342 lsu_ctrl.vaddr,
343 1'b1
344 };
345
346 end else if (lsu_ctrl.fu == STORE) begin
347 misaligned_exception = {
348 riscv::ST_ACCESS_FAULT,
349 lsu_ctrl.vaddr,
350 1'b1
351 };
352 end
353 end
354 end
355
356 // ------------------
357 // LSU Control
358 // ------------------
359 // new data arrives here
360 lsu_ctrl_t lsu_req_i;
361
362 assign lsu_req_i = {lsu_valid_i, vaddr_i, fu_data_i.operand_b, be_i, fu_data_i.fu, fu_data_i.operator, fu_data_i.trans_id};
363
364 lsu_bypass lsu_bypass_i (
365 .lsu_req_i ( lsu_req_i ),
366 .lus_req_valid_i ( lsu_valid_i ),
367 .pop_ld_i ( pop_ld ),
368 .pop_st_i ( pop_st ),
369
370 .lsu_ctrl_o ( lsu_ctrl ),
371 .ready_o ( lsu_ready_o ),
372 .*
373 );
374 #docstring_end
375 endmodule
376
377 #docstring_begin
378 // ------------------
379 // LSU Control
380 // ------------------
381 // The LSU consists of two independent block which share a common address translation block.
382 // The one block is the load unit, the other one is the store unit. They will signal their readiness
383 // with separate signals. If they are not ready the LSU control should keep the last applied signals stable.
384 // Furthermore it can be the case that another request for one of the two store units arrives in which case
385 // the LSU control should sample it and store it for later application to the units. It does so, by storing it in a
386 // two element FIFO. This is necessary as we only know very late in the cycle whether the load/store will succeed (address check,
387 // TLB hit mainly). So we better unconditionally allow another request to arrive and store this request in case we need to.
388 module lsu_bypass (
389 input logic clk_i,
390 input logic rst_ni,
391 input logic flush_i,
392
393 input lsu_ctrl_t lsu_req_i,
394 input logic lus_req_valid_i,
395 input logic pop_ld_i,
396 input logic pop_st_i,
397
398 output lsu_ctrl_t lsu_ctrl_o,
399 output logic ready_o
400 );
401
402 lsu_ctrl_t [1:0] mem_n, mem_q;
403 logic read_pointer_n, read_pointer_q;
404 logic write_pointer_n, write_pointer_q;
405 logic [1:0] status_cnt_n, status_cnt_q;
406
407 logic empty;
408 assign empty = (status_cnt_q == 0);
409 assign ready_o = empty;
410
411 always_comb begin
412 automatic logic [1:0] status_cnt;
413 automatic logic write_pointer;
414 automatic logic read_pointer;
415
416 status_cnt = status_cnt_q;
417 write_pointer = write_pointer_q;
418 read_pointer = read_pointer_q;
419
420 mem_n = mem_q;
421 // we've got a valid LSU request
422 if (lus_req_valid_i) begin
423 mem_n[write_pointer_q] = lsu_req_i;
424 write_pointer++;
425 status_cnt++;
426 end
427
428 if (pop_ld_i) begin
429 // invalidate the result
430 mem_n[read_pointer_q].valid = 1'b0;
431 read_pointer++;
432 status_cnt--;
433 end
434
435 if (pop_st_i) begin
436 // invalidate the result
437 mem_n[read_pointer_q].valid = 1'b0;
438 read_pointer++;
439 status_cnt--;
440 end
441
442 if (pop_st_i && pop_ld_i)
443 mem_n = '0;
444
445 if (flush_i) begin
446 status_cnt = '0;
447 write_pointer = '0;
448 read_pointer = '0;
449 mem_n = '0;
450 end
451 // default assignments
452 read_pointer_n = read_pointer;
453 write_pointer_n = write_pointer;
454 status_cnt_n = status_cnt;
455 end
456
457 // output assignment
458 always_comb begin : output_assignments
459 if (empty) begin
460 lsu_ctrl_o = lsu_req_i;
461 end else begin
462 lsu_ctrl_o = mem_q[read_pointer_q];
463 end
464 end
465
466 // registers
467 always_ff @(posedge clk_i or negedge rst_ni) begin
468 if (~rst_ni) begin
469 mem_q <= '0;
470 status_cnt_q <= '0;
471 write_pointer_q <= '0;
472 read_pointer_q <= '0;
473 end else begin
474 mem_q <= mem_n;
475 status_cnt_q <= status_cnt_n;
476 write_pointer_q <= write_pointer_n;
477 read_pointer_q <= read_pointer_n;
478 end
479 end
480 endmodule
481 #docstring_end