../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: