xref: /XiangShan/src/main/scala/xiangshan/backend/fu/PMA.scala (revision 5b7ef044f8410da3ad97ddb6a93c37566891fa86)
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}
22cef5c4b4SLemoverimport utils.{ParallelPriorityMux, ZeroExt, ValidHold}
23ca2f90a6SLemoverimport xiangshan.cache.mmu.TlbCmd
24ca2f90a6SLemover
2598c71602SJiawei Lin/* Memory Mapped PMA */
2698c71602SJiawei Lincase class MMPMAConfig
2798c71602SJiawei Lin(
2898c71602SJiawei Lin  address: BigInt,
2998c71602SJiawei Lin  mask: BigInt,
3098c71602SJiawei Lin  lgMaxSize: Int,
3198c71602SJiawei Lin  sameCycle: Boolean,
3298c71602SJiawei Lin  num: Int
3398c71602SJiawei Lin)
3498c71602SJiawei Lin
3598c71602SJiawei Lintrait PMAConst extends PMPConst
3698c71602SJiawei Lin
3798c71602SJiawei Lintrait MMPMAMethod extends PMAConst with PMAMethod with PMPReadWriteMethodBare {
3898c71602SJiawei Lin  def gen_mmpma_mapping(num: Int) = {
3998c71602SJiawei Lin    val pmaCfgPerCSR = PMXLEN / new PMPConfig().getWidth
4098c71602SJiawei Lin    def pmaCfgLogicIndex(i: Int) = (PMXLEN / 32) * (i / pmaCfgPerCSR)
4198c71602SJiawei Lin    def pmaCfgIndex(i: Int) = (i / pmaCfgPerCSR)
4298c71602SJiawei Lin
4398c71602SJiawei Lin    val pma = Wire(Vec(num, new PMPEntry))
4498c71602SJiawei Lin
4598c71602SJiawei Lin    /* pma init value */
4698c71602SJiawei Lin    val init_value = pma_init()
4798c71602SJiawei Lin
4898c71602SJiawei Lin    val pmaCfgMerged = RegInit(init_value._1)
4998c71602SJiawei Lin    val addr = RegInit(init_value._2)
5098c71602SJiawei Lin    val mask = RegInit(init_value._3)
5198c71602SJiawei Lin    val cfg = WireInit(pmaCfgMerged).asTypeOf(Vec(num, new PMPConfig()))
5298c71602SJiawei Lin    //  pmaMask are implicit regs that just used for timing optimization
5398c71602SJiawei Lin    for (i <- pma.indices) {
5498c71602SJiawei Lin      pma(i).gen(cfg(i), addr(i), mask(i))
5598c71602SJiawei Lin    }
5698c71602SJiawei Lin
5798c71602SJiawei Lin    val blankCfg = PMXLEN == 32
5898c71602SJiawei Lin    val cfg_index_wrapper = (0 until num by 4).zip((0 until num by 4).map(a => blankCfg || (a % pmaCfgPerCSR == 0)))
5998c71602SJiawei Lin    val cfg_map = (cfg_index_wrapper).map{ case(i, notempty) => {
6098c71602SJiawei Lin//      println(s"tlbpma i:$i notempty:$notempty")
61cef5c4b4SLemover      RegField.apply(n = PMXLEN, r = RegReadFn{(ivalid, oready) =>
62cef5c4b4SLemover        val r_ready = Wire(Bool())
63cef5c4b4SLemover        val o_valid = Wire(Bool())
64cef5c4b4SLemover        val v_reg = ValidHold(r_ready && ivalid, o_valid && oready, false.B)
65cef5c4b4SLemover        r_ready := !v_reg
66cef5c4b4SLemover        o_valid := v_reg
67cef5c4b4SLemover
68cef5c4b4SLemover        if (notempty) { (r_ready, o_valid, pmaCfgMerged(pmaCfgIndex(i))) }
69cef5c4b4SLemover        else { (r_ready, o_valid, 0.U) }
70cef5c4b4SLemover      }, w = RegWriteFn((valid, data) => {
7198c71602SJiawei Lin        if (notempty) { when (valid) { pmaCfgMerged(pmaCfgIndex(i)) := write_cfg_vec(mask, addr, i)(data) } }
7298c71602SJiawei Lin        true.B
7398c71602SJiawei Lin      }), desc = RegFieldDesc(s"MMPMA_config_${i}", s"pma config register #${i}"))
7498c71602SJiawei Lin    }}
7598c71602SJiawei Lin
7698c71602SJiawei Lin    val addr_map = (0 until num).map{ i => {
7798c71602SJiawei Lin      val next_cfg = if (i == 0) 0.U.asTypeOf(new PMPConfig()) else cfg(i-1)
7898c71602SJiawei Lin      RegField(
7998c71602SJiawei Lin        n = PMXLEN,
8098c71602SJiawei Lin        r = ZeroExt(read_addr(cfg(i))(addr(i)), PMXLEN),
8198c71602SJiawei Lin        w = RegWriteFn((valid, data) => {
8298c71602SJiawei Lin          when (valid) { addr(i) := write_addr(next_cfg, mask(i))(data(addr(0).getWidth-1, 0), cfg(i), addr(i))}
8398c71602SJiawei Lin          true.B
8498c71602SJiawei Lin        }),
8598c71602SJiawei Lin        desc = RegFieldDesc(s"MMPMA_addr_${i}", s"pma addr register #${i}")
8698c71602SJiawei Lin      )
8798c71602SJiawei Lin    }}
8898c71602SJiawei Lin
8998c71602SJiawei Lin    (cfg_map, addr_map, pma)
9098c71602SJiawei Lin  }
9198c71602SJiawei Lin
9298c71602SJiawei Lin}
9398c71602SJiawei Lin
9498c71602SJiawei Lintrait PMAMethod extends PMAConst {
95ca2f90a6SLemover  /**
96ca2f90a6SLemover  def SimpleMemMapList = List(
97ca2f90a6SLemover      //     Base address      Top address       Width  Description    Mode (RWXIDSAC)
98ca2f90a6SLemover      MemMap("h00_0000_0000", "h00_0FFF_FFFF",   "h0", "Reserved",    "RW"),
99ca2f90a6SLemover      MemMap("h00_1000_0000", "h00_1FFF_FFFF",   "h0", "QSPI_Flash",  "RWX"),
100ca2f90a6SLemover      MemMap("h00_2000_0000", "h00_2FFF_FFFF",   "h0", "Reserved",    "RW"),
101ca2f90a6SLemover      MemMap("h00_3000_0000", "h00_3000_FFFF",   "h0", "DMA",         "RW"),
102ca2f90a6SLemover      MemMap("h00_3001_0000", "h00_3004_FFFF",   "h0", "GPU",         "RWC"),
103ca2f90a6SLemover      MemMap("h00_3005_0000", "h00_3006_FFFF",   "h0", "USB/SDMMC",   "RW"),
104ca2f90a6SLemover      MemMap("h00_3007_0000", "h00_30FF_FFFF",   "h0", "Reserved",    "RW"),
105ca2f90a6SLemover      MemMap("h00_3100_0000", "h00_3111_FFFF",   "h0", "MMIO",        "RW"),
106ca2f90a6SLemover      MemMap("h00_3112_0000", "h00_37FF_FFFF",   "h0", "Reserved",    "RW"),
107ca2f90a6SLemover      MemMap("h00_3800_0000", "h00_3800_FFFF",   "h0", "CLINT",       "RW"),
108ca2f90a6SLemover      MemMap("h00_3801_0000", "h00_3801_FFFF",   "h0", "BEU",         "RW"),
109ca2f90a6SLemover      MemMap("h00_3802_0000", "h00_3802_0FFF",   "h0", "DebugModule", "RWX"),
110*5b7ef044SLemover      MemMap("h00_3802_1000", "h00_3802_1FFF",   "h0", "MMPMA",       "RW"),
111*5b7ef044SLemover      MemMap("h00_3802_2000", "h00_3900_0FFF",   "h0", "Reserved",    ""),
112*5b7ef044SLemover      MemMap("h00_3900_1000", "h00_3900_1FFF",   "h0", "Core_reset",  "RW"),
113*5b7ef044SLemover      MemMap("h00_3900_2000", "h00_39FF_FFFF",   "h0", "Reserved",    ""),
114*5b7ef044SLemover      MemMap("h00_3A00_0000", "h00_3A00_0FFF",   "h0", "PLL0",        "RW),
115*5b7ef044SLemover      MemMap('h00_3A00_1000", "h00_3BFF_FFFF",   "h0", "Reserved",    ""),
116ca2f90a6SLemover      MemMap("h00_3C00_0000", "h00_3FFF_FFFF",   "h0", "PLIC",        "RW"),
117ca2f90a6SLemover      MemMap("h00_4000_0000", "h00_7FFF_FFFF",   "h0", "PCIe",        "RW"),
1182f30d658SYinan Xu      MemMap("h00_8000_0000", "h0F_FFFF_FFFF",   "h0", "DDR",         "RWXIDSA"),
119ca2f90a6SLemover    )
120ca2f90a6SLemover   */
121ca2f90a6SLemover
122ca2f90a6SLemover  def pma_init() : (Vec[UInt], Vec[UInt], Vec[UInt]) = {
123ca2f90a6SLemover    // the init value is zero
124ca2f90a6SLemover    // from 0 to num(default 16) - 1, lower priority
125ca2f90a6SLemover    // according to simple map, 9 entries is needed, pick 6-14, leave 0-5 & 15 unusedcfgMerged.map(_ := 0.U)
126ca2f90a6SLemover
127ca2f90a6SLemover    val num = NumPMA
128ca2f90a6SLemover    require(num >= 16)
129ca2f90a6SLemover    val cfg = WireInit(0.U.asTypeOf(Vec(num, new PMPConfig())))
130ca2f90a6SLemover
13198c71602SJiawei Lin    val addr = Wire(Vec(num, UInt((PMPAddrBits-PMPOffBits).W)))
13298c71602SJiawei Lin    val mask = Wire(Vec(num, UInt(PMPAddrBits.W)))
133ca2f90a6SLemover    addr := DontCare
134ca2f90a6SLemover    mask := DontCare
135ca2f90a6SLemover
136aec79401SLemover    var idx = num-1
1372f30d658SYinan Xu
138aec79401SLemover    // TODO: turn to napot to save entries
139ca2f90a6SLemover    // use tor instead of napot, for napot may be confusing and hard to understand
140aec79401SLemover    // NOTE: all the addr space are default set to DDR, RWXCA
141aec79401SLemover    idx = idx - 1
142aec79401SLemover    addr(idx) := shift_addr(0xFFFFFFFFFL) // all the addr are default ddr, whicn means rwxca
143aec79401SLemover    cfg(idx).a := 3.U; cfg(idx).r := true.B; cfg(idx).w := true.B; cfg(idx).x := true.B; cfg(idx).c := true.B; cfg(idx).atomic := true.B
144aec79401SLemover    mask(idx) := match_mask(addr(idx), cfg(idx))
145aec79401SLemover    idx = idx - 1
146ca2f90a6SLemover
147aec79401SLemover    // NOTE: (0x0_0000_0000L, 0x0_8000_0000L) are default set to MMIO, only RW
148aec79401SLemover    addr(idx) := get_napot(0x00000000L, 0x80000000L)
149aec79401SLemover    cfg(idx).a := 3.U; cfg(idx).r := true.B; cfg(idx).w := true.B
150aec79401SLemover    mask(idx) := match_mask(addr(idx), cfg(idx))
151aec79401SLemover    idx = idx - 1
152ca2f90a6SLemover
153aec79401SLemover    addr(idx) := shift_addr(0x3C000000)
154aec79401SLemover    cfg(idx).a := 1.U
155aec79401SLemover    idx = idx - 1
156ca2f90a6SLemover
157*5b7ef044SLemover    addr(idx) := shift_addr(0x3A001000)
158630aeed7Srvcoresjw    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
159aec79401SLemover    idx = idx - 1
160ca2f90a6SLemover
161aec79401SLemover    addr(idx) := shift_addr(0x3A000000)
162aec79401SLemover    cfg(idx).a := 1.U
163aec79401SLemover    idx = idx - 1
164ca2f90a6SLemover
165*5b7ef044SLemover    addr(idx) := shift_addr(0x39002000)
166630aeed7Srvcoresjw    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
167aec79401SLemover    idx = idx - 1
168ca2f90a6SLemover
169aec79401SLemover    addr(idx) := shift_addr(0x39001000)
170aec79401SLemover    cfg(idx).a := 1.U
171aec79401SLemover    idx = idx - 1
172ca2f90a6SLemover
173*5b7ef044SLemover    addr(idx) := shift_addr(0x38022000)
17498c71602SJiawei Lin    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
17598c71602SJiawei Lin    idx = idx - 1
17698c71602SJiawei Lin
177aec79401SLemover    addr(idx) := shift_addr(0x38021000)
178aec79401SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B; cfg(idx).x := true.B
179aec79401SLemover    idx = idx - 1
180ca2f90a6SLemover
181aec79401SLemover    addr(idx) := shift_addr(0x38020000)
182aec79401SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
183aec79401SLemover    idx = idx - 1
184ca2f90a6SLemover
185aec79401SLemover    addr(idx) := shift_addr( 0x30050000)
186cef5c4b4SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
187aec79401SLemover    idx = idx - 1
188aec79401SLemover
189aec79401SLemover    addr(idx) := shift_addr( 0x30010000)
190aec79401SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
191aec79401SLemover    idx = idx - 1
192aec79401SLemover
193aec79401SLemover    addr(idx) := shift_addr( 0x20000000)
194aec79401SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B; cfg(idx).x := true.B
195aec79401SLemover    idx = idx - 1
196aec79401SLemover
197aec79401SLemover    addr(idx) := shift_addr( 0x10000000)
198aec79401SLemover    cfg(idx).a := 1.U; cfg(idx).r := true.B; cfg(idx).w := true.B
199aec79401SLemover    idx = idx - 1
200aec79401SLemover
201aec79401SLemover    addr(idx) := shift_addr(0)
202aec79401SLemover
203aec79401SLemover    require(idx >= 0)
204ca2f90a6SLemover
20598c71602SJiawei Lin    val cfgInitMerge = cfg.asTypeOf(Vec(num/8, UInt(PMXLEN.W)))
206ca2f90a6SLemover    (cfgInitMerge, addr, mask)
207ca2f90a6SLemover  }
208ca2f90a6SLemover
209aec79401SLemover  def get_napot(base: BigInt, range: BigInt) = {
210aec79401SLemover    val PlatformGrainBytes = (1 << PlatformGrain)
211aec79401SLemover    if ((base % PlatformGrainBytes) != 0) {
212aec79401SLemover      println("base:%x", base)
213aec79401SLemover    }
214aec79401SLemover    if ((range % PlatformGrainBytes) != 0) {
215aec79401SLemover      println("range: %x", range)
216aec79401SLemover    }
217aec79401SLemover    require((base % PlatformGrainBytes) == 0)
218aec79401SLemover    require((range % PlatformGrainBytes) == 0)
219aec79401SLemover
220aec79401SLemover    ((base + (range/2 - 1)) >> PMPOffBits).U
221aec79401SLemover  }
222aec79401SLemover
223aec79401SLemover  def match_mask(paddr: UInt, cfg: PMPConfig) = {
224aec79401SLemover    val match_mask_addr: UInt = Cat(paddr, cfg.a(0)).asUInt() | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
225aec79401SLemover    Cat(match_mask_addr & ~(match_mask_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
226aec79401SLemover  }
227aec79401SLemover
228ca2f90a6SLemover  def shift_addr(addr: BigInt) = {
229ca2f90a6SLemover    (addr >> 2).U
230ca2f90a6SLemover  }
231ca2f90a6SLemover}
232ca2f90a6SLemover
23398c71602SJiawei Lintrait PMACheckMethod extends PMPConst {
234ca2f90a6SLemover  def pma_check(cmd: UInt, cfg: PMPConfig) = {
235ca2f90a6SLemover    val resp = Wire(new PMPRespBundle)
236ca2f90a6SLemover    resp.ld := TlbCmd.isRead(cmd) && !TlbCmd.isAtom(cmd) && !cfg.r
237ca2f90a6SLemover    resp.st := (TlbCmd.isWrite(cmd) || TlbCmd.isAtom(cmd) && cfg.atomic) && !cfg.w
238ca2f90a6SLemover    resp.instr := TlbCmd.isExec(cmd) && !cfg.x
239ca2f90a6SLemover    resp.mmio := !cfg.c
240ca2f90a6SLemover    resp
241ca2f90a6SLemover  }
242ca2f90a6SLemover
2435cf62c1aSLemover  def pma_match_res(leaveHitMux: Boolean = false, valid: Bool = true.B)(
2445cf62c1aSLemover    addr: UInt,
2455cf62c1aSLemover    size: UInt,
2465cf62c1aSLemover    pmaEntries: Vec[PMPEntry],
2475cf62c1aSLemover    mode: UInt,
2485cf62c1aSLemover    lgMaxSize: Int
2495cf62c1aSLemover  ) = {
250ca2f90a6SLemover    val num = pmaEntries.size
251ca2f90a6SLemover    require(num == NumPMA)
252ca2f90a6SLemover    // pma should always be checked, could not be ignored
253ca2f90a6SLemover    // like amo and cached, it is the attribute not protection
254ca2f90a6SLemover    // so it must have initialization.
255ca2f90a6SLemover    require(!pmaEntries.isEmpty)
256ca2f90a6SLemover
257a15116bdSLemover    val pmaDefault = WireInit(0.U.asTypeOf(new PMPEntry()))
258a15116bdSLemover    val match_vec = Wire(Vec(num+1, Bool()))
259a15116bdSLemover    val cfg_vec = Wire(Vec(num+1, new PMPEntry()))
260a15116bdSLemover
261a15116bdSLemover    pmaEntries.zip(pmaDefault +: pmaEntries.take(num-1)).zipWithIndex.foreach{ case ((pma, last_pma), i) =>
262ca2f90a6SLemover      val is_match = pma.is_match(addr, size, lgMaxSize, last_pma)
263ca2f90a6SLemover      val aligned = pma.aligned(addr, size, lgMaxSize, last_pma)
264ca2f90a6SLemover
265ca2f90a6SLemover      val cur = WireInit(pma)
266ca2f90a6SLemover      cur.cfg.r := aligned && pma.cfg.r
267ca2f90a6SLemover      cur.cfg.w := aligned && pma.cfg.w
268ca2f90a6SLemover      cur.cfg.x := aligned && pma.cfg.x
269ca2f90a6SLemover      cur.cfg.atomic := aligned && pma.cfg.atomic
270ca2f90a6SLemover      cur.cfg.c := aligned && pma.cfg.c
271ca2f90a6SLemover
272a15116bdSLemover      match_vec(i) := is_match
273a15116bdSLemover      cfg_vec(i) := cur
274ca2f90a6SLemover    }
275a15116bdSLemover
276a15116bdSLemover    match_vec(num) := true.B
277a15116bdSLemover    cfg_vec(num) := pmaDefault
2785cf62c1aSLemover    if (leaveHitMux) {
2795cf62c1aSLemover      ParallelPriorityMux(match_vec.map(RegEnable(_, init = false.B, valid)), RegEnable(cfg_vec, valid))
2805cf62c1aSLemover    } else {
281a15116bdSLemover      ParallelPriorityMux(match_vec, cfg_vec)
282ca2f90a6SLemover    }
283ca2f90a6SLemover  }
2845cf62c1aSLemover}
285