hw/vendor/lowrisc_ibex/rtl/ibex_pmp.sv Cov: 39.6%
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: module ibex_pmp #(
6: // Granularity of NAPOT access,
7: // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
8: parameter int unsigned PMPGranularity = 0,
9: // Number of access channels (e.g. i-side + d-side)
10: parameter int unsigned PMPNumChan = 2,
11: // Number of implemented regions
12: parameter int unsigned PMPNumRegions = 4
13: ) (
14: // Clock and Reset
15: input logic clk_i,
16: input logic rst_ni,
17:
18: // Interface to CSRs
19: input ibex_pkg::pmp_cfg_t csr_pmp_cfg_i [PMPNumRegions],
20: input logic [33:0] csr_pmp_addr_i [PMPNumRegions],
21:
22: input ibex_pkg::priv_lvl_e priv_mode_i [PMPNumChan],
23: // Access checking channels
24: input logic [33:0] pmp_req_addr_i [PMPNumChan],
25: input ibex_pkg::pmp_req_e pmp_req_type_i [PMPNumChan],
26: output logic pmp_req_err_o [PMPNumChan]
27:
28: );
29:
30: import ibex_pkg::*;
31:
32: // Access Checking Signals
33: logic [33:0] region_start_addr [PMPNumRegions];
34: logic [33:PMPGranularity+2] region_addr_mask [PMPNumRegions];
35: logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_high;
36: logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_low;
37: logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_both;
38: logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_perm_check;
39: logic [PMPNumChan-1:0][PMPNumRegions-1:0] machine_access_fault;
40: logic [PMPNumChan-1:0][PMPNumRegions-1:0] user_access_allowed;
41: logic [PMPNumChan-1:0] access_fault;
42:
43:
44: // ---------------
45: // Access checking
46: // ---------------
47:
48: for (genvar r = 0; r < PMPNumRegions; r++) begin : g_addr_exp
49: // Start address for TOR matching
50: if (r == 0) begin : g_entry0
51: assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? 34'h000000000 :
52: csr_pmp_addr_i[r];
53: end else begin : g_oth
54: assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? csr_pmp_addr_i[r-1] :
55: csr_pmp_addr_i[r];
56: end
57: // Address mask for NA matching
58: for (genvar b = PMPGranularity+2; b < 34; b++) begin : g_bitmask
59: if (b == PMPGranularity+2) begin : g_bit0
60: // Always mask bit (G+2) for NAPOT
61: assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT);
62: end else begin : g_others
63: // We will mask this bit if it is within the programmed granule
64: // i.e. addr = yyyy 0111
65: // ^
66: // | This bit pos is the top of the mask, all lower bits set
67: // thus mask = 1111 0000
68: assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT) |
69: ~&csr_pmp_addr_i[r][b-1:PMPGranularity+2];
70: end
71: end
72: end
73:
74: for (genvar c = 0; c < PMPNumChan; c++) begin : g_access_check
75: for (genvar r = 0; r < PMPNumRegions; r++) begin : g_regions
76: // TOR Region high/low matching is reused for all match types
77: assign region_match_low[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] >=
78: // Comparators are sized according to granularity
79: (region_start_addr[r][33:PMPGranularity+2] &
80: region_addr_mask[r]));
81: assign region_match_high[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] <=
82: csr_pmp_addr_i[r][33:PMPGranularity+2]);
83: assign region_match_both[c][r] = region_match_low[c][r] & region_match_high[c][r] &
84: (csr_pmp_cfg_i[r].mode != PMP_MODE_OFF);
85: // Check specific required permissions
86: assign region_perm_check[c][r] =
87: ((pmp_req_type_i[c] == PMP_ACC_EXEC) & csr_pmp_cfg_i[r].exec) |
88: ((pmp_req_type_i[c] == PMP_ACC_WRITE) & csr_pmp_cfg_i[r].write) |
89: ((pmp_req_type_i[c] == PMP_ACC_READ) & csr_pmp_cfg_i[r].read);
90: // In machine mode, any match to a locked region without sufficient permissions is a fault
91: assign machine_access_fault[c][r] = region_match_both[c][r] & csr_pmp_cfg_i[r].lock &
92: ~region_perm_check[c][r];
93: // In any other mode, any access should fault unless is matches a region
94: assign user_access_allowed[c][r] = region_match_both[c][r] & region_perm_check[c][r];
95: end
96: assign access_fault[c] = (priv_mode_i[c] == PRIV_LVL_M) ? |machine_access_fault[c] :
97: ~|user_access_allowed[c];
98:
99: assign pmp_req_err_o[c] = access_fault[c];
100: end
101:
102: endmodule
103: