xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/L2TLB.scala (revision 63632028e4f04e10c83fd34b02289fc6fab3679c)
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))
103*63632028SHaoyuan Feng  val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwSectorResp, 1)).io)
104*63632028SHaoyuan Feng  val mergeArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwMergeResp, 3)).io)
10592e3bfefSLemover  val outArbCachePort = 0
10692e3bfefSLemover  val outArbFsmPort = 1
10792e3bfefSLemover  val outArbMqPort = 2
10892e3bfefSLemover
1099c503409SLemover  // arb2 input port
1109c503409SLemover  val InArbPTWPort = 0
1119c503409SLemover  val InArbMissQueuePort = 1
1129c503409SLemover  val InArbTlbPort = 2
1139c503409SLemover  val InArbPrefetchPort = 3
11492e3bfefSLemover  // NOTE: when cache out but miss and ptw doesnt accept,
11592e3bfefSLemover  arb1.io.in <> VecInit(io.tlb.map(_.req(0)))
1169c503409SLemover  arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready
11792e3bfefSLemover
1189c503409SLemover  arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid
1199c503409SLemover  arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn
1209c503409SLemover  arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source
1219c503409SLemover  ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready
12292e3bfefSLemover  block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready)
1237797f035SbugGenerator
12492e3bfefSLemover  arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid
12592e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn
12692e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen
12792e3bfefSLemover  if (l2tlbParams.enablePrefetch) {
12892e3bfefSLemover    val prefetch = Module(new L2TlbPrefetch())
12992e3bfefSLemover    val recv = cache.io.resp
13092e3bfefSLemover    // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch
13192e3bfefSLemover    // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch
13292e3bfefSLemover    prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit  ||
13392e3bfefSLemover      recv.bits.prefetch) && recv.bits.isFirst
13492e3bfefSLemover    prefetch.io.in.bits.vpn := recv.bits.req_info.vpn
1357797f035SbugGenerator    prefetch.io.sfence := sfence_dup(0)
1367797f035SbugGenerator    prefetch.io.csr := csr_dup(0)
13792e3bfefSLemover    arb2.io.in(InArbPrefetchPort) <> prefetch.io.out
1385afdf73cSHaoyuan Feng
1395afdf73cSHaoyuan Feng    val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB)
1405afdf73cSHaoyuan Feng    val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB)
1415afdf73cSHaoyuan Feng    L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn
1425afdf73cSHaoyuan Feng    L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset)
14392e3bfefSLemover  }
14492e3bfefSLemover  arb2.io.out.ready := cache.io.req.ready
14592e3bfefSLemover
1467797f035SbugGenerator
1477797f035SbugGenerator  val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2))
1487797f035SbugGenerator  mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit &&
1497797f035SbugGenerator    (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) &&
1507797f035SbugGenerator    !from_pre(cache.io.resp.bits.req_info.source) &&
1517797f035SbugGenerator    (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready)
1527797f035SbugGenerator  mq_arb.io.in(0).bits :=  cache.io.resp.bits.req_info
1537797f035SbugGenerator  mq_arb.io.in(1) <> llptw.io.cache
1547797f035SbugGenerator  missQueue.io.in <> mq_arb.io.out
1557797f035SbugGenerator  missQueue.io.sfence  := sfence_dup(6)
1567797f035SbugGenerator  missQueue.io.csr := csr_dup(5)
1577797f035SbugGenerator
1587797f035SbugGenerator  blockmq.io.start := missQueue.io.out.fire
1597797f035SbugGenerator  blockmq.io.enable := ptw.io.req.fire()
1607797f035SbugGenerator
1619c503409SLemover  llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed
1629c503409SLemover  llptw.io.in.bits.req_info := cache.io.resp.bits.req_info
1639c503409SLemover  llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn
1647797f035SbugGenerator  llptw.io.sfence := sfence_dup(1)
1657797f035SbugGenerator  llptw.io.csr := csr_dup(1)
16692e3bfefSLemover
16792e3bfefSLemover  cache.io.req.valid := arb2.io.out.valid
16892e3bfefSLemover  cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn
16992e3bfefSLemover  cache.io.req.bits.req_info.source := arb2.io.out.bits.source
17092e3bfefSLemover  cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U
1711f4a7c0cSLemover  cache.io.req.bits.bypassed.map(_ := false.B)
1727797f035SbugGenerator  cache.io.sfence := sfence_dup(2)
1737797f035SbugGenerator  cache.io.csr := csr_dup(2)
1747797f035SbugGenerator  cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2)
1757797f035SbugGenerator  cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2)
17692e3bfefSLemover  cache.io.resp.ready := Mux(cache.io.resp.bits.hit,
17792e3bfefSLemover    outReady(cache.io.resp.bits.req_info.source, outArbCachePort),
1789c503409SLemover    Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready,
1797797f035SbugGenerator    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)))
18092e3bfefSLemover
18192e3bfefSLemover  // NOTE: missQueue req has higher priority
1827797f035SbugGenerator  ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit &&
1837797f035SbugGenerator    !cache.io.resp.bits.bypassed &&
1847797f035SbugGenerator    !cache.io.resp.bits.isFirst
18592e3bfefSLemover  ptw.io.req.bits.req_info := cache.io.resp.bits.req_info
18692e3bfefSLemover  ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit
18792e3bfefSLemover  ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn
1887797f035SbugGenerator  ptw.io.sfence := sfence_dup(7)
1897797f035SbugGenerator  ptw.io.csr := csr_dup(6)
19092e3bfefSLemover  ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort)
19192e3bfefSLemover
19292e3bfefSLemover  // mem req
19392e3bfefSLemover  def blockBytes_align(addr: UInt) = {
19492e3bfefSLemover    Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W))
19592e3bfefSLemover  }
19692e3bfefSLemover  def addr_low_from_vpn(vpn: UInt) = {
19792e3bfefSLemover    vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0)
19892e3bfefSLemover  }
19992e3bfefSLemover  def addr_low_from_paddr(paddr: UInt) = {
20092e3bfefSLemover    paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8))
20192e3bfefSLemover  }
20292e3bfefSLemover  def from_missqueue(id: UInt) = {
20392e3bfefSLemover    (id =/= l2tlbParams.llptwsize.U)
20492e3bfefSLemover  }
20592e3bfefSLemover  val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20692e3bfefSLemover  val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20792e3bfefSLemover  for (i <- waiting_resp.indices) {
20892e3bfefSLemover    assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true
20992e3bfefSLemover  }
21092e3bfefSLemover
21192e3bfefSLemover  val llptw_out = llptw.io.out
21292e3bfefSLemover  val llptw_mem = llptw.io.mem
21392e3bfefSLemover  llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize)
21492e3bfefSLemover  ptw.io.mem.mask := waiting_resp.last
21592e3bfefSLemover
21692e3bfefSLemover  val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2))
21792e3bfefSLemover  mem_arb.io.in(0) <> ptw.io.mem.req
21892e3bfefSLemover  mem_arb.io.in(1) <> llptw_mem.req
21992e3bfefSLemover  mem_arb.io.out.ready := mem.a.ready && !flush
22092e3bfefSLemover
2211f4a7c0cSLemover  // assert, should not send mem access at same addr for twice.
2227797f035SbugGenerator  val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid)
2237797f035SbugGenerator  val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid)
2241f4a7c0cSLemover  val last_resp_v = RegInit(false.B)
225dd7fe201SHaoyuan Feng  val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR || cache.io.refill.bits.sel_pte_dup(0).asTypeOf(new PteBundle).isAf()
2261f4a7c0cSLemover  when (cache.io.refill.valid) { last_resp_v := !last_has_invalid}
2271f4a7c0cSLemover  when (flush) { last_resp_v := false.B }
2281f4a7c0cSLemover  XSError(last_resp_v && cache.io.refill.valid &&
2297797f035SbugGenerator    (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) &&
2307797f035SbugGenerator    (cache.io.refill.bits.level_dup(0) === last_resp_level),
2311f4a7c0cSLemover    "l2tlb should not access mem at same addr for twice")
2321f4a7c0cSLemover  // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid,
2331f4a7c0cSLemover  // but the current part is invalid, so one more mem access happened
2341f4a7c0cSLemover  // If this happened, remove the assert.
2351f4a7c0cSLemover
23692e3bfefSLemover  val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W)))
23792e3bfefSLemover
23892e3bfefSLemover  when (llptw.io.in.fire()) {
23992e3bfefSLemover    // when enq miss queue, set the req_addr_low to receive the mem resp data part
24092e3bfefSLemover    req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn)
24192e3bfefSLemover  }
24292e3bfefSLemover  when (mem_arb.io.out.fire()) {
24392e3bfefSLemover    req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr)
24492e3bfefSLemover    waiting_resp(mem_arb.io.out.bits.id) := true.B
24592e3bfefSLemover  }
24692e3bfefSLemover  // mem read
24792e3bfefSLemover  val memRead =  edge.Get(
24892e3bfefSLemover    fromSource = mem_arb.io.out.bits.id,
24992e3bfefSLemover    // toAddress  = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0),
25092e3bfefSLemover    toAddress  = blockBytes_align(mem_arb.io.out.bits.addr),
25192e3bfefSLemover    lgSize     = log2Up(l2tlbParams.blockBytes).U
25292e3bfefSLemover  )._2
25392e3bfefSLemover  mem.a.bits := memRead
25492e3bfefSLemover  mem.a.valid := mem_arb.io.out.valid && !flush
25592e3bfefSLemover  mem.d.ready := true.B
25692e3bfefSLemover  // mem -> data buffer
25792e3bfefSLemover  val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W)))
25892e3bfefSLemover  val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire())
25992e3bfefSLemover  val mem_resp_done = refill_helper._3
26092e3bfefSLemover  val mem_resp_from_mq = from_missqueue(mem.d.bits.source)
26192e3bfefSLemover  when (mem.d.valid) {
26292e3bfefSLemover    assert(mem.d.bits.source <= l2tlbParams.llptwsize.U)
26392e3bfefSLemover    refill_data(refill_helper._4) := mem.d.bits.data
26492e3bfefSLemover  }
2657797f035SbugGenerator  // refill_data_tmp is the wire fork of refill_data, but one cycle earlier
2667797f035SbugGenerator  val refill_data_tmp = WireInit(refill_data)
2677797f035SbugGenerator  refill_data_tmp(refill_helper._4) := mem.d.bits.data
2687797f035SbugGenerator
26992e3bfefSLemover  // save only one pte for each id
27092e3bfefSLemover  // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache)
27192e3bfefSLemover  val resp_pte = VecInit((0 until MemReqWidth).map(i =>
2727797f035SbugGenerator    if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) }
27392e3bfefSLemover    else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) }
2747797f035SbugGenerator    // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle
27592e3bfefSLemover  ))
27692e3bfefSLemover
277*63632028SHaoyuan Feng  // save eight ptes for each id when sector tlb
278*63632028SHaoyuan Feng  // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache)
279*63632028SHaoyuan Feng  val resp_pte_sector = VecInit((0 until MemReqWidth).map(i =>
280*63632028SHaoyuan Feng    if (i == l2tlbParams.llptwsize) {RegEnable(refill_data_tmp, mem_resp_done && !mem_resp_from_mq) }
281*63632028SHaoyuan Feng    else { DataHoldBypass(refill_data, llptw_mem.buffer_it(i)) }
282*63632028SHaoyuan Feng    // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle
283*63632028SHaoyuan Feng  ))
284*63632028SHaoyuan Feng
28592e3bfefSLemover  // mem -> miss queue
28692e3bfefSLemover  llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq
2877797f035SbugGenerator  llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid)
28892e3bfefSLemover  // mem -> ptw
28992e3bfefSLemover  ptw.io.mem.req.ready := mem.a.ready
29092e3bfefSLemover  ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq
29192e3bfefSLemover  ptw.io.mem.resp.bits := resp_pte.last
29292e3bfefSLemover  // mem -> cache
2937797f035SbugGenerator  val refill_from_mq = mem_resp_from_mq
2947797f035SbugGenerator  val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire()))
2957797f035SbugGenerator  val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source)
2967797f035SbugGenerator
2977797f035SbugGenerator  cache.io.refill.valid := RegNext(refill_valid, false.B)
29892e3bfefSLemover  cache.io.refill.bits.ptes := refill_data.asUInt
2997797f035SbugGenerator  cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid))
3007797f035SbugGenerator  cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid))
3017797f035SbugGenerator  cache.io.refill.bits.levelOH(refill_level, refill_valid)
3027797f035SbugGenerator  cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source))))
30392e3bfefSLemover
3049c26bab7SHaoyuan Feng  if (env.EnableDifftest) {
3059c26bab7SHaoyuan Feng    val difftest_ptw_addr = RegInit(VecInit(Seq.fill(MemReqWidth)(0.U(PAddrBits.W))))
3069c26bab7SHaoyuan Feng    when (mem.a.valid) {
3079c26bab7SHaoyuan Feng      difftest_ptw_addr(mem.a.bits.source) := mem.a.bits.address
3089c26bab7SHaoyuan Feng    }
3099c26bab7SHaoyuan Feng
3109c26bab7SHaoyuan Feng    val difftest = Module(new DifftestRefillEvent)
3119c26bab7SHaoyuan Feng    difftest.io.clock := clock
3129c26bab7SHaoyuan Feng    difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt
3139c26bab7SHaoyuan Feng    difftest.io.cacheid := 2.U
3149c26bab7SHaoyuan Feng    difftest.io.valid := cache.io.refill.valid
3159c26bab7SHaoyuan Feng    difftest.io.addr := difftest_ptw_addr(RegNext(mem.d.bits.source))
3169c26bab7SHaoyuan Feng    difftest.io.data := refill_data.asTypeOf(difftest.io.data)
3179c26bab7SHaoyuan Feng  }
3189c26bab7SHaoyuan Feng
3195ab1b84dSHaoyuan Feng  if (env.EnableDifftest) {
3205ab1b84dSHaoyuan Feng    for (i <- 0 until PtwWidth) {
3215ab1b84dSHaoyuan Feng      val difftest = Module(new DifftestL2TLBEvent)
3225ab1b84dSHaoyuan Feng      difftest.io.clock := clock
3235ab1b84dSHaoyuan Feng      difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt
3245ab1b84dSHaoyuan Feng      difftest.io.valid := io.tlb(i).resp.fire && !io.tlb(i).resp.bits.af
3255ab1b84dSHaoyuan Feng      difftest.io.index := i.U
3265ab1b84dSHaoyuan Feng      difftest.io.satp := io.csr.tlb.satp.ppn
327*63632028SHaoyuan Feng      difftest.io.vpn := Cat(io.tlb(i).resp.bits.entry.tag, 0.U(sectortlbwidth.W))
328*63632028SHaoyuan Feng      for (j <- 0 until tlbcontiguous) {
329*63632028SHaoyuan Feng        difftest.io.ppn(j) := Cat(io.tlb(i).resp.bits.entry.ppn, io.tlb(i).resp.bits.ppn_low(j))
330*63632028SHaoyuan Feng        difftest.io.valididx(j) := io.tlb(i).resp.bits.valididx(j)
331*63632028SHaoyuan Feng      }
3325ab1b84dSHaoyuan Feng      difftest.io.perm := io.tlb(i).resp.bits.entry.perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt
3335ab1b84dSHaoyuan Feng      difftest.io.level := io.tlb(i).resp.bits.entry.level.getOrElse(0.U.asUInt)
3345ab1b84dSHaoyuan Feng      difftest.io.pf := io.tlb(i).resp.bits.pf
3355ab1b84dSHaoyuan Feng    }
3365ab1b84dSHaoyuan Feng  }
3375ab1b84dSHaoyuan Feng
33892e3bfefSLemover  // pmp
33992e3bfefSLemover  pmp_check(0).req <> ptw.io.pmp.req
34092e3bfefSLemover  ptw.io.pmp.resp <> pmp_check(0).resp
34192e3bfefSLemover  pmp_check(1).req <> llptw.io.pmp.req
34292e3bfefSLemover  llptw.io.pmp.resp <> pmp_check(1).resp
34392e3bfefSLemover
34492e3bfefSLemover  llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort)
345*63632028SHaoyuan Feng
346*63632028SHaoyuan Feng  // Timing: Maybe need to do some optimization or even add one more cycle
34792e3bfefSLemover  for (i <- 0 until PtwWidth) {
348*63632028SHaoyuan Feng    mergeArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U
349*63632028SHaoyuan Feng    mergeArb(i).in(outArbCachePort).bits := cache.io.resp.bits.toTlb
350*63632028SHaoyuan Feng    mergeArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U
351*63632028SHaoyuan Feng    mergeArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp
352*63632028SHaoyuan Feng    mergeArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U
353*63632028SHaoyuan Feng    mergeArb(i).in(outArbMqPort).bits := contiguous_pte_to_merge_ptwResp(resp_pte_sector(llptw_out.bits.id).asUInt, llptw_out.bits.req_info.vpn, llptw_out.bits.af, true)
354*63632028SHaoyuan Feng    mergeArb(i).out.ready := outArb(i).in(0).ready
355*63632028SHaoyuan Feng  }
356*63632028SHaoyuan Feng
357*63632028SHaoyuan Feng  for (i <- 0 until PtwWidth) {
358*63632028SHaoyuan Feng    outArb(i).in(0).valid := mergeArb(i).out.valid
359*63632028SHaoyuan Feng    outArb(i).in(0).bits := merge_ptwResp_to_sector_ptwResp(mergeArb(i).out.bits)
36092e3bfefSLemover  }
36192e3bfefSLemover
36292e3bfefSLemover  // io.tlb.map(_.resp) <> outArb.map(_.out)
36392e3bfefSLemover  io.tlb.map(_.resp).zip(outArb.map(_.out)).map{
36492e3bfefSLemover    case (resp, out) => resp <> out
36592e3bfefSLemover  }
36692e3bfefSLemover
36792e3bfefSLemover  // sfence
36892e3bfefSLemover  when (flush) {
36992e3bfefSLemover    for (i <- 0 until MemReqWidth) {
37092e3bfefSLemover      when (waiting_resp(i)) {
37192e3bfefSLemover        flush_latch(i) := true.B
37292e3bfefSLemover      }
37392e3bfefSLemover    }
37492e3bfefSLemover  }
37592e3bfefSLemover  // mem -> control signal
37692e3bfefSLemover  // waiting_resp and sfence_latch will be reset when mem_resp_done
37792e3bfefSLemover  when (mem_resp_done) {
37892e3bfefSLemover    waiting_resp(mem.d.bits.source) := false.B
37992e3bfefSLemover    flush_latch(mem.d.bits.source) := false.B
38092e3bfefSLemover  }
38192e3bfefSLemover
38292e3bfefSLemover  def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = {
38392e3bfefSLemover    sink.valid   := source.valid && !block_signal
38492e3bfefSLemover    source.ready := sink.ready   && !block_signal
38592e3bfefSLemover    sink.bits    := source.bits
38692e3bfefSLemover  }
38792e3bfefSLemover
38892e3bfefSLemover  def get_part(data: Vec[UInt], index: UInt): UInt = {
38992e3bfefSLemover    val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W)))
39092e3bfefSLemover    inner_data(index)
39192e3bfefSLemover  }
39292e3bfefSLemover
39392e3bfefSLemover  def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = {
39492e3bfefSLemover    val pte_in = pte.asTypeOf(new PteBundle())
39592e3bfefSLemover    val ptw_resp = Wire(new PtwResp())
39692e3bfefSLemover    ptw_resp.entry.ppn := pte_in.ppn
39792e3bfefSLemover    ptw_resp.entry.level.map(_ := 2.U)
39892e3bfefSLemover    ptw_resp.entry.perm.map(_ := pte_in.getPerm())
39992e3bfefSLemover    ptw_resp.entry.tag := vpn
40092e3bfefSLemover    ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U)
4010d94d540SHaoyuan Feng    ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && (af || pte_in.isAf())
40292e3bfefSLemover    ptw_resp.entry.v := !ptw_resp.pf
40392e3bfefSLemover    ptw_resp.entry.prefetch := DontCare
40492e3bfefSLemover    ptw_resp.entry.asid := satp.asid
40592e3bfefSLemover    ptw_resp
40692e3bfefSLemover  }
40792e3bfefSLemover
408*63632028SHaoyuan Feng  // not_super means that this is a normal page
409*63632028SHaoyuan Feng  // valididx(i) will be all true when super page to be convenient for l1 tlb matching
410*63632028SHaoyuan Feng  def contiguous_pte_to_merge_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean, not_super: Boolean = true) : PtwMergeResp = {
411*63632028SHaoyuan Feng    assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!")
412*63632028SHaoyuan Feng    val ptw_merge_resp = Wire(new PtwMergeResp())
413*63632028SHaoyuan Feng    for (i <- 0 until tlbcontiguous) {
414*63632028SHaoyuan Feng      val pte_in = pte(64 * i + 63, 64 * i).asTypeOf(new PteBundle())
415*63632028SHaoyuan Feng      val ptw_resp = Wire(new PtwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true))
416*63632028SHaoyuan Feng      ptw_resp.ppn := pte_in.ppn(ppnLen - 1, sectortlbwidth)
417*63632028SHaoyuan Feng      ptw_resp.ppn_low := pte_in.ppn(sectortlbwidth - 1, 0)
418*63632028SHaoyuan Feng      ptw_resp.level.map(_ := 2.U)
419*63632028SHaoyuan Feng      ptw_resp.perm.map(_ := pte_in.getPerm())
420*63632028SHaoyuan Feng      ptw_resp.tag := vpn(vpnLen - 1, sectortlbwidth)
421*63632028SHaoyuan Feng      ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U)
422*63632028SHaoyuan Feng      ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && (af || pte_in.isAf())
423*63632028SHaoyuan Feng      ptw_resp.v := !ptw_resp.pf
424*63632028SHaoyuan Feng      ptw_resp.prefetch := DontCare
425*63632028SHaoyuan Feng      ptw_resp.asid := satp.asid
426*63632028SHaoyuan Feng      ptw_merge_resp.entry(i) := ptw_resp
427*63632028SHaoyuan Feng    }
428*63632028SHaoyuan Feng    ptw_merge_resp.pteidx := UIntToOH(vpn(sectortlbwidth - 1, 0)).asBools
429*63632028SHaoyuan Feng    ptw_merge_resp.not_super := not_super.B
430*63632028SHaoyuan Feng    ptw_merge_resp
431*63632028SHaoyuan Feng  }
432*63632028SHaoyuan Feng
433*63632028SHaoyuan Feng  def merge_ptwResp_to_sector_ptwResp(pte: PtwMergeResp) : PtwSectorResp = {
434*63632028SHaoyuan Feng    assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!")
435*63632028SHaoyuan Feng    val ptw_sector_resp = Wire(new PtwSectorResp)
436*63632028SHaoyuan Feng    ptw_sector_resp.entry.tag := pte.entry(OHToUInt(pte.pteidx)).tag
437*63632028SHaoyuan Feng    ptw_sector_resp.entry.asid := pte.entry(OHToUInt(pte.pteidx)).asid
438*63632028SHaoyuan Feng    ptw_sector_resp.entry.ppn := pte.entry(OHToUInt(pte.pteidx)).ppn
439*63632028SHaoyuan Feng    ptw_sector_resp.entry.perm.map(_ := pte.entry(OHToUInt(pte.pteidx)).perm.getOrElse(0.U.asTypeOf(new PtePermBundle)))
440*63632028SHaoyuan Feng    ptw_sector_resp.entry.level.map(_ := pte.entry(OHToUInt(pte.pteidx)).level.getOrElse(0.U(2.W)))
441*63632028SHaoyuan Feng    ptw_sector_resp.entry.prefetch := pte.entry(OHToUInt(pte.pteidx)).prefetch
442*63632028SHaoyuan Feng    ptw_sector_resp.entry.v := pte.entry(OHToUInt(pte.pteidx)).v
443*63632028SHaoyuan Feng    ptw_sector_resp.af := pte.entry(OHToUInt(pte.pteidx)).af
444*63632028SHaoyuan Feng    ptw_sector_resp.pf := pte.entry(OHToUInt(pte.pteidx)).pf
445*63632028SHaoyuan Feng    ptw_sector_resp.addr_low := OHToUInt(pte.pteidx)
446*63632028SHaoyuan Feng    for (i <- 0 until tlbcontiguous) {
447*63632028SHaoyuan Feng      val ppn_equal = pte.entry(i).ppn === pte.entry(OHToUInt(pte.pteidx)).ppn
448*63632028SHaoyuan Feng      val perm_equal = pte.entry(i).perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt === pte.entry(OHToUInt(pte.pteidx)).perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt
449*63632028SHaoyuan Feng      val v_equal = pte.entry(i).v === pte.entry(OHToUInt(pte.pteidx)).v
450*63632028SHaoyuan Feng      val af_equal = pte.entry(i).af === pte.entry(OHToUInt(pte.pteidx)).af
451*63632028SHaoyuan Feng      val pf_equal = pte.entry(i).pf === pte.entry(OHToUInt(pte.pteidx)).pf
452*63632028SHaoyuan Feng      ptw_sector_resp.valididx(i) := (ppn_equal && perm_equal && v_equal && af_equal && pf_equal) || !pte.not_super
453*63632028SHaoyuan Feng      ptw_sector_resp.ppn_low(i) := pte.entry(i).ppn_low
454*63632028SHaoyuan Feng    }
455*63632028SHaoyuan Feng    ptw_sector_resp.valididx(OHToUInt(pte.pteidx)) := true.B
456*63632028SHaoyuan Feng    ptw_sector_resp
457*63632028SHaoyuan Feng  }
458*63632028SHaoyuan Feng
45992e3bfefSLemover  def outReady(source: UInt, port: Int): Bool = {
46092e3bfefSLemover    MuxLookup(source, true.B,
461*63632028SHaoyuan Feng      (0 until PtwWidth).map(i => i.U -> mergeArb(i).in(port).ready))
46292e3bfefSLemover  }
46392e3bfefSLemover
46492e3bfefSLemover  // debug info
46592e3bfefSLemover  for (i <- 0 until PtwWidth) {
46692e3bfefSLemover    XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n")
46792e3bfefSLemover  }
4687797f035SbugGenerator  XSDebug(p"[sfence] ${io.sfence}\n")
46992e3bfefSLemover  XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n")
47092e3bfefSLemover
47192e3bfefSLemover  for (i <- 0 until PtwWidth) {
47292e3bfefSLemover    XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire())
47392e3bfefSLemover    XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready)
47492e3bfefSLemover  }
47592e3bfefSLemover  XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid)
47692e3bfefSLemover  for (i <- 0 until (MemReqWidth + 1)) {
47792e3bfefSLemover    XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U)
47892e3bfefSLemover  }
47992e3bfefSLemover  XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U)
48092e3bfefSLemover  XSPerfAccumulate("mem_count", mem.a.fire())
481dd7fe201SHaoyuan Feng  for (i <- 0 until PtwWidth) {
482*63632028SHaoyuan Feng    XSPerfAccumulate(s"llptw_ppn_af${i}", mergeArb(i).in(outArbMqPort).valid && mergeArb(i).in(outArbMqPort).bits.entry(OHToUInt(mergeArb(i).in(outArbMqPort).bits.pteidx)).af && !llptw_out.bits.af)
483dd7fe201SHaoyuan Feng    XSPerfAccumulate(s"access_fault${i}", io.tlb(i).resp.fire && io.tlb(i).resp.bits.af)
484dd7fe201SHaoyuan Feng  }
48592e3bfefSLemover
48692e3bfefSLemover  // print configs
487f1fe8698SLemover  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}")
48892e3bfefSLemover
48992e3bfefSLemover  // time out assert
49092e3bfefSLemover  for (i <- 0 until MemReqWidth) {
49192e3bfefSLemover    TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}")
49292e3bfefSLemover    TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}")
49392e3bfefSLemover  }
49492e3bfefSLemover
49592e3bfefSLemover
49692e3bfefSLemover  val perfEvents  = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents)
49792e3bfefSLemover  generatePerfEvent()
4985afdf73cSHaoyuan Feng
4995afdf73cSHaoyuan Feng  val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB)
5005afdf73cSHaoyuan Feng  val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB)
5015afdf73cSHaoyuan Feng  ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn
5025afdf73cSHaoyuan Feng  DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn
5035afdf73cSHaoyuan Feng  ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag
5045afdf73cSHaoyuan Feng  DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag
5055afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset)
5065afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset)
5075afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset)
5085afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset)
5095afdf73cSHaoyuan Feng
5105afdf73cSHaoyuan Feng  val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB)
5115afdf73cSHaoyuan Feng  val PageCacheDB = Wire(new PageCacheDB)
512*63632028SHaoyuan Feng  PageCacheDB.vpn := Cat(cache.io.resp.bits.toTlb.entry(0).tag, OHToUInt(cache.io.resp.bits.toTlb.pteidx))
5135afdf73cSHaoyuan Feng  PageCacheDB.source := cache.io.resp.bits.req_info.source
5145afdf73cSHaoyuan Feng  PageCacheDB.bypassed := cache.io.resp.bits.bypassed
5155afdf73cSHaoyuan Feng  PageCacheDB.is_first := cache.io.resp.bits.isFirst
516*63632028SHaoyuan Feng  PageCacheDB.prefetched := cache.io.resp.bits.toTlb.entry(0).prefetch
5175afdf73cSHaoyuan Feng  PageCacheDB.prefetch := cache.io.resp.bits.prefetch
5185afdf73cSHaoyuan Feng  PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit
5195afdf73cSHaoyuan Feng  PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit
5205afdf73cSHaoyuan Feng  PageCacheDB.hit := cache.io.resp.bits.hit
5215afdf73cSHaoyuan Feng  PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset)
5225afdf73cSHaoyuan Feng
5235afdf73cSHaoyuan Feng  val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB)
5245afdf73cSHaoyuan Feng  val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB)
5255afdf73cSHaoyuan Feng  PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn
5265afdf73cSHaoyuan Feng  PTWReqDB.source := ptw.io.req.bits.req_info.source
5275afdf73cSHaoyuan Feng  PTWRespDB.vpn := ptw.io.refill.req_info.vpn
5285afdf73cSHaoyuan Feng  PTWRespDB.source := ptw.io.refill.req_info.source
5295afdf73cSHaoyuan Feng  LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn
5305afdf73cSHaoyuan Feng  LLPTWReqDB.source := llptw.io.in.bits.req_info.source
5315afdf73cSHaoyuan Feng  LLPTWRespDB.vpn := llptw.io.mem.refill.vpn
5325afdf73cSHaoyuan Feng  LLPTWRespDB.source := llptw.io.mem.refill.source
5335afdf73cSHaoyuan Feng  PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset)
5345afdf73cSHaoyuan Feng  PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset)
5355afdf73cSHaoyuan Feng  PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset)
5365afdf73cSHaoyuan Feng  PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset)
5375afdf73cSHaoyuan Feng
5385afdf73cSHaoyuan Feng  val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB)
5395afdf73cSHaoyuan Feng  val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB)
5405afdf73cSHaoyuan Feng  L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn
5415afdf73cSHaoyuan Feng  L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn
5425afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset)
5435afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset)
54492e3bfefSLemover}
54592e3bfefSLemover
5467797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache
5477797f035SbugGenerator *  Parameter:
5487797f035SbugGenerator *    enable: enable BlockHelper, mq should not send too many reqs
5497797f035SbugGenerator *    start: when miss queue out fire and need, block miss queue's out
5507797f035SbugGenerator *    block: block miss queue's out
5517797f035SbugGenerator *    latency: last missqueue out's cache access latency
5527797f035SbugGenerator */
5537797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule {
5547797f035SbugGenerator  val io = IO(new Bundle {
5557797f035SbugGenerator    val enable = Input(Bool())
5567797f035SbugGenerator    val start = Input(Bool())
5577797f035SbugGenerator    val block = Output(Bool())
5587797f035SbugGenerator  })
5597797f035SbugGenerator
5607797f035SbugGenerator  val count = RegInit(0.U(log2Ceil(latency).W))
5617797f035SbugGenerator  val valid = RegInit(false.B)
5627797f035SbugGenerator  val work = RegInit(true.B)
5637797f035SbugGenerator
5647797f035SbugGenerator  io.block := valid
5657797f035SbugGenerator
5667797f035SbugGenerator  when (io.start && work) { valid := true.B }
5677797f035SbugGenerator  when (valid) { count := count + 1.U }
5687797f035SbugGenerator  when (count === (latency.U) || io.enable) {
5697797f035SbugGenerator    valid := false.B
5707797f035SbugGenerator    work := io.enable
5717797f035SbugGenerator    count := 0.U
5727797f035SbugGenerator  }
5737797f035SbugGenerator}
5747797f035SbugGenerator
57592e3bfefSLemoverclass PTEHelper() extends ExtModule {
57692e3bfefSLemover  val clock  = IO(Input(Clock()))
57792e3bfefSLemover  val enable = IO(Input(Bool()))
57892e3bfefSLemover  val satp   = IO(Input(UInt(64.W)))
57992e3bfefSLemover  val vpn    = IO(Input(UInt(64.W)))
58092e3bfefSLemover  val pte    = IO(Output(UInt(64.W)))
58192e3bfefSLemover  val level  = IO(Output(UInt(8.W)))
58292e3bfefSLemover  val pf     = IO(Output(UInt(8.W)))
58392e3bfefSLemover}
58492e3bfefSLemover
5855afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module {
5865afdf73cSHaoyuan Feng  val io = IO(new Bundle() {
5875afdf73cSHaoyuan Feng    val in = Input(gen)
5885afdf73cSHaoyuan Feng    val out = Output(gen)
5895afdf73cSHaoyuan Feng    val ptwflush = Input(flush.cloneType)
5905afdf73cSHaoyuan Feng  })
5915afdf73cSHaoyuan Feng  val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5925afdf73cSHaoyuan Feng  val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
5935afdf73cSHaoyuan Feng  out(0) := io.in
5945afdf73cSHaoyuan Feng  if (n == 1) {
5955afdf73cSHaoyuan Feng    io.out := out(0)
5965afdf73cSHaoyuan Feng  } else {
5975afdf73cSHaoyuan Feng    when (io.ptwflush) {
5985afdf73cSHaoyuan Feng      for (i <- 0 until n) {
5995afdf73cSHaoyuan Feng        t(i) := 0.U.asTypeOf(gen)
6005afdf73cSHaoyuan Feng        out(i) := 0.U.asTypeOf(gen)
6015afdf73cSHaoyuan Feng      }
6025afdf73cSHaoyuan Feng      io.out := 0.U.asTypeOf(gen)
6035afdf73cSHaoyuan Feng    } .otherwise {
6045afdf73cSHaoyuan Feng      for (i <- 1 until n) {
6055afdf73cSHaoyuan Feng        t(i-1) := out(i-1)
6065afdf73cSHaoyuan Feng        out(i) := t(i-1)
6075afdf73cSHaoyuan Feng      }
6085afdf73cSHaoyuan Feng      io.out := out(n-1)
6095afdf73cSHaoyuan Feng    }
6105afdf73cSHaoyuan Feng  }
6115afdf73cSHaoyuan Feng}
6125afdf73cSHaoyuan Feng
6135afdf73cSHaoyuan Fengobject PTWDelayN {
6145afdf73cSHaoyuan Feng  def apply[T <: Data](in: T, n: Int, flush: Bool): T = {
6155afdf73cSHaoyuan Feng    val delay = Module(new PTWDelayN(in.cloneType, n, flush))
6165afdf73cSHaoyuan Feng    delay.io.in := in
6175afdf73cSHaoyuan Feng    delay.io.ptwflush := flush
6185afdf73cSHaoyuan Feng    delay.io.out
6195afdf73cSHaoyuan Feng  }
6205afdf73cSHaoyuan Feng}
6215afdf73cSHaoyuan Feng
62292e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst {
62392e3bfefSLemover  val io = IO(new L2TLBIO)
6245afdf73cSHaoyuan Feng  val flush = VecInit(Seq.fill(PtwWidth)(false.B))
6255afdf73cSHaoyuan Feng  flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay)
6265afdf73cSHaoyuan Feng  flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay)
62792e3bfefSLemover  for (i <- 0 until PtwWidth) {
62892e3bfefSLemover    val helper = Module(new PTEHelper())
62992e3bfefSLemover    helper.clock := clock
63092e3bfefSLemover    helper.satp := io.csr.tlb.satp.ppn
6315afdf73cSHaoyuan Feng
6325afdf73cSHaoyuan Feng    if (coreParams.softPTWDelay == 1) {
6335afdf73cSHaoyuan Feng      helper.enable := io.tlb(i).req(0).fire
63492e3bfefSLemover      helper.vpn := io.tlb(i).req(0).bits.vpn
6355afdf73cSHaoyuan Feng    } else {
6365afdf73cSHaoyuan Feng      helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i))
6375afdf73cSHaoyuan Feng      helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i))
6385afdf73cSHaoyuan Feng    }
6395afdf73cSHaoyuan Feng
64092e3bfefSLemover    val pte = helper.pte.asTypeOf(new PteBundle)
64192e3bfefSLemover    val level = helper.level
64292e3bfefSLemover    val pf = helper.pf
6435afdf73cSHaoyuan Feng    val empty = RegInit(true.B)
6445afdf73cSHaoyuan Feng    when (io.tlb(i).req(0).fire) {
6455afdf73cSHaoyuan Feng      empty := false.B
6465afdf73cSHaoyuan Feng    } .elsewhen (io.tlb(i).resp.fire || flush(i)) {
6475afdf73cSHaoyuan Feng      empty := true.B
6485afdf73cSHaoyuan Feng    }
64992e3bfefSLemover
6505afdf73cSHaoyuan Feng    io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire
6515afdf73cSHaoyuan Feng    io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i))
65292e3bfefSLemover    assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready)
6535afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i))
65492e3bfefSLemover    io.tlb(i).resp.bits.entry.ppn := pte.ppn
65592e3bfefSLemover    io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm())
65692e3bfefSLemover    io.tlb(i).resp.bits.entry.level.map(_ := level)
65792e3bfefSLemover    io.tlb(i).resp.bits.pf := pf
65892e3bfefSLemover    io.tlb(i).resp.bits.af := DontCare // TODO: implement it
6595afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.v := !pf
6605afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.prefetch := DontCare
6615afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid
66292e3bfefSLemover  }
66392e3bfefSLemover}
66492e3bfefSLemover
66592e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter {
66692e3bfefSLemover  val useSoftPTW = coreParams.softPTW
66792e3bfefSLemover  val node = if (!useSoftPTW) TLIdentityNode() else null
66892e3bfefSLemover  val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null
66992e3bfefSLemover  if (!useSoftPTW) {
67092e3bfefSLemover    node := ptw.node
67192e3bfefSLemover  }
67292e3bfefSLemover
67392e3bfefSLemover  lazy val module = new LazyModuleImp(this) with HasPerfEvents {
67492e3bfefSLemover    val io = IO(new L2TLBIO)
67592e3bfefSLemover    val perfEvents = if (useSoftPTW) {
67692e3bfefSLemover      val fake_ptw = Module(new FakePTW())
67792e3bfefSLemover      io <> fake_ptw.io
67892e3bfefSLemover      Seq()
67992e3bfefSLemover    }
68092e3bfefSLemover    else {
68192e3bfefSLemover        io <> ptw.module.io
68292e3bfefSLemover        ptw.module.getPerfEvents
68392e3bfefSLemover    }
68492e3bfefSLemover    generatePerfEvent()
68592e3bfefSLemover  }
68692e3bfefSLemover}
687