xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/TLB.scala (revision 92e3bfefd90c9c71e8a65e5955c61ee13765fb9d)
16d5ddbceSLemover/***************************************************************************************
26d5ddbceSLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3f320e0f0SYinan Xu* Copyright (c) 2020-2021 Peng Cheng Laboratory
46d5ddbceSLemover*
56d5ddbceSLemover* XiangShan is licensed under Mulan PSL v2.
66d5ddbceSLemover* You can use this software according to the terms and conditions of the Mulan PSL v2.
76d5ddbceSLemover* You may obtain a copy of Mulan PSL v2 at:
86d5ddbceSLemover*          http://license.coscl.org.cn/MulanPSL2
96d5ddbceSLemover*
106d5ddbceSLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
116d5ddbceSLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
126d5ddbceSLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
136d5ddbceSLemover*
146d5ddbceSLemover* See the Mulan PSL v2 for more details.
156d5ddbceSLemover***************************************************************************************/
166d5ddbceSLemover
176d5ddbceSLemoverpackage xiangshan.cache.mmu
186d5ddbceSLemover
196d5ddbceSLemoverimport chipsalliance.rocketchip.config.Parameters
206d5ddbceSLemoverimport chisel3._
21a0301c0dSLemoverimport chisel3.internal.naming.chiselName
226d5ddbceSLemoverimport chisel3.util._
23a0301c0dSLemoverimport freechips.rocketchip.util.SRAMAnnotation
246d5ddbceSLemoverimport xiangshan._
256d5ddbceSLemoverimport utils._
26b6982e83SLemoverimport xiangshan.backend.fu.{PMPChecker, PMPReqBundle}
279aca92b9SYinan Xuimport xiangshan.backend.rob.RobPtr
286d5ddbceSLemoverimport xiangshan.backend.fu.util.HasCSRConst
296d5ddbceSLemover
30a0301c0dSLemover
31a0301c0dSLemover@chiselName
321ca0e4f3SYinan Xuclass TLB(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule with HasCSRConst with HasPerfEvents {
33a0301c0dSLemover  val io = IO(new TlbIO(Width, q))
34a0301c0dSLemover
35a0301c0dSLemover  require(q.superAssociative == "fa")
36fb90f54dSLemover  if (q.sameCycle || q.missSameCycle) {
37a0301c0dSLemover    require(q.normalAssociative == "fa")
38a0301c0dSLemover  }
396d5ddbceSLemover
406d5ddbceSLemover  val req = io.requestor.map(_.req)
416d5ddbceSLemover  val resp = io.requestor.map(_.resp)
426d5ddbceSLemover  val ptw = io.ptw
43b6982e83SLemover  val pmp = io.pmp
446d5ddbceSLemover
456d5ddbceSLemover  val sfence = io.sfence
466d5ddbceSLemover  val csr = io.csr
476d5ddbceSLemover  val satp = csr.satp
486d5ddbceSLemover  val priv = csr.priv
49a0301c0dSLemover  val ifecth = if (q.fetchi) true.B else false.B
50a0301c0dSLemover  val mode = if (q.useDmode) priv.dmode else priv.imode
516d5ddbceSLemover  // val vmEnable = satp.mode === 8.U // && (mode < ModeM) // FIXME: fix me when boot xv6/linux...
526d5ddbceSLemover  val vmEnable = if (EnbaleTlbDebug) (satp.mode === 8.U)
536d5ddbceSLemover  else (satp.mode === 8.U && (mode < ModeM))
546d5ddbceSLemover
552c2c1588SLemover  val reqAddr = req.map(_.bits.vaddr.asTypeOf(new VaBundle))
56a0301c0dSLemover  val vpn = reqAddr.map(_.vpn)
576d5ddbceSLemover  val cmd = req.map(_.bits.cmd)
586d5ddbceSLemover  val valid = req.map(_.valid)
596d5ddbceSLemover
606d5ddbceSLemover  def widthMapSeq[T <: Seq[Data]](f: Int => T) = (0 until Width).map(f)
61a0301c0dSLemover
626d5ddbceSLemover  def widthMap[T <: Data](f: Int => T) = (0 until Width).map(f)
636d5ddbceSLemover
646d5ddbceSLemover  // Normal page && Super page
65a0301c0dSLemover  val normalPage = TlbStorage(
66a0301c0dSLemover    name = "normal",
67a0301c0dSLemover    associative = q.normalAssociative,
68a0301c0dSLemover    sameCycle = q.sameCycle,
69a0301c0dSLemover    ports = Width,
70a0301c0dSLemover    nSets = q.normalNSets,
71a0301c0dSLemover    nWays = q.normalNWays,
72a0301c0dSLemover    sramSinglePort = sramSinglePort,
735cf62c1aSLemover    saveLevel = q.saveLevel,
74a0301c0dSLemover    normalPage = true,
75a0301c0dSLemover    superPage = false
766d5ddbceSLemover  )
77a0301c0dSLemover  val superPage = TlbStorage(
78a0301c0dSLemover    name = "super",
79a0301c0dSLemover    associative = q.superAssociative,
80a0301c0dSLemover    sameCycle = q.sameCycle,
81a0301c0dSLemover    ports = Width,
82a0301c0dSLemover    nSets = q.superNSets,
83a0301c0dSLemover    nWays = q.superNWays,
84a0301c0dSLemover    sramSinglePort = sramSinglePort,
855cf62c1aSLemover    saveLevel = q.saveLevel,
86a0301c0dSLemover    normalPage = q.normalAsVictim,
87a0301c0dSLemover    superPage = true,
886d5ddbceSLemover  )
896d5ddbceSLemover
90a0301c0dSLemover
916d5ddbceSLemover  for (i <- 0 until Width) {
92a0301c0dSLemover    normalPage.r_req_apply(
93a0301c0dSLemover      valid = io.requestor(i).req.valid,
94a0301c0dSLemover      vpn = vpn(i),
9545f497a4Shappy-lx      asid = csr.satp.asid,
96a0301c0dSLemover      i = i
976d5ddbceSLemover    )
98a0301c0dSLemover    superPage.r_req_apply(
99a0301c0dSLemover      valid = io.requestor(i).req.valid,
100a0301c0dSLemover      vpn = vpn(i),
10145f497a4Shappy-lx      asid = csr.satp.asid,
102a0301c0dSLemover      i = i
103a0301c0dSLemover    )
104a0301c0dSLemover  }
1056d5ddbceSLemover
106a0301c0dSLemover  normalPage.victim.in <> superPage.victim.out
107a0301c0dSLemover  normalPage.victim.out <> superPage.victim.in
108a0301c0dSLemover  normalPage.sfence <> io.sfence
109a0301c0dSLemover  superPage.sfence <> io.sfence
11045f497a4Shappy-lx  normalPage.csr <> io.csr
11145f497a4Shappy-lx  superPage.csr <> io.csr
112149086eaSLemover
113a0301c0dSLemover  def TLBNormalRead(i: Int) = {
114fb90f54dSLemover    val (n_hit_sameCycle, normal_hit, normal_ppn, normal_perm) = normalPage.r_resp_apply(i)
115fb90f54dSLemover    val (s_hit_sameCycle, super_hit, super_ppn, super_perm) = superPage.r_resp_apply(i)
11670083794SLemover    // assert(!(normal_hit && super_hit && vmEnable && RegNext(req(i).valid, init = false.B)))
1176d5ddbceSLemover
118a0301c0dSLemover    val hit = normal_hit || super_hit
119fb90f54dSLemover    val hit_sameCycle = n_hit_sameCycle || s_hit_sameCycle
120cccfc98dSLemover    val ppn = Mux(super_hit, super_ppn, normal_ppn)
121cccfc98dSLemover    val perm = Mux(super_hit, super_perm, normal_perm)
122a0301c0dSLemover
123e9092fe2SLemover    val pf = perm.pf
124e9092fe2SLemover    val af = perm.af
125a0301c0dSLemover    val cmdReg = if (!q.sameCycle) RegNext(cmd(i)) else cmd(i)
126a0301c0dSLemover    val validReg = if (!q.sameCycle) RegNext(valid(i)) else valid(i)
127a0301c0dSLemover    val offReg = if (!q.sameCycle) RegNext(reqAddr(i).off) else reqAddr(i).off
128b6982e83SLemover    val sizeReg = if (!q.sameCycle) RegNext(req(i).bits.size) else req(i).bits.size
129a0301c0dSLemover
130a0301c0dSLemover    /** *************** next cycle when two cycle is false******************* */
131a0301c0dSLemover    val miss = !hit && vmEnable
132cccfc98dSLemover    val fast_miss = !super_hit && vmEnable
133fb90f54dSLemover    val miss_sameCycle = !hit_sameCycle && vmEnable
1346d5ddbceSLemover    hit.suggestName(s"hit_${i}")
1356d5ddbceSLemover    miss.suggestName(s"miss_${i}")
1366d5ddbceSLemover
137a0301c0dSLemover    XSDebug(validReg, p"(${i.U}) hit:${hit} miss:${miss} ppn:${Hexadecimal(ppn)} perm:${perm}\n")
1386d5ddbceSLemover
139a0301c0dSLemover    val paddr = Cat(ppn, offReg)
1406d5ddbceSLemover    val vaddr = SignExt(req(i).bits.vaddr, PAddrBits)
14170083794SLemover    val refill_reg = RegNext(io.ptw.resp.valid)
1426d5ddbceSLemover    req(i).ready := resp(i).ready
1436d5ddbceSLemover    resp(i).valid := validReg
144a0301c0dSLemover    resp(i).bits.paddr := Mux(vmEnable, paddr, if (!q.sameCycle) RegNext(vaddr) else vaddr)
14570083794SLemover    resp(i).bits.miss := { if (q.missSameCycle) miss_sameCycle else (miss || refill_reg) }
14670083794SLemover    resp(i).bits.fast_miss := fast_miss || refill_reg
1476d5ddbceSLemover    resp(i).bits.ptwBack := io.ptw.resp.fire()
1486d5ddbceSLemover
1495b7ef044SLemover    // for timing optimization, pmp check is divided into dynamic and static
1505b7ef044SLemover    // dynamic: superpage (or full-connected reg entries) -> check pmp when translation done
1515b7ef044SLemover    // static: 4K pages (or sram entries) -> check pmp with pre-checked results
1525b7ef044SLemover    val pmp_paddr = Mux(vmEnable, Cat(super_ppn, offReg), if (!q.sameCycle) RegNext(vaddr) else vaddr)
153b6982e83SLemover    pmp(i).valid := resp(i).valid
1545b7ef044SLemover    pmp(i).bits.addr := pmp_paddr
155b6982e83SLemover    pmp(i).bits.size := sizeReg
156b6982e83SLemover    pmp(i).bits.cmd := cmdReg
157b6982e83SLemover
158e9092fe2SLemover    val ldUpdate = !perm.a && TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg) // update A/D through exception
159e9092fe2SLemover    val stUpdate = (!perm.a || !perm.d) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg)) // update A/D through exception
160e9092fe2SLemover    val instrUpdate = !perm.a && TlbCmd.isExec(cmdReg) // update A/D through exception
1616d5ddbceSLemover    val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth))
162a79fef67Swakafa    val ldPermFail = !(modeCheck && (perm.r || priv.mxr && perm.x))
163a79fef67Swakafa    val stPermFail = !(modeCheck && perm.w)
164a79fef67Swakafa    val instrPermFail = !(modeCheck && perm.x)
165a79fef67Swakafa    val ldPf = (ldPermFail || pf) && (TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg))
166a79fef67Swakafa    val stPf = (stPermFail || pf) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg))
167a79fef67Swakafa    val instrPf = (instrPermFail || pf) && TlbCmd.isExec(cmdReg)
1682c2c1588SLemover    val fault_valid = vmEnable
169ca2f90a6SLemover    resp(i).bits.excp.pf.ld := (ldPf || ldUpdate) && fault_valid && !af
170ca2f90a6SLemover    resp(i).bits.excp.pf.st := (stPf || stUpdate) && fault_valid && !af
171ca2f90a6SLemover    resp(i).bits.excp.pf.instr := (instrPf || instrUpdate) && fault_valid && !af
172b6982e83SLemover    // NOTE: pf need && with !af, page fault has higher priority than access fault
173b6982e83SLemover    // but ptw may also have access fault, then af happens, the translation is wrong.
174b6982e83SLemover    // In this case, pf has lower priority than af
1756d5ddbceSLemover
1765b7ef044SLemover    val spm = normal_perm.pm // static physical memory protection or attribute
1775b7ef044SLemover    val spm_v = !super_hit && vmEnable && q.partialStaticPMP.B // static pm valid; do not use normal_hit, it's too long.
1785b7ef044SLemover    // for tlb without sram, tlb will miss, pm should be ignored outsize
1795b7ef044SLemover    resp(i).bits.excp.af.ld    := (af || (spm_v && !spm.r)) && TlbCmd.isRead(cmdReg) && fault_valid
1805b7ef044SLemover    resp(i).bits.excp.af.st    := (af || (spm_v && !spm.w)) && TlbCmd.isWrite(cmdReg) && fault_valid
1815b7ef044SLemover    resp(i).bits.excp.af.instr := (af || (spm_v && !spm.x)) && TlbCmd.isExec(cmdReg) && fault_valid
1825b7ef044SLemover    resp(i).bits.static_pm.valid := spm_v && fault_valid // ls/st unit should use this mmio, not the result from pmp
1835b7ef044SLemover    resp(i).bits.static_pm.bits := !spm.c
1846d5ddbceSLemover
1853889e11eSLemover    (hit, miss, validReg)
1866d5ddbceSLemover  }
1876d5ddbceSLemover
1886d5ddbceSLemover  val readResult = (0 until Width).map(TLBNormalRead(_))
189a0301c0dSLemover  val hitVec = readResult.map(_._1)
190a0301c0dSLemover  val missVec = readResult.map(_._2)
1913889e11eSLemover  val validRegVec = readResult.map(_._3)
1926d5ddbceSLemover
193149086eaSLemover  // replacement
194a0301c0dSLemover  def get_access(one_hot: UInt, valid: Bool): Valid[UInt] = {
195149086eaSLemover    val res = Wire(Valid(UInt(log2Up(one_hot.getWidth).W)))
196a0301c0dSLemover    res.valid := Cat(one_hot).orR && valid
197149086eaSLemover    res.bits := OHToUInt(one_hot)
198149086eaSLemover    res
199149086eaSLemover  }
200a0301c0dSLemover
201a0301c0dSLemover  val normal_refill_idx = if (q.outReplace) {
2023889e11eSLemover    io.replace.normalPage.access <> normalPage.access
2033889e11eSLemover    io.replace.normalPage.chosen_set := get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets)
204a0301c0dSLemover    io.replace.normalPage.refillIdx
205a0301c0dSLemover  } else if (q.normalAssociative == "fa") {
206a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays)
2073889e11eSLemover    re.access(normalPage.access.map(_.touch_ways)) // normalhitVecVec.zipWithIndex.map{ case (hv, i) => get_access(hv, validRegVec(i))})
208a0301c0dSLemover    re.way
209a0301c0dSLemover  } else { // set-acco && plru
210a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays)
2113889e11eSLemover    re.access(normalPage.access.map(_.sets), normalPage.access.map(_.touch_ways))
2123889e11eSLemover    re.way(get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets))
213149086eaSLemover  }
214a0301c0dSLemover
215a0301c0dSLemover  val super_refill_idx = if (q.outReplace) {
2163889e11eSLemover    io.replace.superPage.access <> superPage.access
217a0301c0dSLemover    io.replace.superPage.chosen_set := DontCare
218a0301c0dSLemover    io.replace.superPage.refillIdx
219149086eaSLemover  } else {
220a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays)
2213889e11eSLemover    re.access(superPage.access.map(_.touch_ways))
222a0301c0dSLemover    re.way
223149086eaSLemover  }
224149086eaSLemover
22545f497a4Shappy-lx  val refill = ptw.resp.fire() && !sfence.valid && !satp.changed
226a0301c0dSLemover  normalPage.w_apply(
227a0301c0dSLemover    valid = { if (q.normalAsVictim) false.B
228a0301c0dSLemover    else refill && ptw.resp.bits.entry.level.get === 2.U },
229a0301c0dSLemover    wayIdx = normal_refill_idx,
2305b7ef044SLemover    data = ptw.resp.bits,
2315b7ef044SLemover    data_replenish = io.ptw_replenish
232a0301c0dSLemover  )
233a0301c0dSLemover  superPage.w_apply(
234a0301c0dSLemover    valid = { if (q.normalAsVictim) refill
235a0301c0dSLemover    else refill && ptw.resp.bits.entry.level.get =/= 2.U },
236a0301c0dSLemover    wayIdx = super_refill_idx,
2375b7ef044SLemover    data = ptw.resp.bits,
2385b7ef044SLemover    data_replenish = io.ptw_replenish
239a0301c0dSLemover  )
240a0301c0dSLemover
2412c2c1588SLemover  // if sameCycle, just req.valid
2422c2c1588SLemover  // if !sameCycle, add one more RegNext based on !sameCycle's RegNext
2432c2c1588SLemover  // because sram is too slow and dtlb is too distant from dtlbRepeater
2446d5ddbceSLemover  for (i <- 0 until Width) {
2452c2c1588SLemover    io.ptw.req(i).valid :=  need_RegNextInit(!q.sameCycle, validRegVec(i) && missVec(i), false.B) &&
2462c2c1588SLemover      !RegNext(refill, init = false.B) &&
2472c2c1588SLemover      param_choose(!q.sameCycle, !RegNext(RegNext(refill, init = false.B), init = false.B), true.B)
2482c2c1588SLemover    io.ptw.req(i).bits.vpn := need_RegNext(!q.sameCycle, need_RegNext(!q.sameCycle, reqAddr(i).vpn))
2496d5ddbceSLemover  }
2506d5ddbceSLemover  io.ptw.resp.ready := true.B
2516d5ddbceSLemover
2522c2c1588SLemover  def need_RegNext[T <: Data](need: Boolean, data: T): T = {
2532c2c1588SLemover    if (need) RegNext(data)
2542c2c1588SLemover    else data
2552c2c1588SLemover  }
2562c2c1588SLemover  def need_RegNextInit[T <: Data](need: Boolean, data: T, init_value: T): T = {
2572c2c1588SLemover    if (need) RegNext(data, init = init_value)
2582c2c1588SLemover    else data
2592c2c1588SLemover  }
2602c2c1588SLemover
2612c2c1588SLemover  def param_choose[T <: Data](need: Boolean, truedata: T, falsedata: T): T = {
2622c2c1588SLemover    if (need) truedata
2632c2c1588SLemover    else falsedata
2642c2c1588SLemover  }
2652c2c1588SLemover
266a0301c0dSLemover  if (!q.shouldBlock) {
2676d5ddbceSLemover    for (i <- 0 until Width) {
2686d5ddbceSLemover      XSPerfAccumulate("first_access" + Integer.toString(i, 10), validRegVec(i) && vmEnable && RegNext(req(i).bits.debug.isFirstIssue))
2696d5ddbceSLemover      XSPerfAccumulate("access" + Integer.toString(i, 10), validRegVec(i) && vmEnable)
2706d5ddbceSLemover    }
2716d5ddbceSLemover    for (i <- 0 until Width) {
2726d5ddbceSLemover      XSPerfAccumulate("first_miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i) && RegNext(req(i).bits.debug.isFirstIssue))
2736d5ddbceSLemover      XSPerfAccumulate("miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i))
2746d5ddbceSLemover    }
2756d5ddbceSLemover  } else {
2766d5ddbceSLemover    // NOTE: ITLB is blocked, so every resp will be valid only when hit
2776d5ddbceSLemover    // every req will be ready only when hit
278a0301c0dSLemover    for (i <- 0 until Width) {
279a0301c0dSLemover      XSPerfAccumulate(s"access${i}", io.requestor(i).req.fire() && vmEnable)
280a0301c0dSLemover      XSPerfAccumulate(s"miss${i}", ptw.req(i).fire())
281a0301c0dSLemover    }
282a0301c0dSLemover
2836d5ddbceSLemover  }
2846d5ddbceSLemover  //val reqCycleCnt = Reg(UInt(16.W))
2856d5ddbceSLemover  //reqCycleCnt := reqCycleCnt + BoolStopWatch(ptw.req(0).fire(), ptw.resp.fire || sfence.valid)
2866d5ddbceSLemover  //XSPerfAccumulate("ptw_req_count", ptw.req.fire())
2876d5ddbceSLemover  //XSPerfAccumulate("ptw_req_cycle", Mux(ptw.resp.fire(), reqCycleCnt, 0.U))
2886d5ddbceSLemover  XSPerfAccumulate("ptw_resp_count", ptw.resp.fire())
2896d5ddbceSLemover  XSPerfAccumulate("ptw_resp_pf_count", ptw.resp.fire() && ptw.resp.bits.pf)
2906d5ddbceSLemover
2916d5ddbceSLemover  // Log
2926d5ddbceSLemover  for(i <- 0 until Width) {
2936d5ddbceSLemover    XSDebug(req(i).valid, p"req(${i.U}): (${req(i).valid} ${req(i).ready}) ${req(i).bits}\n")
2946d5ddbceSLemover    XSDebug(resp(i).valid, p"resp(${i.U}): (${resp(i).valid} ${resp(i).ready}) ${resp(i).bits}\n")
2956d5ddbceSLemover  }
2966d5ddbceSLemover
2976d5ddbceSLemover  XSDebug(sfence.valid, p"Sfence: ${sfence}\n")
2986d5ddbceSLemover  XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n")
299a0301c0dSLemover  XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hitVec).asUInt)} miss:${Binary(VecInit(missVec).asUInt)}\n")
3006d5ddbceSLemover  for (i <- ptw.req.indices) {
301*92e3bfefSLemover    XSDebug(ptw.req(i).fire(), p"L2TLB req:${ptw.req(i).bits}\n")
3026d5ddbceSLemover  }
303*92e3bfefSLemover  XSDebug(ptw.resp.valid, p"L2TLB resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n")
3046d5ddbceSLemover
305a0301c0dSLemover  println(s"${q.name}: normal page: ${q.normalNWays} ${q.normalAssociative} ${q.normalReplacer.get} super page: ${q.superNWays} ${q.superAssociative} ${q.superReplacer.get}")
306a0301c0dSLemover
3076d5ddbceSLemover//   // NOTE: just for simple tlb debug, comment it after tlb's debug
3086d5ddbceSLemover  // assert(!io.ptw.resp.valid || io.ptw.resp.bits.entry.tag === io.ptw.resp.bits.entry.ppn, "Simple tlb debug requires vpn === ppn")
3091ca0e4f3SYinan Xu
3101ca0e4f3SYinan Xu  val perfEvents = if(!q.shouldBlock) {
3111ca0e4f3SYinan Xu    Seq(
312cd365d4cSrvcoresjw      ("access", PopCount((0 until Width).map(i => vmEnable && validRegVec(i)))              ),
313cd365d4cSrvcoresjw      ("miss  ", PopCount((0 until Width).map(i => vmEnable && validRegVec(i) && missVec(i)))),
314cd365d4cSrvcoresjw    )
315cd365d4cSrvcoresjw  } else {
3161ca0e4f3SYinan Xu    Seq(
317cd365d4cSrvcoresjw      ("access", PopCount((0 until Width).map(i => io.requestor(i).req.fire()))),
318cd365d4cSrvcoresjw      ("miss  ", PopCount((0 until Width).map(i => ptw.req(i).fire()))         ),
319cd365d4cSrvcoresjw    )
320cd365d4cSrvcoresjw  }
3211ca0e4f3SYinan Xu  generatePerfEvent()
3226d5ddbceSLemover}
3236d5ddbceSLemover
324a0301c0dSLemoverclass TlbReplace(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule {
325a0301c0dSLemover  val io = IO(new TlbReplaceIO(Width, q))
326a0301c0dSLemover
327a0301c0dSLemover  if (q.normalAssociative == "fa") {
328a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays)
3293889e11eSLemover    re.access(io.normalPage.access.map(_.touch_ways))
330a0301c0dSLemover    io.normalPage.refillIdx := re.way
331a0301c0dSLemover  } else { // set-acco && plru
332a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays)
3333889e11eSLemover    re.access(io.normalPage.access.map(_.sets), io.normalPage.access.map(_.touch_ways))
334a0301c0dSLemover    io.normalPage.refillIdx := { if (q.normalNWays == 1) 0.U else re.way(io.normalPage.chosen_set) }
335a0301c0dSLemover  }
336a0301c0dSLemover
337a0301c0dSLemover  if (q.superAssociative == "fa") {
338a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays)
3393889e11eSLemover    re.access(io.superPage.access.map(_.touch_ways))
340a0301c0dSLemover    io.superPage.refillIdx := re.way
341a0301c0dSLemover  } else { // set-acco && plru
342a0301c0dSLemover    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNSets, q.superNWays)
3433889e11eSLemover    re.access(io.superPage.access.map(_.sets), io.superPage.access.map(_.touch_ways))
344a0301c0dSLemover    io.superPage.refillIdx := { if (q.superNWays == 1) 0.U else re.way(io.superPage.chosen_set) }
345a0301c0dSLemover  }
346a0301c0dSLemover}
347a0301c0dSLemover
3486d5ddbceSLemoverobject TLB {
3496d5ddbceSLemover  def apply
3506d5ddbceSLemover  (
3516d5ddbceSLemover    in: Seq[BlockTlbRequestIO],
3526d5ddbceSLemover    sfence: SfenceBundle,
3536d5ddbceSLemover    csr: TlbCsrBundle,
3546d5ddbceSLemover    width: Int,
355a0301c0dSLemover    shouldBlock: Boolean,
356a0301c0dSLemover    q: TLBParameters
3576d5ddbceSLemover  )(implicit p: Parameters) = {
3586d5ddbceSLemover    require(in.length == width)
3596d5ddbceSLemover
360a0301c0dSLemover    val tlb = Module(new TLB(width, q))
3616d5ddbceSLemover
3626d5ddbceSLemover    tlb.io.sfence <> sfence
3636d5ddbceSLemover    tlb.io.csr <> csr
364a0301c0dSLemover    tlb.suggestName(s"tlb_${q.name}")
3656d5ddbceSLemover
3666d5ddbceSLemover    if (!shouldBlock) { // dtlb
3676d5ddbceSLemover      for (i <- 0 until width) {
3686d5ddbceSLemover        tlb.io.requestor(i) <> in(i)
3696d5ddbceSLemover        // tlb.io.requestor(i).req.valid := in(i).req.valid
3706d5ddbceSLemover        // tlb.io.requestor(i).req.bits := in(i).req.bits
3716d5ddbceSLemover        // in(i).req.ready := tlb.io.requestor(i).req.ready
3726d5ddbceSLemover
3736d5ddbceSLemover        // in(i).resp.valid := tlb.io.requestor(i).resp.valid
3746d5ddbceSLemover        // in(i).resp.bits := tlb.io.requestor(i).resp.bits
3756d5ddbceSLemover        // tlb.io.requestor(i).resp.ready := in(i).resp.ready
3766d5ddbceSLemover      }
3776d5ddbceSLemover    } else { // itlb
378d57bda64SJinYue      //require(width == 1)
379d57bda64SJinYue      (0 until width).map{ i =>
380d57bda64SJinYue        tlb.io.requestor(i).req.valid := in(i).req.valid
381d57bda64SJinYue        tlb.io.requestor(i).req.bits := in(i).req.bits
382d57bda64SJinYue        in(i).req.ready := !tlb.io.requestor(i).resp.bits.miss && in(i).resp.ready && tlb.io.requestor(i).req.ready
3836d5ddbceSLemover
384fb90f54dSLemover        require(q.missSameCycle || q.sameCycle)
385fb90f54dSLemover        // NOTE: the resp.valid seems to be useless, it must be true when need
386fb90f54dSLemover        //       But don't know what happens when true but not need, so keep it correct value, not just true.B
387fb90f54dSLemover        if (q.missSameCycle && !q.sameCycle) {
388fb90f54dSLemover          in(i).resp.valid := tlb.io.requestor(i).resp.valid && !RegNext(tlb.io.requestor(i).resp.bits.miss)
389fb90f54dSLemover        } else {
390d57bda64SJinYue          in(i).resp.valid := tlb.io.requestor(i).resp.valid && !tlb.io.requestor(i).resp.bits.miss
391fb90f54dSLemover        }
392d57bda64SJinYue        in(i).resp.bits := tlb.io.requestor(i).resp.bits
393d57bda64SJinYue        tlb.io.requestor(i).resp.ready := in(i).resp.ready
394d57bda64SJinYue      }
3955b7ef044SLemover      tlb.io.ptw_replenish <> DontCare // itlb only use reg, so no static pmp/pma
3966d5ddbceSLemover    }
3976d5ddbceSLemover    tlb.io.ptw
3986d5ddbceSLemover  }
3996d5ddbceSLemover}
400