hw/ip/flash_ctrl/rtl/flash_mp.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 Memory Protection
   6: //
   7: 
   8: module flash_mp #(
   9:   parameter int MpRegions = 8,
  10:   parameter int NumBanks = 2,
  11:   parameter int AllPagesW = 16,
  12:   localparam int TotalRegions = MpRegions+1,
  13:   localparam int BankW = $clog2(NumBanks)
  14: ) (
  15:   input clk_i,
  16:   input rst_ni,
  17: 
  18:   // configuration from sw
  19:   input flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_region_cfg_mreg_t [TotalRegions-1:0] region_cfgs_i,
  20:   input flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_bank_cfg_mreg_t [NumBanks-1:0] bank_cfgs_i,
  21: 
  22:   // interface signals to/from *_ctrl
  23:   input req_i,
  24:   input [AllPagesW-1:0] req_addr_i,
  25:   input addr_ovfl_i,
  26:   input [BankW-1:0] req_bk_i,
  27:   input rd_i,
  28:   input prog_i,
  29:   input pg_erase_i,
  30:   input bk_erase_i,
  31:   output logic rd_done_o,
  32:   output logic prog_done_o,
  33:   output logic erase_done_o,
  34:   output logic error_o,
  35:   output logic [AllPagesW-1:0] err_addr_o,
  36:   output logic [BankW-1:0] err_bank_o,
  37: 
  38:   // interface signals to/from flash_phy
  39:   output logic req_o,
  40:   output logic rd_o,
  41:   output logic prog_o,
  42:   output logic pg_erase_o,
  43:   output logic bk_erase_o,
  44:   input rd_done_i,
  45:   input prog_done_i,
  46:   input erase_done_i
  47: 
  48: );
  49:   import flash_ctrl_pkg::*;
  50: 
  51:   // There could be multiple region matches due to region overlap
  52:   logic [AllPagesW-1:0] region_end[TotalRegions];
  53:   logic [TotalRegions-1:0] region_match;
  54:   logic [TotalRegions-1:0] region_sel;
  55:   logic [TotalRegions-1:0] rd_en;
  56:   logic [TotalRegions-1:0] prog_en;
  57:   logic [TotalRegions-1:0] pg_erase_en;
  58:   logic [NumBanks-1:0] bk_erase_en;
  59:   logic final_rd_en;
  60:   logic final_prog_en;
  61:   logic final_pg_erase_en;
  62:   logic final_bk_erase_en;
  63: 
  64:   // Lower indices always have priority
  65:   assign region_sel[0] = region_match[0];
  66:   for (genvar i = 1; i < TotalRegions; i++) begin: gen_region_priority
  67:     assign region_sel[i] = region_match[i] & ~|region_match[i-1:0];
  68:   end
  69: 
  70:   // check for region match
  71:   always_comb begin
  72:     for (int unsigned i = 0; i < TotalRegions; i++) begin: region_comps
  73:       region_end[i] = region_cfgs_i[i].base.q + region_cfgs_i[i].size.q;
  74:       region_match[i] = req_addr_i >= region_cfgs_i[i].base.q &
  75:                         req_addr_i <  region_end[i] &
  76:                         req_i;
  77: 
  78:       rd_en[i] = region_cfgs_i[i].en.q & region_cfgs_i[i].rd_en.q & region_sel[i];
  79:       prog_en[i] = region_cfgs_i[i].en.q & region_cfgs_i[i].prog_en.q & region_sel[i];
  80:       pg_erase_en[i] = region_cfgs_i[i].en.q & region_cfgs_i[i].erase_en.q & region_sel[i];
  81:     end
  82:   end
  83: 
  84:   // check for bank erase
  85:   always_comb begin
  86:     for (int unsigned i = 0; i < NumBanks; i++) begin: bank_comps
  87:       bk_erase_en[i] = (req_bk_i == i) & bank_cfgs_i[i].q;
  88:     end
  89:   end
  90: 
  91:   assign final_rd_en = rd_i & |rd_en;
  92:   assign final_prog_en = prog_i & |prog_en;
  93:   assign final_pg_erase_en = pg_erase_i & |pg_erase_en;
  94:   assign final_bk_erase_en = bk_erase_i & |bk_erase_en;
  95: 
  96:   assign rd_o = req_i & final_rd_en;
  97:   assign prog_o = req_i & final_prog_en;
  98:   assign pg_erase_o = req_i & final_pg_erase_en;
  99:   assign bk_erase_o = req_i & final_bk_erase_en;
 100:   assign req_o = rd_o | prog_o | pg_erase_o | bk_erase_o;
 101: 
 102:   logic txn_err;
 103:   logic txn_ens;
 104:   logic no_allowed_txn;
 105:   assign txn_ens = final_rd_en | final_prog_en | final_pg_erase_en | final_bk_erase_en;
 106:   // if incoming address overflowed or no transaction enbales, error back
 107:   assign no_allowed_txn = req_i & (addr_ovfl_i | ~txn_ens);
 108: 
 109:   // return done and error the next cycle
 110:   always_ff @(posedge clk_i or negedge rst_ni) begin
 111:     if (!rst_ni) begin
 112:       txn_err <= 1'b0;
 113:       err_addr_o <= '0;
 114:       err_bank_o <= '0;
 115:     end else if (txn_err) begin
 116:       txn_err <= 1'b0;
 117:     end else if (no_allowed_txn) begin
 118:       txn_err <= 1'b1;
 119:       err_addr_o <= req_addr_i;
 120:       err_bank_o <= req_bk_i;
 121:     end
 122:   end
 123: 
 124:   assign rd_done_o = rd_done_i | txn_err;
 125:   assign prog_done_o = prog_done_i | txn_err;
 126:   assign erase_done_o = erase_done_i | txn_err;
 127:   assign error_o = txn_err;
 128: 
 129:   //////////////////////////////////////////////
 130:   // Assertions, Assumptions, and Coverpoints //
 131:   //////////////////////////////////////////////
 132: 
 133:   // Bank erase enable should always be one-hot.  We cannot erase multiple banks
 134:   // at the same time
 135:   `ASSERT(bkEraseEnOnehot_a, (req_o & bk_erase_o) |-> $onehot(bk_erase_en), clk_i, !rst_ni)
 136:   // Requests can only happen one at a time
 137:   `ASSERT(requestTypesOnehot_a, req_o |-> $onehot({rd_o, prog_o, pg_erase_o, bk_erase_o}),
 138:                                                     clk_i, !rst_ni)
 139: 
 140: endmodule // flash_erase_ctrl
 141: