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