xref: /XiangShan/src/main/scala/xiangshan/backend/fu/PMP.scala (revision 8882eb685de93177da606ee717b5ec8e459a768a)
1b6982e83SLemover/***************************************************************************************
2e3da8badSTang Haojin* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3e3da8badSTang Haojin* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
4b6982e83SLemover* Copyright (c) 2020-2021 Peng Cheng Laboratory
5b6982e83SLemover*
6b6982e83SLemover* XiangShan is licensed under Mulan PSL v2.
7b6982e83SLemover* You can use this software according to the terms and conditions of the Mulan PSL v2.
8b6982e83SLemover* You may obtain a copy of Mulan PSL v2 at:
9b6982e83SLemover*          http://license.coscl.org.cn/MulanPSL2
10b6982e83SLemover*
11b6982e83SLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12b6982e83SLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13b6982e83SLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14b6982e83SLemover*
15b6982e83SLemover* See the Mulan PSL v2 for more details.
16b6982e83SLemover***************************************************************************************/
17b6982e83SLemover
18a15116bdSLemover// See LICENSE.SiFive for license details.
19a15116bdSLemover
20b6982e83SLemoverpackage xiangshan.backend.fu
21b6982e83SLemover
228891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
23b6982e83SLemoverimport chisel3._
24b6982e83SLemoverimport chisel3.util._
253c02ee8fSwakafaimport utility.MaskedRegMap.WritableMask
26b6982e83SLemoverimport xiangshan._
27b6982e83SLemoverimport xiangshan.backend.fu.util.HasCSRConst
28b6982e83SLemoverimport utils._
293c02ee8fSwakafaimport utility._
30b6982e83SLemoverimport xiangshan.cache.mmu.{TlbCmd, TlbExceptionBundle}
31075d4937Sjunxiong-jiimport freechips.rocketchip.rocket.CSRs
32b6982e83SLemover
3398c71602SJiawei Lintrait PMPConst extends HasPMParameters {
34b6982e83SLemover  val PMPOffBits = 2 // minimal 4bytes
35b6982e83SLemover  val CoarserGrain: Boolean = PlatformGrain > PMPOffBits
36b6982e83SLemover}
37b6982e83SLemover
3898c71602SJiawei Linabstract class PMPBundle(implicit val p: Parameters) extends Bundle with PMPConst
3998c71602SJiawei Linabstract class PMPModule(implicit val p: Parameters) extends Module with PMPConst
4098c71602SJiawei Linabstract class PMPXSModule(implicit p: Parameters) extends XSModule with PMPConst
41b6982e83SLemover
42b6982e83SLemoverclass PMPConfig(implicit p: Parameters) extends PMPBundle {
43b6982e83SLemover  val l = Bool()
44ca2f90a6SLemover  val c = Bool() // res(1), unuse in pmp
45ca2f90a6SLemover  val atomic = Bool() // res(0), unuse in pmp
46b6982e83SLemover  val a = UInt(2.W)
47b6982e83SLemover  val x = Bool()
48b6982e83SLemover  val w = Bool()
49b6982e83SLemover  val r = Bool()
50b6982e83SLemover
51ca2f90a6SLemover  def res: UInt = Cat(c, atomic) // in pmp, unused
52b6982e83SLemover  def off = a === 0.U
53b6982e83SLemover  def tor = a === 1.U
54b6982e83SLemover  def na4 = { if (CoarserGrain) false.B else a === 2.U }
55b6982e83SLemover  def napot = { if (CoarserGrain) a(1).asBool else a === 3.U }
56b6982e83SLemover  def off_tor = !a(1)
57b6982e83SLemover  def na4_napot = a(1)
58b6982e83SLemover
59b6982e83SLemover  def locked = l
60b6982e83SLemover  def addr_locked: Bool = locked
61b6982e83SLemover  def addr_locked(next: PMPConfig): Bool = locked || (next.locked && next.tor)
62ca2f90a6SLemover}
63b6982e83SLemover
6467ba96b4SYinan Xuobject PMPConfigUInt {
6567ba96b4SYinan Xu  def apply(
6667ba96b4SYinan Xu    l: Boolean = false,
6767ba96b4SYinan Xu    c: Boolean = false,
6867ba96b4SYinan Xu    atomic: Boolean = false,
6967ba96b4SYinan Xu    a: Int = 0,
7067ba96b4SYinan Xu    x: Boolean = false,
7167ba96b4SYinan Xu    w: Boolean = false,
7267ba96b4SYinan Xu    r: Boolean = false)(implicit p: Parameters): UInt = {
7367ba96b4SYinan Xu    var config = 0
7467ba96b4SYinan Xu    if (l) { config += (1 << 7) }
7567ba96b4SYinan Xu    if (c) { config += (1 << 6) }
7667ba96b4SYinan Xu    if (atomic) { config += (1 << 5) }
7767ba96b4SYinan Xu    if (a > 0) { config += (a << 3) }
7867ba96b4SYinan Xu    if (x) { config += (1 << 2) }
7967ba96b4SYinan Xu    if (w) { config += (1 << 1) }
8067ba96b4SYinan Xu    if (r) { config += (1 << 0) }
8167ba96b4SYinan Xu    config.U(8.W)
8267ba96b4SYinan Xu  }
8367ba96b4SYinan Xu}
8498c71602SJiawei Lintrait PMPReadWriteMethodBare extends PMPConst {
8598c71602SJiawei Lin  def match_mask(cfg: PMPConfig, paddr: UInt) = {
8698c71602SJiawei Lin    val match_mask_c_addr = Cat(paddr, cfg.a(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
8798c71602SJiawei Lin    Cat(match_mask_c_addr & ~(match_mask_c_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
88b6982e83SLemover  }
89b6982e83SLemover
90aa438b8eSHaoyuan Feng  def write_cfg_vec(mask: Vec[UInt], addr: Vec[UInt], index: Int, oldcfg: UInt)(cfgs: UInt): UInt = {
91b6982e83SLemover    val cfgVec = Wire(Vec(cfgs.getWidth/8, new PMPConfig))
92b6982e83SLemover    for (i <- cfgVec.indices) {
93ca2f90a6SLemover      val cfg_w_m_tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
94aa438b8eSHaoyuan Feng      val cfg_old_tmp = oldcfg((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
95aa438b8eSHaoyuan Feng      cfgVec(i) := cfg_old_tmp
96aa438b8eSHaoyuan Feng      when (!cfg_old_tmp.l) {
97ca2f90a6SLemover        cfgVec(i) := cfg_w_m_tmp
98ca2f90a6SLemover        cfgVec(i).w := cfg_w_m_tmp.w && cfg_w_m_tmp.r
99ca2f90a6SLemover        if (CoarserGrain) { cfgVec(i).a := Cat(cfg_w_m_tmp.a(1), cfg_w_m_tmp.a.orR) }
100b6982e83SLemover        when (cfgVec(i).na4_napot) {
10198c71602SJiawei Lin          mask(index + i) := match_mask(cfgVec(i), addr(index + i))
102b6982e83SLemover        }
103b6982e83SLemover      }
104ff1b5dbbSLemover    }
105b6982e83SLemover    cfgVec.asUInt
106b6982e83SLemover  }
107b6982e83SLemover
108b6982e83SLemover  def read_addr(cfg: PMPConfig)(addr: UInt): UInt = {
109b6982e83SLemover    val G = PlatformGrain - PMPOffBits
110b6982e83SLemover    require(G >= 0)
111b6982e83SLemover    if (G == 0) {
112b6982e83SLemover      addr
113b6982e83SLemover    } else if (G >= 2) {
114b6982e83SLemover      Mux(cfg.na4_napot, set_low_bits(addr, G-1), clear_low_bits(addr, G))
115b6982e83SLemover    } else { // G is 1
116b6982e83SLemover      Mux(cfg.off_tor, clear_low_bits(addr, G), addr)
117b6982e83SLemover    }
118b6982e83SLemover  }
11998c71602SJiawei Lin
12098c71602SJiawei Lin  def write_addr(next: PMPConfig, mask: UInt)(paddr: UInt, cfg: PMPConfig, addr: UInt): UInt = {
12198c71602SJiawei Lin    val locked = cfg.addr_locked(next)
12298c71602SJiawei Lin    mask := Mux(!locked, match_mask(cfg, paddr), mask)
12398c71602SJiawei Lin    Mux(!locked, paddr, addr)
124b6982e83SLemover  }
125b6982e83SLemover
126b6982e83SLemover  def set_low_bits(data: UInt, num: Int): UInt = {
127b6982e83SLemover    require(num >= 0)
128b6982e83SLemover    data | ((1 << num)-1).U
129b6982e83SLemover  }
130b6982e83SLemover
131b6982e83SLemover  /** mask the data's low num bits (lsb) */
132b6982e83SLemover  def clear_low_bits(data: UInt, num: Int): UInt = {
133b6982e83SLemover    require(num >= 0)
134b6982e83SLemover    // use Cat instead of & with mask to avoid "Signal Width" problem
135b6982e83SLemover    if (num == 0) { data }
136b6982e83SLemover    else { Cat(data(data.getWidth-1, num), 0.U(num.W)) }
137b6982e83SLemover  }
138ca2f90a6SLemover}
139ca2f90a6SLemover
14098c71602SJiawei Lintrait PMPReadWriteMethod extends PMPReadWriteMethodBare  { this: PMPBase =>
141aa438b8eSHaoyuan Feng  def write_cfg_vec(oldcfg: UInt)(cfgs: UInt): UInt = {
14298c71602SJiawei Lin    val cfgVec = Wire(Vec(cfgs.getWidth/8, new PMPConfig))
14398c71602SJiawei Lin    for (i <- cfgVec.indices) {
14498c71602SJiawei Lin      val cfg_w_tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
145aa438b8eSHaoyuan Feng      val cfg_old_tmp = oldcfg((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
146aa438b8eSHaoyuan Feng      cfgVec(i) := cfg_old_tmp
147aa438b8eSHaoyuan Feng      when (!cfg_old_tmp.l) {
14898c71602SJiawei Lin        cfgVec(i) := cfg_w_tmp
14998c71602SJiawei Lin        cfgVec(i).w := cfg_w_tmp.w && cfg_w_tmp.r
15098c71602SJiawei Lin        if (CoarserGrain) { cfgVec(i).a := Cat(cfg_w_tmp.a(1), cfg_w_tmp.a.orR) }
15198c71602SJiawei Lin      }
152ff1b5dbbSLemover    }
15398c71602SJiawei Lin    cfgVec.asUInt
15498c71602SJiawei Lin  }
15598c71602SJiawei Lin
15698c71602SJiawei Lin  /** In general, the PMP grain is 2**{G+2} bytes. when G >= 1, na4 is not selectable.
15798c71602SJiawei Lin   * When G >= 2 and cfg.a(1) is set(then the mode is napot), the bits addr(G-2, 0) read as zeros.
15898c71602SJiawei Lin   * When G >= 1 and cfg.a(1) is clear(the mode is off or tor), the addr(G-1, 0) read as zeros.
15998c71602SJiawei Lin   * The low OffBits is dropped
16098c71602SJiawei Lin   */
16198c71602SJiawei Lin  def read_addr(): UInt = {
16298c71602SJiawei Lin    read_addr(cfg)(addr)
16398c71602SJiawei Lin  }
16498c71602SJiawei Lin
16598c71602SJiawei Lin  /** addr for inside addr, drop OffBits with.
16698c71602SJiawei Lin   * compare_addr for inside addr for comparing.
16798c71602SJiawei Lin   * paddr for outside addr.
16898c71602SJiawei Lin   */
16998c71602SJiawei Lin  def write_addr(next: PMPConfig)(paddr: UInt): UInt = {
17098c71602SJiawei Lin    Mux(!cfg.addr_locked(next), paddr, addr)
17198c71602SJiawei Lin  }
17298c71602SJiawei Lin  def write_addr(paddr: UInt): UInt = {
17398c71602SJiawei Lin    Mux(!cfg.addr_locked, paddr, addr)
17498c71602SJiawei Lin  }
17598c71602SJiawei Lin}
17698c71602SJiawei Lin
177ca2f90a6SLemover/** PMPBase for CSR unit
178ca2f90a6SLemover  * with only read and write logic
179ca2f90a6SLemover  */
180ca2f90a6SLemoverclass PMPBase(implicit p: Parameters) extends PMPBundle with PMPReadWriteMethod {
181ca2f90a6SLemover  val cfg = new PMPConfig
18298c71602SJiawei Lin  val addr = UInt((PMPAddrBits - PMPOffBits).W)
183b6982e83SLemover
184b6982e83SLemover  def gen(cfg: PMPConfig, addr: UInt) = {
185b6982e83SLemover    require(addr.getWidth == this.addr.getWidth)
186b6982e83SLemover    this.cfg := cfg
187b6982e83SLemover    this.addr := addr
188b6982e83SLemover  }
189b6982e83SLemover}
190b6982e83SLemover
191ca2f90a6SLemovertrait PMPMatchMethod extends PMPConst { this: PMPEntry =>
192b6982e83SLemover  /** compare_addr is used to compare with input addr */
19398c71602SJiawei Lin  def compare_addr: UInt = ((addr << PMPOffBits) & ~(((1 << PlatformGrain) - 1).U(PMPAddrBits.W))).asUInt
194b6982e83SLemover
195b6982e83SLemover  /** size and maxSize are all log2 Size
19698c71602SJiawei Lin   * for dtlb, the maxSize is bPMXLEN which is 8
197b6982e83SLemover   * for itlb and ptw, the maxSize is log2(512) ?
198b6982e83SLemover   * but we may only need the 64 bytes? how to prevent the bugs?
19998c71602SJiawei Lin   * TODO: handle the special case that itlb & ptw & dcache access wider size than PMXLEN
200b6982e83SLemover   */
201b6982e83SLemover  def is_match(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last_pmp: PMPEntry): Bool = {
202b6982e83SLemover    Mux(cfg.na4_napot, napotMatch(paddr, lgSize, lgMaxSize),
203b6982e83SLemover      Mux(cfg.tor, torMatch(paddr, lgSize, lgMaxSize, last_pmp), false.B))
204b6982e83SLemover  }
205b6982e83SLemover
206b6982e83SLemover  /** generate match mask to help match in napot mode */
20798c71602SJiawei Lin  def match_mask(paddr: UInt): UInt = {
20898c71602SJiawei Lin    match_mask(cfg, paddr)
209b6982e83SLemover  }
210b6982e83SLemover
211ca2f90a6SLemover  def boundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int): Bool = {
212b6982e83SLemover    if (lgMaxSize <= PlatformGrain) {
213ca2f90a6SLemover      (paddr < compare_addr)
214b6982e83SLemover    } else {
215b6982e83SLemover      val highLess = (paddr >> lgMaxSize) < (compare_addr >> lgMaxSize)
216b6982e83SLemover      val highEqual = (paddr >> lgMaxSize) === (compare_addr >> lgMaxSize)
217b6982e83SLemover      val lowLess = (paddr(lgMaxSize-1, 0) | OneHot.UIntToOH1(lgSize, lgMaxSize))  < compare_addr(lgMaxSize-1, 0)
218b6982e83SLemover      highLess || (highEqual && lowLess)
219b6982e83SLemover    }
220b6982e83SLemover  }
221b6982e83SLemover
222ca2f90a6SLemover  def lowerBoundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int): Bool = {
223b6982e83SLemover    !boundMatch(paddr, lgSize, lgMaxSize)
224b6982e83SLemover  }
225b6982e83SLemover
226b6982e83SLemover  def higherBoundMatch(paddr: UInt, lgMaxSize: Int) = {
227b6982e83SLemover    boundMatch(paddr, 0.U, lgMaxSize)
228b6982e83SLemover  }
229b6982e83SLemover
230ca2f90a6SLemover  def torMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last_pmp: PMPEntry): Bool = {
231b6982e83SLemover    last_pmp.lowerBoundMatch(paddr, lgSize, lgMaxSize) && higherBoundMatch(paddr, lgMaxSize)
232b6982e83SLemover  }
233b6982e83SLemover
234b6982e83SLemover  def unmaskEqual(a: UInt, b: UInt, m: UInt) = {
235b6982e83SLemover    (a & ~m) === (b & ~m)
236b6982e83SLemover  }
237b6982e83SLemover
238b6982e83SLemover  def napotMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int) = {
239b6982e83SLemover    if (lgMaxSize <= PlatformGrain) {
240b6982e83SLemover      unmaskEqual(paddr, compare_addr, mask)
241b6982e83SLemover    } else {
242b6982e83SLemover      val lowMask = mask | OneHot.UIntToOH1(lgSize, lgMaxSize)
243b6982e83SLemover      val highMatch = unmaskEqual(paddr >> lgMaxSize, compare_addr >> lgMaxSize, mask >> lgMaxSize)
244b6982e83SLemover      val lowMatch = unmaskEqual(paddr(lgMaxSize-1, 0), compare_addr(lgMaxSize-1, 0), lowMask(lgMaxSize-1, 0))
245b6982e83SLemover      highMatch && lowMatch
246b6982e83SLemover    }
247b6982e83SLemover  }
248b6982e83SLemover
249b6982e83SLemover  def aligned(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last: PMPEntry) = {
250b6982e83SLemover    if (lgMaxSize <= PlatformGrain) {
251b6982e83SLemover      true.B
252b6982e83SLemover    } else {
253b6982e83SLemover      val lowBitsMask = OneHot.UIntToOH1(lgSize, lgMaxSize)
254b6982e83SLemover      val lowerBound = ((paddr >> lgMaxSize) === (last.compare_addr >> lgMaxSize)) &&
255b6982e83SLemover        ((~paddr(lgMaxSize-1, 0) & last.compare_addr(lgMaxSize-1, 0)) =/= 0.U)
256b6982e83SLemover      val upperBound = ((paddr >> lgMaxSize) === (compare_addr >> lgMaxSize)) &&
257b6982e83SLemover        ((compare_addr(lgMaxSize-1, 0) & (paddr(lgMaxSize-1, 0) | lowBitsMask)) =/= 0.U)
258b6982e83SLemover      val torAligned = !(lowerBound || upperBound)
259b6982e83SLemover      val napotAligned = (lowBitsMask & ~mask(lgMaxSize-1, 0)) === 0.U
260b6982e83SLemover      Mux(cfg.na4_napot, napotAligned, torAligned)
261b6982e83SLemover    }
262b6982e83SLemover  }
263ca2f90a6SLemover}
264ca2f90a6SLemover
265ca2f90a6SLemover/** PMPEntry for outside pmp copies
266ca2f90a6SLemover  * with one more elements mask to help napot match
267ca2f90a6SLemover  * TODO: make mask an element, not an method, for timing opt
268ca2f90a6SLemover  */
269ca2f90a6SLemoverclass PMPEntry(implicit p: Parameters) extends PMPBase with PMPMatchMethod {
27098c71602SJiawei Lin  val mask = UInt(PMPAddrBits.W) // help to match in napot
271ca2f90a6SLemover
27298c71602SJiawei Lin  def write_addr(next: PMPConfig, mask: UInt)(paddr: UInt) = {
27398c71602SJiawei Lin    mask := Mux(!cfg.addr_locked(next), match_mask(paddr), mask)
27498c71602SJiawei Lin    Mux(!cfg.addr_locked(next), paddr, addr)
275ca2f90a6SLemover  }
276ca2f90a6SLemover
277ca2f90a6SLemover  def write_addr(mask: UInt)(paddr: UInt) = {
278ca2f90a6SLemover    mask := Mux(!cfg.addr_locked, match_mask(paddr), mask)
279ca2f90a6SLemover    Mux(!cfg.addr_locked, paddr, addr)
280ca2f90a6SLemover  }
281b6982e83SLemover
282b6982e83SLemover  def gen(cfg: PMPConfig, addr: UInt, mask: UInt) = {
283b6982e83SLemover    require(addr.getWidth == this.addr.getWidth)
284b6982e83SLemover    this.cfg := cfg
285b6982e83SLemover    this.addr := addr
286b6982e83SLemover    this.mask := mask
287b6982e83SLemover  }
288ca2f90a6SLemover}
289b6982e83SLemover
29098c71602SJiawei Lintrait PMPMethod extends PMPConst {
291ca2f90a6SLemover  def pmp_init() : (Vec[UInt], Vec[UInt], Vec[UInt])= {
29298c71602SJiawei Lin    val cfg = WireInit(0.U.asTypeOf(Vec(NumPMP/8, UInt(PMXLEN.W))))
293672c4648Sceba    // val addr = Wire(Vec(NumPMP, UInt((PMPAddrBits-PMPOffBits).W)))
294672c4648Sceba    // val mask = Wire(Vec(NumPMP, UInt(PMPAddrBits.W)))
295672c4648Sceba    // INFO: these CSRs could be uninitialized, but for difftesting with NEMU, we opt to initialize them.
296672c4648Sceba    val addr = WireInit(0.U.asTypeOf(Vec(NumPMP, UInt((PMPAddrBits-PMPOffBits).W))))
297672c4648Sceba    val mask = WireInit(0.U.asTypeOf(Vec(NumPMP, UInt(PMPAddrBits.W))))
298ca2f90a6SLemover    (cfg, addr, mask)
299ca2f90a6SLemover  }
300ca2f90a6SLemover
301ca2f90a6SLemover  def pmp_gen_mapping
302ca2f90a6SLemover  (
303ca2f90a6SLemover    init: () => (Vec[UInt], Vec[UInt], Vec[UInt]),
304ca2f90a6SLemover    num: Int = 16,
305ca2f90a6SLemover    cfgBase: Int,
306ca2f90a6SLemover    addrBase: Int,
307ca2f90a6SLemover    entries: Vec[PMPEntry]
308ca2f90a6SLemover  ) = {
30998c71602SJiawei Lin    val pmpCfgPerCSR = PMXLEN / new PMPConfig().getWidth
31098c71602SJiawei Lin    def pmpCfgIndex(i: Int) = (PMXLEN / 32) * (i / pmpCfgPerCSR)
311ca2f90a6SLemover    val init_value = init()
312ca2f90a6SLemover    /** to fit MaskedRegMap's write, declare cfgs as Merged CSRs and split them into each pmp */
31398c71602SJiawei Lin    val cfgMerged = RegInit(init_value._1) //(Vec(num / pmpCfgPerCSR, UInt(PMXLEN.W))) // RegInit(VecInit(Seq.fill(num / pmpCfgPerCSR)(0.U(PMXLEN.W))))
314ca2f90a6SLemover    val cfgs = WireInit(cfgMerged).asTypeOf(Vec(num, new PMPConfig()))
31598c71602SJiawei Lin    val addr = RegInit(init_value._2) // (Vec(num, UInt((PMPAddrBits-PMPOffBits).W)))
31698c71602SJiawei Lin    val mask = RegInit(init_value._3) // (Vec(num, UInt(PMPAddrBits.W)))
317ca2f90a6SLemover
318ca2f90a6SLemover    for (i <- entries.indices) {
319ca2f90a6SLemover      entries(i).gen(cfgs(i), addr(i), mask(i))
320ca2f90a6SLemover    }
321ca2f90a6SLemover
322ca2f90a6SLemover    val cfg_mapping = (0 until num by pmpCfgPerCSR).map(i => {Map(
323ca2f90a6SLemover      MaskedRegMap(
324ca2f90a6SLemover        addr = cfgBase + pmpCfgIndex(i),
325ca2f90a6SLemover        reg = cfgMerged(i/pmpCfgPerCSR),
326ca2f90a6SLemover        wmask = WritableMask,
327aa438b8eSHaoyuan Feng        wfn = new PMPBase().write_cfg_vec(mask, addr, i, cfgMerged(i/pmpCfgPerCSR))
328ca2f90a6SLemover      ))
329ca2f90a6SLemover    }).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes
330ca2f90a6SLemover
331ca2f90a6SLemover    val addr_mapping = (0 until num).map(i => {Map(
332ca2f90a6SLemover      MaskedRegMap(
333ca2f90a6SLemover        addr = addrBase + i,
334ca2f90a6SLemover        reg = addr(i),
335ca2f90a6SLemover        wmask = WritableMask,
33698c71602SJiawei Lin        wfn = { if (i != num-1) entries(i).write_addr(entries(i+1).cfg, mask(i)) else entries(i).write_addr(mask(i)) },
337ca2f90a6SLemover        rmask = WritableMask,
338ca2f90a6SLemover        rfn = new PMPBase().read_addr(entries(i).cfg)
339ca2f90a6SLemover      ))
340ca2f90a6SLemover    }).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes.
341ca2f90a6SLemover
342ca2f90a6SLemover    cfg_mapping ++ addr_mapping
343b6982e83SLemover  }
344b6982e83SLemover}
345b6982e83SLemover
34698c71602SJiawei Linclass PMP(implicit p: Parameters) extends PMPXSModule with HasXSParameter with PMPMethod with PMAMethod with HasCSRConst {
347b6982e83SLemover  val io = IO(new Bundle {
348b6982e83SLemover    val distribute_csr = Flipped(new DistributedCSRIO())
349b6982e83SLemover    val pmp = Output(Vec(NumPMP, new PMPEntry()))
350ca2f90a6SLemover    val pma = Output(Vec(NumPMA, new PMPEntry()))
351b6982e83SLemover  })
352b6982e83SLemover
353b6982e83SLemover  val w = io.distribute_csr.w
354b6982e83SLemover
355b6982e83SLemover  val pmp = Wire(Vec(NumPMP, new PMPEntry()))
356ca2f90a6SLemover  val pma = Wire(Vec(NumPMA, new PMPEntry()))
357b6982e83SLemover
358075d4937Sjunxiong-ji  val pmpMapping = pmp_gen_mapping(pmp_init, NumPMP, CSRs.pmpcfg0, CSRs.pmpaddr0, pmp)
359ca2f90a6SLemover  val pmaMapping = pmp_gen_mapping(pma_init, NumPMA, PmacfgBase, PmaaddrBase, pma)
360ca2f90a6SLemover  val mapping = pmpMapping ++ pmaMapping
361b6982e83SLemover
36298c71602SJiawei Lin  val rdata = Wire(UInt(PMXLEN.W))
363ca2f90a6SLemover  MaskedRegMap.generate(mapping, w.bits.addr, rdata, w.valid, w.bits.data)
364b6982e83SLemover
365b6982e83SLemover  io.pmp := pmp
366ca2f90a6SLemover  io.pma := pma
367b6982e83SLemover}
368b6982e83SLemover
369b6982e83SLemoverclass PMPReqBundle(lgMaxSize: Int = 3)(implicit p: Parameters) extends PMPBundle {
37098c71602SJiawei Lin  val addr = Output(UInt(PMPAddrBits.W))
371b6982e83SLemover  val size = Output(UInt(log2Ceil(lgMaxSize+1).W))
372b6982e83SLemover  val cmd = Output(TlbCmd())
373b6982e83SLemover
374e3da8badSTang Haojin  def apply(addr: UInt, size: UInt, cmd: UInt): Unit = {
37598c71602SJiawei Lin    this.addr := addr
37698c71602SJiawei Lin    this.size := size
37798c71602SJiawei Lin    this.cmd := cmd
37898c71602SJiawei Lin  }
37998c71602SJiawei Lin
380e3da8badSTang Haojin  def apply(addr: UInt): Unit = { // req minimal permission and req align size
38198c71602SJiawei Lin    apply(addr, lgMaxSize.U, TlbCmd.read)
38298c71602SJiawei Lin  }
38398c71602SJiawei Lin
384b6982e83SLemover}
385b6982e83SLemover
38698c71602SJiawei Linclass PMPRespBundle(implicit p: Parameters) extends PMPBundle {
38798c71602SJiawei Lin  val ld = Output(Bool())
38898c71602SJiawei Lin  val st = Output(Bool())
38998c71602SJiawei Lin  val instr = Output(Bool())
390ca2f90a6SLemover  val mmio = Output(Bool())
39137225120Ssfencevma  val atomic = Output(Bool())
392b6982e83SLemover
393ca2f90a6SLemover  def |(resp: PMPRespBundle): PMPRespBundle = {
394ca2f90a6SLemover    val res = Wire(new PMPRespBundle())
395ca2f90a6SLemover    res.ld := this.ld || resp.ld
396ca2f90a6SLemover    res.st := this.st || resp.st
397ca2f90a6SLemover    res.instr := this.instr || resp.instr
398ca2f90a6SLemover    res.mmio := this.mmio || resp.mmio
39937225120Ssfencevma    res.atomic := this.atomic || resp.atomic
400ca2f90a6SLemover    res
401ca2f90a6SLemover  }
402ca2f90a6SLemover}
403b6982e83SLemover
40498c71602SJiawei Lintrait PMPCheckMethod extends PMPConst {
40598c71602SJiawei Lin  def pmp_check(cmd: UInt, cfg: PMPConfig) = {
406ca2f90a6SLemover    val resp = Wire(new PMPRespBundle)
4070fedb24cSWilliam Wang    resp.ld := TlbCmd.isRead(cmd) && !TlbCmd.isAmo(cmd) && !cfg.r
4080fedb24cSWilliam Wang    resp.st := (TlbCmd.isWrite(cmd) || TlbCmd.isAmo(cmd)) && !cfg.w
409ca2f90a6SLemover    resp.instr := TlbCmd.isExec(cmd) && !cfg.x
410ca2f90a6SLemover    resp.mmio := false.B
41137225120Ssfencevma    resp.atomic := false.B
412ca2f90a6SLemover    resp
413ca2f90a6SLemover  }
414b6982e83SLemover
4155cf62c1aSLemover  def pmp_match_res(leaveHitMux: Boolean = false, valid: Bool = true.B)(
4165cf62c1aSLemover    addr: UInt,
4175cf62c1aSLemover    size: UInt,
4185cf62c1aSLemover    pmpEntries: Vec[PMPEntry],
4195cf62c1aSLemover    mode: UInt,
4205cf62c1aSLemover    lgMaxSize: Int
4215cf62c1aSLemover  ) = {
422ca2f90a6SLemover    val num = pmpEntries.size
423ca2f90a6SLemover    require(num == NumPMP)
424ca2f90a6SLemover
42598c71602SJiawei Lin    val passThrough = if (pmpEntries.isEmpty) true.B else (mode > 1.U)
426a15116bdSLemover    val pmpDefault = WireInit(0.U.asTypeOf(new PMPEntry()))
427a15116bdSLemover    pmpDefault.cfg.r := passThrough
428a15116bdSLemover    pmpDefault.cfg.w := passThrough
429a15116bdSLemover    pmpDefault.cfg.x := passThrough
430b6982e83SLemover
431a15116bdSLemover    val match_vec = Wire(Vec(num+1, Bool()))
432a15116bdSLemover    val cfg_vec = Wire(Vec(num+1, new PMPEntry()))
433a15116bdSLemover
434a15116bdSLemover    pmpEntries.zip(pmpDefault +: pmpEntries.take(num-1)).zipWithIndex.foreach{ case ((pmp, last_pmp), i) =>
435ca2f90a6SLemover      val is_match = pmp.is_match(addr, size, lgMaxSize, last_pmp)
436b6982e83SLemover      val ignore = passThrough && !pmp.cfg.l
437ca2f90a6SLemover      val aligned = pmp.aligned(addr, size, lgMaxSize, last_pmp)
438b6982e83SLemover
439b6982e83SLemover      val cur = WireInit(pmp)
440b6982e83SLemover      cur.cfg.r := aligned && (pmp.cfg.r || ignore)
441b6982e83SLemover      cur.cfg.w := aligned && (pmp.cfg.w || ignore)
442b6982e83SLemover      cur.cfg.x := aligned && (pmp.cfg.x || ignore)
443b6982e83SLemover
444a15116bdSLemover//      Mux(is_match, cur, prev)
445a15116bdSLemover      match_vec(i) := is_match
446a15116bdSLemover      cfg_vec(i) := cur
447b6982e83SLemover    }
448a15116bdSLemover
449a15116bdSLemover    // default value
450a15116bdSLemover    match_vec(num) := true.B
451a15116bdSLemover    cfg_vec(num) := pmpDefault
452a15116bdSLemover
4535cf62c1aSLemover    if (leaveHitMux) {
454005e809bSJiuyang Liu      ParallelPriorityMux(match_vec.map(RegEnable(_, false.B, valid)), RegEnable(cfg_vec, valid))
4555cf62c1aSLemover    } else {
456a15116bdSLemover      ParallelPriorityMux(match_vec, cfg_vec)
457ca2f90a6SLemover    }
458ca2f90a6SLemover  }
4595cf62c1aSLemover}
460b6982e83SLemover
46198c71602SJiawei Linclass PMPCheckerEnv(implicit p: Parameters) extends PMPBundle {
462*8882eb68SXin Tian  val cmode = Bool()
46398c71602SJiawei Lin  val mode = UInt(2.W)
46498c71602SJiawei Lin  val pmp = Vec(NumPMP, new PMPEntry())
46598c71602SJiawei Lin  val pma = Vec(NumPMA, new PMPEntry())
46698c71602SJiawei Lin
467*8882eb68SXin Tian  def apply(cmode: Bool, mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry]): Unit = {
468*8882eb68SXin Tian    this.cmode := cmode
469*8882eb68SXin Tian    this.mode := mode
470*8882eb68SXin Tian    this.pmp := pmp
471*8882eb68SXin Tian    this.pma := pma
472*8882eb68SXin Tian  }
473*8882eb68SXin Tian
47498c71602SJiawei Lin  def apply(mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry]): Unit = {
475*8882eb68SXin Tian    this.cmode := true.B
47698c71602SJiawei Lin    this.mode := mode
47798c71602SJiawei Lin    this.pmp := pmp
47898c71602SJiawei Lin    this.pma := pma
47998c71602SJiawei Lin  }
48098c71602SJiawei Lin}
48198c71602SJiawei Lin
48298c71602SJiawei Linclass PMPCheckIO(lgMaxSize: Int)(implicit p: Parameters) extends PMPBundle {
48398c71602SJiawei Lin  val check_env = Input(new PMPCheckerEnv())
48498c71602SJiawei Lin  val req = Flipped(Valid(new PMPReqBundle(lgMaxSize))) // usage: assign the valid to fire signal
48598c71602SJiawei Lin  val resp = new PMPRespBundle()
48698c71602SJiawei Lin
487*8882eb68SXin Tian  def apply(cmode: Bool, mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], req: Valid[PMPReqBundle]) = {
488*8882eb68SXin Tian    check_env.apply(cmode, mode, pmp, pma)
489*8882eb68SXin Tian    this.req := req
490*8882eb68SXin Tian    resp
491*8882eb68SXin Tian  }
492*8882eb68SXin Tian
49398c71602SJiawei Lin  def apply(mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], req: Valid[PMPReqBundle]) = {
49498c71602SJiawei Lin    check_env.apply(mode, pmp, pma)
49598c71602SJiawei Lin    this.req := req
49698c71602SJiawei Lin    resp
49798c71602SJiawei Lin  }
49898c71602SJiawei Lin
49998c71602SJiawei Lin  def req_apply(valid: Bool, addr: UInt): Unit = {
50098c71602SJiawei Lin    this.req.valid := valid
50198c71602SJiawei Lin    this.req.bits.apply(addr)
50298c71602SJiawei Lin  }
50398c71602SJiawei Lin
50498c71602SJiawei Lin  def apply(mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], valid: Bool, addr: UInt) = {
50598c71602SJiawei Lin    check_env.apply(mode, pmp, pma)
50698c71602SJiawei Lin    req_apply(valid, addr)
50798c71602SJiawei Lin    resp
50898c71602SJiawei Lin  }
50998c71602SJiawei Lin}
51098c71602SJiawei Lin
5115b7ef044SLemoverclass PMPCheckv2IO(lgMaxSize: Int)(implicit p: Parameters) extends PMPBundle {
5125b7ef044SLemover  val check_env = Input(new PMPCheckerEnv())
5135b7ef044SLemover  val req = Flipped(Valid(new PMPReqBundle(lgMaxSize))) // usage: assign the valid to fire signal
5145b7ef044SLemover  val resp = Output(new PMPConfig())
5155b7ef044SLemover
516*8882eb68SXin Tian  def apply(cmode: Bool, mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], valid: Bool, addr: UInt) = {
517*8882eb68SXin Tian    check_env.apply(cmode, mode, pmp, pma)
518*8882eb68SXin Tian    req_apply(valid, addr)
519*8882eb68SXin Tian    resp
520*8882eb68SXin Tian  }
521*8882eb68SXin Tian
5225b7ef044SLemover  def apply(mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], req: Valid[PMPReqBundle]) = {
5235b7ef044SLemover    check_env.apply(mode, pmp, pma)
5245b7ef044SLemover    this.req := req
5255b7ef044SLemover    resp
5265b7ef044SLemover  }
5275b7ef044SLemover
5285b7ef044SLemover  def req_apply(valid: Bool, addr: UInt): Unit = {
5295b7ef044SLemover    this.req.valid := valid
5305b7ef044SLemover    this.req.bits.apply(addr)
5315b7ef044SLemover  }
5325b7ef044SLemover
5335b7ef044SLemover  def apply(mode: UInt, pmp: Vec[PMPEntry], pma: Vec[PMPEntry], valid: Bool, addr: UInt) = {
5345b7ef044SLemover    check_env.apply(mode, pmp, pma)
5355b7ef044SLemover    req_apply(valid, addr)
5365b7ef044SLemover    resp
5375b7ef044SLemover  }
5385b7ef044SLemover}
5395b7ef044SLemover
540ca2f90a6SLemoverclass PMPChecker
541ca2f90a6SLemover(
542ca2f90a6SLemover  lgMaxSize: Int = 3,
5435cf62c1aSLemover  sameCycle: Boolean = false,
54498c71602SJiawei Lin  leaveHitMux: Boolean = false,
54598c71602SJiawei Lin  pmpUsed: Boolean = true
54698c71602SJiawei Lin)(implicit p: Parameters) extends PMPModule
547ca2f90a6SLemover  with PMPCheckMethod
548ca2f90a6SLemover  with PMACheckMethod
549ca2f90a6SLemover{
5505cf62c1aSLemover  require(!(leaveHitMux && sameCycle))
55198c71602SJiawei Lin  val io = IO(new PMPCheckIO(lgMaxSize))
552ca2f90a6SLemover
553ca2f90a6SLemover  val req = io.req.bits
554ca2f90a6SLemover
555*8882eb68SXin Tian  /* The KeyIDBits is used for memary encrypt, as part of address MSB,
556*8882eb68SXin Tian   * so (PMPKeyIDBits > 0) usually set with HasMEMencryption = true.
557*8882eb68SXin Tian   *
558*8882eb68SXin Tian   * Example:
559*8882eb68SXin Tian   * PAddrBits=48 & PMPKeyIDBits=5
560*8882eb68SXin Tian   * [47,46,45,44,43, 42,41,.......,1,0]
561*8882eb68SXin Tian   * {----KeyID----} {----RealPAddr----}
562*8882eb68SXin Tian   *
563*8882eb68SXin Tian   * The nonzero keyID is binding with Enclave/CVM(cmode=1) to select different memary encrypt key,
564*8882eb68SXin Tian   * and the OS/VMM/APP/VM(cmode=0) can only use zero as KeyID.
565*8882eb68SXin Tian   *
566*8882eb68SXin Tian   * So only the RealPAddr need PMP&PMA check.
567*8882eb68SXin Tian   */
568*8882eb68SXin Tian
569*8882eb68SXin Tian  val res_pmp = pmp_match_res(leaveHitMux, io.req.valid)(req.addr(PMPAddrBits-PMPKeyIDBits-1, 0), req.size, io.check_env.pmp, io.check_env.mode, lgMaxSize)
570*8882eb68SXin Tian  val res_pma = pma_match_res(leaveHitMux, io.req.valid)(req.addr(PMPAddrBits-PMPKeyIDBits-1, 0), req.size, io.check_env.pma, io.check_env.mode, lgMaxSize)
571ca2f90a6SLemover
572ca2f90a6SLemover  val resp_pmp = pmp_check(req.cmd, res_pmp.cfg)
573ca2f90a6SLemover  val resp_pma = pma_check(req.cmd, res_pma.cfg)
574*8882eb68SXin Tian
575*8882eb68SXin Tian  def keyid_check(leaveHitMux: Boolean = false, valid: Bool = true.B, addr: UInt) = {
576*8882eb68SXin Tian    val resp = Wire(new PMPRespBundle)
577*8882eb68SXin Tian    val keyid_nz = if (PMPKeyIDBits > 0) addr(PMPAddrBits-1, PMPAddrBits-PMPKeyIDBits) =/= 0.U else false.B
578*8882eb68SXin Tian    resp.ld := keyid_nz && !io.check_env.cmode && (io.check_env.mode < 3.U)
579*8882eb68SXin Tian    resp.st := keyid_nz && !io.check_env.cmode && (io.check_env.mode < 3.U)
580*8882eb68SXin Tian    resp.instr := keyid_nz && !io.check_env.cmode && (io.check_env.mode < 3.U)
581*8882eb68SXin Tian    resp.mmio := false.B
582*8882eb68SXin Tian    resp.atomic := false.B
583*8882eb68SXin Tian    if (leaveHitMux) {
584*8882eb68SXin Tian      RegEnable(resp, valid)
585*8882eb68SXin Tian    } else {
586*8882eb68SXin Tian      resp
587*8882eb68SXin Tian    }
588*8882eb68SXin Tian  }
589*8882eb68SXin Tian
590*8882eb68SXin Tian  val resp_keyid = keyid_check(leaveHitMux, io.req.valid, req.addr)
591*8882eb68SXin Tian
592*8882eb68SXin Tian  val resp = if (pmpUsed) (resp_pmp | resp_pma | resp_keyid) else (resp_pma | resp_keyid)
593ca2f90a6SLemover
5945cf62c1aSLemover  if (sameCycle || leaveHitMux) {
595ca2f90a6SLemover    io.resp := resp
596b6982e83SLemover  } else {
597ca2f90a6SLemover    io.resp := RegEnable(resp, io.req.valid)
598b6982e83SLemover  }
599b6982e83SLemover}
6005b7ef044SLemover
6015b7ef044SLemover/* get config with check */
6025b7ef044SLemoverclass PMPCheckerv2
6035b7ef044SLemover(
6045b7ef044SLemover  lgMaxSize: Int = 3,
6055b7ef044SLemover  sameCycle: Boolean = false,
6065b7ef044SLemover  leaveHitMux: Boolean = false
6075b7ef044SLemover)(implicit p: Parameters) extends PMPModule
6085b7ef044SLemover  with PMPCheckMethod
6095b7ef044SLemover  with PMACheckMethod
6105b7ef044SLemover{
6115b7ef044SLemover  require(!(leaveHitMux && sameCycle))
6125b7ef044SLemover  val io = IO(new PMPCheckv2IO(lgMaxSize))
6135b7ef044SLemover
6145b7ef044SLemover  val req = io.req.bits
6155b7ef044SLemover
6165b7ef044SLemover  val res_pmp = pmp_match_res(leaveHitMux, io.req.valid)(req.addr, req.size, io.check_env.pmp, io.check_env.mode, lgMaxSize)
6175b7ef044SLemover  val res_pma = pma_match_res(leaveHitMux, io.req.valid)(req.addr, req.size, io.check_env.pma, io.check_env.mode, lgMaxSize)
6185b7ef044SLemover
6195b7ef044SLemover  val resp = and(res_pmp, res_pma)
6205b7ef044SLemover
6215b7ef044SLemover  if (sameCycle || leaveHitMux) {
6225b7ef044SLemover    io.resp := resp
6235b7ef044SLemover  } else {
6245b7ef044SLemover    io.resp := RegEnable(resp, io.req.valid)
6255b7ef044SLemover  }
6265b7ef044SLemover
6275b7ef044SLemover  def and(pmp: PMPEntry, pma: PMPEntry): PMPConfig = {
6285b7ef044SLemover    val tmp_res = Wire(new PMPConfig)
6295b7ef044SLemover    tmp_res.l := DontCare
6305b7ef044SLemover    tmp_res.a := DontCare
6315b7ef044SLemover    tmp_res.r := pmp.cfg.r && pma.cfg.r
6325b7ef044SLemover    tmp_res.w := pmp.cfg.w && pma.cfg.w
6335b7ef044SLemover    tmp_res.x := pmp.cfg.x && pma.cfg.x
6345b7ef044SLemover    tmp_res.c := pma.cfg.c
6355b7ef044SLemover    tmp_res.atomic := pma.cfg.atomic
6365b7ef044SLemover    tmp_res
6375b7ef044SLemover  }
6385b7ef044SLemover}
639