xref: /XiangShan/src/main/scala/xiangshan/backend/fu/PMA.scala (revision 5bd65c56355db1d4f5b92a3815df78273c01b892)
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