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