hw/ip/prim_generic/rtl/prim_generic_flash.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: // prim flash module - Emulated using memory
   6: //
   7: 
   8: module prim_generic_flash #(
   9:   parameter int PagesPerBank = 256, // pages per bank
  10:   parameter int WordsPerPage = 256, // words per page
  11:   parameter int DataWidth   = 32,   // bits per word
  12:   parameter bit SkipInit = 1,       // this is an option to reset flash to all F's at reset
  13: 
  14:   // Derived parameters
  15:   localparam int PageW = $clog2(PagesPerBank),
  16:   localparam int WordW = $clog2(WordsPerPage),
  17:   localparam int AddrW = PageW + WordW
  18: ) (
  19:   input                        clk_i,
  20:   input                        rst_ni,
  21:   input                        req_i,
  22:   input                        host_req_i,
  23:   input [AddrW-1:0]            host_addr_i,
  24:   input                        rd_i,
  25:   input                        prog_i,
  26:   input                        pg_erase_i,
  27:   input                        bk_erase_i,
  28:   input [AddrW-1:0]            addr_i,
  29:   input [DataWidth-1:0]        prog_data_i,
  30:   output logic                 host_req_rdy_o,
  31:   output logic                 host_req_done_o,
  32:   output logic                 rd_done_o,
  33:   output logic                 prog_done_o,
  34:   output logic                 erase_done_o,
  35:   output logic [DataWidth-1:0] rd_data_o,
  36:   output logic                 init_busy_o
  37: );
  38: 
  39:   // Emulated flash macro values
  40:   localparam int ReadCycles = 1;
  41:   localparam int ProgCycles = 50;
  42:   localparam int PgEraseCycles = 200;
  43:   localparam int BkEraseCycles = 2000;
  44: 
  45:   // Locally derived values
  46:   localparam int WordsPerBank  = PagesPerBank * WordsPerPage;
  47: 
  48:   typedef enum logic [2:0] {
  49:     StReset    = 'h0,
  50:     StInit     = 'h1,
  51:     StIdle     = 'h2,
  52:     StHostRead = 'h3,
  53:     StRead     = 'h4,
  54:     StProg     = 'h5,
  55:     StErase    = 'h6
  56:   } state_e;
  57: 
  58:   state_e st_next, st;
  59: 
  60:   logic [31:0]              time_cnt;
  61:   logic [31:0]              index_cnt;
  62:   logic                     time_cnt_inc ,time_cnt_clr, time_cnt_set1;
  63:   logic                     index_cnt_inc, index_cnt_clr;
  64:   logic [31:0]              index_limit, index_limit_next;
  65:   logic [31:0]              time_limit, time_limit_next;
  66:   logic                     prog_pend, prog_pend_next;
  67:   logic                     mem_req;
  68:   logic                     mem_wr;
  69:   logic [AddrW-1:0]         mem_addr;
  70:   logic [DataWidth-1:0]     held_data;
  71:   logic [DataWidth-1:0]     mem_wdata;
  72:   logic                     hold_rd_cmd;
  73:   logic [AddrW-1:0]         held_rd_addr;
  74: 
  75:   always_ff @(posedge clk_i or negedge rst_ni) begin
  76:     if (!rst_ni) st <= StReset;
  77:     else st <= st_next;
  78:   end
  79: 
  80:   always_ff @(posedge clk_i or negedge rst_ni) begin
  81:     if (!rst_ni) held_rd_addr <= '0;
  82:     else if (hold_rd_cmd) held_rd_addr <= host_addr_i;
  83:   end
  84: 
  85:   // prog_pend is necessary to emulate flash behavior that a bit written to 0 cannot be written
  86:   // back to 1 without an erase
  87:   always_ff @(posedge clk_i or negedge rst_ni) begin
  88:     if (!rst_ni) begin
  89:       time_cnt <= 32'h0;
  90:       index_cnt <= 32'h0;
  91:       time_limit <= 32'h0;
  92:       index_limit <= 32'h0;
  93:       held_data <= 'h0;
  94:       prog_pend <= 1'h0;
  95:     end else begin
  96: 
  97:       time_limit <= time_limit_next;
  98:       index_limit <= index_limit_next;
  99:       prog_pend <= prog_pend_next;
 100: 
 101:       if (time_cnt_inc) time_cnt <= time_cnt + 1'b1;
 102:       else if (time_cnt_set1) time_cnt <= 32'h1;
 103:       else if (time_cnt_clr) time_cnt <= 32'h0;
 104: 
 105:       if (index_cnt_inc) index_cnt <= index_cnt + 1'b1;
 106:       else if (index_cnt_clr) index_cnt <= 32'h0;
 107: 
 108:       if (prog_pend) held_data <= rd_data_o;
 109: 
 110:     end
 111:   end
 112: 
 113: 
 114:   always_comb begin
 115:     st_next          = st;
 116:     index_limit_next = index_limit;
 117:     time_limit_next  = time_limit;
 118:     prog_pend_next   = prog_pend;
 119:     mem_req          = 'h0;
 120:     mem_wr           = 'h0;
 121:     mem_addr         = 'h0;
 122:     mem_wdata        = 'h0;
 123:     time_cnt_inc     = 1'h0;
 124:     time_cnt_clr     = 1'h0;
 125:     time_cnt_set1    = 1'h0;
 126:     index_cnt_inc    = 1'h0;
 127:     index_cnt_clr    = 1'h0;
 128:     rd_done_o        = 1'h0;
 129:     prog_done_o      = 1'h0;
 130:     erase_done_o     = 1'h0;
 131:     init_busy_o      = 1'h0;
 132:     host_req_rdy_o   = 1'h1;
 133:     host_req_done_o  = 1'h0;
 134:     hold_rd_cmd      = 1'h0;
 135: 
 136:     unique case (st)
 137:       StReset: begin
 138:         host_req_rdy_o = 1'b0;
 139:         init_busy_o = 1'h1;
 140:         st_next = StInit;
 141:       end
 142:       // Emulate flash power up to all 1's
 143:       // This implies this flash will not survive a reset
 144:       // Might need a different RESET for FPGA purposes
 145:       StInit: begin
 146:         host_req_rdy_o = 1'b0;
 147:         init_busy_o = 1'h1;
 148:         if (index_cnt < WordsPerBank && !SkipInit) begin
 149:           st_next = StInit;
 150:           index_cnt_inc = 1'b1;
 151:           mem_req = 1'h0;
 152:           mem_wr  = 1'h0;
 153:           mem_addr = index_cnt[AddrW-1:0];
 154:           mem_wdata = {DataWidth{1'b1}};
 155:         end else begin
 156:           st_next = StIdle;
 157:           index_cnt_clr = 1'b1;
 158:         end
 159:       end
 160:       StIdle: begin
 161:         // host reads will always take priority over controller operations.  However ongoing
 162:         // controller operations will not be interrupted
 163:         if (host_req_i) begin
 164:           // reads begin immediately
 165:           hold_rd_cmd = 1'b1;
 166:           mem_addr = host_addr_i;
 167:           mem_req = 1'b1;
 168:           time_cnt_inc = 1'b1;
 169:           st_next = StHostRead;
 170:         end else if (req_i && rd_i) begin
 171:           st_next = StRead;
 172:         end else if (req_i && prog_i) begin
 173:           st_next = StRead;
 174:           prog_pend_next = 1'b1;
 175:         end else if (req_i && pg_erase_i) begin
 176:           st_next = StErase;
 177:           index_limit_next = WordsPerPage;
 178:           time_limit_next = PgEraseCycles;
 179:         end else if (req_i && bk_erase_i) begin
 180:           st_next = StErase;
 181:           index_limit_next = WordsPerBank;
 182:           time_limit_next = BkEraseCycles;
 183:         end
 184:       end
 185:       StHostRead: begin
 186:         mem_addr = held_rd_addr;
 187:         if (time_cnt < ReadCycles) begin
 188:           mem_req = 1'b1;
 189:           time_cnt_inc = 1'b1;
 190:           host_req_rdy_o = 1'b0;
 191:         end else begin
 192:           host_req_done_o = 1'b1; //finish up transaction
 193: 
 194:           // if another request already pending
 195:           if (host_req_i) begin
 196:             hold_rd_cmd = 1'b1;
 197:             mem_addr = host_addr_i;
 198:             mem_req = 1'b1;
 199:             time_cnt_set1 = 1'b1;
 200:             st_next = StHostRead;
 201:           end else begin
 202:             time_cnt_clr = 1'b1;
 203:             st_next = StIdle;
 204:           end
 205:         end
 206:       end
 207:       StRead: begin
 208:         host_req_rdy_o = 1'b0;
 209:         mem_addr = addr_i;
 210:         if (time_cnt < ReadCycles) begin
 211:           mem_req = 1'b1;
 212:           time_cnt_inc = 1'b1;
 213:         end else begin
 214:           prog_pend_next = 1'b0;
 215:           rd_done_o  = 1'b1;
 216:           time_cnt_clr = 1'b1;
 217:           st_next = prog_pend ? StProg : StIdle;
 218:         end
 219:       end
 220:       StProg: begin
 221:         host_req_rdy_o = 1'b0;
 222:         mem_addr = addr_i;
 223: 
 224:         // if data is already 0, cannot program to 1 without erase
 225:         mem_wdata = prog_data_i & held_data;
 226:         if (time_cnt < ProgCycles) begin
 227:           mem_req = 1'b1;
 228:           mem_wr = 1'b1;
 229:           time_cnt_inc = 1'b1;
 230:         end else begin
 231:           st_next = StIdle;
 232:           prog_done_o  = 1'b1;
 233:           time_cnt_clr = 1'b1;
 234:         end
 235:       end
 236:       StErase: begin
 237:         host_req_rdy_o = 1'b0;
 238: 
 239:         // Actual erasing of the page
 240:         if (index_cnt < index_limit || time_cnt < time_limit) begin
 241:           mem_req = 1'b1;
 242:           mem_wr = 1'b1;
 243:           mem_wdata = {DataWidth{1'b1}};
 244: 
 245:           mem_addr = addr_i + index_cnt[AddrW-1:0];
 246:           time_cnt_inc = (time_cnt < time_limit);
 247:           index_cnt_inc = (index_cnt < index_limit);
 248:         end else begin
 249:           st_next = StIdle;
 250:           erase_done_o = 1'b1;
 251:           time_cnt_clr = 1'b1;
 252:           index_cnt_clr = 1'b1;
 253:         end
 254:       end
 255:       default: begin
 256:         host_req_rdy_o = 1'b0;
 257:         st_next = StIdle;
 258:       end
 259:     endcase // unique case (st)
 260:   end // always_comb
 261: 
 262:   prim_ram_1p #(
 263:     .Width(DataWidth),
 264:     .Depth(WordsPerBank),
 265:     .DataBitsPerMask(DataWidth)
 266:   ) u_mem (
 267:     .clk_i,
 268:     .rst_ni,
 269:     .req_i    (mem_req),
 270:     .write_i  (mem_wr),
 271:     .addr_i   (mem_addr),
 272:     .wdata_i  (mem_wdata),
 273:     .wmask_i  ({DataWidth{1'b1}}),
 274:     .rvalid_o (),
 275:     .rdata_o  (rd_data_o)
 276:   );
 277: 
 278: 
 279: 
 280: endmodule // prim_generic_flash
 281: