xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/L2TLB.scala (revision 9c26bab7fac28aafcdaaab239829a22a3d702189)
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
33*9c26bab7SHaoyuan 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
295*9c26bab7SHaoyuan Feng  if (env.EnableDifftest) {
296*9c26bab7SHaoyuan Feng    val difftest_ptw_addr = RegInit(VecInit(Seq.fill(MemReqWidth)(0.U(PAddrBits.W))))
297*9c26bab7SHaoyuan Feng    when (mem.a.valid) {
298*9c26bab7SHaoyuan Feng      difftest_ptw_addr(mem.a.bits.source) := mem.a.bits.address
299*9c26bab7SHaoyuan Feng    }
300*9c26bab7SHaoyuan Feng
301*9c26bab7SHaoyuan Feng    val difftest = Module(new DifftestRefillEvent)
302*9c26bab7SHaoyuan Feng    difftest.io.clock := clock
303*9c26bab7SHaoyuan Feng    difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt
304*9c26bab7SHaoyuan Feng    difftest.io.cacheid := 2.U
305*9c26bab7SHaoyuan Feng    difftest.io.valid := cache.io.refill.valid
306*9c26bab7SHaoyuan Feng    difftest.io.addr := difftest_ptw_addr(RegNext(mem.d.bits.source))
307*9c26bab7SHaoyuan Feng    difftest.io.data := refill_data.asTypeOf(difftest.io.data)
308*9c26bab7SHaoyuan Feng  }
309*9c26bab7SHaoyuan Feng
31092e3bfefSLemover  // pmp
31192e3bfefSLemover  pmp_check(0).req <> ptw.io.pmp.req
31292e3bfefSLemover  ptw.io.pmp.resp <> pmp_check(0).resp
31392e3bfefSLemover  pmp_check(1).req <> llptw.io.pmp.req
31492e3bfefSLemover  llptw.io.pmp.resp <> pmp_check(1).resp
31592e3bfefSLemover
31692e3bfefSLemover  llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort)
31792e3bfefSLemover  for (i <- 0 until PtwWidth) {
31892e3bfefSLemover    outArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U
31992e3bfefSLemover    outArb(i).in(outArbCachePort).bits.entry := cache.io.resp.bits.toTlb
32092e3bfefSLemover    outArb(i).in(outArbCachePort).bits.pf := !cache.io.resp.bits.toTlb.v
32192e3bfefSLemover    outArb(i).in(outArbCachePort).bits.af := false.B
32292e3bfefSLemover    outArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U
32392e3bfefSLemover    outArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp
32492e3bfefSLemover    outArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U
32592e3bfefSLemover    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)
32692e3bfefSLemover  }
32792e3bfefSLemover
32892e3bfefSLemover  // io.tlb.map(_.resp) <> outArb.map(_.out)
32992e3bfefSLemover  io.tlb.map(_.resp).zip(outArb.map(_.out)).map{
33092e3bfefSLemover    case (resp, out) => resp <> out
33192e3bfefSLemover  }
33292e3bfefSLemover
33392e3bfefSLemover  // sfence
33492e3bfefSLemover  when (flush) {
33592e3bfefSLemover    for (i <- 0 until MemReqWidth) {
33692e3bfefSLemover      when (waiting_resp(i)) {
33792e3bfefSLemover        flush_latch(i) := true.B
33892e3bfefSLemover      }
33992e3bfefSLemover    }
34092e3bfefSLemover  }
34192e3bfefSLemover  // mem -> control signal
34292e3bfefSLemover  // waiting_resp and sfence_latch will be reset when mem_resp_done
34392e3bfefSLemover  when (mem_resp_done) {
34492e3bfefSLemover    waiting_resp(mem.d.bits.source) := false.B
34592e3bfefSLemover    flush_latch(mem.d.bits.source) := false.B
34692e3bfefSLemover  }
34792e3bfefSLemover
34892e3bfefSLemover  def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = {
34992e3bfefSLemover    sink.valid   := source.valid && !block_signal
35092e3bfefSLemover    source.ready := sink.ready   && !block_signal
35192e3bfefSLemover    sink.bits    := source.bits
35292e3bfefSLemover  }
35392e3bfefSLemover
35492e3bfefSLemover  def get_part(data: Vec[UInt], index: UInt): UInt = {
35592e3bfefSLemover    val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W)))
35692e3bfefSLemover    inner_data(index)
35792e3bfefSLemover  }
35892e3bfefSLemover
35992e3bfefSLemover  def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = {
36092e3bfefSLemover    val pte_in = pte.asTypeOf(new PteBundle())
36192e3bfefSLemover    val ptw_resp = Wire(new PtwResp())
36292e3bfefSLemover    ptw_resp.entry.ppn := pte_in.ppn
36392e3bfefSLemover    ptw_resp.entry.level.map(_ := 2.U)
36492e3bfefSLemover    ptw_resp.entry.perm.map(_ := pte_in.getPerm())
36592e3bfefSLemover    ptw_resp.entry.tag := vpn
36692e3bfefSLemover    ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U)
36792e3bfefSLemover    ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && af
36892e3bfefSLemover    ptw_resp.entry.v := !ptw_resp.pf
36992e3bfefSLemover    ptw_resp.entry.prefetch := DontCare
37092e3bfefSLemover    ptw_resp.entry.asid := satp.asid
37192e3bfefSLemover    ptw_resp
37292e3bfefSLemover  }
37392e3bfefSLemover
37492e3bfefSLemover  def outReady(source: UInt, port: Int): Bool = {
37592e3bfefSLemover    MuxLookup(source, true.B,
37692e3bfefSLemover      (0 until PtwWidth).map(i => i.U -> outArb(i).in(port).ready))
37792e3bfefSLemover  }
37892e3bfefSLemover
37992e3bfefSLemover  // debug info
38092e3bfefSLemover  for (i <- 0 until PtwWidth) {
38192e3bfefSLemover    XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n")
38292e3bfefSLemover  }
3837797f035SbugGenerator  XSDebug(p"[sfence] ${io.sfence}\n")
38492e3bfefSLemover  XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n")
38592e3bfefSLemover
38692e3bfefSLemover  for (i <- 0 until PtwWidth) {
38792e3bfefSLemover    XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire())
38892e3bfefSLemover    XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready)
38992e3bfefSLemover  }
39092e3bfefSLemover  XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid)
39192e3bfefSLemover  for (i <- 0 until (MemReqWidth + 1)) {
39292e3bfefSLemover    XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U)
39392e3bfefSLemover  }
39492e3bfefSLemover  XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U)
39592e3bfefSLemover  XSPerfAccumulate("mem_count", mem.a.fire())
39692e3bfefSLemover
39792e3bfefSLemover  // print configs
398f1fe8698SLemover  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}")
39992e3bfefSLemover
40092e3bfefSLemover  // time out assert
40192e3bfefSLemover  for (i <- 0 until MemReqWidth) {
40292e3bfefSLemover    TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}")
40392e3bfefSLemover    TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}")
40492e3bfefSLemover  }
40592e3bfefSLemover
40692e3bfefSLemover
40792e3bfefSLemover  val perfEvents  = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents)
40892e3bfefSLemover  generatePerfEvent()
4095afdf73cSHaoyuan Feng
4105afdf73cSHaoyuan Feng  val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB)
4115afdf73cSHaoyuan Feng  val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB)
4125afdf73cSHaoyuan Feng  ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn
4135afdf73cSHaoyuan Feng  DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn
4145afdf73cSHaoyuan Feng  ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag
4155afdf73cSHaoyuan Feng  DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag
4165afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset)
4175afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset)
4185afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset)
4195afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset)
4205afdf73cSHaoyuan Feng
4215afdf73cSHaoyuan Feng  val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB)
4225afdf73cSHaoyuan Feng  val PageCacheDB = Wire(new PageCacheDB)
4235afdf73cSHaoyuan Feng  PageCacheDB.vpn := cache.io.resp.bits.toTlb.tag
4245afdf73cSHaoyuan Feng  PageCacheDB.source := cache.io.resp.bits.req_info.source
4255afdf73cSHaoyuan Feng  PageCacheDB.bypassed := cache.io.resp.bits.bypassed
4265afdf73cSHaoyuan Feng  PageCacheDB.is_first := cache.io.resp.bits.isFirst
4275afdf73cSHaoyuan Feng  PageCacheDB.prefetched := cache.io.resp.bits.toTlb.prefetch
4285afdf73cSHaoyuan Feng  PageCacheDB.prefetch := cache.io.resp.bits.prefetch
4295afdf73cSHaoyuan Feng  PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit
4305afdf73cSHaoyuan Feng  PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit
4315afdf73cSHaoyuan Feng  PageCacheDB.hit := cache.io.resp.bits.hit
4325afdf73cSHaoyuan Feng  PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset)
4335afdf73cSHaoyuan Feng
4345afdf73cSHaoyuan Feng  val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB)
4355afdf73cSHaoyuan Feng  val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB)
4365afdf73cSHaoyuan Feng  PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn
4375afdf73cSHaoyuan Feng  PTWReqDB.source := ptw.io.req.bits.req_info.source
4385afdf73cSHaoyuan Feng  PTWRespDB.vpn := ptw.io.refill.req_info.vpn
4395afdf73cSHaoyuan Feng  PTWRespDB.source := ptw.io.refill.req_info.source
4405afdf73cSHaoyuan Feng  LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn
4415afdf73cSHaoyuan Feng  LLPTWReqDB.source := llptw.io.in.bits.req_info.source
4425afdf73cSHaoyuan Feng  LLPTWRespDB.vpn := llptw.io.mem.refill.vpn
4435afdf73cSHaoyuan Feng  LLPTWRespDB.source := llptw.io.mem.refill.source
4445afdf73cSHaoyuan Feng  PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset)
4455afdf73cSHaoyuan Feng  PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset)
4465afdf73cSHaoyuan Feng  PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset)
4475afdf73cSHaoyuan Feng  PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset)
4485afdf73cSHaoyuan Feng
4495afdf73cSHaoyuan Feng  val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB)
4505afdf73cSHaoyuan Feng  val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB)
4515afdf73cSHaoyuan Feng  L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn
4525afdf73cSHaoyuan Feng  L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn
4535afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset)
4545afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset)
45592e3bfefSLemover}
45692e3bfefSLemover
4577797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache
4587797f035SbugGenerator *  Parameter:
4597797f035SbugGenerator *    enable: enable BlockHelper, mq should not send too many reqs
4607797f035SbugGenerator *    start: when miss queue out fire and need, block miss queue's out
4617797f035SbugGenerator *    block: block miss queue's out
4627797f035SbugGenerator *    latency: last missqueue out's cache access latency
4637797f035SbugGenerator */
4647797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule {
4657797f035SbugGenerator  val io = IO(new Bundle {
4667797f035SbugGenerator    val enable = Input(Bool())
4677797f035SbugGenerator    val start = Input(Bool())
4687797f035SbugGenerator    val block = Output(Bool())
4697797f035SbugGenerator  })
4707797f035SbugGenerator
4717797f035SbugGenerator  val count = RegInit(0.U(log2Ceil(latency).W))
4727797f035SbugGenerator  val valid = RegInit(false.B)
4737797f035SbugGenerator  val work = RegInit(true.B)
4747797f035SbugGenerator
4757797f035SbugGenerator  io.block := valid
4767797f035SbugGenerator
4777797f035SbugGenerator  when (io.start && work) { valid := true.B }
4787797f035SbugGenerator  when (valid) { count := count + 1.U }
4797797f035SbugGenerator  when (count === (latency.U) || io.enable) {
4807797f035SbugGenerator    valid := false.B
4817797f035SbugGenerator    work := io.enable
4827797f035SbugGenerator    count := 0.U
4837797f035SbugGenerator  }
4847797f035SbugGenerator}
4857797f035SbugGenerator
48692e3bfefSLemoverclass PTEHelper() extends ExtModule {
48792e3bfefSLemover  val clock  = IO(Input(Clock()))
48892e3bfefSLemover  val enable = IO(Input(Bool()))
48992e3bfefSLemover  val satp   = IO(Input(UInt(64.W)))
49092e3bfefSLemover  val vpn    = IO(Input(UInt(64.W)))
49192e3bfefSLemover  val pte    = IO(Output(UInt(64.W)))
49292e3bfefSLemover  val level  = IO(Output(UInt(8.W)))
49392e3bfefSLemover  val pf     = IO(Output(UInt(8.W)))
49492e3bfefSLemover}
49592e3bfefSLemover
4965afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module {
4975afdf73cSHaoyuan Feng  val io = IO(new Bundle() {
4985afdf73cSHaoyuan Feng    val in = Input(gen)
4995afdf73cSHaoyuan Feng    val out = Output(gen)
5005afdf73cSHaoyuan Feng    val ptwflush = Input(flush.cloneType)
5015afdf73cSHaoyuan Feng  })
5025afdf73cSHaoyuan Feng  val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5035afdf73cSHaoyuan Feng  val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5045afdf73cSHaoyuan Feng  out(0) := io.in
5055afdf73cSHaoyuan Feng  if (n == 1) {
5065afdf73cSHaoyuan Feng    io.out := out(0)
5075afdf73cSHaoyuan Feng  } else {
5085afdf73cSHaoyuan Feng    when (io.ptwflush) {
5095afdf73cSHaoyuan Feng      for (i <- 0 until n) {
5105afdf73cSHaoyuan Feng        t(i) := 0.U.asTypeOf(gen)
5115afdf73cSHaoyuan Feng        out(i) := 0.U.asTypeOf(gen)
5125afdf73cSHaoyuan Feng      }
5135afdf73cSHaoyuan Feng      io.out := 0.U.asTypeOf(gen)
5145afdf73cSHaoyuan Feng    } .otherwise {
5155afdf73cSHaoyuan Feng      for (i <- 1 until n) {
5165afdf73cSHaoyuan Feng        t(i-1) := out(i-1)
5175afdf73cSHaoyuan Feng        out(i) := t(i-1)
5185afdf73cSHaoyuan Feng      }
5195afdf73cSHaoyuan Feng      io.out := out(n-1)
5205afdf73cSHaoyuan Feng    }
5215afdf73cSHaoyuan Feng  }
5225afdf73cSHaoyuan Feng}
5235afdf73cSHaoyuan Feng
5245afdf73cSHaoyuan Fengobject PTWDelayN {
5255afdf73cSHaoyuan Feng  def apply[T <: Data](in: T, n: Int, flush: Bool): T = {
5265afdf73cSHaoyuan Feng    val delay = Module(new PTWDelayN(in.cloneType, n, flush))
5275afdf73cSHaoyuan Feng    delay.io.in := in
5285afdf73cSHaoyuan Feng    delay.io.ptwflush := flush
5295afdf73cSHaoyuan Feng    delay.io.out
5305afdf73cSHaoyuan Feng  }
5315afdf73cSHaoyuan Feng}
5325afdf73cSHaoyuan Feng
53392e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst {
53492e3bfefSLemover  val io = IO(new L2TLBIO)
5355afdf73cSHaoyuan Feng  val flush = VecInit(Seq.fill(PtwWidth)(false.B))
5365afdf73cSHaoyuan Feng  flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay)
5375afdf73cSHaoyuan Feng  flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay)
53892e3bfefSLemover  for (i <- 0 until PtwWidth) {
53992e3bfefSLemover    val helper = Module(new PTEHelper())
54092e3bfefSLemover    helper.clock := clock
54192e3bfefSLemover    helper.satp := io.csr.tlb.satp.ppn
5425afdf73cSHaoyuan Feng
5435afdf73cSHaoyuan Feng    if (coreParams.softPTWDelay == 1) {
5445afdf73cSHaoyuan Feng      helper.enable := io.tlb(i).req(0).fire
54592e3bfefSLemover      helper.vpn := io.tlb(i).req(0).bits.vpn
5465afdf73cSHaoyuan Feng    } else {
5475afdf73cSHaoyuan Feng      helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i))
5485afdf73cSHaoyuan Feng      helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i))
5495afdf73cSHaoyuan Feng    }
5505afdf73cSHaoyuan Feng
55192e3bfefSLemover    val pte = helper.pte.asTypeOf(new PteBundle)
55292e3bfefSLemover    val level = helper.level
55392e3bfefSLemover    val pf = helper.pf
5545afdf73cSHaoyuan Feng    val empty = RegInit(true.B)
5555afdf73cSHaoyuan Feng    when (io.tlb(i).req(0).fire) {
5565afdf73cSHaoyuan Feng      empty := false.B
5575afdf73cSHaoyuan Feng    } .elsewhen (io.tlb(i).resp.fire || flush(i)) {
5585afdf73cSHaoyuan Feng      empty := true.B
5595afdf73cSHaoyuan Feng    }
56092e3bfefSLemover
5615afdf73cSHaoyuan Feng    io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire
5625afdf73cSHaoyuan Feng    io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i))
56392e3bfefSLemover    assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready)
5645afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i))
56592e3bfefSLemover    io.tlb(i).resp.bits.entry.ppn := pte.ppn
56692e3bfefSLemover    io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm())
56792e3bfefSLemover    io.tlb(i).resp.bits.entry.level.map(_ := level)
56892e3bfefSLemover    io.tlb(i).resp.bits.pf := pf
56992e3bfefSLemover    io.tlb(i).resp.bits.af := DontCare // TODO: implement it
5705afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.v := !pf
5715afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.prefetch := DontCare
5725afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid
57392e3bfefSLemover  }
57492e3bfefSLemover}
57592e3bfefSLemover
57692e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter {
57792e3bfefSLemover  val useSoftPTW = coreParams.softPTW
57892e3bfefSLemover  val node = if (!useSoftPTW) TLIdentityNode() else null
57992e3bfefSLemover  val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null
58092e3bfefSLemover  if (!useSoftPTW) {
58192e3bfefSLemover    node := ptw.node
58292e3bfefSLemover  }
58392e3bfefSLemover
58492e3bfefSLemover  lazy val module = new LazyModuleImp(this) with HasPerfEvents {
58592e3bfefSLemover    val io = IO(new L2TLBIO)
58692e3bfefSLemover    val perfEvents = if (useSoftPTW) {
58792e3bfefSLemover      val fake_ptw = Module(new FakePTW())
58892e3bfefSLemover      io <> fake_ptw.io
58992e3bfefSLemover      Seq()
59092e3bfefSLemover    }
59192e3bfefSLemover    else {
59292e3bfefSLemover        io <> ptw.module.io
59392e3bfefSLemover        ptw.module.getPerfEvents
59492e3bfefSLemover    }
59592e3bfefSLemover    generatePerfEvent()
59692e3bfefSLemover  }
59792e3bfefSLemover}
598