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