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: