xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/L2TLB.scala (revision 5ab1b84d02afebec93f68fa9ef6f37243fbdc0f9)
192e3bfefSLemover/***************************************************************************************
292e3bfefSLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
392e3bfefSLemover* Copyright (c) 2020-2021 Peng Cheng Laboratory
492e3bfefSLemover*
592e3bfefSLemover* XiangShan is licensed under Mulan PSL v2.
692e3bfefSLemover* You can use this software according to the terms and conditions of the Mulan PSL v2.
792e3bfefSLemover* You may obtain a copy of Mulan PSL v2 at:
892e3bfefSLemover*          http://license.coscl.org.cn/MulanPSL2
992e3bfefSLemover*
1092e3bfefSLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1192e3bfefSLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1292e3bfefSLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1392e3bfefSLemover*
1492e3bfefSLemover* See the Mulan PSL v2 for more details.
1592e3bfefSLemover***************************************************************************************/
1692e3bfefSLemover
1792e3bfefSLemoverpackage xiangshan.cache.mmu
1892e3bfefSLemover
1992e3bfefSLemoverimport chipsalliance.rocketchip.config.Parameters
2092e3bfefSLemoverimport chisel3._
2192e3bfefSLemoverimport chisel3.experimental.ExtModule
2292e3bfefSLemoverimport chisel3.util._
2392e3bfefSLemoverimport chisel3.internal.naming.chiselName
2492e3bfefSLemoverimport xiangshan._
2592e3bfefSLemoverimport xiangshan.cache.{HasDCacheParameters, MemoryOpConstants}
2692e3bfefSLemoverimport utils._
273c02ee8fSwakafaimport utility._
2892e3bfefSLemoverimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp}
2992e3bfefSLemoverimport freechips.rocketchip.tilelink._
3092e3bfefSLemoverimport xiangshan.backend.fu.{PMP, PMPChecker, PMPReqBundle, PMPRespBundle}
3192e3bfefSLemoverimport xiangshan.backend.fu.util.HasCSRConst
323c02ee8fSwakafaimport utility.ChiselDB
339c26bab7SHaoyuan Fengimport difftest._
3492e3bfefSLemover
3592e3bfefSLemoverclass L2TLB()(implicit p: Parameters) extends LazyModule with HasPtwConst {
3692e3bfefSLemover
3792e3bfefSLemover  val node = TLClientNode(Seq(TLMasterPortParameters.v1(
3892e3bfefSLemover    clients = Seq(TLMasterParameters.v1(
3992e3bfefSLemover      "ptw",
4092e3bfefSLemover      sourceId = IdRange(0, MemReqWidth)
4192e3bfefSLemover    ))
4292e3bfefSLemover  )))
4392e3bfefSLemover
4492e3bfefSLemover  lazy val module = new L2TLBImp(this)
4592e3bfefSLemover}
4692e3bfefSLemover
4792e3bfefSLemover@chiselName
4892e3bfefSLemoverclass L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) with HasCSRConst with HasPerfEvents {
4992e3bfefSLemover
5092e3bfefSLemover  val (mem, edge) = outer.node.out.head
5192e3bfefSLemover
5292e3bfefSLemover  val io = IO(new L2TLBIO)
5392e3bfefSLemover  val difftestIO = IO(new Bundle() {
5492e3bfefSLemover    val ptwResp = Output(Bool())
5592e3bfefSLemover    val ptwAddr = Output(UInt(64.W))
5692e3bfefSLemover    val ptwData = Output(Vec(4, UInt(64.W)))
5792e3bfefSLemover  })
5892e3bfefSLemover
5992e3bfefSLemover  /* Ptw processes multiple requests
6092e3bfefSLemover   * Divide Ptw procedure into two stages: cache access ; mem access if cache miss
6192e3bfefSLemover   *           miss queue itlb       dtlb
6292e3bfefSLemover   *               |       |         |
6392e3bfefSLemover   *               ------arbiter------
6492e3bfefSLemover   *                            |
6592e3bfefSLemover   *                    l1 - l2 - l3 - sp
6692e3bfefSLemover   *                            |
6792e3bfefSLemover   *          -------------------------------------------
6892e3bfefSLemover   *    miss  |  queue                                  | hit
6992e3bfefSLemover   *    [][][][][][]                                    |
7092e3bfefSLemover   *          |                                         |
7192e3bfefSLemover   *    state machine accessing mem                     |
7292e3bfefSLemover   *          |                                         |
7392e3bfefSLemover   *          ---------------arbiter---------------------
7492e3bfefSLemover   *                 |                    |
7592e3bfefSLemover   *                itlb                 dtlb
7692e3bfefSLemover   */
7792e3bfefSLemover
7892e3bfefSLemover  difftestIO <> DontCare
7992e3bfefSLemover
807797f035SbugGenerator  val sfence_tmp = DelayN(io.sfence, 1)
817797f035SbugGenerator  val csr_tmp    = DelayN(io.csr.tlb, 1)
827797f035SbugGenerator  val sfence_dup = Seq.fill(8)(RegNext(sfence_tmp))
837797f035SbugGenerator  val csr_dup = Seq.fill(7)(RegNext(csr_tmp))
847797f035SbugGenerator  val satp   = csr_dup(0).satp
857797f035SbugGenerator  val priv   = csr_dup(0).priv
867797f035SbugGenerator  val flush  = sfence_dup(0).valid || satp.changed
8792e3bfefSLemover
8892e3bfefSLemover  val pmp = Module(new PMP())
8992e3bfefSLemover  val pmp_check = VecInit(Seq.fill(2)(Module(new PMPChecker(lgMaxSize = 3, sameCycle = true)).io))
9092e3bfefSLemover  pmp.io.distribute_csr := io.csr.distribute_csr
9192e3bfefSLemover  pmp_check.foreach(_.check_env.apply(ModeS, pmp.io.pmp, pmp.io.pma))
9292e3bfefSLemover
9392e3bfefSLemover  val missQueue = Module(new L2TlbMissQueue)
9492e3bfefSLemover  val cache = Module(new PtwCache)
9592e3bfefSLemover  val ptw = Module(new PTW)
9692e3bfefSLemover  val llptw = Module(new LLPTW)
977797f035SbugGenerator  val blockmq = Module(new BlockHelper(3))
9892e3bfefSLemover  val arb1 = Module(new Arbiter(new PtwReq, PtwWidth))
9992e3bfefSLemover  val arb2 = Module(new Arbiter(new Bundle {
10092e3bfefSLemover    val vpn = UInt(vpnLen.W)
10192e3bfefSLemover    val source = UInt(bSourceWidth.W)
1029c503409SLemover  }, if (l2tlbParams.enablePrefetch) 4 else 3))
10392e3bfefSLemover  val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwResp, 3)).io)
10492e3bfefSLemover  val outArbCachePort = 0
10592e3bfefSLemover  val outArbFsmPort = 1
10692e3bfefSLemover  val outArbMqPort = 2
10792e3bfefSLemover
1089c503409SLemover  // arb2 input port
1099c503409SLemover  val InArbPTWPort = 0
1109c503409SLemover  val InArbMissQueuePort = 1
1119c503409SLemover  val InArbTlbPort = 2
1129c503409SLemover  val InArbPrefetchPort = 3
11392e3bfefSLemover  // NOTE: when cache out but miss and ptw doesnt accept,
11492e3bfefSLemover  arb1.io.in <> VecInit(io.tlb.map(_.req(0)))
1159c503409SLemover  arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready
11692e3bfefSLemover
1179c503409SLemover  arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid
1189c503409SLemover  arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn
1199c503409SLemover  arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source
1209c503409SLemover  ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready
12192e3bfefSLemover  block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready)
1227797f035SbugGenerator
12392e3bfefSLemover  arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid
12492e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn
12592e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen
12692e3bfefSLemover  if (l2tlbParams.enablePrefetch) {
12792e3bfefSLemover    val prefetch = Module(new L2TlbPrefetch())
12892e3bfefSLemover    val recv = cache.io.resp
12992e3bfefSLemover    // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch
13092e3bfefSLemover    // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch
13192e3bfefSLemover    prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit  ||
13292e3bfefSLemover      recv.bits.prefetch) && recv.bits.isFirst
13392e3bfefSLemover    prefetch.io.in.bits.vpn := recv.bits.req_info.vpn
1347797f035SbugGenerator    prefetch.io.sfence := sfence_dup(0)
1357797f035SbugGenerator    prefetch.io.csr := csr_dup(0)
13692e3bfefSLemover    arb2.io.in(InArbPrefetchPort) <> prefetch.io.out
1375afdf73cSHaoyuan Feng
1385afdf73cSHaoyuan Feng    val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB)
1395afdf73cSHaoyuan Feng    val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB)
1405afdf73cSHaoyuan Feng    L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn
1415afdf73cSHaoyuan Feng    L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset)
14292e3bfefSLemover  }
14392e3bfefSLemover  arb2.io.out.ready := cache.io.req.ready
14492e3bfefSLemover
1457797f035SbugGenerator
1467797f035SbugGenerator  val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2))
1477797f035SbugGenerator  mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit &&
1487797f035SbugGenerator    (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) &&
1497797f035SbugGenerator    !from_pre(cache.io.resp.bits.req_info.source) &&
1507797f035SbugGenerator    (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready)
1517797f035SbugGenerator  mq_arb.io.in(0).bits :=  cache.io.resp.bits.req_info
1527797f035SbugGenerator  mq_arb.io.in(1) <> llptw.io.cache
1537797f035SbugGenerator  missQueue.io.in <> mq_arb.io.out
1547797f035SbugGenerator  missQueue.io.sfence  := sfence_dup(6)
1557797f035SbugGenerator  missQueue.io.csr := csr_dup(5)
1567797f035SbugGenerator
1577797f035SbugGenerator  blockmq.io.start := missQueue.io.out.fire
1587797f035SbugGenerator  blockmq.io.enable := ptw.io.req.fire()
1597797f035SbugGenerator
1609c503409SLemover  llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed
1619c503409SLemover  llptw.io.in.bits.req_info := cache.io.resp.bits.req_info
1629c503409SLemover  llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn
1637797f035SbugGenerator  llptw.io.sfence := sfence_dup(1)
1647797f035SbugGenerator  llptw.io.csr := csr_dup(1)
16592e3bfefSLemover
16692e3bfefSLemover  cache.io.req.valid := arb2.io.out.valid
16792e3bfefSLemover  cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn
16892e3bfefSLemover  cache.io.req.bits.req_info.source := arb2.io.out.bits.source
16992e3bfefSLemover  cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U
1701f4a7c0cSLemover  cache.io.req.bits.bypassed.map(_ := false.B)
1717797f035SbugGenerator  cache.io.sfence := sfence_dup(2)
1727797f035SbugGenerator  cache.io.csr := csr_dup(2)
1737797f035SbugGenerator  cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2)
1747797f035SbugGenerator  cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2)
17592e3bfefSLemover  cache.io.resp.ready := Mux(cache.io.resp.bits.hit,
17692e3bfefSLemover    outReady(cache.io.resp.bits.req_info.source, outArbCachePort),
1779c503409SLemover    Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready,
1787797f035SbugGenerator    Mux(cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst, mq_arb.io.in(0).ready, mq_arb.io.in(0).ready || ptw.io.req.ready)))
17992e3bfefSLemover
18092e3bfefSLemover  // NOTE: missQueue req has higher priority
1817797f035SbugGenerator  ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit &&
1827797f035SbugGenerator    !cache.io.resp.bits.bypassed &&
1837797f035SbugGenerator    !cache.io.resp.bits.isFirst
18492e3bfefSLemover  ptw.io.req.bits.req_info := cache.io.resp.bits.req_info
18592e3bfefSLemover  ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit
18692e3bfefSLemover  ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn
1877797f035SbugGenerator  ptw.io.sfence := sfence_dup(7)
1887797f035SbugGenerator  ptw.io.csr := csr_dup(6)
18992e3bfefSLemover  ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort)
19092e3bfefSLemover
19192e3bfefSLemover  // mem req
19292e3bfefSLemover  def blockBytes_align(addr: UInt) = {
19392e3bfefSLemover    Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W))
19492e3bfefSLemover  }
19592e3bfefSLemover  def addr_low_from_vpn(vpn: UInt) = {
19692e3bfefSLemover    vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0)
19792e3bfefSLemover  }
19892e3bfefSLemover  def addr_low_from_paddr(paddr: UInt) = {
19992e3bfefSLemover    paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8))
20092e3bfefSLemover  }
20192e3bfefSLemover  def from_missqueue(id: UInt) = {
20292e3bfefSLemover    (id =/= l2tlbParams.llptwsize.U)
20392e3bfefSLemover  }
20492e3bfefSLemover  val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20592e3bfefSLemover  val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20692e3bfefSLemover  for (i <- waiting_resp.indices) {
20792e3bfefSLemover    assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true
20892e3bfefSLemover  }
20992e3bfefSLemover
21092e3bfefSLemover  val llptw_out = llptw.io.out
21192e3bfefSLemover  val llptw_mem = llptw.io.mem
21292e3bfefSLemover  llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize)
21392e3bfefSLemover  ptw.io.mem.mask := waiting_resp.last
21492e3bfefSLemover
21592e3bfefSLemover  val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2))
21692e3bfefSLemover  mem_arb.io.in(0) <> ptw.io.mem.req
21792e3bfefSLemover  mem_arb.io.in(1) <> llptw_mem.req
21892e3bfefSLemover  mem_arb.io.out.ready := mem.a.ready && !flush
21992e3bfefSLemover
2201f4a7c0cSLemover  // assert, should not send mem access at same addr for twice.
2217797f035SbugGenerator  val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid)
2227797f035SbugGenerator  val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid)
2231f4a7c0cSLemover  val last_resp_v = RegInit(false.B)
2241f4a7c0cSLemover  val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR
2251f4a7c0cSLemover  when (cache.io.refill.valid) { last_resp_v := !last_has_invalid}
2261f4a7c0cSLemover  when (flush) { last_resp_v := false.B }
2271f4a7c0cSLemover  XSError(last_resp_v && cache.io.refill.valid &&
2287797f035SbugGenerator    (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) &&
2297797f035SbugGenerator    (cache.io.refill.bits.level_dup(0) === last_resp_level),
2301f4a7c0cSLemover    "l2tlb should not access mem at same addr for twice")
2311f4a7c0cSLemover  // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid,
2321f4a7c0cSLemover  // but the current part is invalid, so one more mem access happened
2331f4a7c0cSLemover  // If this happened, remove the assert.
2341f4a7c0cSLemover
23592e3bfefSLemover  val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W)))
23692e3bfefSLemover
23792e3bfefSLemover  when (llptw.io.in.fire()) {
23892e3bfefSLemover    // when enq miss queue, set the req_addr_low to receive the mem resp data part
23992e3bfefSLemover    req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn)
24092e3bfefSLemover  }
24192e3bfefSLemover  when (mem_arb.io.out.fire()) {
24292e3bfefSLemover    req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr)
24392e3bfefSLemover    waiting_resp(mem_arb.io.out.bits.id) := true.B
24492e3bfefSLemover  }
24592e3bfefSLemover  // mem read
24692e3bfefSLemover  val memRead =  edge.Get(
24792e3bfefSLemover    fromSource = mem_arb.io.out.bits.id,
24892e3bfefSLemover    // toAddress  = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0),
24992e3bfefSLemover    toAddress  = blockBytes_align(mem_arb.io.out.bits.addr),
25092e3bfefSLemover    lgSize     = log2Up(l2tlbParams.blockBytes).U
25192e3bfefSLemover  )._2
25292e3bfefSLemover  mem.a.bits := memRead
25392e3bfefSLemover  mem.a.valid := mem_arb.io.out.valid && !flush
25492e3bfefSLemover  mem.d.ready := true.B
25592e3bfefSLemover  // mem -> data buffer
25692e3bfefSLemover  val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W)))
25792e3bfefSLemover  val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire())
25892e3bfefSLemover  val mem_resp_done = refill_helper._3
25992e3bfefSLemover  val mem_resp_from_mq = from_missqueue(mem.d.bits.source)
26092e3bfefSLemover  when (mem.d.valid) {
26192e3bfefSLemover    assert(mem.d.bits.source <= l2tlbParams.llptwsize.U)
26292e3bfefSLemover    refill_data(refill_helper._4) := mem.d.bits.data
26392e3bfefSLemover  }
2647797f035SbugGenerator  // refill_data_tmp is the wire fork of refill_data, but one cycle earlier
2657797f035SbugGenerator  val refill_data_tmp = WireInit(refill_data)
2667797f035SbugGenerator  refill_data_tmp(refill_helper._4) := mem.d.bits.data
2677797f035SbugGenerator
26892e3bfefSLemover  // save only one pte for each id
26992e3bfefSLemover  // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache)
27092e3bfefSLemover  val resp_pte = VecInit((0 until MemReqWidth).map(i =>
2717797f035SbugGenerator    if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) }
27292e3bfefSLemover    else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) }
2737797f035SbugGenerator    // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle
27492e3bfefSLemover  ))
27592e3bfefSLemover
27692e3bfefSLemover  // mem -> miss queue
27792e3bfefSLemover  llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq
2787797f035SbugGenerator  llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid)
27992e3bfefSLemover  // mem -> ptw
28092e3bfefSLemover  ptw.io.mem.req.ready := mem.a.ready
28192e3bfefSLemover  ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq
28292e3bfefSLemover  ptw.io.mem.resp.bits := resp_pte.last
28392e3bfefSLemover  // mem -> cache
2847797f035SbugGenerator  val refill_from_mq = mem_resp_from_mq
2857797f035SbugGenerator  val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire()))
2867797f035SbugGenerator  val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source)
2877797f035SbugGenerator
2887797f035SbugGenerator  cache.io.refill.valid := RegNext(refill_valid, false.B)
28992e3bfefSLemover  cache.io.refill.bits.ptes := refill_data.asUInt
2907797f035SbugGenerator  cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid))
2917797f035SbugGenerator  cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid))
2927797f035SbugGenerator  cache.io.refill.bits.levelOH(refill_level, refill_valid)
2937797f035SbugGenerator  cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source))))
29492e3bfefSLemover
2959c26bab7SHaoyuan Feng  if (env.EnableDifftest) {
2969c26bab7SHaoyuan Feng    val difftest_ptw_addr = RegInit(VecInit(Seq.fill(MemReqWidth)(0.U(PAddrBits.W))))
2979c26bab7SHaoyuan Feng    when (mem.a.valid) {
2989c26bab7SHaoyuan Feng      difftest_ptw_addr(mem.a.bits.source) := mem.a.bits.address
2999c26bab7SHaoyuan Feng    }
3009c26bab7SHaoyuan Feng
3019c26bab7SHaoyuan Feng    val difftest = Module(new DifftestRefillEvent)
3029c26bab7SHaoyuan Feng    difftest.io.clock := clock
3039c26bab7SHaoyuan Feng    difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt
3049c26bab7SHaoyuan Feng    difftest.io.cacheid := 2.U
3059c26bab7SHaoyuan Feng    difftest.io.valid := cache.io.refill.valid
3069c26bab7SHaoyuan Feng    difftest.io.addr := difftest_ptw_addr(RegNext(mem.d.bits.source))
3079c26bab7SHaoyuan Feng    difftest.io.data := refill_data.asTypeOf(difftest.io.data)
3089c26bab7SHaoyuan Feng  }
3099c26bab7SHaoyuan Feng
310*5ab1b84dSHaoyuan Feng  if (env.EnableDifftest) {
311*5ab1b84dSHaoyuan Feng    for (i <- 0 until PtwWidth) {
312*5ab1b84dSHaoyuan Feng      val difftest = Module(new DifftestL2TLBEvent)
313*5ab1b84dSHaoyuan Feng      difftest.io.clock := clock
314*5ab1b84dSHaoyuan Feng      difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt
315*5ab1b84dSHaoyuan Feng      difftest.io.valid := io.tlb(i).resp.fire && !io.tlb(i).resp.bits.af
316*5ab1b84dSHaoyuan Feng      difftest.io.index := i.U
317*5ab1b84dSHaoyuan Feng      difftest.io.satp := io.csr.tlb.satp.ppn
318*5ab1b84dSHaoyuan Feng      difftest.io.vpn := io.tlb(i).resp.bits.entry.tag
319*5ab1b84dSHaoyuan Feng      difftest.io.ppn := io.tlb(i).resp.bits.entry.ppn
320*5ab1b84dSHaoyuan Feng      difftest.io.perm := io.tlb(i).resp.bits.entry.perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt
321*5ab1b84dSHaoyuan Feng      difftest.io.level := io.tlb(i).resp.bits.entry.level.getOrElse(0.U.asUInt)
322*5ab1b84dSHaoyuan Feng      difftest.io.pf := io.tlb(i).resp.bits.pf
323*5ab1b84dSHaoyuan Feng    }
324*5ab1b84dSHaoyuan Feng  }
325*5ab1b84dSHaoyuan Feng
32692e3bfefSLemover  // pmp
32792e3bfefSLemover  pmp_check(0).req <> ptw.io.pmp.req
32892e3bfefSLemover  ptw.io.pmp.resp <> pmp_check(0).resp
32992e3bfefSLemover  pmp_check(1).req <> llptw.io.pmp.req
33092e3bfefSLemover  llptw.io.pmp.resp <> pmp_check(1).resp
33192e3bfefSLemover
33292e3bfefSLemover  llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort)
33392e3bfefSLemover  for (i <- 0 until PtwWidth) {
33492e3bfefSLemover    outArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U
33592e3bfefSLemover    outArb(i).in(outArbCachePort).bits.entry := cache.io.resp.bits.toTlb
33692e3bfefSLemover    outArb(i).in(outArbCachePort).bits.pf := !cache.io.resp.bits.toTlb.v
33792e3bfefSLemover    outArb(i).in(outArbCachePort).bits.af := false.B
33892e3bfefSLemover    outArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U
33992e3bfefSLemover    outArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp
34092e3bfefSLemover    outArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U
34192e3bfefSLemover    outArb(i).in(outArbMqPort).bits := pte_to_ptwResp(resp_pte(llptw_out.bits.id), llptw_out.bits.req_info.vpn, llptw_out.bits.af, true)
34292e3bfefSLemover  }
34392e3bfefSLemover
34492e3bfefSLemover  // io.tlb.map(_.resp) <> outArb.map(_.out)
34592e3bfefSLemover  io.tlb.map(_.resp).zip(outArb.map(_.out)).map{
34692e3bfefSLemover    case (resp, out) => resp <> out
34792e3bfefSLemover  }
34892e3bfefSLemover
34992e3bfefSLemover  // sfence
35092e3bfefSLemover  when (flush) {
35192e3bfefSLemover    for (i <- 0 until MemReqWidth) {
35292e3bfefSLemover      when (waiting_resp(i)) {
35392e3bfefSLemover        flush_latch(i) := true.B
35492e3bfefSLemover      }
35592e3bfefSLemover    }
35692e3bfefSLemover  }
35792e3bfefSLemover  // mem -> control signal
35892e3bfefSLemover  // waiting_resp and sfence_latch will be reset when mem_resp_done
35992e3bfefSLemover  when (mem_resp_done) {
36092e3bfefSLemover    waiting_resp(mem.d.bits.source) := false.B
36192e3bfefSLemover    flush_latch(mem.d.bits.source) := false.B
36292e3bfefSLemover  }
36392e3bfefSLemover
36492e3bfefSLemover  def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = {
36592e3bfefSLemover    sink.valid   := source.valid && !block_signal
36692e3bfefSLemover    source.ready := sink.ready   && !block_signal
36792e3bfefSLemover    sink.bits    := source.bits
36892e3bfefSLemover  }
36992e3bfefSLemover
37092e3bfefSLemover  def get_part(data: Vec[UInt], index: UInt): UInt = {
37192e3bfefSLemover    val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W)))
37292e3bfefSLemover    inner_data(index)
37392e3bfefSLemover  }
37492e3bfefSLemover
37592e3bfefSLemover  def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = {
37692e3bfefSLemover    val pte_in = pte.asTypeOf(new PteBundle())
37792e3bfefSLemover    val ptw_resp = Wire(new PtwResp())
37892e3bfefSLemover    ptw_resp.entry.ppn := pte_in.ppn
37992e3bfefSLemover    ptw_resp.entry.level.map(_ := 2.U)
38092e3bfefSLemover    ptw_resp.entry.perm.map(_ := pte_in.getPerm())
38192e3bfefSLemover    ptw_resp.entry.tag := vpn
38292e3bfefSLemover    ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U)
38392e3bfefSLemover    ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && af
38492e3bfefSLemover    ptw_resp.entry.v := !ptw_resp.pf
38592e3bfefSLemover    ptw_resp.entry.prefetch := DontCare
38692e3bfefSLemover    ptw_resp.entry.asid := satp.asid
38792e3bfefSLemover    ptw_resp
38892e3bfefSLemover  }
38992e3bfefSLemover
39092e3bfefSLemover  def outReady(source: UInt, port: Int): Bool = {
39192e3bfefSLemover    MuxLookup(source, true.B,
39292e3bfefSLemover      (0 until PtwWidth).map(i => i.U -> outArb(i).in(port).ready))
39392e3bfefSLemover  }
39492e3bfefSLemover
39592e3bfefSLemover  // debug info
39692e3bfefSLemover  for (i <- 0 until PtwWidth) {
39792e3bfefSLemover    XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n")
39892e3bfefSLemover  }
3997797f035SbugGenerator  XSDebug(p"[sfence] ${io.sfence}\n")
40092e3bfefSLemover  XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n")
40192e3bfefSLemover
40292e3bfefSLemover  for (i <- 0 until PtwWidth) {
40392e3bfefSLemover    XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire())
40492e3bfefSLemover    XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready)
40592e3bfefSLemover  }
40692e3bfefSLemover  XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid)
40792e3bfefSLemover  for (i <- 0 until (MemReqWidth + 1)) {
40892e3bfefSLemover    XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U)
40992e3bfefSLemover  }
41092e3bfefSLemover  XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U)
41192e3bfefSLemover  XSPerfAccumulate("mem_count", mem.a.fire())
41292e3bfefSLemover
41392e3bfefSLemover  // print configs
414f1fe8698SLemover  println(s"${l2tlbParams.name}: a ptw, a llptw with size ${l2tlbParams.llptwsize}, miss queue size ${MissQueueSize} l1:${l2tlbParams.l1Size} fa l2: nSets ${l2tlbParams.l2nSets} nWays ${l2tlbParams.l2nWays} l3: ${l2tlbParams.l3nSets} nWays ${l2tlbParams.l3nWays} blockBytes:${l2tlbParams.blockBytes}")
41592e3bfefSLemover
41692e3bfefSLemover  // time out assert
41792e3bfefSLemover  for (i <- 0 until MemReqWidth) {
41892e3bfefSLemover    TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}")
41992e3bfefSLemover    TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}")
42092e3bfefSLemover  }
42192e3bfefSLemover
42292e3bfefSLemover
42392e3bfefSLemover  val perfEvents  = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents)
42492e3bfefSLemover  generatePerfEvent()
4255afdf73cSHaoyuan Feng
4265afdf73cSHaoyuan Feng  val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB)
4275afdf73cSHaoyuan Feng  val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB)
4285afdf73cSHaoyuan Feng  ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn
4295afdf73cSHaoyuan Feng  DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn
4305afdf73cSHaoyuan Feng  ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag
4315afdf73cSHaoyuan Feng  DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag
4325afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset)
4335afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset)
4345afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset)
4355afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset)
4365afdf73cSHaoyuan Feng
4375afdf73cSHaoyuan Feng  val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB)
4385afdf73cSHaoyuan Feng  val PageCacheDB = Wire(new PageCacheDB)
4395afdf73cSHaoyuan Feng  PageCacheDB.vpn := cache.io.resp.bits.toTlb.tag
4405afdf73cSHaoyuan Feng  PageCacheDB.source := cache.io.resp.bits.req_info.source
4415afdf73cSHaoyuan Feng  PageCacheDB.bypassed := cache.io.resp.bits.bypassed
4425afdf73cSHaoyuan Feng  PageCacheDB.is_first := cache.io.resp.bits.isFirst
4435afdf73cSHaoyuan Feng  PageCacheDB.prefetched := cache.io.resp.bits.toTlb.prefetch
4445afdf73cSHaoyuan Feng  PageCacheDB.prefetch := cache.io.resp.bits.prefetch
4455afdf73cSHaoyuan Feng  PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit
4465afdf73cSHaoyuan Feng  PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit
4475afdf73cSHaoyuan Feng  PageCacheDB.hit := cache.io.resp.bits.hit
4485afdf73cSHaoyuan Feng  PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset)
4495afdf73cSHaoyuan Feng
4505afdf73cSHaoyuan Feng  val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB)
4515afdf73cSHaoyuan Feng  val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB)
4525afdf73cSHaoyuan Feng  PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn
4535afdf73cSHaoyuan Feng  PTWReqDB.source := ptw.io.req.bits.req_info.source
4545afdf73cSHaoyuan Feng  PTWRespDB.vpn := ptw.io.refill.req_info.vpn
4555afdf73cSHaoyuan Feng  PTWRespDB.source := ptw.io.refill.req_info.source
4565afdf73cSHaoyuan Feng  LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn
4575afdf73cSHaoyuan Feng  LLPTWReqDB.source := llptw.io.in.bits.req_info.source
4585afdf73cSHaoyuan Feng  LLPTWRespDB.vpn := llptw.io.mem.refill.vpn
4595afdf73cSHaoyuan Feng  LLPTWRespDB.source := llptw.io.mem.refill.source
4605afdf73cSHaoyuan Feng  PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset)
4615afdf73cSHaoyuan Feng  PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset)
4625afdf73cSHaoyuan Feng  PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset)
4635afdf73cSHaoyuan Feng  PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset)
4645afdf73cSHaoyuan Feng
4655afdf73cSHaoyuan Feng  val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB)
4665afdf73cSHaoyuan Feng  val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB)
4675afdf73cSHaoyuan Feng  L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn
4685afdf73cSHaoyuan Feng  L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn
4695afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset)
4705afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset)
47192e3bfefSLemover}
47292e3bfefSLemover
4737797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache
4747797f035SbugGenerator *  Parameter:
4757797f035SbugGenerator *    enable: enable BlockHelper, mq should not send too many reqs
4767797f035SbugGenerator *    start: when miss queue out fire and need, block miss queue's out
4777797f035SbugGenerator *    block: block miss queue's out
4787797f035SbugGenerator *    latency: last missqueue out's cache access latency
4797797f035SbugGenerator */
4807797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule {
4817797f035SbugGenerator  val io = IO(new Bundle {
4827797f035SbugGenerator    val enable = Input(Bool())
4837797f035SbugGenerator    val start = Input(Bool())
4847797f035SbugGenerator    val block = Output(Bool())
4857797f035SbugGenerator  })
4867797f035SbugGenerator
4877797f035SbugGenerator  val count = RegInit(0.U(log2Ceil(latency).W))
4887797f035SbugGenerator  val valid = RegInit(false.B)
4897797f035SbugGenerator  val work = RegInit(true.B)
4907797f035SbugGenerator
4917797f035SbugGenerator  io.block := valid
4927797f035SbugGenerator
4937797f035SbugGenerator  when (io.start && work) { valid := true.B }
4947797f035SbugGenerator  when (valid) { count := count + 1.U }
4957797f035SbugGenerator  when (count === (latency.U) || io.enable) {
4967797f035SbugGenerator    valid := false.B
4977797f035SbugGenerator    work := io.enable
4987797f035SbugGenerator    count := 0.U
4997797f035SbugGenerator  }
5007797f035SbugGenerator}
5017797f035SbugGenerator
50292e3bfefSLemoverclass PTEHelper() extends ExtModule {
50392e3bfefSLemover  val clock  = IO(Input(Clock()))
50492e3bfefSLemover  val enable = IO(Input(Bool()))
50592e3bfefSLemover  val satp   = IO(Input(UInt(64.W)))
50692e3bfefSLemover  val vpn    = IO(Input(UInt(64.W)))
50792e3bfefSLemover  val pte    = IO(Output(UInt(64.W)))
50892e3bfefSLemover  val level  = IO(Output(UInt(8.W)))
50992e3bfefSLemover  val pf     = IO(Output(UInt(8.W)))
51092e3bfefSLemover}
51192e3bfefSLemover
5125afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module {
5135afdf73cSHaoyuan Feng  val io = IO(new Bundle() {
5145afdf73cSHaoyuan Feng    val in = Input(gen)
5155afdf73cSHaoyuan Feng    val out = Output(gen)
5165afdf73cSHaoyuan Feng    val ptwflush = Input(flush.cloneType)
5175afdf73cSHaoyuan Feng  })
5185afdf73cSHaoyuan Feng  val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5195afdf73cSHaoyuan Feng  val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5205afdf73cSHaoyuan Feng  out(0) := io.in
5215afdf73cSHaoyuan Feng  if (n == 1) {
5225afdf73cSHaoyuan Feng    io.out := out(0)
5235afdf73cSHaoyuan Feng  } else {
5245afdf73cSHaoyuan Feng    when (io.ptwflush) {
5255afdf73cSHaoyuan Feng      for (i <- 0 until n) {
5265afdf73cSHaoyuan Feng        t(i) := 0.U.asTypeOf(gen)
5275afdf73cSHaoyuan Feng        out(i) := 0.U.asTypeOf(gen)
5285afdf73cSHaoyuan Feng      }
5295afdf73cSHaoyuan Feng      io.out := 0.U.asTypeOf(gen)
5305afdf73cSHaoyuan Feng    } .otherwise {
5315afdf73cSHaoyuan Feng      for (i <- 1 until n) {
5325afdf73cSHaoyuan Feng        t(i-1) := out(i-1)
5335afdf73cSHaoyuan Feng        out(i) := t(i-1)
5345afdf73cSHaoyuan Feng      }
5355afdf73cSHaoyuan Feng      io.out := out(n-1)
5365afdf73cSHaoyuan Feng    }
5375afdf73cSHaoyuan Feng  }
5385afdf73cSHaoyuan Feng}
5395afdf73cSHaoyuan Feng
5405afdf73cSHaoyuan Fengobject PTWDelayN {
5415afdf73cSHaoyuan Feng  def apply[T <: Data](in: T, n: Int, flush: Bool): T = {
5425afdf73cSHaoyuan Feng    val delay = Module(new PTWDelayN(in.cloneType, n, flush))
5435afdf73cSHaoyuan Feng    delay.io.in := in
5445afdf73cSHaoyuan Feng    delay.io.ptwflush := flush
5455afdf73cSHaoyuan Feng    delay.io.out
5465afdf73cSHaoyuan Feng  }
5475afdf73cSHaoyuan Feng}
5485afdf73cSHaoyuan Feng
54992e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst {
55092e3bfefSLemover  val io = IO(new L2TLBIO)
5515afdf73cSHaoyuan Feng  val flush = VecInit(Seq.fill(PtwWidth)(false.B))
5525afdf73cSHaoyuan Feng  flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay)
5535afdf73cSHaoyuan Feng  flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay)
55492e3bfefSLemover  for (i <- 0 until PtwWidth) {
55592e3bfefSLemover    val helper = Module(new PTEHelper())
55692e3bfefSLemover    helper.clock := clock
55792e3bfefSLemover    helper.satp := io.csr.tlb.satp.ppn
5585afdf73cSHaoyuan Feng
5595afdf73cSHaoyuan Feng    if (coreParams.softPTWDelay == 1) {
5605afdf73cSHaoyuan Feng      helper.enable := io.tlb(i).req(0).fire
56192e3bfefSLemover      helper.vpn := io.tlb(i).req(0).bits.vpn
5625afdf73cSHaoyuan Feng    } else {
5635afdf73cSHaoyuan Feng      helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i))
5645afdf73cSHaoyuan Feng      helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i))
5655afdf73cSHaoyuan Feng    }
5665afdf73cSHaoyuan Feng
56792e3bfefSLemover    val pte = helper.pte.asTypeOf(new PteBundle)
56892e3bfefSLemover    val level = helper.level
56992e3bfefSLemover    val pf = helper.pf
5705afdf73cSHaoyuan Feng    val empty = RegInit(true.B)
5715afdf73cSHaoyuan Feng    when (io.tlb(i).req(0).fire) {
5725afdf73cSHaoyuan Feng      empty := false.B
5735afdf73cSHaoyuan Feng    } .elsewhen (io.tlb(i).resp.fire || flush(i)) {
5745afdf73cSHaoyuan Feng      empty := true.B
5755afdf73cSHaoyuan Feng    }
57692e3bfefSLemover
5775afdf73cSHaoyuan Feng    io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire
5785afdf73cSHaoyuan Feng    io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i))
57992e3bfefSLemover    assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready)
5805afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i))
58192e3bfefSLemover    io.tlb(i).resp.bits.entry.ppn := pte.ppn
58292e3bfefSLemover    io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm())
58392e3bfefSLemover    io.tlb(i).resp.bits.entry.level.map(_ := level)
58492e3bfefSLemover    io.tlb(i).resp.bits.pf := pf
58592e3bfefSLemover    io.tlb(i).resp.bits.af := DontCare // TODO: implement it
5865afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.v := !pf
5875afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.prefetch := DontCare
5885afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid
58992e3bfefSLemover  }
59092e3bfefSLemover}
59192e3bfefSLemover
59292e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter {
59392e3bfefSLemover  val useSoftPTW = coreParams.softPTW
59492e3bfefSLemover  val node = if (!useSoftPTW) TLIdentityNode() else null
59592e3bfefSLemover  val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null
59692e3bfefSLemover  if (!useSoftPTW) {
59792e3bfefSLemover    node := ptw.node
59892e3bfefSLemover  }
59992e3bfefSLemover
60092e3bfefSLemover  lazy val module = new LazyModuleImp(this) with HasPerfEvents {
60192e3bfefSLemover    val io = IO(new L2TLBIO)
60292e3bfefSLemover    val perfEvents = if (useSoftPTW) {
60392e3bfefSLemover      val fake_ptw = Module(new FakePTW())
60492e3bfefSLemover      io <> fake_ptw.io
60592e3bfefSLemover      Seq()
60692e3bfefSLemover    }
60792e3bfefSLemover    else {
60892e3bfefSLemover        io <> ptw.module.io
60992e3bfefSLemover        ptw.module.getPerfEvents
61092e3bfefSLemover    }
61192e3bfefSLemover    generatePerfEvent()
61292e3bfefSLemover  }
61392e3bfefSLemover}
614