hw/ip/flash_ctrl/rtl/flash_phy.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: // Flash Phy Module
   6: //
   7: //
   8: // This module is an early attempt to model what a custom phy module might look like
   9: // Long term, it is expected this module will split into its own entity under hw/ip
  10: // with its own set of register that support technology / node specific flash settings
  11: // More of those details will be worked out with future partner engagement
  12: 
  13: module flash_phy #(
  14:   parameter int NumBanks = 2,
  15:   parameter int PagesPerBank = 256, // pages per bank
  16:   parameter int WordsPerPage = 256, // words per page
  17:   parameter int DataWidth   = 32, // bits per word
  18: 
  19:   //Do not touch - Derived parameters
  20:   localparam int BankW = $clog2(NumBanks),
  21:   localparam int PageW = $clog2(PagesPerBank),
  22:   localparam int WordW = $clog2(WordsPerPage),
  23:   localparam int AddrW = BankW + PageW + WordW
  24: ) (
  25:   input clk_i,
  26:   input rst_ni,
  27:   input host_req_i,
  28:   input [AddrW-1:0] host_addr_i,
  29:   output logic host_req_rdy_o,
  30:   output logic host_req_done_o,
  31:   output logic [DataWidth-1:0] host_rdata_o,
  32:   input flash_ctrl_pkg::flash_c2m_t flash_ctrl_i,
  33:   output flash_ctrl_pkg::flash_m2c_t flash_ctrl_o
  34: );
  35: 
  36:   // Flash macro outstanding refers to how many reads we allow a macro to move ahead of an
  37:   // in order blocking read. Since the data cannot be returned out of order, this simply
  38:   // does the reads in advance and store them in a FIFO
  39:   localparam int FlashMacroOustanding = 1;
  40:   localparam int SeqFifoDepth = FlashMacroOustanding * NumBanks;
  41: 
  42:   // flash_phy forwards incoming host transactions to the appropriate bank but is not aware of
  43:   // any controller / host arbitration within the bank.  This means it is possible for
  44:   // flash_phy to forward one transaction to bank N and another to bank N+1 only for bank N+1
  45:   // to finish its transaction first (if for example a controller operation were ongoing in bank
  46:   // N).
  47:   // This implies that even though transactions are received in-order, they can complete out of
  48:   // order.  Thus it is the responsibility of the flash_phy to sequence the responses correctly.
  49:   // For banks that have finished ahead of time, it is also important to hold its output until
  50:   // consumed.
  51: 
  52:   // host to flash_phy interface
  53:   logic [BankW-1:0]     host_bank_sel;
  54:   logic [BankW-1:0]     rsp_bank_sel;
  55:   logic [NumBanks-1:0]  host_req_rdy;
  56:   logic [NumBanks-1:0]  host_req_done;
  57:   logic [NumBanks-1:0]  host_rsp_avail;
  58:   logic [NumBanks-1:0]  host_rsp_vld;
  59:   logic [NumBanks-1:0]  host_rsp_ack;
  60:   logic [DataWidth-1:0] host_rsp_data [NumBanks];
  61:   logic                 seq_fifo_rdy;
  62:   logic                 seq_fifo_pending;
  63: 
  64: 
  65:   // flash_ctrl to flash_phy interface
  66:   logic [BankW-1:0]     ctrl_bank_sel;
  67:   logic [NumBanks-1:0]  rd_done;
  68:   logic [NumBanks-1:0]  prog_done;
  69:   logic [NumBanks-1:0]  erase_done;
  70:   logic [NumBanks-1:0]  init_busy;
  71: 
  72:   // common interface
  73:   logic [DataWidth-1:0] rd_data [NumBanks];
  74: 
  75:   // select which bank each is operating on
  76:   assign host_bank_sel = host_req_i ? host_addr_i[PageW + WordW +: BankW] : '0;
  77:   assign ctrl_bank_sel = flash_ctrl_i.addr[PageW + WordW +: BankW];
  78: 
  79:   // accept transaction if bank is ready and previous response NOT pending
  80:   assign host_req_rdy_o = host_req_rdy[host_bank_sel] & host_rsp_avail[host_bank_sel] &
  81:                           seq_fifo_rdy;
  82: 
  83:   assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
  84:   assign host_rdata_o = host_rsp_data[rsp_bank_sel];
  85: 
  86:   assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
  87:   assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
  88:   assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
  89:   assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
  90:   assign flash_ctrl_o.init_busy = |init_busy;
  91: 
  92:   // This fifo holds the expected return order
  93:   prim_fifo_sync #(
  94:       .Width  (BankW),
  95:       .Pass   (0),
  96:       .Depth  (SeqFifoDepth)
  97:     ) bank_sequence_fifo (
  98:       .clk_i,
  99:       .rst_ni,
 100:       .clr_i  (1'b0),
 101:       .wvalid (host_req_i & host_req_rdy_o),
 102:       .wready (seq_fifo_rdy),
 103:       .wdata  (host_bank_sel),
 104:       .depth  (),
 105:       .rvalid (seq_fifo_pending),
 106:       .rready (host_req_done_o),
 107:       .rdata  (rsp_bank_sel)
 108:     );
 109: 
 110:   for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_flash_banks
 111: 
 112:     // pop if the response came from the appropriate fifo
 113:     assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
 114: 
 115:     prim_fifo_sync #(
 116:       .Width  (DataWidth),
 117:       .Pass   (1'b1),
 118:       .Depth  (FlashMacroOustanding)
 119:     ) host_rsp_fifo (
 120:       .clk_i,
 121:       .rst_ni,
 122:       .clr_i  (1'b0),
 123:       .wvalid (host_req_done[bank]),
 124:       .wready (host_rsp_avail[bank]),
 125:       .wdata  (rd_data[bank]),
 126:       .depth  (),
 127:       .rvalid (host_rsp_vld[bank]),
 128:       .rready (host_rsp_ack[bank]),
 129:       .rdata  (host_rsp_data[bank])
 130:     );
 131: 
 132:     prim_flash #(
 133:       .PagesPerBank(PagesPerBank),
 134:       .WordsPerPage(WordsPerPage),
 135:       .DataWidth(DataWidth)
 136:     ) u_flash (
 137:       .clk_i,
 138:       .rst_ni,
 139:       .req_i(flash_ctrl_i.req & (ctrl_bank_sel == bank)),
 140:       .host_req_i(host_req_i & host_req_rdy_o & (host_bank_sel == bank)),
 141:       .host_addr_i(host_addr_i[0 +: PageW + WordW]),
 142:       .rd_i(flash_ctrl_i.rd),
 143:       .prog_i(flash_ctrl_i.prog),
 144:       .pg_erase_i(flash_ctrl_i.pg_erase),
 145:       .bk_erase_i(flash_ctrl_i.bk_erase),
 146:       .addr_i(flash_ctrl_i.addr[0 +: PageW + WordW]),
 147:       .prog_data_i(flash_ctrl_i.prog_data),
 148:       .host_req_rdy_o(host_req_rdy[bank]),
 149:       .host_req_done_o(host_req_done[bank]),
 150:       .rd_done_o(rd_done[bank]),
 151:       .prog_done_o(prog_done[bank]),
 152:       .erase_done_o(erase_done[bank]),
 153:       .rd_data_o(rd_data[bank]),
 154:       .init_busy_o(init_busy[bank])
 155:     );
 156:   end
 157: 
 158: endmodule // flash_phy
 159: