xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/L2TLB.scala (revision 3c02ee8f82edea481fa8336c7f54ffc17fafba91)
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._
27*3c02ee8fSwakafaimport 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
32*3c02ee8fSwakafaimport utility.ChiselDB
3392e3bfefSLemover
3492e3bfefSLemoverclass L2TLB()(implicit p: Parameters) extends LazyModule with HasPtwConst {
3592e3bfefSLemover
3692e3bfefSLemover  val node = TLClientNode(Seq(TLMasterPortParameters.v1(
3792e3bfefSLemover    clients = Seq(TLMasterParameters.v1(
3892e3bfefSLemover      "ptw",
3992e3bfefSLemover      sourceId = IdRange(0, MemReqWidth)
4092e3bfefSLemover    ))
4192e3bfefSLemover  )))
4292e3bfefSLemover
4392e3bfefSLemover  lazy val module = new L2TLBImp(this)
4492e3bfefSLemover}
4592e3bfefSLemover
4692e3bfefSLemover@chiselName
4792e3bfefSLemoverclass L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) with HasCSRConst with HasPerfEvents {
4892e3bfefSLemover
4992e3bfefSLemover  val (mem, edge) = outer.node.out.head
5092e3bfefSLemover
5192e3bfefSLemover  val io = IO(new L2TLBIO)
5292e3bfefSLemover  val difftestIO = IO(new Bundle() {
5392e3bfefSLemover    val ptwResp = Output(Bool())
5492e3bfefSLemover    val ptwAddr = Output(UInt(64.W))
5592e3bfefSLemover    val ptwData = Output(Vec(4, UInt(64.W)))
5692e3bfefSLemover  })
5792e3bfefSLemover
5892e3bfefSLemover  /* Ptw processes multiple requests
5992e3bfefSLemover   * Divide Ptw procedure into two stages: cache access ; mem access if cache miss
6092e3bfefSLemover   *           miss queue itlb       dtlb
6192e3bfefSLemover   *               |       |         |
6292e3bfefSLemover   *               ------arbiter------
6392e3bfefSLemover   *                            |
6492e3bfefSLemover   *                    l1 - l2 - l3 - sp
6592e3bfefSLemover   *                            |
6692e3bfefSLemover   *          -------------------------------------------
6792e3bfefSLemover   *    miss  |  queue                                  | hit
6892e3bfefSLemover   *    [][][][][][]                                    |
6992e3bfefSLemover   *          |                                         |
7092e3bfefSLemover   *    state machine accessing mem                     |
7192e3bfefSLemover   *          |                                         |
7292e3bfefSLemover   *          ---------------arbiter---------------------
7392e3bfefSLemover   *                 |                    |
7492e3bfefSLemover   *                itlb                 dtlb
7592e3bfefSLemover   */
7692e3bfefSLemover
7792e3bfefSLemover  difftestIO <> DontCare
7892e3bfefSLemover
797797f035SbugGenerator  val sfence_tmp = DelayN(io.sfence, 1)
807797f035SbugGenerator  val csr_tmp    = DelayN(io.csr.tlb, 1)
817797f035SbugGenerator  val sfence_dup = Seq.fill(8)(RegNext(sfence_tmp))
827797f035SbugGenerator  val csr_dup = Seq.fill(7)(RegNext(csr_tmp))
837797f035SbugGenerator  val satp   = csr_dup(0).satp
847797f035SbugGenerator  val priv   = csr_dup(0).priv
857797f035SbugGenerator  val flush  = sfence_dup(0).valid || satp.changed
8692e3bfefSLemover
8792e3bfefSLemover  val pmp = Module(new PMP())
8892e3bfefSLemover  val pmp_check = VecInit(Seq.fill(2)(Module(new PMPChecker(lgMaxSize = 3, sameCycle = true)).io))
8992e3bfefSLemover  pmp.io.distribute_csr := io.csr.distribute_csr
9092e3bfefSLemover  pmp_check.foreach(_.check_env.apply(ModeS, pmp.io.pmp, pmp.io.pma))
9192e3bfefSLemover
9292e3bfefSLemover  val missQueue = Module(new L2TlbMissQueue)
9392e3bfefSLemover  val cache = Module(new PtwCache)
9492e3bfefSLemover  val ptw = Module(new PTW)
9592e3bfefSLemover  val llptw = Module(new LLPTW)
967797f035SbugGenerator  val blockmq = Module(new BlockHelper(3))
9792e3bfefSLemover  val arb1 = Module(new Arbiter(new PtwReq, PtwWidth))
9892e3bfefSLemover  val arb2 = Module(new Arbiter(new Bundle {
9992e3bfefSLemover    val vpn = UInt(vpnLen.W)
10092e3bfefSLemover    val source = UInt(bSourceWidth.W)
1019c503409SLemover  }, if (l2tlbParams.enablePrefetch) 4 else 3))
10292e3bfefSLemover  val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwResp, 3)).io)
10392e3bfefSLemover  val outArbCachePort = 0
10492e3bfefSLemover  val outArbFsmPort = 1
10592e3bfefSLemover  val outArbMqPort = 2
10692e3bfefSLemover
1079c503409SLemover  // arb2 input port
1089c503409SLemover  val InArbPTWPort = 0
1099c503409SLemover  val InArbMissQueuePort = 1
1109c503409SLemover  val InArbTlbPort = 2
1119c503409SLemover  val InArbPrefetchPort = 3
11292e3bfefSLemover  // NOTE: when cache out but miss and ptw doesnt accept,
11392e3bfefSLemover  arb1.io.in <> VecInit(io.tlb.map(_.req(0)))
1149c503409SLemover  arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready
11592e3bfefSLemover
1169c503409SLemover  arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid
1179c503409SLemover  arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn
1189c503409SLemover  arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source
1199c503409SLemover  ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready
12092e3bfefSLemover  block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready)
1217797f035SbugGenerator
12292e3bfefSLemover  arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid
12392e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn
12492e3bfefSLemover  arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen
12592e3bfefSLemover  if (l2tlbParams.enablePrefetch) {
12692e3bfefSLemover    val prefetch = Module(new L2TlbPrefetch())
12792e3bfefSLemover    val recv = cache.io.resp
12892e3bfefSLemover    // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch
12992e3bfefSLemover    // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch
13092e3bfefSLemover    prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit  ||
13192e3bfefSLemover      recv.bits.prefetch) && recv.bits.isFirst
13292e3bfefSLemover    prefetch.io.in.bits.vpn := recv.bits.req_info.vpn
1337797f035SbugGenerator    prefetch.io.sfence := sfence_dup(0)
1347797f035SbugGenerator    prefetch.io.csr := csr_dup(0)
13592e3bfefSLemover    arb2.io.in(InArbPrefetchPort) <> prefetch.io.out
1365afdf73cSHaoyuan Feng
1375afdf73cSHaoyuan Feng    val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB)
1385afdf73cSHaoyuan Feng    val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB)
1395afdf73cSHaoyuan Feng    L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn
1405afdf73cSHaoyuan Feng    L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset)
14192e3bfefSLemover  }
14292e3bfefSLemover  arb2.io.out.ready := cache.io.req.ready
14392e3bfefSLemover
1447797f035SbugGenerator
1457797f035SbugGenerator  val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2))
1467797f035SbugGenerator  mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit &&
1477797f035SbugGenerator    (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) &&
1487797f035SbugGenerator    !from_pre(cache.io.resp.bits.req_info.source) &&
1497797f035SbugGenerator    (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready)
1507797f035SbugGenerator  mq_arb.io.in(0).bits :=  cache.io.resp.bits.req_info
1517797f035SbugGenerator  mq_arb.io.in(1) <> llptw.io.cache
1527797f035SbugGenerator  missQueue.io.in <> mq_arb.io.out
1537797f035SbugGenerator  missQueue.io.sfence  := sfence_dup(6)
1547797f035SbugGenerator  missQueue.io.csr := csr_dup(5)
1557797f035SbugGenerator
1567797f035SbugGenerator  blockmq.io.start := missQueue.io.out.fire
1577797f035SbugGenerator  blockmq.io.enable := ptw.io.req.fire()
1587797f035SbugGenerator
1599c503409SLemover  llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed
1609c503409SLemover  llptw.io.in.bits.req_info := cache.io.resp.bits.req_info
1619c503409SLemover  llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn
1627797f035SbugGenerator  llptw.io.sfence := sfence_dup(1)
1637797f035SbugGenerator  llptw.io.csr := csr_dup(1)
16492e3bfefSLemover
16592e3bfefSLemover  cache.io.req.valid := arb2.io.out.valid
16692e3bfefSLemover  cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn
16792e3bfefSLemover  cache.io.req.bits.req_info.source := arb2.io.out.bits.source
16892e3bfefSLemover  cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U
1691f4a7c0cSLemover  cache.io.req.bits.bypassed.map(_ := false.B)
1707797f035SbugGenerator  cache.io.sfence := sfence_dup(2)
1717797f035SbugGenerator  cache.io.csr := csr_dup(2)
1727797f035SbugGenerator  cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2)
1737797f035SbugGenerator  cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2)
17492e3bfefSLemover  cache.io.resp.ready := Mux(cache.io.resp.bits.hit,
17592e3bfefSLemover    outReady(cache.io.resp.bits.req_info.source, outArbCachePort),
1769c503409SLemover    Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready,
1777797f035SbugGenerator    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)))
17892e3bfefSLemover
17992e3bfefSLemover  // NOTE: missQueue req has higher priority
1807797f035SbugGenerator  ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit &&
1817797f035SbugGenerator    !cache.io.resp.bits.bypassed &&
1827797f035SbugGenerator    !cache.io.resp.bits.isFirst
18392e3bfefSLemover  ptw.io.req.bits.req_info := cache.io.resp.bits.req_info
18492e3bfefSLemover  ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit
18592e3bfefSLemover  ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn
1867797f035SbugGenerator  ptw.io.sfence := sfence_dup(7)
1877797f035SbugGenerator  ptw.io.csr := csr_dup(6)
18892e3bfefSLemover  ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort)
18992e3bfefSLemover
19092e3bfefSLemover  // mem req
19192e3bfefSLemover  def blockBytes_align(addr: UInt) = {
19292e3bfefSLemover    Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W))
19392e3bfefSLemover  }
19492e3bfefSLemover  def addr_low_from_vpn(vpn: UInt) = {
19592e3bfefSLemover    vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0)
19692e3bfefSLemover  }
19792e3bfefSLemover  def addr_low_from_paddr(paddr: UInt) = {
19892e3bfefSLemover    paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8))
19992e3bfefSLemover  }
20092e3bfefSLemover  def from_missqueue(id: UInt) = {
20192e3bfefSLemover    (id =/= l2tlbParams.llptwsize.U)
20292e3bfefSLemover  }
20392e3bfefSLemover  val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20492e3bfefSLemover  val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B)))
20592e3bfefSLemover  for (i <- waiting_resp.indices) {
20692e3bfefSLemover    assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true
20792e3bfefSLemover  }
20892e3bfefSLemover
20992e3bfefSLemover  val llptw_out = llptw.io.out
21092e3bfefSLemover  val llptw_mem = llptw.io.mem
21192e3bfefSLemover  llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize)
21292e3bfefSLemover  ptw.io.mem.mask := waiting_resp.last
21392e3bfefSLemover
21492e3bfefSLemover  val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2))
21592e3bfefSLemover  mem_arb.io.in(0) <> ptw.io.mem.req
21692e3bfefSLemover  mem_arb.io.in(1) <> llptw_mem.req
21792e3bfefSLemover  mem_arb.io.out.ready := mem.a.ready && !flush
21892e3bfefSLemover
2191f4a7c0cSLemover  // assert, should not send mem access at same addr for twice.
2207797f035SbugGenerator  val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid)
2217797f035SbugGenerator  val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid)
2221f4a7c0cSLemover  val last_resp_v = RegInit(false.B)
2231f4a7c0cSLemover  val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR
2241f4a7c0cSLemover  when (cache.io.refill.valid) { last_resp_v := !last_has_invalid}
2251f4a7c0cSLemover  when (flush) { last_resp_v := false.B }
2261f4a7c0cSLemover  XSError(last_resp_v && cache.io.refill.valid &&
2277797f035SbugGenerator    (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) &&
2287797f035SbugGenerator    (cache.io.refill.bits.level_dup(0) === last_resp_level),
2291f4a7c0cSLemover    "l2tlb should not access mem at same addr for twice")
2301f4a7c0cSLemover  // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid,
2311f4a7c0cSLemover  // but the current part is invalid, so one more mem access happened
2321f4a7c0cSLemover  // If this happened, remove the assert.
2331f4a7c0cSLemover
23492e3bfefSLemover  val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W)))
23592e3bfefSLemover
23692e3bfefSLemover  when (llptw.io.in.fire()) {
23792e3bfefSLemover    // when enq miss queue, set the req_addr_low to receive the mem resp data part
23892e3bfefSLemover    req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn)
23992e3bfefSLemover  }
24092e3bfefSLemover  when (mem_arb.io.out.fire()) {
24192e3bfefSLemover    req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr)
24292e3bfefSLemover    waiting_resp(mem_arb.io.out.bits.id) := true.B
24392e3bfefSLemover  }
24492e3bfefSLemover  // mem read
24592e3bfefSLemover  val memRead =  edge.Get(
24692e3bfefSLemover    fromSource = mem_arb.io.out.bits.id,
24792e3bfefSLemover    // toAddress  = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0),
24892e3bfefSLemover    toAddress  = blockBytes_align(mem_arb.io.out.bits.addr),
24992e3bfefSLemover    lgSize     = log2Up(l2tlbParams.blockBytes).U
25092e3bfefSLemover  )._2
25192e3bfefSLemover  mem.a.bits := memRead
25292e3bfefSLemover  mem.a.valid := mem_arb.io.out.valid && !flush
25392e3bfefSLemover  mem.d.ready := true.B
25492e3bfefSLemover  // mem -> data buffer
25592e3bfefSLemover  val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W)))
25692e3bfefSLemover  val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire())
25792e3bfefSLemover  val mem_resp_done = refill_helper._3
25892e3bfefSLemover  val mem_resp_from_mq = from_missqueue(mem.d.bits.source)
25992e3bfefSLemover  when (mem.d.valid) {
26092e3bfefSLemover    assert(mem.d.bits.source <= l2tlbParams.llptwsize.U)
26192e3bfefSLemover    refill_data(refill_helper._4) := mem.d.bits.data
26292e3bfefSLemover  }
2637797f035SbugGenerator  // refill_data_tmp is the wire fork of refill_data, but one cycle earlier
2647797f035SbugGenerator  val refill_data_tmp = WireInit(refill_data)
2657797f035SbugGenerator  refill_data_tmp(refill_helper._4) := mem.d.bits.data
2667797f035SbugGenerator
26792e3bfefSLemover  // save only one pte for each id
26892e3bfefSLemover  // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache)
26992e3bfefSLemover  val resp_pte = VecInit((0 until MemReqWidth).map(i =>
2707797f035SbugGenerator    if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) }
27192e3bfefSLemover    else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) }
2727797f035SbugGenerator    // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle
27392e3bfefSLemover  ))
27492e3bfefSLemover
27592e3bfefSLemover  // mem -> miss queue
27692e3bfefSLemover  llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq
2777797f035SbugGenerator  llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid)
27892e3bfefSLemover  // mem -> ptw
27992e3bfefSLemover  ptw.io.mem.req.ready := mem.a.ready
28092e3bfefSLemover  ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq
28192e3bfefSLemover  ptw.io.mem.resp.bits := resp_pte.last
28292e3bfefSLemover  // mem -> cache
2837797f035SbugGenerator  val refill_from_mq = mem_resp_from_mq
2847797f035SbugGenerator  val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire()))
2857797f035SbugGenerator  val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source)
2867797f035SbugGenerator
2877797f035SbugGenerator  cache.io.refill.valid := RegNext(refill_valid, false.B)
28892e3bfefSLemover  cache.io.refill.bits.ptes := refill_data.asUInt
2897797f035SbugGenerator  cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid))
2907797f035SbugGenerator  cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid))
2917797f035SbugGenerator  cache.io.refill.bits.levelOH(refill_level, refill_valid)
2927797f035SbugGenerator  cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source))))
29392e3bfefSLemover
29492e3bfefSLemover  // pmp
29592e3bfefSLemover  pmp_check(0).req <> ptw.io.pmp.req
29692e3bfefSLemover  ptw.io.pmp.resp <> pmp_check(0).resp
29792e3bfefSLemover  pmp_check(1).req <> llptw.io.pmp.req
29892e3bfefSLemover  llptw.io.pmp.resp <> pmp_check(1).resp
29992e3bfefSLemover
30092e3bfefSLemover  llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort)
30192e3bfefSLemover  for (i <- 0 until PtwWidth) {
30292e3bfefSLemover    outArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U
30392e3bfefSLemover    outArb(i).in(outArbCachePort).bits.entry := cache.io.resp.bits.toTlb
30492e3bfefSLemover    outArb(i).in(outArbCachePort).bits.pf := !cache.io.resp.bits.toTlb.v
30592e3bfefSLemover    outArb(i).in(outArbCachePort).bits.af := false.B
30692e3bfefSLemover    outArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U
30792e3bfefSLemover    outArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp
30892e3bfefSLemover    outArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U
30992e3bfefSLemover    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)
31092e3bfefSLemover  }
31192e3bfefSLemover
31292e3bfefSLemover  // io.tlb.map(_.resp) <> outArb.map(_.out)
31392e3bfefSLemover  io.tlb.map(_.resp).zip(outArb.map(_.out)).map{
31492e3bfefSLemover    case (resp, out) => resp <> out
31592e3bfefSLemover  }
31692e3bfefSLemover
31792e3bfefSLemover  // sfence
31892e3bfefSLemover  when (flush) {
31992e3bfefSLemover    for (i <- 0 until MemReqWidth) {
32092e3bfefSLemover      when (waiting_resp(i)) {
32192e3bfefSLemover        flush_latch(i) := true.B
32292e3bfefSLemover      }
32392e3bfefSLemover    }
32492e3bfefSLemover  }
32592e3bfefSLemover  // mem -> control signal
32692e3bfefSLemover  // waiting_resp and sfence_latch will be reset when mem_resp_done
32792e3bfefSLemover  when (mem_resp_done) {
32892e3bfefSLemover    waiting_resp(mem.d.bits.source) := false.B
32992e3bfefSLemover    flush_latch(mem.d.bits.source) := false.B
33092e3bfefSLemover  }
33192e3bfefSLemover
33292e3bfefSLemover  def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = {
33392e3bfefSLemover    sink.valid   := source.valid && !block_signal
33492e3bfefSLemover    source.ready := sink.ready   && !block_signal
33592e3bfefSLemover    sink.bits    := source.bits
33692e3bfefSLemover  }
33792e3bfefSLemover
33892e3bfefSLemover  def get_part(data: Vec[UInt], index: UInt): UInt = {
33992e3bfefSLemover    val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W)))
34092e3bfefSLemover    inner_data(index)
34192e3bfefSLemover  }
34292e3bfefSLemover
34392e3bfefSLemover  def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = {
34492e3bfefSLemover    val pte_in = pte.asTypeOf(new PteBundle())
34592e3bfefSLemover    val ptw_resp = Wire(new PtwResp())
34692e3bfefSLemover    ptw_resp.entry.ppn := pte_in.ppn
34792e3bfefSLemover    ptw_resp.entry.level.map(_ := 2.U)
34892e3bfefSLemover    ptw_resp.entry.perm.map(_ := pte_in.getPerm())
34992e3bfefSLemover    ptw_resp.entry.tag := vpn
35092e3bfefSLemover    ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U)
35192e3bfefSLemover    ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && af
35292e3bfefSLemover    ptw_resp.entry.v := !ptw_resp.pf
35392e3bfefSLemover    ptw_resp.entry.prefetch := DontCare
35492e3bfefSLemover    ptw_resp.entry.asid := satp.asid
35592e3bfefSLemover    ptw_resp
35692e3bfefSLemover  }
35792e3bfefSLemover
35892e3bfefSLemover  def outReady(source: UInt, port: Int): Bool = {
35992e3bfefSLemover    MuxLookup(source, true.B,
36092e3bfefSLemover      (0 until PtwWidth).map(i => i.U -> outArb(i).in(port).ready))
36192e3bfefSLemover  }
36292e3bfefSLemover
36392e3bfefSLemover  // debug info
36492e3bfefSLemover  for (i <- 0 until PtwWidth) {
36592e3bfefSLemover    XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n")
36692e3bfefSLemover  }
3677797f035SbugGenerator  XSDebug(p"[sfence] ${io.sfence}\n")
36892e3bfefSLemover  XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n")
36992e3bfefSLemover
37092e3bfefSLemover  for (i <- 0 until PtwWidth) {
37192e3bfefSLemover    XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire())
37292e3bfefSLemover    XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready)
37392e3bfefSLemover  }
37492e3bfefSLemover  XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid)
37592e3bfefSLemover  for (i <- 0 until (MemReqWidth + 1)) {
37692e3bfefSLemover    XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U)
37792e3bfefSLemover  }
37892e3bfefSLemover  XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U)
37992e3bfefSLemover  XSPerfAccumulate("mem_count", mem.a.fire())
38092e3bfefSLemover
38192e3bfefSLemover  // print configs
382f1fe8698SLemover  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}")
38392e3bfefSLemover
38492e3bfefSLemover  // time out assert
38592e3bfefSLemover  for (i <- 0 until MemReqWidth) {
38692e3bfefSLemover    TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}")
38792e3bfefSLemover    TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}")
38892e3bfefSLemover  }
38992e3bfefSLemover
39092e3bfefSLemover
39192e3bfefSLemover  val perfEvents  = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents)
39292e3bfefSLemover  generatePerfEvent()
3935afdf73cSHaoyuan Feng
3945afdf73cSHaoyuan Feng  val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB)
3955afdf73cSHaoyuan Feng  val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB)
3965afdf73cSHaoyuan Feng  ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn
3975afdf73cSHaoyuan Feng  DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn
3985afdf73cSHaoyuan Feng  ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag
3995afdf73cSHaoyuan Feng  DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag
4005afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset)
4015afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset)
4025afdf73cSHaoyuan Feng  L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset)
4035afdf73cSHaoyuan Feng  L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset)
4045afdf73cSHaoyuan Feng
4055afdf73cSHaoyuan Feng  val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB)
4065afdf73cSHaoyuan Feng  val PageCacheDB = Wire(new PageCacheDB)
4075afdf73cSHaoyuan Feng  PageCacheDB.vpn := cache.io.resp.bits.toTlb.tag
4085afdf73cSHaoyuan Feng  PageCacheDB.source := cache.io.resp.bits.req_info.source
4095afdf73cSHaoyuan Feng  PageCacheDB.bypassed := cache.io.resp.bits.bypassed
4105afdf73cSHaoyuan Feng  PageCacheDB.is_first := cache.io.resp.bits.isFirst
4115afdf73cSHaoyuan Feng  PageCacheDB.prefetched := cache.io.resp.bits.toTlb.prefetch
4125afdf73cSHaoyuan Feng  PageCacheDB.prefetch := cache.io.resp.bits.prefetch
4135afdf73cSHaoyuan Feng  PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit
4145afdf73cSHaoyuan Feng  PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit
4155afdf73cSHaoyuan Feng  PageCacheDB.hit := cache.io.resp.bits.hit
4165afdf73cSHaoyuan Feng  PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset)
4175afdf73cSHaoyuan Feng
4185afdf73cSHaoyuan Feng  val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB)
4195afdf73cSHaoyuan Feng  val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB)
4205afdf73cSHaoyuan Feng  PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn
4215afdf73cSHaoyuan Feng  PTWReqDB.source := ptw.io.req.bits.req_info.source
4225afdf73cSHaoyuan Feng  PTWRespDB.vpn := ptw.io.refill.req_info.vpn
4235afdf73cSHaoyuan Feng  PTWRespDB.source := ptw.io.refill.req_info.source
4245afdf73cSHaoyuan Feng  LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn
4255afdf73cSHaoyuan Feng  LLPTWReqDB.source := llptw.io.in.bits.req_info.source
4265afdf73cSHaoyuan Feng  LLPTWRespDB.vpn := llptw.io.mem.refill.vpn
4275afdf73cSHaoyuan Feng  LLPTWRespDB.source := llptw.io.mem.refill.source
4285afdf73cSHaoyuan Feng  PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset)
4295afdf73cSHaoyuan Feng  PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset)
4305afdf73cSHaoyuan Feng  PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset)
4315afdf73cSHaoyuan Feng  PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset)
4325afdf73cSHaoyuan Feng
4335afdf73cSHaoyuan Feng  val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB)
4345afdf73cSHaoyuan Feng  val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB)
4355afdf73cSHaoyuan Feng  L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn
4365afdf73cSHaoyuan Feng  L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn
4375afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset)
4385afdf73cSHaoyuan Feng  L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset)
43992e3bfefSLemover}
44092e3bfefSLemover
4417797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache
4427797f035SbugGenerator *  Parameter:
4437797f035SbugGenerator *    enable: enable BlockHelper, mq should not send too many reqs
4447797f035SbugGenerator *    start: when miss queue out fire and need, block miss queue's out
4457797f035SbugGenerator *    block: block miss queue's out
4467797f035SbugGenerator *    latency: last missqueue out's cache access latency
4477797f035SbugGenerator */
4487797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule {
4497797f035SbugGenerator  val io = IO(new Bundle {
4507797f035SbugGenerator    val enable = Input(Bool())
4517797f035SbugGenerator    val start = Input(Bool())
4527797f035SbugGenerator    val block = Output(Bool())
4537797f035SbugGenerator  })
4547797f035SbugGenerator
4557797f035SbugGenerator  val count = RegInit(0.U(log2Ceil(latency).W))
4567797f035SbugGenerator  val valid = RegInit(false.B)
4577797f035SbugGenerator  val work = RegInit(true.B)
4587797f035SbugGenerator
4597797f035SbugGenerator  io.block := valid
4607797f035SbugGenerator
4617797f035SbugGenerator  when (io.start && work) { valid := true.B }
4627797f035SbugGenerator  when (valid) { count := count + 1.U }
4637797f035SbugGenerator  when (count === (latency.U) || io.enable) {
4647797f035SbugGenerator    valid := false.B
4657797f035SbugGenerator    work := io.enable
4667797f035SbugGenerator    count := 0.U
4677797f035SbugGenerator  }
4687797f035SbugGenerator}
4697797f035SbugGenerator
47092e3bfefSLemoverclass PTEHelper() extends ExtModule {
47192e3bfefSLemover  val clock  = IO(Input(Clock()))
47292e3bfefSLemover  val enable = IO(Input(Bool()))
47392e3bfefSLemover  val satp   = IO(Input(UInt(64.W)))
47492e3bfefSLemover  val vpn    = IO(Input(UInt(64.W)))
47592e3bfefSLemover  val pte    = IO(Output(UInt(64.W)))
47692e3bfefSLemover  val level  = IO(Output(UInt(8.W)))
47792e3bfefSLemover  val pf     = IO(Output(UInt(8.W)))
47892e3bfefSLemover}
47992e3bfefSLemover
4805afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module {
4815afdf73cSHaoyuan Feng  val io = IO(new Bundle() {
4825afdf73cSHaoyuan Feng    val in = Input(gen)
4835afdf73cSHaoyuan Feng    val out = Output(gen)
4845afdf73cSHaoyuan Feng    val ptwflush = Input(flush.cloneType)
4855afdf73cSHaoyuan Feng  })
4865afdf73cSHaoyuan Feng  val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
4875afdf73cSHaoyuan Feng  val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen))))
4885afdf73cSHaoyuan Feng  out(0) := io.in
4895afdf73cSHaoyuan Feng  if (n == 1) {
4905afdf73cSHaoyuan Feng    io.out := out(0)
4915afdf73cSHaoyuan Feng  } else {
4925afdf73cSHaoyuan Feng    when (io.ptwflush) {
4935afdf73cSHaoyuan Feng      for (i <- 0 until n) {
4945afdf73cSHaoyuan Feng        t(i) := 0.U.asTypeOf(gen)
4955afdf73cSHaoyuan Feng        out(i) := 0.U.asTypeOf(gen)
4965afdf73cSHaoyuan Feng      }
4975afdf73cSHaoyuan Feng      io.out := 0.U.asTypeOf(gen)
4985afdf73cSHaoyuan Feng    } .otherwise {
4995afdf73cSHaoyuan Feng      for (i <- 1 until n) {
5005afdf73cSHaoyuan Feng        t(i-1) := out(i-1)
5015afdf73cSHaoyuan Feng        out(i) := t(i-1)
5025afdf73cSHaoyuan Feng      }
5035afdf73cSHaoyuan Feng      io.out := out(n-1)
5045afdf73cSHaoyuan Feng    }
5055afdf73cSHaoyuan Feng  }
5065afdf73cSHaoyuan Feng}
5075afdf73cSHaoyuan Feng
5085afdf73cSHaoyuan Fengobject PTWDelayN {
5095afdf73cSHaoyuan Feng  def apply[T <: Data](in: T, n: Int, flush: Bool): T = {
5105afdf73cSHaoyuan Feng    val delay = Module(new PTWDelayN(in.cloneType, n, flush))
5115afdf73cSHaoyuan Feng    delay.io.in := in
5125afdf73cSHaoyuan Feng    delay.io.ptwflush := flush
5135afdf73cSHaoyuan Feng    delay.io.out
5145afdf73cSHaoyuan Feng  }
5155afdf73cSHaoyuan Feng}
5165afdf73cSHaoyuan Feng
51792e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst {
51892e3bfefSLemover  val io = IO(new L2TLBIO)
5195afdf73cSHaoyuan Feng  val flush = VecInit(Seq.fill(PtwWidth)(false.B))
5205afdf73cSHaoyuan Feng  flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay)
5215afdf73cSHaoyuan Feng  flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay)
52292e3bfefSLemover  for (i <- 0 until PtwWidth) {
52392e3bfefSLemover    val helper = Module(new PTEHelper())
52492e3bfefSLemover    helper.clock := clock
52592e3bfefSLemover    helper.satp := io.csr.tlb.satp.ppn
5265afdf73cSHaoyuan Feng
5275afdf73cSHaoyuan Feng    if (coreParams.softPTWDelay == 1) {
5285afdf73cSHaoyuan Feng      helper.enable := io.tlb(i).req(0).fire
52992e3bfefSLemover      helper.vpn := io.tlb(i).req(0).bits.vpn
5305afdf73cSHaoyuan Feng    } else {
5315afdf73cSHaoyuan Feng      helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i))
5325afdf73cSHaoyuan Feng      helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i))
5335afdf73cSHaoyuan Feng    }
5345afdf73cSHaoyuan Feng
53592e3bfefSLemover    val pte = helper.pte.asTypeOf(new PteBundle)
53692e3bfefSLemover    val level = helper.level
53792e3bfefSLemover    val pf = helper.pf
5385afdf73cSHaoyuan Feng    val empty = RegInit(true.B)
5395afdf73cSHaoyuan Feng    when (io.tlb(i).req(0).fire) {
5405afdf73cSHaoyuan Feng      empty := false.B
5415afdf73cSHaoyuan Feng    } .elsewhen (io.tlb(i).resp.fire || flush(i)) {
5425afdf73cSHaoyuan Feng      empty := true.B
5435afdf73cSHaoyuan Feng    }
54492e3bfefSLemover
5455afdf73cSHaoyuan Feng    io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire
5465afdf73cSHaoyuan Feng    io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i))
54792e3bfefSLemover    assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready)
5485afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i))
54992e3bfefSLemover    io.tlb(i).resp.bits.entry.ppn := pte.ppn
55092e3bfefSLemover    io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm())
55192e3bfefSLemover    io.tlb(i).resp.bits.entry.level.map(_ := level)
55292e3bfefSLemover    io.tlb(i).resp.bits.pf := pf
55392e3bfefSLemover    io.tlb(i).resp.bits.af := DontCare // TODO: implement it
5545afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.v := !pf
5555afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.prefetch := DontCare
5565afdf73cSHaoyuan Feng    io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid
55792e3bfefSLemover  }
55892e3bfefSLemover}
55992e3bfefSLemover
56092e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter {
56192e3bfefSLemover  val useSoftPTW = coreParams.softPTW
56292e3bfefSLemover  val node = if (!useSoftPTW) TLIdentityNode() else null
56392e3bfefSLemover  val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null
56492e3bfefSLemover  if (!useSoftPTW) {
56592e3bfefSLemover    node := ptw.node
56692e3bfefSLemover  }
56792e3bfefSLemover
56892e3bfefSLemover  lazy val module = new LazyModuleImp(this) with HasPerfEvents {
56992e3bfefSLemover    val io = IO(new L2TLBIO)
57092e3bfefSLemover    val perfEvents = if (useSoftPTW) {
57192e3bfefSLemover      val fake_ptw = Module(new FakePTW())
57292e3bfefSLemover      io <> fake_ptw.io
57392e3bfefSLemover      Seq()
57492e3bfefSLemover    }
57592e3bfefSLemover    else {
57692e3bfefSLemover        io <> ptw.module.io
57792e3bfefSLemover        ptw.module.getPerfEvents
57892e3bfefSLemover    }
57992e3bfefSLemover    generatePerfEvent()
58092e3bfefSLemover  }
58192e3bfefSLemover}
582