1ca2f90a6SLemover/*************************************************************************************** 2ca2f90a6SLemover * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3ca2f90a6SLemover * Copyright (c) 2020-2021 Peng Cheng Laboratory 4ca2f90a6SLemover * 5ca2f90a6SLemover * XiangShan is licensed under Mulan PSL v2. 6ca2f90a6SLemover * You can use this software according to the terms and conditions of the Mulan PSL v2. 7ca2f90a6SLemover * You may obtain a copy of Mulan PSL v2 at: 8ca2f90a6SLemover * http://license.coscl.org.cn/MulanPSL2 9ca2f90a6SLemover * 10ca2f90a6SLemover * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11ca2f90a6SLemover * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12ca2f90a6SLemover * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13ca2f90a6SLemover * 14ca2f90a6SLemover * See the Mulan PSL v2 for more details. 15ca2f90a6SLemover ***************************************************************************************/ 16ca2f90a6SLemover 17ca2f90a6SLemoverpackage xiangshan.backend.fu 18ca2f90a6SLemover 19ca2f90a6SLemoverimport chisel3._ 20ca2f90a6SLemoverimport chisel3.util._ 2198c71602SJiawei Linimport freechips.rocketchip.regmapper.{RegField, RegFieldDesc, RegReadFn, RegWriteFn} 2267ba96b4SYinan Xuimport utility.{ParallelPriorityMux, ValidHold, ZeroExt} 23ca2f90a6SLemoverimport xiangshan.cache.mmu.TlbCmd 24ca2f90a6SLemover 2567ba96b4SYinan Xuimport scala.collection.mutable.ListBuffer 2667ba96b4SYinan Xu 2798c71602SJiawei Lin/* Memory Mapped PMA */ 2898c71602SJiawei Lincase class MMPMAConfig 2998c71602SJiawei Lin( 3098c71602SJiawei Lin address: BigInt, 3198c71602SJiawei Lin mask: BigInt, 3298c71602SJiawei Lin lgMaxSize: Int, 3398c71602SJiawei Lin sameCycle: Boolean, 3498c71602SJiawei Lin num: Int 3598c71602SJiawei Lin) 3698c71602SJiawei Lin 37*5bd65c56STang Haojincase class MemoryRange(lower: BigInt, upper: BigInt) { 38*5bd65c56STang Haojin def cover(addr: BigInt): Boolean = addr >= lower && addr < upper 39*5bd65c56STang Haojin def cover(addr: UInt): Bool = addr >= lower.U && addr < upper.U 40*5bd65c56STang Haojin} 41*5bd65c56STang Haojin 42*5bd65c56STang Haojincase class PMAConfigEntry( 43*5bd65c56STang Haojin base_addr: BigInt, 44*5bd65c56STang Haojin range: BigInt = 0L, // only use for napot mode 45*5bd65c56STang Haojin l: Boolean = false, 46*5bd65c56STang Haojin c: Boolean = false, 47*5bd65c56STang Haojin atomic: Boolean = false, 48*5bd65c56STang Haojin a: Int = 0, 49*5bd65c56STang Haojin x: Boolean = false, 50*5bd65c56STang Haojin w: Boolean = false, 51*5bd65c56STang Haojin r: Boolean = false 52*5bd65c56STang Haojin) 53*5bd65c56STang Haojin 5498c71602SJiawei Lintrait PMAConst extends PMPConst 5598c71602SJiawei Lin 5698c71602SJiawei Lintrait MMPMAMethod extends PMAConst with PMAMethod with PMPReadWriteMethodBare { 5798c71602SJiawei Lin def gen_mmpma_mapping(num: Int) = { 5898c71602SJiawei Lin val pmaCfgPerCSR = PMXLEN / new PMPConfig().getWidth 5998c71602SJiawei Lin def pmaCfgLogicIndex(i: Int) = (PMXLEN / 32) * (i / pmaCfgPerCSR) 6098c71602SJiawei Lin def pmaCfgIndex(i: Int) = (i / pmaCfgPerCSR) 6198c71602SJiawei Lin 6298c71602SJiawei Lin val pma = Wire(Vec(num, new PMPEntry)) 6398c71602SJiawei Lin 6498c71602SJiawei Lin /* pma init value */ 6598c71602SJiawei Lin val init_value = pma_init() 6698c71602SJiawei Lin 6798c71602SJiawei Lin val pmaCfgMerged = RegInit(init_value._1) 6898c71602SJiawei Lin val addr = RegInit(init_value._2) 6998c71602SJiawei Lin val mask = RegInit(init_value._3) 7098c71602SJiawei Lin val cfg = WireInit(pmaCfgMerged).asTypeOf(Vec(num, new PMPConfig())) 7198c71602SJiawei Lin // pmaMask are implicit regs that just used for timing optimization 7298c71602SJiawei Lin for (i <- pma.indices) { 7398c71602SJiawei Lin pma(i).gen(cfg(i), addr(i), mask(i)) 7498c71602SJiawei Lin } 7598c71602SJiawei Lin 7698c71602SJiawei Lin val blankCfg = PMXLEN == 32 7798c71602SJiawei Lin val cfg_index_wrapper = (0 until num by 4).zip((0 until num by 4).map(a => blankCfg || (a % pmaCfgPerCSR == 0))) 7898c71602SJiawei Lin val cfg_map = (cfg_index_wrapper).map{ case(i, notempty) => { 7998c71602SJiawei Lin// println(s"tlbpma i:$i notempty:$notempty") 80cef5c4b4SLemover RegField.apply(n = PMXLEN, r = RegReadFn{(ivalid, oready) => 81cef5c4b4SLemover val r_ready = Wire(Bool()) 82cef5c4b4SLemover val o_valid = Wire(Bool()) 83cef5c4b4SLemover val v_reg = ValidHold(r_ready && ivalid, o_valid && oready, false.B) 84cef5c4b4SLemover r_ready := !v_reg 85cef5c4b4SLemover o_valid := v_reg 86cef5c4b4SLemover 87cef5c4b4SLemover if (notempty) { (r_ready, o_valid, pmaCfgMerged(pmaCfgIndex(i))) } 88cef5c4b4SLemover else { (r_ready, o_valid, 0.U) } 89cef5c4b4SLemover }, w = RegWriteFn((valid, data) => { 90aa438b8eSHaoyuan Feng if (notempty) { when (valid) { pmaCfgMerged(pmaCfgIndex(i)) := write_cfg_vec(mask, addr, i, pmaCfgMerged(pmaCfgIndex(i)))(data) } } 9198c71602SJiawei Lin true.B 9298c71602SJiawei Lin }), desc = RegFieldDesc(s"MMPMA_config_${i}", s"pma config register #${i}")) 9398c71602SJiawei Lin }} 9498c71602SJiawei Lin 9598c71602SJiawei Lin val addr_map = (0 until num).map{ i => { 9698c71602SJiawei Lin val next_cfg = if (i == 0) 0.U.asTypeOf(new PMPConfig()) else cfg(i-1) 9798c71602SJiawei Lin RegField( 9898c71602SJiawei Lin n = PMXLEN, 9998c71602SJiawei Lin r = ZeroExt(read_addr(cfg(i))(addr(i)), PMXLEN), 10098c71602SJiawei Lin w = RegWriteFn((valid, data) => { 10198c71602SJiawei Lin when (valid) { addr(i) := write_addr(next_cfg, mask(i))(data(addr(0).getWidth-1, 0), cfg(i), addr(i))} 10298c71602SJiawei Lin true.B 10398c71602SJiawei Lin }), 10498c71602SJiawei Lin desc = RegFieldDesc(s"MMPMA_addr_${i}", s"pma addr register #${i}") 10598c71602SJiawei Lin ) 10698c71602SJiawei Lin }} 10798c71602SJiawei Lin 10898c71602SJiawei Lin (cfg_map, addr_map, pma) 10998c71602SJiawei Lin } 11098c71602SJiawei Lin 11198c71602SJiawei Lin} 11298c71602SJiawei Lin 11398c71602SJiawei Lintrait PMAMethod extends PMAConst { 114ca2f90a6SLemover /** 115ca2f90a6SLemover def SimpleMemMapList = List( 116ca2f90a6SLemover // Base address Top address Width Description Mode (RWXIDSAC) 117ca2f90a6SLemover MemMap("h00_0000_0000", "h00_0FFF_FFFF", "h0", "Reserved", "RW"), 118ca2f90a6SLemover MemMap("h00_1000_0000", "h00_1FFF_FFFF", "h0", "QSPI_Flash", "RWX"), 119ca2f90a6SLemover MemMap("h00_2000_0000", "h00_2FFF_FFFF", "h0", "Reserved", "RW"), 120ca2f90a6SLemover MemMap("h00_3000_0000", "h00_3000_FFFF", "h0", "DMA", "RW"), 121ca2f90a6SLemover MemMap("h00_3001_0000", "h00_3004_FFFF", "h0", "GPU", "RWC"), 122ca2f90a6SLemover MemMap("h00_3005_0000", "h00_3006_FFFF", "h0", "USB/SDMMC", "RW"), 123ca2f90a6SLemover MemMap("h00_3007_0000", "h00_30FF_FFFF", "h0", "Reserved", "RW"), 124ca2f90a6SLemover MemMap("h00_3100_0000", "h00_3111_FFFF", "h0", "MMIO", "RW"), 125ca2f90a6SLemover MemMap("h00_3112_0000", "h00_37FF_FFFF", "h0", "Reserved", "RW"), 126ca2f90a6SLemover MemMap("h00_3800_0000", "h00_3800_FFFF", "h0", "CLINT", "RW"), 127ca2f90a6SLemover MemMap("h00_3801_0000", "h00_3801_FFFF", "h0", "BEU", "RW"), 128ca2f90a6SLemover MemMap("h00_3802_0000", "h00_3802_0FFF", "h0", "DebugModule", "RWX"), 1295b7ef044SLemover MemMap("h00_3802_1000", "h00_3802_1FFF", "h0", "MMPMA", "RW"), 13072dab974Scz4e MemMap("h00_3802_2000", "h00_3802_207F", "h0", "L1DCacheCtrl", "RW"), 1316c106319Sxu_zh MemMap("h00_3802_2080", "h00_3802_20FF", "h0", "L1ICacheCtrl", "RW"), 1326c106319Sxu_zh MemMap("h00_3802_2100", "h00_38FF_FFFF", "h0", "Reserved", ""), 1339e2176fbSwakafa MemMap("h00_3900_0000", "h00_3900_1FFF", "h0", "L3CacheCtrl", "RW"), 1345b7ef044SLemover MemMap("h00_3900_2000", "h00_39FF_FFFF", "h0", "Reserved", ""), 1359143e232SJiuyue Ma MemMap("h00_3A00_0000", "h00_3FFF_FFFF", "h0", "", "RW), 1369143e232SJiuyue Ma Sub("h00_3A00_0000", "h00_3A00_0FFF", "h0", "PLL0", "RW), 1379143e232SJiuyue Ma Sub('h00_3A00_1000", "h00_3A7F_FFFF", "h0", "Reserved", "RW"), 1389143e232SJiuyue Ma Sub('h00_3A80_0000", "h00_3AFF_FFFF", "h0", "IMSIC(M)", "RW"), 1399143e232SJiuyue Ma Sub('h00_3B00_0000", "h00_3BFF_FFFF", "h0", "IMSIC(S/VS)", "RW"), 1409143e232SJiuyue Ma Sub("h00_3C00_0000", "h00_3FFF_FFFF", "h0", "PLIC", "RW"), 141ca2f90a6SLemover MemMap("h00_4000_0000", "h00_7FFF_FFFF", "h0", "PCIe", "RW"), 14221a17f35SHaoyuan Feng MemMap("h00_8000_0000", "h7FF_FFFF_FFFF", "h0", "DDR", "RWXIDSA"), 143ca2f90a6SLemover ) 144ca2f90a6SLemover */ 145ca2f90a6SLemover 146ca2f90a6SLemover def pma_init() : (Vec[UInt], Vec[UInt], Vec[UInt]) = { 14767ba96b4SYinan Xu def genAddr(init_addr: BigInt) = { 14867ba96b4SYinan Xu init_addr.U((PMPAddrBits - PMPOffBits).W) 14967ba96b4SYinan Xu } 15067ba96b4SYinan Xu def genMask(init_addr: BigInt, a: BigInt) = { 15167ba96b4SYinan Xu val match_mask_addr = (init_addr << 1) | (a & 0x1) | (((1 << PlatformGrain) - 1) >> PMPOffBits) 15267ba96b4SYinan Xu val mask = ((match_mask_addr & ~(match_mask_addr + 1)) << PMPOffBits) | ((1 << PMPOffBits) - 1) 15367ba96b4SYinan Xu mask.U(PMPAddrBits.W) 15467ba96b4SYinan Xu } 155ca2f90a6SLemover 156ca2f90a6SLemover val num = NumPMA 157ca2f90a6SLemover require(num >= 16) 158ca2f90a6SLemover 15967ba96b4SYinan Xu val cfg_list = ListBuffer[UInt]() 16067ba96b4SYinan Xu val addr_list = ListBuffer[UInt]() 16167ba96b4SYinan Xu val mask_list = ListBuffer[UInt]() 162*5bd65c56STang Haojin 163*5bd65c56STang Haojin def addPMA(conf: PMAConfigEntry) = { 164*5bd65c56STang Haojin val addr = if (conf.a < 2) { shift_addr(conf.base_addr) } 165*5bd65c56STang Haojin else { get_napot(conf.base_addr, conf.range) } 166*5bd65c56STang Haojin cfg_list.append(PMPConfigUInt(conf.l, conf.c, conf.atomic, conf.a, conf.x, conf.w, conf.r)) 16767ba96b4SYinan Xu addr_list.append(genAddr(addr)) 168*5bd65c56STang Haojin mask_list.append(genMask(addr, conf.a)) 169ca2f90a6SLemover } 170ca2f90a6SLemover 171*5bd65c56STang Haojin PMAConfigs.foreach(addPMA) 17267ba96b4SYinan Xu while (cfg_list.length < 16) { 173*5bd65c56STang Haojin addPMA(PMAConfigEntry(0)) 17467ba96b4SYinan Xu } 17567ba96b4SYinan Xu 17667ba96b4SYinan Xu val cfgInitMerge = Seq.tabulate(num / 8)(i => { 17767ba96b4SYinan Xu cfg_list.reverse.drop(8 * i).take(8).foldRight(BigInt(0L)) { case (a, result) => 17867ba96b4SYinan Xu (result << a.getWidth) | a.litValue 17967ba96b4SYinan Xu }.U(PMXLEN.W) 18067ba96b4SYinan Xu }) 18167ba96b4SYinan Xu val addr = addr_list.reverse 18267ba96b4SYinan Xu val mask = mask_list.reverse 183935edac4STang Haojin (VecInit(cfgInitMerge), VecInit(addr.toSeq), VecInit(mask.toSeq)) 18467ba96b4SYinan Xu } 18567ba96b4SYinan Xu 18667ba96b4SYinan Xu def get_napot(base: BigInt, range: BigInt): BigInt = { 187aec79401SLemover val PlatformGrainBytes = (1 << PlatformGrain) 188aec79401SLemover if ((base % PlatformGrainBytes) != 0) { 189aec79401SLemover println("base:%x", base) 190aec79401SLemover } 191aec79401SLemover if ((range % PlatformGrainBytes) != 0) { 192aec79401SLemover println("range: %x", range) 193aec79401SLemover } 194aec79401SLemover require((base % PlatformGrainBytes) == 0) 195aec79401SLemover require((range % PlatformGrainBytes) == 0) 196aec79401SLemover 19767ba96b4SYinan Xu ((base + (range/2 - 1)) >> PMPOffBits) 198aec79401SLemover } 199aec79401SLemover 200aec79401SLemover def match_mask(paddr: UInt, cfg: PMPConfig) = { 201935edac4STang Haojin val match_mask_addr: UInt = Cat(paddr, cfg.a(0)).asUInt | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W) 202aec79401SLemover Cat(match_mask_addr & ~(match_mask_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W)) 203aec79401SLemover } 204aec79401SLemover 205ca2f90a6SLemover def shift_addr(addr: BigInt) = { 20667ba96b4SYinan Xu addr >> 2 207ca2f90a6SLemover } 208ca2f90a6SLemover} 209ca2f90a6SLemover 21098c71602SJiawei Lintrait PMACheckMethod extends PMPConst { 211ca2f90a6SLemover def pma_check(cmd: UInt, cfg: PMPConfig) = { 212ca2f90a6SLemover val resp = Wire(new PMPRespBundle) 213134181f4SHaoyuan Feng resp.ld := TlbCmd.isRead(cmd) && !TlbCmd.isAmo(cmd) && !cfg.r 214134181f4SHaoyuan Feng resp.st := (TlbCmd.isWrite(cmd) || TlbCmd.isAmo(cmd) && cfg.atomic) && !cfg.w 215ca2f90a6SLemover resp.instr := TlbCmd.isExec(cmd) && !cfg.x 216729ce9eeSAnzo //TODO We require that a `PMA` can generate an mmio response only if the address has the appropriate `PMA` permissions. 217729ce9eeSAnzo resp.mmio := !cfg.c && 218729ce9eeSAnzo (TlbCmd.isRead(cmd) && cfg.r || 219729ce9eeSAnzo (TlbCmd.isWrite(cmd) || TlbCmd.isAmo(cmd) && cfg.atomic) && cfg.w || 220729ce9eeSAnzo TlbCmd.isExec(cmd) && cfg.x) 22137225120Ssfencevma resp.atomic := cfg.atomic 222ca2f90a6SLemover resp 223ca2f90a6SLemover } 224ca2f90a6SLemover 2255cf62c1aSLemover def pma_match_res(leaveHitMux: Boolean = false, valid: Bool = true.B)( 2265cf62c1aSLemover addr: UInt, 2275cf62c1aSLemover size: UInt, 2285cf62c1aSLemover pmaEntries: Vec[PMPEntry], 2295cf62c1aSLemover mode: UInt, 2305cf62c1aSLemover lgMaxSize: Int 2315cf62c1aSLemover ) = { 232ca2f90a6SLemover val num = pmaEntries.size 233ca2f90a6SLemover require(num == NumPMA) 234ca2f90a6SLemover // pma should always be checked, could not be ignored 235ca2f90a6SLemover // like amo and cached, it is the attribute not protection 236ca2f90a6SLemover // so it must have initialization. 237ca2f90a6SLemover require(!pmaEntries.isEmpty) 238ca2f90a6SLemover 239a15116bdSLemover val pmaDefault = WireInit(0.U.asTypeOf(new PMPEntry())) 240a15116bdSLemover val match_vec = Wire(Vec(num+1, Bool())) 241a15116bdSLemover val cfg_vec = Wire(Vec(num+1, new PMPEntry())) 242a15116bdSLemover 243a15116bdSLemover pmaEntries.zip(pmaDefault +: pmaEntries.take(num-1)).zipWithIndex.foreach{ case ((pma, last_pma), i) => 244ca2f90a6SLemover val is_match = pma.is_match(addr, size, lgMaxSize, last_pma) 245ca2f90a6SLemover val aligned = pma.aligned(addr, size, lgMaxSize, last_pma) 246ca2f90a6SLemover 247ca2f90a6SLemover val cur = WireInit(pma) 248ca2f90a6SLemover cur.cfg.r := aligned && pma.cfg.r 249ca2f90a6SLemover cur.cfg.w := aligned && pma.cfg.w 250ca2f90a6SLemover cur.cfg.x := aligned && pma.cfg.x 251ca2f90a6SLemover cur.cfg.atomic := aligned && pma.cfg.atomic 252ca2f90a6SLemover cur.cfg.c := aligned && pma.cfg.c 253ca2f90a6SLemover 254a15116bdSLemover match_vec(i) := is_match 255a15116bdSLemover cfg_vec(i) := cur 256ca2f90a6SLemover } 257a15116bdSLemover 258a15116bdSLemover match_vec(num) := true.B 259a15116bdSLemover cfg_vec(num) := pmaDefault 2605cf62c1aSLemover if (leaveHitMux) { 261005e809bSJiuyang Liu ParallelPriorityMux(match_vec.map(RegEnable(_, false.B, valid)), RegEnable(cfg_vec, valid)) 2625cf62c1aSLemover } else { 263a15116bdSLemover ParallelPriorityMux(match_vec, cfg_vec) 264ca2f90a6SLemover } 265ca2f90a6SLemover } 2665cf62c1aSLemover} 267