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