hw/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
4: // SPDX-License-Identifier: Apache-2.0
5:
6: /**
7: * Load Store Unit
8: *
9: * Load Store Unit, used to eliminate multiple access during processor stalls,
10: * and to align bytes and halfwords.
11: */
12: module ibex_load_store_unit (
13: input logic clk_i,
14: input logic rst_ni,
15:
16: // data interface
17: output logic data_req_o,
18: input logic data_gnt_i,
19: input logic data_rvalid_i,
20: input logic data_err_i,
21: input logic data_pmp_err_i,
22:
23: output logic [31:0] data_addr_o,
24: output logic data_we_o,
25: output logic [3:0] data_be_o,
26: output logic [31:0] data_wdata_o,
27: input logic [31:0] data_rdata_i,
28:
29: // signals to/from ID/EX stage
30: input logic data_we_ex_i, // write enable -> from ID/EX
31: input logic [1:0] data_type_ex_i, // data type: word, half word, byte -> from ID/EX
32: input logic [31:0] data_wdata_ex_i, // data to write to memory -> from ID/EX
33: input logic data_sign_ext_ex_i, // sign extension -> from ID/EX
34:
35: output logic [31:0] data_rdata_ex_o, // requested data -> to ID/EX
36: input logic data_req_ex_i, // data request -> from ID/EX
37:
38: input logic [31:0] adder_result_ex_i, // address computed in ALU -> from ID/EX
39:
40: output logic addr_incr_req_o, // request address increment for
41: // misaligned accesses -> to ID/EX
42: output logic [31:0] addr_last_o, // address of last transaction -> to controller
43: // -> mtval
44: // -> AGU for misaligned accesses
45: output logic data_valid_o, // LSU has completed transaction -> to ID/EX
46:
47: // exception signals
48: output logic load_err_o,
49: output logic store_err_o,
50:
51: output logic busy_o
52: );
53:
54: logic [31:0] data_addr;
55: logic [31:0] data_addr_w_aligned;
56: logic [31:0] addr_last_q;
57:
58: logic addr_update;
59: logic ctrl_update;
60: logic rdata_update;
61: logic [31:8] rdata_q;
62: logic [1:0] rdata_offset_q;
63: logic [1:0] data_type_q;
64: logic data_sign_ext_q;
65: logic data_we_q;
66:
67: logic [1:0] data_offset; // mux control for data to be written to memory
68:
69: logic [3:0] data_be;
70: logic [31:0] data_wdata;
71:
72: logic [31:0] data_rdata_ext;
73:
74: logic [31:0] rdata_w_ext; // word realignment for misaligned loads
75: logic [31:0] rdata_h_ext; // sign extension for half words
76: logic [31:0] rdata_b_ext; // sign extension for bytes
77:
78: logic split_misaligned_access;
79: logic handle_misaligned_q, handle_misaligned_d; // high after receiving grant for first
80: // part of a misaligned access
81: logic pmp_err_q, pmp_err_d;
82: logic lsu_err_q, lsu_err_d;
83: logic data_or_pmp_err;
84:
85: typedef enum logic [2:0] {
86: IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID,
87: WAIT_RVALID_DONE
88: } ls_fsm_e;
89:
90: ls_fsm_e ls_fsm_cs, ls_fsm_ns;
91:
92: assign data_addr = adder_result_ex_i;
93: assign data_offset = data_addr[1:0];
94:
95: ///////////////////
96: // BE generation //
97: ///////////////////
98:
99: always_comb begin
100: unique case (data_type_ex_i) // Data type 00 Word, 01 Half word, 11,10 byte
101: 2'b00: begin // Writing a word
102: if (!handle_misaligned_q) begin // first part of potentially misaligned transaction
103: unique case (data_offset)
104: 2'b00: data_be = 4'b1111;
105: 2'b01: data_be = 4'b1110;
106: 2'b10: data_be = 4'b1100;
107: 2'b11: data_be = 4'b1000;
108: default: data_be = 4'b1111;
109: endcase // case (data_offset)
110: end else begin // second part of misaligned transaction
111: unique case (data_offset)
112: 2'b00: data_be = 4'b0000; // this is not used, but included for completeness
113: 2'b01: data_be = 4'b0001;
114: 2'b10: data_be = 4'b0011;
115: 2'b11: data_be = 4'b0111;
116: default: data_be = 4'b1111;
117: endcase // case (data_offset)
118: end
119: end
120:
121: 2'b01: begin // Writing a half word
122: if (!handle_misaligned_q) begin // first part of potentially misaligned transaction
123: unique case (data_offset)
124: 2'b00: data_be = 4'b0011;
125: 2'b01: data_be = 4'b0110;
126: 2'b10: data_be = 4'b1100;
127: 2'b11: data_be = 4'b1000;
128: default: data_be = 4'b1111;
129: endcase // case (data_offset)
130: end else begin // second part of misaligned transaction
131: data_be = 4'b0001;
132: end
133: end
134:
135: 2'b10,
136: 2'b11: begin // Writing a byte
137: unique case (data_offset)
138: 2'b00: data_be = 4'b0001;
139: 2'b01: data_be = 4'b0010;
140: 2'b10: data_be = 4'b0100;
141: 2'b11: data_be = 4'b1000;
142: default: data_be = 4'b1111;
143: endcase // case (data_offset)
144: end
145:
146: default: data_be = 4'b1111;
147: endcase // case (data_type_ex_i)
148: end
149:
150: /////////////////////
151: // WData alignment //
152: /////////////////////
153:
154: // prepare data to be written to the memory
155: // we handle misaligned accesses, half word and byte accesses here
156: always_comb begin
157: unique case (data_offset)
158: 2'b00: data_wdata = data_wdata_ex_i[31:0];
159: 2'b01: data_wdata = {data_wdata_ex_i[23:0], data_wdata_ex_i[31:24]};
160: 2'b10: data_wdata = {data_wdata_ex_i[15:0], data_wdata_ex_i[31:16]};
161: 2'b11: data_wdata = {data_wdata_ex_i[ 7:0], data_wdata_ex_i[31: 8]};
162: default: data_wdata = data_wdata_ex_i[31:0];
163: endcase // case (data_offset)
164: end
165:
166: /////////////////////
167: // RData alignment //
168: /////////////////////
169:
170: // register for unaligned rdata
171: always_ff @(posedge clk_i or negedge rst_ni) begin
172: if (!rst_ni) begin
173: rdata_q <= '0;
174: end else if (rdata_update) begin
175: rdata_q <= data_rdata_i[31:8];
176: end
177: end
178:
179: // registers for transaction control
180: always_ff @(posedge clk_i or negedge rst_ni) begin
181: if (!rst_ni) begin
182: rdata_offset_q <= 2'h0;
183: data_type_q <= 2'h0;
184: data_sign_ext_q <= 1'b0;
185: data_we_q <= 1'b0;
186: end else if (ctrl_update) begin
187: rdata_offset_q <= data_offset;
188: data_type_q <= data_type_ex_i;
189: data_sign_ext_q <= data_sign_ext_ex_i;
190: data_we_q <= data_we_ex_i;
191: end
192: end
193:
194: // Store last address for mtval + AGU for misaligned transactions.
195: // Do not update in case of errors, mtval needs the (first) failing address
196: always_ff @(posedge clk_i or negedge rst_ni) begin
197: if (!rst_ni) begin
198: addr_last_q <= '0;
199: end else if (addr_update) begin
200: addr_last_q <= data_addr;
201: end
202: end
203:
204: // take care of misaligned words
205: always_comb begin
206: unique case (rdata_offset_q)
207: 2'b00: rdata_w_ext = data_rdata_i[31:0];
208: 2'b01: rdata_w_ext = {data_rdata_i[ 7:0], rdata_q[31:8]};
209: 2'b10: rdata_w_ext = {data_rdata_i[15:0], rdata_q[31:16]};
210: 2'b11: rdata_w_ext = {data_rdata_i[23:0], rdata_q[31:24]};
211: default: rdata_w_ext = data_rdata_i[31:0];
212: endcase
213: end
214:
215: ////////////////////
216: // Sign extension //
217: ////////////////////
218:
219: // sign extension for half words
220: always_comb begin
221: unique case (rdata_offset_q)
222: 2'b00: begin
223: if (!data_sign_ext_q) begin
224: rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
225: end else begin
226: rdata_h_ext = {{16{data_rdata_i[15]}}, data_rdata_i[15:0]};
227: end
228: end
229:
230: 2'b01: begin
231: if (!data_sign_ext_q) begin
232: rdata_h_ext = {16'h0000, data_rdata_i[23:8]};
233: end else begin
234: rdata_h_ext = {{16{data_rdata_i[23]}}, data_rdata_i[23:8]};
235: end
236: end
237:
238: 2'b10: begin
239: if (!data_sign_ext_q) begin
240: rdata_h_ext = {16'h0000, data_rdata_i[31:16]};
241: end else begin
242: rdata_h_ext = {{16{data_rdata_i[31]}}, data_rdata_i[31:16]};
243: end
244: end
245:
246: 2'b11: begin
247: if (!data_sign_ext_q) begin
248: rdata_h_ext = {16'h0000, data_rdata_i[7:0], rdata_q[31:24]};
249: end else begin
250: rdata_h_ext = {{16{data_rdata_i[7]}}, data_rdata_i[7:0], rdata_q[31:24]};
251: end
252: end
253:
254: default: rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
255: endcase // case (rdata_offset_q)
256: end
257:
258: // sign extension for bytes
259: always_comb begin
260: unique case (rdata_offset_q)
261: 2'b00: begin
262: if (!data_sign_ext_q) begin
263: rdata_b_ext = {24'h00_0000, data_rdata_i[7:0]};
264: end else begin
265: rdata_b_ext = {{24{data_rdata_i[7]}}, data_rdata_i[7:0]};
266: end
267: end
268:
269: 2'b01: begin
270: if (!data_sign_ext_q) begin
271: rdata_b_ext = {24'h00_0000, data_rdata_i[15:8]};
272: end else begin
273: rdata_b_ext = {{24{data_rdata_i[15]}}, data_rdata_i[15:8]};
274: end
275: end
276:
277: 2'b10: begin
278: if (!data_sign_ext_q) begin
279: rdata_b_ext = {24'h00_0000, data_rdata_i[23:16]};
280: end else begin
281: rdata_b_ext = {{24{data_rdata_i[23]}}, data_rdata_i[23:16]};
282: end
283: end
284:
285: 2'b11: begin
286: if (!data_sign_ext_q) begin
287: rdata_b_ext = {24'h00_0000, data_rdata_i[31:24]};
288: end else begin
289: rdata_b_ext = {{24{data_rdata_i[31]}}, data_rdata_i[31:24]};
290: end
291: end
292:
293: default: rdata_b_ext = {24'h00_0000, data_rdata_i[7:0]};
294: endcase // case (rdata_offset_q)
295: end
296:
297: // select word, half word or byte sign extended version
298: always_comb begin
299: unique case (data_type_q)
300: 2'b00: data_rdata_ext = rdata_w_ext;
301: 2'b01: data_rdata_ext = rdata_h_ext;
302: 2'b10,2'b11: data_rdata_ext = rdata_b_ext;
303: default: data_rdata_ext = rdata_w_ext;
304: endcase // case (data_type_q)
305: end
306:
307: /////////////
308: // LSU FSM //
309: /////////////
310:
311: // check for misaligned accesses that need to be split into two word-aligned accesses
312: assign split_misaligned_access =
313: ((data_type_ex_i == 2'b00) && (data_offset != 2'b00)) || // misaligned word access
314: ((data_type_ex_i == 2'b01) && (data_offset == 2'b11)); // misaligned half-word access
315:
316: // FSM
317: always_comb begin
318: ls_fsm_ns = ls_fsm_cs;
319:
320: data_req_o = 1'b0;
321: data_valid_o = 1'b0;
322: addr_incr_req_o = 1'b0;
323: handle_misaligned_d = handle_misaligned_q;
324: data_or_pmp_err = 1'b0;
325: pmp_err_d = pmp_err_q;
326: lsu_err_d = lsu_err_q;
327:
328: addr_update = 1'b0;
329: ctrl_update = 1'b0;
330: rdata_update = 1'b0;
331:
332: unique case (ls_fsm_cs)
333:
334: IDLE: begin
335: if (data_req_ex_i) begin
336: data_req_o = 1'b1;
337: pmp_err_d = data_pmp_err_i;
338: lsu_err_d = 1'b0;
339: if (data_gnt_i) begin
340: ctrl_update = 1'b1;
341: addr_update = 1'b1;
342: handle_misaligned_d = split_misaligned_access;
343: ls_fsm_ns = split_misaligned_access ? WAIT_RVALID_MIS : WAIT_RVALID;
344: end else begin
345: ls_fsm_ns = split_misaligned_access ? WAIT_GNT_MIS : WAIT_GNT;
346: end
347: end
348: end
349:
350: WAIT_GNT_MIS: begin
351: data_req_o = 1'b1;
352: // data_pmp_err_i is valid during the address phase of a request. An error will block the
353: // external request and so a data_gnt_i might never be signalled. The registered version
354: // pmp_err_q is only updated for new address phases and so can be used in WAIT_GNT* and
355: // WAIT_RVALID* states
356: if (data_gnt_i || pmp_err_q) begin
357: addr_update = 1'b1;
358: ctrl_update = 1'b1;
359: handle_misaligned_d = 1'b1;
360: ls_fsm_ns = WAIT_RVALID_MIS;
361: end
362: end
363:
364: WAIT_RVALID_MIS: begin
365: // push out second request
366: data_req_o = 1'b1;
367: // tell ID/EX stage to update the address
368: addr_incr_req_o = 1'b1;
369:
370: // first part rvalid is received, or gets a PMP error
371: if (data_rvalid_i || pmp_err_q) begin
372: // Update the PMP error for the second part
373: pmp_err_d = data_pmp_err_i;
374: // Record the error status of the first part
375: lsu_err_d = data_err_i | pmp_err_q;
376: // Capture the first rdata for loads
377: rdata_update = ~data_we_q;
378: // If already granted, wait for second rvalid
379: ls_fsm_ns = data_gnt_i ? WAIT_RVALID : WAIT_GNT;
380: // Update the address for the second part, if no error
381: addr_update = data_gnt_i & ~(data_err_i | pmp_err_q);
382:
383: end else begin
384: // first part rvalid is NOT received
385: if (data_gnt_i) begin
386: // second grant is received
387: ls_fsm_ns = WAIT_RVALID_DONE;
388: end
389: end
390: end
391:
392: WAIT_GNT: begin
393: // tell ID/EX stage to update the address
394: addr_incr_req_o = handle_misaligned_q;
395: data_req_o = 1'b1;
396: if (data_gnt_i || pmp_err_q) begin
397: ctrl_update = 1'b1;
398: // Update the address, unless there was an error
399: addr_update = ~lsu_err_q;
400: ls_fsm_ns = WAIT_RVALID;
401: end
402: end
403:
404: WAIT_RVALID: begin
405: if (data_rvalid_i || pmp_err_q) begin
406: data_valid_o = 1'b1;
407: // Data error from either part
408: data_or_pmp_err = lsu_err_q | data_err_i | pmp_err_q;
409: handle_misaligned_d = 1'b0;
410: ls_fsm_ns = IDLE;
411: end else begin
412: ls_fsm_ns = WAIT_RVALID;
413: end
414: end
415:
416: WAIT_RVALID_DONE: begin
417: // tell ID/EX stage to update the address (to make sure the
418: // second address can be captured correctly for mtval and PMP checking)
419: addr_incr_req_o = 1'b1;
420: // Wait for the first rvalid, second request is already granted
421: if (data_rvalid_i) begin
422: // Update the pmp error for the second part
423: pmp_err_d = data_pmp_err_i;
424: // The first part cannot see a PMP error in this state
425: lsu_err_d = data_err_i;
426: // Now we can update the address for the second part if no error
427: addr_update = ~data_err_i;
428: // Capture the first rdata for loads
429: rdata_update = ~data_we_q;
430: // Wait for second rvalid
431: ls_fsm_ns = WAIT_RVALID;
432: end
433: end
434:
435: default: begin
436: ls_fsm_ns = IDLE;
437: end
438: endcase
439: end
440:
441: // registers for FSM
442: always_ff @(posedge clk_i or negedge rst_ni) begin
443: if (!rst_ni) begin
444: ls_fsm_cs <= IDLE;
445: handle_misaligned_q <= '0;
446: pmp_err_q <= '0;
447: lsu_err_q <= '0;
448: end else begin
449: ls_fsm_cs <= ls_fsm_ns;
450: handle_misaligned_q <= handle_misaligned_d;
451: pmp_err_q <= pmp_err_d;
452: lsu_err_q <= lsu_err_d;
453: end
454: end
455:
456: /////////////
457: // Outputs //
458: /////////////
459:
460: // output to register file
461: assign data_rdata_ex_o = data_rdata_ext;
462:
463: // output data address must be word aligned
464: assign data_addr_w_aligned = {data_addr[31:2], 2'b00};
465:
466: // output to data interface
467: assign data_addr_o = data_addr_w_aligned;
468: assign data_wdata_o = data_wdata;
469: assign data_we_o = data_we_ex_i;
470: assign data_be_o = data_be;
471:
472: // output to ID stage: mtval + AGU for misaligned transactions
473: assign addr_last_o = addr_last_q;
474:
475: // Signal a load or store error depending on the transaction type outstanding
476: assign load_err_o = data_or_pmp_err & ~data_we_q;
477: assign store_err_o = data_or_pmp_err & data_we_q;
478:
479: assign busy_o = (ls_fsm_cs != IDLE);
480:
481: ////////////////
482: // Assertions //
483: ////////////////
484:
485: // Selectors must be known/valid.
486: `ASSERT_KNOWN(IbexDataTypeKnown, data_type_ex_i, clk_i, !rst_ni)
487: `ASSERT_KNOWN(IbexDataOffsetKnown, data_offset, clk_i, !rst_ni)
488: `ASSERT_KNOWN(IbexRDataOffsetQKnown, rdata_offset_q, clk_i, !rst_ni)
489: `ASSERT_KNOWN(IbexDataTypeQKnown, data_type_q, clk_i, !rst_ni)
490: `ASSERT(IbexLsuStateValid, ls_fsm_cs inside {
491: IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID,
492: WAIT_RVALID_DONE
493: }, clk_i, !rst_ni)
494:
495: // There must not be an rvalid unless the FSM is handlling it.
496: `ASSERT(IbexRvalidNotHandled, data_rvalid_i |-> (
497: (ls_fsm_cs == WAIT_RVALID) ||
498: (ls_fsm_cs == WAIT_RVALID_MIS) ||
499: (ls_fsm_cs == WAIT_RVALID_DONE)
500: ), clk_i, !rst_ni)
501:
502: // Errors must only be sent together with rvalid.
503: `ASSERT(IbexDataErrWithoutRvalid, data_err_i |-> data_rvalid_i, clk_i, !rst_ni)
504:
505: // Address must not contain X when request is sent.
506: `ASSERT(IbexDataAddrUnknown, data_req_o |-> !$isunknown(data_addr_o), clk_i, !rst_ni)
507:
508: // Address must be word aligned when request is sent.
509: `ASSERT(IbexDataAddrUnaligned, data_req_o |-> (data_addr_o[1:0] == 2'b00), clk_i, !rst_ni)
510:
511: endmodule
512: