../src/lowrisc_ip_flash_ctrl_0.1/rtl/flash_ctrl.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // Faux Flash Controller Module
   6: //
   7: //
   8: 
   9: `include "prim_assert.sv"
  10: 
  11: module flash_ctrl import flash_ctrl_pkg::*; (
  12:   input        clk_i,
  13:   input        rst_ni,
  14: 
  15:   // Bus Interface
  16:   input        tlul_pkg::tl_h2d_t tl_i,
  17:   output       tlul_pkg::tl_d2h_t tl_o,
  18: 
  19:   // Flash Interface
  20:   input        flash_rsp_t flash_i,
  21:   output       flash_req_t flash_o,
  22: 
  23:   // Interrupts
  24:   output logic intr_prog_empty_o, // Program fifo is empty
  25:   output logic intr_prog_lvl_o,   // Program fifo is empty
  26:   output logic intr_rd_full_o,    // Read fifo is full
  27:   output logic intr_rd_lvl_o,     // Read fifo is full
  28:   output logic intr_op_done_o,    // Requested flash operation (wr/erase) done
  29:   output logic intr_op_error_o    // Requested flash operation (wr/erase) done
  30: );
  31: 
  32:   import flash_ctrl_reg_pkg::*;
  33: 
  34:   localparam int DataBitWidth = $clog2(BytesPerWord);
  35:   localparam int EraseBitWidth = $bits(flash_erase_op_e);
  36: 
  37:   flash_ctrl_reg2hw_t reg2hw;
  38:   flash_ctrl_hw2reg_t hw2reg;
  39: 
  40:   tlul_pkg::tl_h2d_t tl_fifo_h2d [2];
  41:   tlul_pkg::tl_d2h_t tl_fifo_d2h [2];
  42: 
  43:   // Register module
  44:   flash_ctrl_reg_top u_reg (
  45:     .clk_i,
  46:     .rst_ni,
  47: 
  48:     .tl_i,
  49:     .tl_o,
  50: 
  51:     .tl_win_o (tl_fifo_h2d),
  52:     .tl_win_i (tl_fifo_d2h),
  53: 
  54:     .reg2hw,
  55:     .hw2reg,
  56: 
  57:     .devmode_i  (1'b1)
  58:   );
  59: 
  60:   // FIFO Connections
  61:   logic                 prog_fifo_wready;
  62:   logic                 prog_fifo_rvalid;
  63:   logic                 prog_fifo_req;
  64:   logic                 prog_fifo_wen;
  65:   logic                 prog_fifo_ren;
  66:   logic [BusWidth-1:0]  prog_fifo_wdata;
  67:   logic [BusWidth-1:0]  prog_fifo_rdata;
  68:   logic [FifoDepthW-1:0] prog_fifo_depth;
  69:   logic                 rd_fifo_wready;
  70:   logic                 rd_fifo_rvalid;
  71:   logic                 rd_fifo_wen;
  72:   logic                 rd_fifo_ren;
  73:   logic [BusWidth-1:0]  rd_fifo_wdata;
  74:   logic [BusWidth-1:0]  rd_fifo_rdata;
  75:   logic [FifoDepthW-1:0] rd_fifo_depth;
  76: 
  77:   // Program Control Connections
  78:   logic prog_flash_req;
  79:   logic prog_flash_ovfl;
  80:   logic [AddrW-1:0] prog_flash_addr;
  81:   logic prog_op_valid;
  82: 
  83:   // Read Control Connections
  84:   logic rd_flash_req;
  85:   logic rd_flash_ovfl;
  86:   logic [AddrW-1:0] rd_flash_addr;
  87: 
  88:   // Erase Control Connections
  89:   logic erase_flash_req;
  90:   logic [AddrW-1:0] erase_flash_addr;
  91:   logic [EraseBitWidth-1:0] erase_flash_type;
  92: 
  93:   // Done / Error signaling from ctrl modules
  94:   logic [2:0] ctrl_done, ctrl_err;
  95: 
  96:   // Flash Memory Protection Connections
  97:   logic flash_req;
  98:   logic flash_rd_done, flash_prog_done, flash_erase_done;
  99:   logic flash_error;
 100:   logic [AddrW-1:0] flash_addr;
 101:   logic [BusWidth-1:0] flash_prog_data;
 102:   logic [BusWidth-1:0] flash_rd_data;
 103:   logic init_busy;
 104:   logic rd_op;
 105:   logic prog_op;
 106:   logic erase_op;
 107:   logic [AllPagesW-1:0] err_page;
 108:   logic [BankW-1:0] err_bank;
 109: 
 110:   assign rd_op = reg2hw.control.op.q == FlashRead;
 111:   assign prog_op = reg2hw.control.op.q == FlashProg;
 112:   assign erase_op = reg2hw.control.op.q == FlashErase;
 113: 
 114:   // Program FIFO
 115:   // Since the program and read FIFOs are never used at the same time, it should really be one
 116:   // FIFO with muxed inputs and outputs.  This should be addressed once the flash integration
 117:   // strategy has been identified
 118: 
 119:   assign prog_op_valid = reg2hw.control.start.q & prog_op;
 120: 
 121:   tlul_adapter_sram #(
 122:     .SramAw(1),         //address unused
 123:     .SramDw(BusWidth),
 124:     .ByteAccess(0),     //flash may not support byte access
 125:     .ErrOnRead(1)       //reads not supported
 126:   ) u_to_prog_fifo (
 127:     .clk_i,
 128:     .rst_ni,
 129:     .tl_i       (tl_fifo_h2d[0]),
 130:     .tl_o       (tl_fifo_d2h[0]),
 131:     .req_o      (prog_fifo_req),
 132:     .gnt_i      (prog_fifo_wready),
 133:     .we_o       (prog_fifo_wen),
 134:     .addr_o     (),
 135:     .wmask_o    (),
 136:     .wdata_o    (prog_fifo_wdata),
 137:     .rdata_i    (BusWidth'(0)),
 138:     .rvalid_i   (1'b0),
 139:     .rerror_i   (2'b0)
 140:   );
 141: 
 142:   prim_fifo_sync #(
 143:     .Width(BusWidth),
 144:     .Depth(FifoDepth)
 145:   ) u_prog_fifo (
 146:     .clk_i,
 147:     .rst_ni (rst_ni),
 148:     .clr_i  (reg2hw.control.fifo_rst.q),
 149:     .wvalid (prog_fifo_req & prog_fifo_wen & prog_op_valid),
 150:     .wready (prog_fifo_wready),
 151:     .wdata  (prog_fifo_wdata),
 152:     .depth  (prog_fifo_depth),
 153:     .rvalid (prog_fifo_rvalid),
 154:     .rready (prog_fifo_ren),
 155:     .rdata  (prog_fifo_rdata)
 156:   );
 157: 
 158:   // Program handler is consumer of prog_fifo
 159:   flash_prog_ctrl #(
 160:     .DataW(BusWidth),
 161:     .AddrW(AddrW)
 162:   ) u_flash_prog_ctrl (
 163:     .clk_i,
 164:     .rst_ni,
 165: 
 166:     // Software Interface
 167:     .op_start_i     (prog_op_valid),
 168:     .op_num_words_i (reg2hw.control.num.q),
 169:     .op_done_o      (ctrl_done[0]),
 170:     .op_err_o       (ctrl_err[0]),
 171:     .op_addr_i      (reg2hw.addr.q[DataBitWidth +: AddrW]),
 172: 
 173:     // FIFO Interface
 174:     .data_i         (prog_fifo_rdata),
 175:     .data_rdy_i     (prog_fifo_rvalid),
 176:     .data_rd_o      (prog_fifo_ren),
 177: 
 178:     // Flash Macro Interface
 179:     .flash_req_o    (prog_flash_req),
 180:     .flash_addr_o   (prog_flash_addr),
 181:     .flash_ovfl_o   (prog_flash_ovfl),
 182:     .flash_data_o   (flash_prog_data),
 183:     .flash_done_i   (flash_prog_done),
 184:     .flash_error_i  (flash_error)
 185:   );
 186: 
 187:   // Read FIFO
 188:   logic adapter_rvalid;
 189:   always_ff @(posedge clk_i or negedge rst_ni) begin
 190:     if (!rst_ni) begin
 191:       adapter_rvalid <= 1'b0;
 192:     end else begin
 193:       adapter_rvalid <= rd_fifo_ren && rd_fifo_rvalid;
 194:     end
 195:   end
 196: 
 197:   tlul_adapter_sram #(
 198:     .SramAw(1),         //address unused
 199:     .SramDw(BusWidth),
 200:     .ByteAccess(0),     //flash may not support byte access
 201:     .ErrOnWrite(1)      //writes not supported
 202:   ) u_to_rd_fifo (
 203:     .clk_i,
 204:     .rst_ni,
 205:     .tl_i       (tl_fifo_h2d[1]),
 206:     .tl_o       (tl_fifo_d2h[1]),
 207:     .req_o      (rd_fifo_ren),
 208:     .gnt_i      (rd_fifo_rvalid),
 209:     .we_o       (),
 210:     .addr_o     (),
 211:     .wmask_o    (),
 212:     .wdata_o    (),
 213:     .rdata_i    (rd_fifo_rdata),
 214:     .rvalid_i   (adapter_rvalid),
 215:     .rerror_i   (2'b0)
 216:   );
 217: 
 218:   prim_fifo_sync #(
 219:     .Width(BusWidth),
 220:     .Depth(FifoDepth)
 221:   ) u_rd_fifo (
 222:     .clk_i,
 223:     .rst_ni (rst_ni),
 224:     .clr_i  (reg2hw.control.fifo_rst.q),
 225:     .wvalid (rd_fifo_wen),
 226:     .wready (rd_fifo_wready),
 227:     .wdata  (rd_fifo_wdata),
 228:     .depth  (rd_fifo_depth),
 229:     .rvalid (rd_fifo_rvalid),
 230:     //adapter_rvalid is used here because adapter_sram does not accept data the same cycle.
 231:     //It expects an sram like interface where data arrives during the next cycle
 232:     .rready (adapter_rvalid),
 233:     .rdata  (rd_fifo_rdata)
 234:   );
 235: 
 236:   // Read handler is consumer of rd_fifo
 237:   flash_rd_ctrl #(
 238:     .DataW(BusWidth),
 239:     .AddrW(AddrW)
 240:   ) u_flash_rd_ctrl (
 241:     .clk_i,
 242:     .rst_ni,
 243: 
 244:     // Software Interface
 245:     .op_start_i     (reg2hw.control.start.q & rd_op),
 246:     .op_num_words_i (reg2hw.control.num.q),
 247:     .op_done_o      (ctrl_done[1]),
 248:     .op_err_o       (ctrl_err[1]),
 249:     .op_addr_i      (reg2hw.addr.q[DataBitWidth +: AddrW]),
 250: 
 251:     // FIFO Interface
 252:     .data_rdy_i     (rd_fifo_wready),
 253:     .data_o         (rd_fifo_wdata),
 254:     .data_wr_o      (rd_fifo_wen),
 255: 
 256:     // Flash Macro Interface
 257:     .flash_req_o    (rd_flash_req),
 258:     .flash_addr_o   (rd_flash_addr),
 259:     .flash_ovfl_o   (rd_flash_ovfl),
 260:     .flash_data_i   (flash_rd_data),
 261:     .flash_done_i   (flash_rd_done),
 262:     .flash_error_i  (flash_error)
 263:   );
 264: 
 265:   // Erase handler does not consume fifo
 266:   flash_erase_ctrl #(
 267:     .AddrW(AddrW),
 268:     .PagesPerBank(PagesPerBank),
 269:     .WordsPerPage(WordsPerPage),
 270:     .EraseBitWidth(EraseBitWidth)
 271:   ) u_flash_erase_ctrl (
 272:     // Software Interface
 273:     .op_start_i     (reg2hw.control.start.q & erase_op),
 274:     .op_type_i      (reg2hw.control.erase_sel.q),
 275:     .op_done_o      (ctrl_done[2]),
 276:     .op_err_o       (ctrl_err[2]),
 277:     .op_addr_i      (reg2hw.addr.q[DataBitWidth +: AddrW]),
 278: 
 279:     // Flash Macro Interface
 280:     .flash_req_o    (erase_flash_req),
 281:     .flash_addr_o   (erase_flash_addr),
 282:     .flash_op_o     (erase_flash_type),
 283:     .flash_done_i   (flash_erase_done),
 284:     .flash_error_i  (flash_error)
 285:   );
 286: 
 287:   // Final muxing to flash macro module
 288:   always_comb begin
 289:     unique case (reg2hw.control.op.q)
 290:       FlashRead: begin
 291:         flash_req = rd_flash_req;
 292:         flash_addr = rd_flash_addr;
 293:       end
 294:       FlashProg: begin
 295:         flash_req = prog_flash_req;
 296:         flash_addr = prog_flash_addr;
 297:       end
 298:       FlashErase: begin
 299:         flash_req = erase_flash_req;
 300:         flash_addr = erase_flash_addr;
 301:       end
 302:       default: begin
 303:         flash_req = 1'b0;
 304:         flash_addr  = '0;
 305:       end
 306:     endcase // unique case (flash_op_e'(reg2hw.control.op.q))
 307:   end
 308: 
 309:   // extra region is the default region
 310:   flash_ctrl_reg2hw_mp_region_cfg_mreg_t [MpRegions:0] region_cfgs;
 311: 
 312:   assign region_cfgs[MpRegions-1:0] = reg2hw.mp_region_cfg[MpRegions-1:0];
 313: 
 314:   //last region
 315:   assign region_cfgs[MpRegions].base.q = '0;
 316:   assign region_cfgs[MpRegions].size.q = {AllPagesW{1'b1}};
 317:   assign region_cfgs[MpRegions].en.q = 1'b1;
 318:   assign region_cfgs[MpRegions].rd_en.q = reg2hw.default_region.rd_en.q;
 319:   assign region_cfgs[MpRegions].prog_en.q = reg2hw.default_region.prog_en.q;
 320:   assign region_cfgs[MpRegions].erase_en.q = reg2hw.default_region.erase_en.q;
 321: 
 322:   // Flash memory protection
 323:   flash_mp #(
 324:     .MpRegions(MpRegions),
 325:     .NumBanks(NumBanks),
 326:     .AllPagesW(AllPagesW)
 327:   ) u_flash_mp (
 328:     .clk_i,
 329:     .rst_ni,
 330: 
 331:     // sw configuration
 332:     .region_cfgs_i(region_cfgs),
 333:     .bank_cfgs_i(reg2hw.mp_bank_cfg),
 334: 
 335:     // read / prog / erase controls
 336:     .req_i(flash_req),
 337:     .req_addr_i(flash_addr[WordW +: AllPagesW]),
 338:     .addr_ovfl_i(rd_flash_ovfl | prog_flash_ovfl),
 339:     .req_bk_i(flash_addr[BankAddrW +: BankW]),
 340:     .rd_i(rd_op),
 341:     .prog_i(prog_op),
 342:     .pg_erase_i(erase_op & (erase_flash_type == PageErase)),
 343:     .bk_erase_i(erase_op & (erase_flash_type == BankErase)),
 344:     .rd_done_o(flash_rd_done),
 345:     .prog_done_o(flash_prog_done),
 346:     .erase_done_o(flash_erase_done),
 347:     .error_o(flash_error),
 348:     .err_addr_o(err_page),
 349:     .err_bank_o(err_bank),
 350: 
 351:     // flash phy interface
 352:     .req_o(flash_o.req),
 353:     .rd_o(flash_o.rd),
 354:     .prog_o(flash_o.prog),
 355:     .pg_erase_o(flash_o.pg_erase),
 356:     .bk_erase_o(flash_o.bk_erase),
 357:     .rd_done_i(flash_i.rd_done),
 358:     .prog_done_i(flash_i.prog_done),
 359:     .erase_done_i(flash_i.erase_done)
 360:   );
 361: 
 362: 
 363:   assign hw2reg.op_status.done.d = 1'b1;
 364:   assign hw2reg.op_status.done.de = |ctrl_done;
 365:   assign hw2reg.op_status.err.d = 1'b1;
 366:   assign hw2reg.op_status.err.de = |ctrl_err;
 367:   assign hw2reg.status.rd_full.d = ~rd_fifo_wready;
 368:   assign hw2reg.status.rd_empty.d = ~rd_fifo_rvalid;
 369:   assign hw2reg.status.prog_full.d = ~prog_fifo_wready;
 370:   assign hw2reg.status.prog_empty.d = ~prog_fifo_rvalid;
 371:   assign hw2reg.status.init_wip.d = init_busy;
 372:   assign hw2reg.status.error_page.d = err_page;
 373:   assign hw2reg.status.error_bank.d = err_bank;
 374:   assign hw2reg.control.start.d = 1'b0;
 375:   assign hw2reg.control.start.de = |ctrl_done;
 376: 
 377:   // Flash Interface
 378:   assign flash_o.addr = flash_addr;
 379:   assign flash_o.prog_data = flash_prog_data;
 380:   assign flash_rd_data = flash_i.rd_data;
 381:   assign init_busy = flash_i.init_busy;
 382: 
 383:   // Interrupts
 384:   // Generate edge triggered signals for sources that are level
 385:   logic [3:0] intr_src;
 386:   logic [3:0] intr_src_q;
 387:   logic [3:0] intr_assert;
 388: 
 389:   assign intr_src = { ~prog_fifo_rvalid,
 390:                       reg2hw.fifo_lvl.prog.q == prog_fifo_depth,
 391:                       ~rd_fifo_wready,
 392:                       reg2hw.fifo_lvl.rd.q == rd_fifo_depth
 393:                     };
 394: 
 395:   always_ff @(posedge clk_i or negedge rst_ni) begin
 396:     if (!rst_ni) begin
 397:       intr_src_q <= 4'h8; //prog_fifo is empty by default
 398:     end else begin
 399:       intr_src_q <= intr_src;
 400:     end
 401:   end
 402: 
 403:   assign intr_assert = ~intr_src_q & intr_src;
 404: 
 405: 
 406:   assign intr_prog_empty_o = reg2hw.intr_enable.prog_empty.q & reg2hw.intr_state.prog_empty.q;
 407:   assign intr_prog_lvl_o = reg2hw.intr_enable.prog_lvl.q & reg2hw.intr_state.prog_lvl.q;
 408:   assign intr_rd_full_o = reg2hw.intr_enable.rd_full.q & reg2hw.intr_state.rd_full.q;
 409:   assign intr_rd_lvl_o = reg2hw.intr_enable.rd_lvl.q & reg2hw.intr_state.rd_lvl.q;
 410:   assign intr_op_done_o = reg2hw.intr_enable.op_done.q & reg2hw.intr_state.op_done.q;
 411:   assign intr_op_error_o = reg2hw.intr_enable.op_error.q & reg2hw.intr_state.op_error.q;
 412: 
 413:   assign hw2reg.intr_state.prog_empty.d  = 1'b1;
 414:   assign hw2reg.intr_state.prog_empty.de = intr_assert[3]  |
 415:                                            (reg2hw.intr_test.prog_empty.qe  &
 416:                                            reg2hw.intr_test.prog_empty.q);
 417: 
 418:   assign hw2reg.intr_state.prog_lvl.d  = 1'b1;
 419:   assign hw2reg.intr_state.prog_lvl.de = intr_assert[2]  |
 420:                                          (reg2hw.intr_test.prog_lvl.qe  &
 421:                                          reg2hw.intr_test.prog_lvl.q);
 422: 
 423:   assign hw2reg.intr_state.rd_full.d  = 1'b1;
 424:   assign hw2reg.intr_state.rd_full.de = intr_assert[1] |
 425:                                         (reg2hw.intr_test.rd_full.qe  &
 426:                                         reg2hw.intr_test.rd_full.q);
 427: 
 428:   assign hw2reg.intr_state.rd_lvl.d  = 1'b1;
 429:   assign hw2reg.intr_state.rd_lvl.de =  intr_assert[0] |
 430:                                        (reg2hw.intr_test.rd_lvl.qe  &
 431:                                        reg2hw.intr_test.rd_lvl.q);
 432: 
 433: 
 434:   assign hw2reg.intr_state.op_done.d  = 1'b1;
 435:   assign hw2reg.intr_state.op_done.de = |ctrl_done  |
 436:                                         (reg2hw.intr_test.op_done.qe  &
 437:                                         reg2hw.intr_test.op_done.q);
 438: 
 439:   assign hw2reg.intr_state.op_error.d  = 1'b1;
 440:   assign hw2reg.intr_state.op_error.de = |ctrl_err  |
 441:                                         (reg2hw.intr_test.op_error.qe  &
 442:                                         reg2hw.intr_test.op_error.q);
 443: 
 444: 
 445: 
 446:   // Unused bits
 447:   logic [DataBitWidth-1:0] unused_byte_sel;
 448:   logic [31-AddrW:0] unused_higher_addr_bits;
 449:   logic [31:0] unused_scratch;
 450: 
 451: 
 452:   // Unused signals
 453:   assign unused_byte_sel = reg2hw.addr.q[DataBitWidth-1:0];
 454:   assign unused_higher_addr_bits = reg2hw.addr.q[31:AddrW];
 455:   assign unused_scratch = reg2hw.scratch;
 456: 
 457: 
 458:   // Assertions
 459: 
 460:   `ASSERT_KNOWN(TlDValidKnownO_A,       tl_o.d_valid     )
 461:   `ASSERT_KNOWN(TlAReadyKnownO_A,       tl_o.a_ready     )
 462:   `ASSERT_KNOWN(FlashKnownO_A,          {flash_o.req, flash_o.rd, flash_o.prog, flash_o.pg_erase,
 463:                                          flash_o.bk_erase})
 464:   `ASSERT_KNOWN_IF(FlashAddrKnown_A,    flash_o.addr, flash_o.req)
 465:   `ASSERT_KNOWN_IF(FlashProgKnown_A,    flash_o.prog_data, flash_o.prog & flash_o.req)
 466:   `ASSERT_KNOWN(IntrProgEmptyKnownO_A,  intr_prog_empty_o)
 467:   `ASSERT_KNOWN(IntrProgLvlKnownO_A,    intr_prog_lvl_o  )
 468:   `ASSERT_KNOWN(IntrProgRdFullKnownO_A, intr_rd_full_o   )
 469:   `ASSERT_KNOWN(IntrRdLvlKnownO_A,      intr_rd_lvl_o    )
 470:   `ASSERT_KNOWN(IntrOpDoneKnownO_A,     intr_op_done_o   )
 471:   `ASSERT_KNOWN(IntrOpErrorKnownO_A,    intr_op_error_o  )
 472: 
 473: endmodule
 474: