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: