../src/lowrisc_ip_flash_ctrl_0.1/rtl/flash_phy_core.sv Cov: 98.5%

   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 Core Module
   6: //
   7: //
   8: // This module wraps every single flash bank and contains most of the region attribute,
   9: // scramble, ECC, security and arbitration logic.
  10: // Most of the items are TODO, at the moment only arbitration logic exists.
  11: 
  12: module flash_phy_core import flash_phy_pkg::*; #(
  13:   parameter bit SkipInit     = 1   // this is an option to reset flash to all F's at reset
  14: ) (
  15:   input                        clk_i,
  16:   input                        rst_ni,
  17:   input                        host_req_i, // host request - read only
  18:   input [BankAddrW-1:0]        host_addr_i,
  19:   input                        req_i,      // controller request
  20:   input                        rd_i,
  21:   input                        prog_i,
  22:   input                        pg_erase_i,
  23:   input                        bk_erase_i,
  24:   input [BankAddrW-1:0]        addr_i,
  25:   input [BusWidth-1:0]         prog_data_i,
  26:   output logic                 host_req_rdy_o,
  27:   output logic                 host_req_done_o,
  28:   output logic                 rd_done_o,
  29:   output logic                 prog_done_o,
  30:   output logic                 erase_done_o,
  31:   output logic [BusWidth-1:0]  rd_data_o,
  32:   output logic                 init_busy_o
  33: );
  34: 
  35:   typedef enum logic [1:0] {
  36:     StIdle,
  37:     StHostRead,
  38:     StCtrlRead,
  39:     StCtrl
  40:   } arb_state_e;
  41: 
  42:   arb_state_e state_q, state_d;
  43: 
  44:   // request signals to flash macro
  45:   logic [PhyOps-1:0] reqs;
  46: 
  47:   // host select for address
  48:   logic host_sel;
  49: 
  50:   // qualifier for host responses
  51:   logic host_rsp;
  52: 
  53:   // controller response valid
  54:   logic ctrl_rsp_vld;
  55: 
  56:   // ack to phy operations from flash macro
  57:   logic ack;
  58: 
  59:   // interface with flash macro
  60:   logic [BankAddrW-1:0] muxed_addr;
  61: 
  62:   // entire read stage is idle, inclusive of all stages
  63:   logic rd_stage_idle;
  64: 
  65:   // the read stage is ready to accept a new transaction
  66:   logic rd_stage_rdy;
  67: 
  68:   // the read stage has valid data return
  69:   logic rd_stage_data_valid;
  70: 
  71: 
  72:   assign host_req_done_o = host_rsp & rd_stage_data_valid;
  73: 
  74:   always_ff @(posedge clk_i or negedge rst_ni) begin
  75:     if (!rst_ni) begin
  76:       state_q <= StIdle;
  77:     end else begin
  78:       state_q <= state_d;
  79:     end
  80:   end
  81: 
  82:   always_comb begin
  83:     state_d = state_q;
  84: 
  85:     reqs = '0;
  86:     host_sel = 1'b0;
  87:     host_rsp = 1'b0;
  88:     ctrl_rsp_vld = 1'b0;
  89:     host_req_rdy_o = 1'b0;
  90: 
  91:     unique case (state_q)
  92:       StIdle: begin
  93:         if (host_req_i) begin
  94:           reqs[PhyRead] = 1'b1;
  95:           host_sel = 1'b1;
  96:           host_req_rdy_o = rd_stage_rdy;
  97:           state_d = host_req_rdy_o ? StHostRead : state_q;
  98:         end else if (req_i && rd_i) begin
  99:           reqs[PhyRead] = 1'b1;
 100:           state_d = rd_stage_rdy ? StCtrlRead : state_q;
 101:         end else if (req_i) begin
 102:           reqs[PhyProg] = prog_i;
 103:           reqs[PhyPgErase] = pg_erase_i;
 104:           reqs[PhyBkErase] = bk_erase_i;
 105:           state_d = StCtrl;
 106:         end
 107:       end
 108: 
 109:       // The host priority may be dangerous, as it could lock-out controller initiated
 110:       // operations. Need to think about whether this should be made round-robin.
 111:       StHostRead: begin
 112:         host_rsp = 1'b1;
 113:         if (host_req_i) begin
 114:           reqs[PhyRead] = 1'b1;
 115:           host_sel = 1'b1;
 116:           host_req_rdy_o = rd_stage_rdy;
 117:         end else if (rd_stage_idle) begin
 118:           // once in pipelined reads, need to wait for the entire pipeline
 119:           // to drain before returning to perform other operations
 120:           state_d = StIdle;
 121:         end
 122:       end
 123: 
 124:       // Controller reads are very slow.
 125:       // Need to update controller end to take advantage of read pipeline.
 126:       // Once that is done, the two read states can merge.
 127:       StCtrlRead: begin
 128:         if (rd_stage_data_valid) begin
 129:           ctrl_rsp_vld = 1'b1;
 130:           state_d = StIdle;
 131:         end
 132:       end
 133: 
 134:       // other controller operations directly interface with flash
 135:       StCtrl: begin
 136:         if (ack) begin
 137:           ctrl_rsp_vld = 1'b1;
 138:           state_d = StIdle;
 139:         end
 140:       end
 141: 
 142:       // state is terminal, no flash transactions are ever accepted again
 143:       // until reboot
 144:       default:;
 145:     endcase // unique case (state_q)
 146:   end
 147: 
 148:   assign muxed_addr = host_sel ? host_addr_i : addr_i;
 149:   assign rd_done_o = ctrl_rsp_vld & rd_i;
 150:   assign prog_done_o = ctrl_rsp_vld & prog_i;
 151:   assign erase_done_o = ctrl_rsp_vld & (pg_erase_i | bk_erase_i);
 152: 
 153:   ////////////////////////
 154:   // read pipeline
 155:   ////////////////////////
 156: 
 157:   logic flash_rd_req;
 158:   logic [DataWidth-1:0] flash_rdata;
 159: 
 160:   flash_phy_rd i_rd (
 161:     .clk_i,
 162:     .rst_ni,
 163:     .req_i(reqs[PhyRead]),
 164:     .prog_i(reqs[PhyProg]),
 165:     .pg_erase_i(reqs[PhyPgErase]),
 166:     .bk_erase_i(reqs[PhyBkErase]),
 167:     .addr_i(muxed_addr),
 168:     .rdy_o(rd_stage_rdy),
 169:     .data_valid_o(rd_stage_data_valid),
 170:     .data_o(rd_data_o),
 171:     .idle_o(rd_stage_idle),
 172:     .req_o(flash_rd_req),
 173:     .ack_i(ack),
 174:     .data_i(flash_rdata)
 175:     );
 176: 
 177:   ////////////////////////
 178:   // program pipeline
 179:   ////////////////////////
 180: 
 181:   // Below code is temporary and does not account for scrambling
 182:   logic [DataWidth-1:0] prog_data;
 183: 
 184:   if (WidthMultiple == 1) begin : gen_single_prog_data
 185:     assign prog_data = prog_data_i;
 186:   end else begin : gen_prog_data
 187:     logic [WidthMultiple-1:0][BusWidth-1:0] prog_data_packed;
 188: 
 189:     always_comb begin
 190:       prog_data_packed = {DataWidth{1'b1}};
 191:       for (int i = 0; i < WidthMultiple; i++) begin
 192:         if (addr_i[0 +: WordSelW] == i) begin
 193:           prog_data_packed[i] = prog_data_i;
 194:         end
 195:       end
 196:     end
 197: 
 198:     assign prog_data = prog_data_packed;
 199:   end
 200: 
 201:   ////////////////////////
 202:   // scrambling / de-scrambling primitive
 203:   ////////////////////////
 204: 
 205: 
 206:   ////////////////////////
 207:   // Actual connection to flash phy
 208:   ////////////////////////
 209: 
 210:   // The actual flash macro wrapper
 211:   // The size of a page is fixed.  However, depending on the sizing of the word,
 212:   // the number of words within a page will change.
 213:   prim_flash #(
 214:     .PagesPerBank(PagesPerBank),
 215:     .WordsPerPage(WordsPerPage / WidthMultiple),
 216:     .DataWidth(DataWidth),
 217:     .SkipInit(SkipInit)
 218:   ) i_flash (
 219:     .clk_i,
 220:     .rst_ni,
 221:     .rd_i(flash_rd_req),
 222:     .prog_i(reqs[PhyProg]),
 223:     .pg_erase_i(reqs[PhyPgErase]),
 224:     .bk_erase_i(reqs[PhyBkErase]),
 225:     //.addr_i(muxed_addr[0 +: PageW + WordW]),
 226:     .addr_i(muxed_addr[BankAddrW-1:LsbAddrBit]),
 227:     .prog_data_i(prog_data),
 228:     .ack_o(ack),
 229:     .rd_data_o(flash_rdata),
 230:     .init_busy_o // TBD this needs to be looked at later. What init do we need to do,
 231:                  // and where does it make the most sense?
 232:   );
 233: 
 234:   /////////////////////////////////
 235:   // Assertions
 236:   /////////////////////////////////
 237: 
 238:   // requests to flash must always be one hot
 239:   `ASSERT(OneHotReqs_A, $onehot0(reqs))
 240:   `ASSERT_INIT(NoRemainder_A, AddrBitsRemain == 0)
 241:   `ASSERT_INIT(Pow2Multiple_A, $onehot(WidthMultiple))
 242: 
 243: endmodule // flash_phy_core
 244: