xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/PageTableCache.scala (revision 8891a219bbc84f568e1d134854d8d5ed86d6d560)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.cache.mmu
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import xiangshan.cache.{HasDCacheParameters, MemoryOpConstants}
24import utils._
25import utility._
26import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
27import freechips.rocketchip.tilelink._
28
29/* ptw cache caches the page table of all the three layers
30 * ptw cache resp at next cycle
31 * the cache should not be blocked
32 * when miss queue if full, just block req outside
33 */
34
35class PageCachePerPespBundle(implicit p: Parameters) extends PtwBundle {
36  val hit = Bool()
37  val pre = Bool()
38  val ppn = UInt(ppnLen.W)
39  val perm = new PtePermBundle()
40  val ecc = Bool()
41  val level = UInt(2.W)
42  val v = Bool()
43
44  def apply(hit: Bool, pre: Bool, ppn: UInt, perm: PtePermBundle = 0.U.asTypeOf(new PtePermBundle()),
45            ecc: Bool = false.B, level: UInt = 0.U, valid: Bool = true.B) {
46    this.hit := hit && !ecc
47    this.pre := pre
48    this.ppn := ppn
49    this.perm := perm
50    this.ecc := ecc && hit
51    this.level := level
52    this.v := valid
53  }
54}
55
56class PageCacheMergePespBundle(implicit p: Parameters) extends PtwBundle {
57  assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!")
58  val hit = Bool()
59  val pre = Bool()
60  val ppn = Vec(tlbcontiguous, UInt(ppnLen.W))
61  val perm = Vec(tlbcontiguous, new PtePermBundle())
62  val ecc = Bool()
63  val level = UInt(2.W)
64  val v = Vec(tlbcontiguous, Bool())
65
66  def apply(hit: Bool, pre: Bool, ppn: Vec[UInt], perm: Vec[PtePermBundle] = Vec(tlbcontiguous, 0.U.asTypeOf(new PtePermBundle())),
67            ecc: Bool = false.B, level: UInt = 0.U, valid: Vec[Bool] = Vec(tlbcontiguous, true.B)) {
68    this.hit := hit && !ecc
69    this.pre := pre
70    this.ppn := ppn
71    this.perm := perm
72    this.ecc := ecc && hit
73    this.level := level
74    this.v := valid
75  }
76}
77
78class PageCacheRespBundle(implicit p: Parameters) extends PtwBundle {
79  val l1 = new PageCachePerPespBundle
80  val l2 = new PageCachePerPespBundle
81  val l3 = new PageCacheMergePespBundle
82  val sp = new PageCachePerPespBundle
83}
84
85class PtwCacheReq(implicit p: Parameters) extends PtwBundle {
86  val req_info = new L2TlbInnerBundle()
87  val isFirst = Bool()
88  val bypassed = Vec(3, Bool())
89}
90
91class PtwCacheIO()(implicit p: Parameters) extends MMUIOBaseBundle with HasPtwConst {
92  val req = Flipped(DecoupledIO(new PtwCacheReq()))
93  val resp = DecoupledIO(new Bundle {
94    val req_info = new L2TlbInnerBundle()
95    val isFirst = Bool()
96    val hit = Bool()
97    val prefetch = Bool() // is the entry fetched by prefetch
98    val bypassed = Bool()
99    val toFsm = new Bundle {
100      val l1Hit = Bool()
101      val l2Hit = Bool()
102      val ppn = UInt(ppnLen.W)
103    }
104    val toTlb = new PtwMergeResp()
105  })
106  val refill = Flipped(ValidIO(new Bundle {
107    val ptes = UInt(blockBits.W)
108    val levelOH = new Bundle {
109      // NOTE: levelOH has (Level+1) bits, each stands for page cache entries
110      val sp = Bool()
111      val l3 = Bool()
112      val l2 = Bool()
113      val l1 = Bool()
114      def apply(levelUInt: UInt, valid: Bool) = {
115        sp := RegNext((levelUInt === 0.U || levelUInt === 1.U) && valid, false.B)
116        l3 := RegNext((levelUInt === 2.U) & valid, false.B)
117        l2 := RegNext((levelUInt === 1.U) & valid, false.B)
118        l1 := RegNext((levelUInt === 0.U) & valid, false.B)
119      }
120    }
121    // duplicate level and sel_pte for each page caches, for better fanout
122    val req_info_dup = Vec(3, new L2TlbInnerBundle())
123    val level_dup = Vec(3, UInt(log2Up(Level).W))
124    val sel_pte_dup = Vec(3, UInt(XLEN.W))
125  }))
126  val sfence_dup = Vec(4, Input(new SfenceBundle()))
127  val csr_dup = Vec(3, Input(new TlbCsrBundle()))
128}
129
130class PtwCache()(implicit p: Parameters) extends XSModule with HasPtwConst with HasPerfEvents {
131  val io = IO(new PtwCacheIO)
132
133  val ecc = Code.fromString(l2tlbParams.ecc)
134  val l2EntryType = new PTWEntriesWithEcc(ecc, num = PtwL2SectorSize, tagLen = PtwL2TagLen, level = 1, hasPerm = false)
135  val l3EntryType = new PTWEntriesWithEcc(ecc, num = PtwL3SectorSize, tagLen = PtwL3TagLen, level = 2, hasPerm = true)
136
137  // TODO: four caches make the codes dirty, think about how to deal with it
138
139  val sfence_dup = io.sfence_dup
140  val refill = io.refill.bits
141  val refill_prefetch_dup = io.refill.bits.req_info_dup.map(a => from_pre(a.source))
142  val flush_dup = sfence_dup.zip(io.csr_dup).map(f => f._1.valid || f._2.satp.changed)
143  val flush = flush_dup(0)
144
145  // when refill, refuce to accept new req
146  val rwHarzad = if (sramSinglePort) io.refill.valid else false.B
147
148  // handle hand signal and req_info
149  // TODO: replace with FlushableQueue
150  val stageReq = Wire(Decoupled(new PtwCacheReq()))         // enq stage & read page cache valid
151  val stageDelay = Wire(Vec(2, Decoupled(new PtwCacheReq()))) // page cache resp
152  val stageCheck = Wire(Vec(2, Decoupled(new PtwCacheReq()))) // check hit & check ecc
153  val stageResp = Wire(Decoupled(new PtwCacheReq()))         // deq stage
154
155  val stageDelay_valid_1cycle = OneCycleValid(stageReq.fire, flush)      // catch ram data
156  val stageCheck_valid_1cycle = OneCycleValid(stageDelay(1).fire, flush) // replace & perf counter
157  val stageResp_valid_1cycle_dup = Wire(Vec(2, Bool()))
158  stageResp_valid_1cycle_dup.map(_ := OneCycleValid(stageCheck(1).fire, flush))  // ecc flush
159
160  stageReq <> io.req
161  PipelineConnect(stageReq, stageDelay(0), stageDelay(1).ready, flush, rwHarzad)
162  InsideStageConnect(stageDelay(0), stageDelay(1), stageDelay_valid_1cycle)
163  PipelineConnect(stageDelay(1), stageCheck(0), stageCheck(1).ready, flush)
164  InsideStageConnect(stageCheck(0), stageCheck(1), stageCheck_valid_1cycle)
165  PipelineConnect(stageCheck(1), stageResp, io.resp.ready, flush)
166  stageResp.ready := !stageResp.valid || io.resp.ready
167
168  // l1: level 0 non-leaf pte
169  val l1 = Reg(Vec(l2tlbParams.l1Size, new PtwEntry(tagLen = PtwL1TagLen)))
170  val l1v = RegInit(0.U(l2tlbParams.l1Size.W))
171  val l1g = Reg(UInt(l2tlbParams.l1Size.W))
172  val l1asids = l1.map(_.asid)
173
174  // l2: level 1 non-leaf pte
175  val l2 = Module(new SRAMTemplate(
176    l2EntryType,
177    set = l2tlbParams.l2nSets,
178    way = l2tlbParams.l2nWays,
179    singlePort = sramSinglePort
180  ))
181  val l2v = RegInit(0.U((l2tlbParams.l2nSets * l2tlbParams.l2nWays).W))
182  val l2g = Reg(UInt((l2tlbParams.l2nSets * l2tlbParams.l2nWays).W))
183  val l2asids = Reg(Vec(l2tlbParams.l2nSets, Vec(l2tlbParams.l2nWays, UInt(AsidLength.W))))
184  def getl2vSet(vpn: UInt) = {
185    require(log2Up(l2tlbParams.l2nWays) == log2Down(l2tlbParams.l2nWays))
186    val set = genPtwL2SetIdx(vpn)
187    require(set.getWidth == log2Up(l2tlbParams.l2nSets))
188    val l2vVec = l2v.asTypeOf(Vec(l2tlbParams.l2nSets, UInt(l2tlbParams.l2nWays.W)))
189    l2vVec(set)
190  }
191  def getl2asidSet(vpn: UInt) = {
192    require(log2Up(l2tlbParams.l2nWays) == log2Down(l2tlbParams.l2nWays))
193    val set = genPtwL2SetIdx(vpn)
194    require(set.getWidth == log2Up(l2tlbParams.l2nSets))
195    l2asids(set)
196  }
197
198  // l3: level 2 leaf pte of 4KB pages
199  val l3 = Module(new SRAMTemplate(
200    l3EntryType,
201    set = l2tlbParams.l3nSets,
202    way = l2tlbParams.l3nWays,
203    singlePort = sramSinglePort
204  ))
205  val l3v = RegInit(0.U((l2tlbParams.l3nSets * l2tlbParams.l3nWays).W))
206  val l3g = Reg(UInt((l2tlbParams.l3nSets * l2tlbParams.l3nWays).W))
207  val l3asids = Reg(Vec(l2tlbParams.l3nSets, Vec(l2tlbParams.l3nWays, UInt(AsidLength.W))))
208  def getl3vSet(vpn: UInt) = {
209    require(log2Up(l2tlbParams.l3nWays) == log2Down(l2tlbParams.l3nWays))
210    val set = genPtwL3SetIdx(vpn)
211    require(set.getWidth == log2Up(l2tlbParams.l3nSets))
212    val l3vVec = l3v.asTypeOf(Vec(l2tlbParams.l3nSets, UInt(l2tlbParams.l3nWays.W)))
213    l3vVec(set)
214  }
215  def getl3asidSet(vpn: UInt) = {
216    require(log2Up(l2tlbParams.l3nWays) == log2Down(l2tlbParams.l3nWays))
217    val set = genPtwL3SetIdx(vpn)
218    require(set.getWidth == log2Up(l2tlbParams.l3nSets))
219    l3asids(set)
220  }
221
222  // sp: level 0/1 leaf pte of 1GB/2MB super pages
223  val sp = Reg(Vec(l2tlbParams.spSize, new PtwEntry(tagLen = SPTagLen, hasPerm = true, hasLevel = true)))
224  val spv = RegInit(0.U(l2tlbParams.spSize.W))
225  val spg = Reg(UInt(l2tlbParams.spSize.W))
226  val spasids = sp.map(_.asid)
227
228  // Access Perf
229  val l1AccessPerf = Wire(Vec(l2tlbParams.l1Size, Bool()))
230  val l2AccessPerf = Wire(Vec(l2tlbParams.l2nWays, Bool()))
231  val l3AccessPerf = Wire(Vec(l2tlbParams.l3nWays, Bool()))
232  val spAccessPerf = Wire(Vec(l2tlbParams.spSize, Bool()))
233  l1AccessPerf.map(_ := false.B)
234  l2AccessPerf.map(_ := false.B)
235  l3AccessPerf.map(_ := false.B)
236  spAccessPerf.map(_ := false.B)
237
238
239
240  def vpn_match(vpn1: UInt, vpn2: UInt, level: Int) = {
241    vpn1(vpnnLen*3-1, vpnnLen*(2-level)+3) === vpn2(vpnnLen*3-1, vpnnLen*(2-level)+3)
242  }
243  // NOTE: not actually bypassed, just check if hit, re-access the page cache
244  def refill_bypass(vpn: UInt, level: Int) = {
245    io.refill.valid && (level.U === io.refill.bits.level_dup(0)) && vpn_match(io.refill.bits.req_info_dup(0).vpn, vpn, level)
246  }
247
248  // l1
249  val ptwl1replace = ReplacementPolicy.fromString(l2tlbParams.l1Replacer, l2tlbParams.l1Size)
250  val (l1Hit, l1HitPPN, l1Pre) = {
251    val hitVecT = l1.zipWithIndex.map { case (e, i) => e.hit(stageReq.bits.req_info.vpn, io.csr_dup(0).satp.asid) && l1v(i) }
252    val hitVec = hitVecT.map(RegEnable(_, stageReq.fire))
253
254    // stageDelay, but check for l1
255    val hitPPN = DataHoldBypass(ParallelPriorityMux(hitVec zip l1.map(_.ppn)), stageDelay_valid_1cycle)
256    val hitPre = DataHoldBypass(ParallelPriorityMux(hitVec zip l1.map(_.prefetch)), stageDelay_valid_1cycle)
257    val hit = DataHoldBypass(ParallelOR(hitVec), stageDelay_valid_1cycle)
258
259    when (hit && stageDelay_valid_1cycle) { ptwl1replace.access(OHToUInt(hitVec)) }
260
261    l1AccessPerf.zip(hitVec).map{ case (l, h) => l := h && stageDelay_valid_1cycle}
262    for (i <- 0 until l2tlbParams.l1Size) {
263      XSDebug(stageReq.fire, p"[l1] l1(${i.U}) ${l1(i)} hit:${l1(i).hit(stageReq.bits.req_info.vpn, io.csr_dup(0).satp.asid)}\n")
264    }
265    XSDebug(stageReq.fire, p"[l1] l1v:${Binary(l1v)} hitVecT:${Binary(VecInit(hitVecT).asUInt)}\n")
266    XSDebug(stageDelay(0).valid, p"[l1] l1Hit:${hit} l1HitPPN:0x${Hexadecimal(hitPPN)} hitVec:${VecInit(hitVec).asUInt}\n")
267
268    VecInit(hitVecT).suggestName(s"l1_hitVecT")
269    VecInit(hitVec).suggestName(s"l1_hitVec")
270
271    // synchronize with other entries with RegEnable
272    (RegEnable(hit, stageDelay(1).fire),
273     RegEnable(hitPPN, stageDelay(1).fire),
274     RegEnable(hitPre, stageDelay(1).fire))
275  }
276
277  // l2
278  val ptwl2replace = ReplacementPolicy.fromString(l2tlbParams.l2Replacer,l2tlbParams.l2nWays,l2tlbParams.l2nSets)
279  val (l2Hit, l2HitPPN, l2Pre, l2eccError) = {
280    val ridx = genPtwL2SetIdx(stageReq.bits.req_info.vpn)
281    l2.io.r.req.valid := stageReq.fire
282    l2.io.r.req.bits.apply(setIdx = ridx)
283    val vVec_req = getl2vSet(stageReq.bits.req_info.vpn)
284
285    // delay one cycle after sram read
286    val delay_vpn = stageDelay(0).bits.req_info.vpn
287    val data_resp = DataHoldBypass(l2.io.r.resp.data, stageDelay_valid_1cycle)
288    val vVec_delay = RegEnable(vVec_req, stageReq.fire)
289    val hitVec_delay = VecInit(data_resp.zip(vVec_delay.asBools).map { case (wayData, v) =>
290      wayData.entries.hit(delay_vpn, io.csr_dup(1).satp.asid) && v })
291
292    // check hit and ecc
293    val check_vpn = stageCheck(0).bits.req_info.vpn
294    val ramDatas = RegEnable(data_resp, stageDelay(1).fire)
295    val vVec = RegEnable(vVec_delay, stageDelay(1).fire).asBools
296
297    val hitVec = RegEnable(hitVec_delay, stageDelay(1).fire)
298    val hitWayEntry = ParallelPriorityMux(hitVec zip ramDatas)
299    val hitWayData = hitWayEntry.entries
300    val hit = ParallelOR(hitVec)
301    val hitWay = ParallelPriorityMux(hitVec zip (0 until l2tlbParams.l2nWays).map(_.U(log2Up(l2tlbParams.l2nWays).W)))
302    val eccError = hitWayEntry.decode()
303
304    ridx.suggestName(s"l2_ridx")
305    ramDatas.suggestName(s"l2_ramDatas")
306    hitVec.suggestName(s"l2_hitVec")
307    hitWayData.suggestName(s"l2_hitWayData")
308    hitWay.suggestName(s"l2_hitWay")
309
310    when (hit && stageCheck_valid_1cycle) { ptwl2replace.access(genPtwL2SetIdx(check_vpn), hitWay) }
311
312    l2AccessPerf.zip(hitVec).map{ case (l, h) => l := h && stageCheck_valid_1cycle }
313    XSDebug(stageDelay_valid_1cycle, p"[l2] ridx:0x${Hexadecimal(ridx)}\n")
314    for (i <- 0 until l2tlbParams.l2nWays) {
315      XSDebug(stageCheck_valid_1cycle, p"[l2] ramDatas(${i.U}) ${ramDatas(i)}  l2v:${vVec(i)}  hit:${hit}\n")
316    }
317    XSDebug(stageCheck_valid_1cycle, p"[l2] l2Hit:${hit} l2HitPPN:0x${Hexadecimal(hitWayData.ppns(genPtwL2SectorIdx(check_vpn)))} hitVec:${Binary(hitVec.asUInt)} hitWay:${hitWay} vidx:${vVec}\n")
318
319    (hit, hitWayData.ppns(genPtwL2SectorIdx(check_vpn)), hitWayData.prefetch, eccError)
320  }
321
322  // l3
323  val ptwl3replace = ReplacementPolicy.fromString(l2tlbParams.l3Replacer,l2tlbParams.l3nWays,l2tlbParams.l3nSets)
324  val (l3Hit, l3HitData, l3Pre, l3eccError) = {
325    val ridx = genPtwL3SetIdx(stageReq.bits.req_info.vpn)
326    l3.io.r.req.valid := stageReq.fire
327    l3.io.r.req.bits.apply(setIdx = ridx)
328    val vVec_req = getl3vSet(stageReq.bits.req_info.vpn)
329
330    // delay one cycle after sram read
331    val delay_vpn = stageDelay(0).bits.req_info.vpn
332    val data_resp = DataHoldBypass(l3.io.r.resp.data, stageDelay_valid_1cycle)
333    val vVec_delay = RegEnable(vVec_req, stageReq.fire)
334    val hitVec_delay = VecInit(data_resp.zip(vVec_delay.asBools).map { case (wayData, v) =>
335      wayData.entries.hit(delay_vpn, io.csr_dup(2).satp.asid) && v })
336
337    // check hit and ecc
338    val check_vpn = stageCheck(0).bits.req_info.vpn
339    val ramDatas = RegEnable(data_resp, stageDelay(1).fire)
340    val vVec = RegEnable(vVec_delay, stageDelay(1).fire).asBools
341
342    val hitVec = RegEnable(hitVec_delay, stageDelay(1).fire)
343    val hitWayEntry = ParallelPriorityMux(hitVec zip ramDatas)
344    val hitWayData = hitWayEntry.entries
345    val hitWayEcc = hitWayEntry.ecc
346    val hit = ParallelOR(hitVec)
347    val hitWay = ParallelPriorityMux(hitVec zip (0 until l2tlbParams.l3nWays).map(_.U(log2Up(l2tlbParams.l3nWays).W)))
348    val eccError = hitWayEntry.decode()
349
350    when (hit && stageCheck_valid_1cycle) { ptwl3replace.access(genPtwL3SetIdx(check_vpn), hitWay) }
351
352    l3AccessPerf.zip(hitVec).map{ case (l, h) => l := h && stageCheck_valid_1cycle }
353    XSDebug(stageReq.fire, p"[l3] ridx:0x${Hexadecimal(ridx)}\n")
354    for (i <- 0 until l2tlbParams.l3nWays) {
355      XSDebug(stageCheck_valid_1cycle, p"[l3] ramDatas(${i.U}) ${ramDatas(i)}  l3v:${vVec(i)}  hit:${hitVec(i)}\n")
356    }
357    XSDebug(stageCheck_valid_1cycle, p"[l3] l3Hit:${hit} l3HitData:${hitWayData} hitVec:${Binary(hitVec.asUInt)} hitWay:${hitWay} v:${vVec}\n")
358
359    ridx.suggestName(s"l3_ridx")
360    ramDatas.suggestName(s"l3_ramDatas")
361    hitVec.suggestName(s"l3_hitVec")
362    hitWay.suggestName(s"l3_hitWay")
363
364    (hit, hitWayData, hitWayData.prefetch, eccError)
365  }
366  val l3HitPPN = l3HitData.ppns
367  val l3HitPerm = l3HitData.perms.getOrElse(0.U.asTypeOf(Vec(PtwL3SectorSize, new PtePermBundle)))
368  val l3HitValid = l3HitData.vs
369
370  // super page
371  val spreplace = ReplacementPolicy.fromString(l2tlbParams.spReplacer, l2tlbParams.spSize)
372  val (spHit, spHitData, spPre, spValid) = {
373    val hitVecT = sp.zipWithIndex.map { case (e, i) => e.hit(stageReq.bits.req_info.vpn, io.csr_dup(0).satp.asid) && spv(i) }
374    val hitVec = hitVecT.map(RegEnable(_, stageReq.fire))
375    val hitData = ParallelPriorityMux(hitVec zip sp)
376    val hit = ParallelOR(hitVec)
377
378    when (hit && stageDelay_valid_1cycle) { spreplace.access(OHToUInt(hitVec)) }
379
380    spAccessPerf.zip(hitVec).map{ case (s, h) => s := h && stageDelay_valid_1cycle }
381    for (i <- 0 until l2tlbParams.spSize) {
382      XSDebug(stageReq.fire, p"[sp] sp(${i.U}) ${sp(i)} hit:${sp(i).hit(stageReq.bits.req_info.vpn, io.csr_dup(0).satp.asid)} spv:${spv(i)}\n")
383    }
384    XSDebug(stageDelay_valid_1cycle, p"[sp] spHit:${hit} spHitData:${hitData} hitVec:${Binary(VecInit(hitVec).asUInt)}\n")
385
386    VecInit(hitVecT).suggestName(s"sp_hitVecT")
387    VecInit(hitVec).suggestName(s"sp_hitVec")
388
389    (RegEnable(hit, stageDelay(1).fire),
390     RegEnable(hitData, stageDelay(1).fire),
391     RegEnable(hitData.prefetch, stageDelay(1).fire),
392     RegEnable(hitData.v, stageDelay(1).fire))
393  }
394  val spHitPerm = spHitData.perm.getOrElse(0.U.asTypeOf(new PtePermBundle))
395  val spHitLevel = spHitData.level.getOrElse(0.U)
396
397  val check_res = Wire(new PageCacheRespBundle)
398  check_res.l1.apply(l1Hit, l1Pre, l1HitPPN)
399  check_res.l2.apply(l2Hit, l2Pre, l2HitPPN, ecc = l2eccError)
400  check_res.l3.apply(l3Hit, l3Pre, l3HitPPN, l3HitPerm, l3eccError, valid = l3HitValid)
401  check_res.sp.apply(spHit, spPre, spHitData.ppn, spHitPerm, false.B, spHitLevel, spValid)
402
403  val resp_res = Reg(new PageCacheRespBundle)
404  when (stageCheck(1).fire) { resp_res := check_res }
405
406  // stageResp bypass
407  val bypassed = Wire(Vec(3, Bool()))
408  bypassed.indices.foreach(i =>
409    bypassed(i) := stageResp.bits.bypassed(i) ||
410      ValidHoldBypass(refill_bypass(stageResp.bits.req_info.vpn, i),
411        OneCycleValid(stageCheck(1).fire, false.B) || io.refill.valid)
412  )
413
414  io.resp.bits.req_info   := stageResp.bits.req_info
415  io.resp.bits.isFirst  := stageResp.bits.isFirst
416  io.resp.bits.hit      := resp_res.l3.hit || resp_res.sp.hit
417  io.resp.bits.bypassed := bypassed(2) || (bypassed(1) && !resp_res.l2.hit) || (bypassed(0) && !resp_res.l1.hit)
418  io.resp.bits.prefetch := resp_res.l3.pre && resp_res.l3.hit || resp_res.sp.pre && resp_res.sp.hit
419  io.resp.bits.toFsm.l1Hit := resp_res.l1.hit
420  io.resp.bits.toFsm.l2Hit := resp_res.l2.hit
421  io.resp.bits.toFsm.ppn   := Mux(resp_res.l2.hit, resp_res.l2.ppn, resp_res.l1.ppn)
422  io.resp.bits.toTlb.entry.map(_.tag := stageResp.bits.req_info.vpn(vpnLen - 1, 3))
423  io.resp.bits.toTlb.entry.map(_.asid := io.csr_dup(0).satp.asid) // DontCare
424  io.resp.bits.toTlb.entry.map(_.level.map(_ := Mux(resp_res.l3.hit, 2.U, resp_res.sp.level)))
425  io.resp.bits.toTlb.entry.map(_.prefetch := from_pre(stageResp.bits.req_info.source))
426  for (i <- 0 until tlbcontiguous) {
427    io.resp.bits.toTlb.entry(i).ppn := Mux(resp_res.l3.hit, resp_res.l3.ppn(i)(ppnLen - 1, sectortlbwidth), resp_res.sp.ppn(ppnLen - 1, sectortlbwidth))
428    io.resp.bits.toTlb.entry(i).ppn_low := Mux(resp_res.l3.hit, resp_res.l3.ppn(i)(sectortlbwidth - 1, 0), resp_res.sp.ppn(sectortlbwidth - 1, 0))
429    io.resp.bits.toTlb.entry(i).perm.map(_ := Mux(resp_res.l3.hit, resp_res.l3.perm(i), resp_res.sp.perm))
430    io.resp.bits.toTlb.entry(i).v := Mux(resp_res.l3.hit, resp_res.l3.v(i), resp_res.sp.v)
431    io.resp.bits.toTlb.entry(i).pf := !io.resp.bits.toTlb.entry(i).v
432    io.resp.bits.toTlb.entry(i).af := false.B
433  }
434  io.resp.bits.toTlb.pteidx := UIntToOH(stageResp.bits.req_info.vpn(2, 0)).asBools
435  io.resp.bits.toTlb.not_super := Mux(resp_res.l3.hit, true.B, false.B)
436  io.resp.valid := stageResp.valid
437  XSError(stageResp.valid && resp_res.l3.hit && resp_res.sp.hit, "normal page and super page both hit")
438  XSError(stageResp.valid && io.resp.bits.hit && bypassed(2), "page cache, bypassed but hit")
439
440  // refill Perf
441  val l1RefillPerf = Wire(Vec(l2tlbParams.l1Size, Bool()))
442  val l2RefillPerf = Wire(Vec(l2tlbParams.l2nWays, Bool()))
443  val l3RefillPerf = Wire(Vec(l2tlbParams.l3nWays, Bool()))
444  val spRefillPerf = Wire(Vec(l2tlbParams.spSize, Bool()))
445  l1RefillPerf.map(_ := false.B)
446  l2RefillPerf.map(_ := false.B)
447  l3RefillPerf.map(_ := false.B)
448  spRefillPerf.map(_ := false.B)
449
450  // refill
451  l2.io.w.req <> DontCare
452  l3.io.w.req <> DontCare
453  l2.io.w.req.valid := false.B
454  l3.io.w.req.valid := false.B
455
456  val memRdata = refill.ptes
457  val memPtes = (0 until (l2tlbParams.blockBytes/(XLEN/8))).map(i => memRdata((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle))
458  val memSelData = io.refill.bits.sel_pte_dup
459  val memPte = memSelData.map(a => a.asTypeOf(new PteBundle))
460
461  // TODO: handle sfenceLatch outsize
462  when (!flush_dup(0) && refill.levelOH.l1 && !memPte(0).isLeaf() && !memPte(0).isPf(refill.level_dup(0)) && !memPte(0).isAf()) {
463    // val refillIdx = LFSR64()(log2Up(l2tlbParams.l1Size)-1,0) // TODO: may be LRU
464    val refillIdx = replaceWrapper(l1v, ptwl1replace.way)
465    refillIdx.suggestName(s"PtwL1RefillIdx")
466    val rfOH = UIntToOH(refillIdx)
467    l1(refillIdx).refill(
468      refill.req_info_dup(0).vpn,
469      io.csr_dup(0).satp.asid,
470      memSelData(0),
471      0.U,
472      refill_prefetch_dup(0)
473    )
474    ptwl1replace.access(refillIdx)
475    l1v := l1v | rfOH
476    l1g := (l1g & ~rfOH) | Mux(memPte(0).perm.g, rfOH, 0.U)
477
478    for (i <- 0 until l2tlbParams.l1Size) {
479      l1RefillPerf(i) := i.U === refillIdx
480    }
481
482    XSDebug(p"[l1 refill] refillIdx:${refillIdx} refillEntry:${l1(refillIdx).genPtwEntry(refill.req_info_dup(0).vpn, io.csr_dup(0).satp.asid, memSelData(0), 0.U, prefetch = refill_prefetch_dup(0))}\n")
483    XSDebug(p"[l1 refill] l1v:${Binary(l1v)}->${Binary(l1v | rfOH)} l1g:${Binary(l1g)}->${Binary((l1g & ~rfOH) | Mux(memPte(0).perm.g, rfOH, 0.U))}\n")
484
485    refillIdx.suggestName(s"l1_refillIdx")
486    rfOH.suggestName(s"l1_rfOH")
487  }
488
489  when (!flush_dup(1) && refill.levelOH.l2 && !memPte(1).isLeaf() && !memPte(1).isPf(refill.level_dup(1)) && !memPte(1).isAf()) {
490    val refillIdx = genPtwL2SetIdx(refill.req_info_dup(1).vpn)
491    val victimWay = replaceWrapper(getl2vSet(refill.req_info_dup(1).vpn), ptwl2replace.way(refillIdx))
492    val victimWayOH = UIntToOH(victimWay)
493    val rfvOH = UIntToOH(Cat(refillIdx, victimWay))
494    val wdata = Wire(l2EntryType)
495    wdata.gen(
496      vpn = refill.req_info_dup(1).vpn,
497      asid = io.csr_dup(1).satp.asid,
498      data = memRdata,
499      levelUInt = 1.U,
500      refill_prefetch_dup(1)
501    )
502    l2.io.w.apply(
503      valid = true.B,
504      setIdx = refillIdx,
505      data = wdata,
506      waymask = victimWayOH
507    )
508    ptwl2replace.access(refillIdx, victimWay)
509    l2v := l2v | rfvOH
510    l2g := l2g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U)
511
512    for (i <- 0 until l2tlbParams.l2nWays) {
513      l2RefillPerf(i) := i.U === victimWay
514    }
515
516    XSDebug(p"[l2 refill] refillIdx:0x${Hexadecimal(refillIdx)} victimWay:${victimWay} victimWayOH:${Binary(victimWayOH)} rfvOH(in UInt):${Cat(refillIdx, victimWay)}\n")
517    XSDebug(p"[l2 refill] refilldata:0x${wdata}\n")
518    XSDebug(p"[l2 refill] l2v:${Binary(l2v)} -> ${Binary(l2v | rfvOH)}\n")
519    XSDebug(p"[l2 refill] l2g:${Binary(l2g)} -> ${Binary(l2g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U))}\n")
520
521    refillIdx.suggestName(s"l2_refillIdx")
522    victimWay.suggestName(s"l2_victimWay")
523    victimWayOH.suggestName(s"l2_victimWayOH")
524    rfvOH.suggestName(s"l2_rfvOH")
525  }
526
527  when (!flush_dup(2) && refill.levelOH.l3 && !memPte(2).isAf()) {
528    val refillIdx = genPtwL3SetIdx(refill.req_info_dup(2).vpn)
529    val victimWay = replaceWrapper(getl3vSet(refill.req_info_dup(2).vpn), ptwl3replace.way(refillIdx))
530    val victimWayOH = UIntToOH(victimWay)
531    val rfvOH = UIntToOH(Cat(refillIdx, victimWay))
532    val wdata = Wire(l3EntryType)
533    wdata.gen(
534      vpn = refill.req_info_dup(2).vpn,
535      asid = io.csr_dup(2).satp.asid,
536      data = memRdata,
537      levelUInt = 2.U,
538      refill_prefetch_dup(2)
539    )
540    l3.io.w.apply(
541      valid = true.B,
542      setIdx = refillIdx,
543      data = wdata,
544      waymask = victimWayOH
545    )
546    ptwl3replace.access(refillIdx, victimWay)
547    l3v := l3v | rfvOH
548    l3g := l3g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U)
549
550    for (i <- 0 until l2tlbParams.l3nWays) {
551      l3RefillPerf(i) := i.U === victimWay
552    }
553
554    XSDebug(p"[l3 refill] refillIdx:0x${Hexadecimal(refillIdx)} victimWay:${victimWay} victimWayOH:${Binary(victimWayOH)} rfvOH(in UInt):${Cat(refillIdx, victimWay)}\n")
555    XSDebug(p"[l3 refill] refilldata:0x${wdata}\n")
556    XSDebug(p"[l3 refill] l3v:${Binary(l3v)} -> ${Binary(l3v | rfvOH)}\n")
557    XSDebug(p"[l3 refill] l3g:${Binary(l3g)} -> ${Binary(l3g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U))}\n")
558
559    refillIdx.suggestName(s"l3_refillIdx")
560    victimWay.suggestName(s"l3_victimWay")
561    victimWayOH.suggestName(s"l3_victimWayOH")
562    rfvOH.suggestName(s"l3_rfvOH")
563  }
564
565
566  // misc entries: super & invalid
567  when (!flush_dup(0) && refill.levelOH.sp && (memPte(0).isLeaf() || memPte(0).isPf(refill.level_dup(0))) && !memPte(0).isAf()) {
568    val refillIdx = spreplace.way// LFSR64()(log2Up(l2tlbParams.spSize)-1,0) // TODO: may be LRU
569    val rfOH = UIntToOH(refillIdx)
570    sp(refillIdx).refill(
571      refill.req_info_dup(0).vpn,
572      io.csr_dup(0).satp.asid,
573      memSelData(0),
574      refill.level_dup(2),
575      refill_prefetch_dup(0),
576      !memPte(0).isPf(refill.level_dup(0)),
577    )
578    spreplace.access(refillIdx)
579    spv := spv | rfOH
580    spg := spg & ~rfOH | Mux(memPte(0).perm.g, rfOH, 0.U)
581
582    for (i <- 0 until l2tlbParams.spSize) {
583      spRefillPerf(i) := i.U === refillIdx
584    }
585
586    XSDebug(p"[sp refill] refillIdx:${refillIdx} refillEntry:${sp(refillIdx).genPtwEntry(refill.req_info_dup(0).vpn, io.csr_dup(0).satp.asid, memSelData(0), refill.level_dup(0), refill_prefetch_dup(0))}\n")
587    XSDebug(p"[sp refill] spv:${Binary(spv)}->${Binary(spv | rfOH)} spg:${Binary(spg)}->${Binary(spg & ~rfOH | Mux(memPte(0).perm.g, rfOH, 0.U))}\n")
588
589    refillIdx.suggestName(s"sp_refillIdx")
590    rfOH.suggestName(s"sp_rfOH")
591  }
592
593  val l2eccFlush = resp_res.l2.ecc && stageResp_valid_1cycle_dup(0) // RegNext(l2eccError, init = false.B)
594  val l3eccFlush = resp_res.l3.ecc && stageResp_valid_1cycle_dup(1) // RegNext(l3eccError, init = false.B)
595  val eccVpn = stageResp.bits.req_info.vpn
596
597  XSError(l2eccFlush, "l2tlb.cache.l2 ecc error. Should not happen at sim stage")
598  XSError(l3eccFlush, "l2tlb.cache.l3 ecc error. Should not happen at sim stage")
599  when (l2eccFlush) {
600    val flushSetIdxOH = UIntToOH(genPtwL2SetIdx(eccVpn))
601    val flushMask = VecInit(flushSetIdxOH.asBools.map { a => Fill(l2tlbParams.l2nWays, a.asUInt) }).asUInt
602    l2v := l2v & ~flushMask
603    l2g := l2g & ~flushMask
604  }
605
606  when (l3eccFlush) {
607    val flushSetIdxOH = UIntToOH(genPtwL3SetIdx(eccVpn))
608    val flushMask = VecInit(flushSetIdxOH.asBools.map { a => Fill(l2tlbParams.l3nWays, a.asUInt) }).asUInt
609    l3v := l3v & ~flushMask
610    l3g := l3g & ~flushMask
611  }
612
613  // sfence
614  when (sfence_dup(3).valid) {
615    val sfence_vpn = sfence_dup(3).bits.addr(sfence_dup(3).bits.addr.getWidth-1, offLen)
616
617    when (sfence_dup(3).bits.rs1/*va*/) {
618      when (sfence_dup(3).bits.rs2) {
619        // all va && all asid
620        l3v := 0.U
621      } .otherwise {
622        // all va && specific asid except global
623        l3v := l3v & l3g
624      }
625    } .otherwise {
626      // val flushMask = UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
627      val flushSetIdxOH = UIntToOH(genPtwL3SetIdx(sfence_vpn))
628      // val flushMask = VecInit(flushSetIdxOH.asBools.map(Fill(l2tlbParams.l3nWays, _.asUInt))).asUInt
629      val flushMask = VecInit(flushSetIdxOH.asBools.map { a => Fill(l2tlbParams.l3nWays, a.asUInt) }).asUInt
630      flushSetIdxOH.suggestName(s"sfence_nrs1_flushSetIdxOH")
631      flushMask.suggestName(s"sfence_nrs1_flushMask")
632
633      when (sfence_dup(3).bits.rs2) {
634        // specific leaf of addr && all asid
635        l3v := l3v & ~flushMask
636      } .otherwise {
637        // specific leaf of addr && specific asid
638        l3v := l3v & (~flushMask | l3g)
639      }
640    }
641  }
642
643  when (sfence_dup(0).valid) {
644    val l1asidhit = VecInit(l1asids.map(_ === sfence_dup(0).bits.asid)).asUInt
645    val spasidhit = VecInit(spasids.map(_ === sfence_dup(0).bits.asid)).asUInt
646    val sfence_vpn = sfence_dup(0).bits.addr(sfence_dup(0).bits.addr.getWidth-1, offLen)
647
648    when (sfence_dup(0).bits.rs1/*va*/) {
649      when (sfence_dup(0).bits.rs2) {
650        // all va && all asid
651        l1v := 0.U
652        l2v := 0.U
653        spv := 0.U
654      } .otherwise {
655        // all va && specific asid except global
656
657        l1v := l1v & (~l1asidhit | l1g)
658        l2v := l2v & l2g
659        spv := spv & (~spasidhit | spg)
660      }
661    } .otherwise {
662      // val flushMask = UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
663      val flushSetIdxOH = UIntToOH(genPtwL3SetIdx(sfence_vpn))
664      // val flushMask = VecInit(flushSetIdxOH.asBools.map(Fill(l2tlbParams.l3nWays, _.asUInt))).asUInt
665      val flushMask = VecInit(flushSetIdxOH.asBools.map { a => Fill(l2tlbParams.l3nWays, a.asUInt) }).asUInt
666      flushSetIdxOH.suggestName(s"sfence_nrs1_flushSetIdxOH")
667      flushMask.suggestName(s"sfence_nrs1_flushMask")
668
669      when (sfence_dup(0).bits.rs2) {
670        // specific leaf of addr && all asid
671        spv := spv & (~VecInit(sp.map(_.hit(sfence_vpn, sfence_dup(0).bits.asid, ignoreAsid = true))).asUInt)
672      } .otherwise {
673        // specific leaf of addr && specific asid
674        spv := spv & (~VecInit(sp.map(_.hit(sfence_vpn, sfence_dup(0).bits.asid))).asUInt | spg)
675      }
676    }
677  }
678
679  def InsideStageConnect(in: DecoupledIO[PtwCacheReq], out: DecoupledIO[PtwCacheReq], inFire: Bool): Unit = {
680    in.ready := !in.valid || out.ready
681    out.valid := in.valid
682    out.bits := in.bits
683    out.bits.bypassed.zip(in.bits.bypassed).zipWithIndex.map{ case (b, i) =>
684      val bypassed_reg = Reg(Bool())
685      val bypassed_wire = refill_bypass(in.bits.req_info.vpn, i) && io.refill.valid
686      when (inFire) { bypassed_reg := bypassed_wire }
687      .elsewhen (io.refill.valid) { bypassed_reg := bypassed_reg || bypassed_wire }
688
689      b._1 := b._2 || (bypassed_wire || (bypassed_reg && !inFire))
690    }
691  }
692
693  // Perf Count
694  val resp_l3 = resp_res.l3.hit
695  val resp_sp = resp_res.sp.hit
696  val resp_l1_pre = resp_res.l1.pre
697  val resp_l2_pre = resp_res.l2.pre
698  val resp_l3_pre = resp_res.l3.pre
699  val resp_sp_pre = resp_res.sp.pre
700  val base_valid_access_0 = !from_pre(io.resp.bits.req_info.source) && io.resp.fire
701  XSPerfAccumulate("access", base_valid_access_0)
702  XSPerfAccumulate("l1_hit", base_valid_access_0 && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
703  XSPerfAccumulate("l2_hit", base_valid_access_0 && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
704  XSPerfAccumulate("l3_hit", base_valid_access_0 && resp_l3)
705  XSPerfAccumulate("sp_hit", base_valid_access_0 && resp_sp)
706  XSPerfAccumulate("pte_hit",base_valid_access_0 && io.resp.bits.hit)
707
708  XSPerfAccumulate("l1_hit_pre", base_valid_access_0 && resp_l1_pre && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
709  XSPerfAccumulate("l2_hit_pre", base_valid_access_0 && resp_l2_pre && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
710  XSPerfAccumulate("l3_hit_pre", base_valid_access_0 && resp_l3_pre && resp_l3)
711  XSPerfAccumulate("sp_hit_pre", base_valid_access_0 && resp_sp_pre && resp_sp)
712  XSPerfAccumulate("pte_hit_pre",base_valid_access_0 && (resp_l3_pre && resp_l3 || resp_sp_pre && resp_sp) && io.resp.bits.hit)
713
714  val base_valid_access_1 = from_pre(io.resp.bits.req_info.source) && io.resp.fire
715  XSPerfAccumulate("pre_access", base_valid_access_1)
716  XSPerfAccumulate("pre_l1_hit", base_valid_access_1 && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
717  XSPerfAccumulate("pre_l2_hit", base_valid_access_1 && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
718  XSPerfAccumulate("pre_l3_hit", base_valid_access_1 && resp_l3)
719  XSPerfAccumulate("pre_sp_hit", base_valid_access_1 && resp_sp)
720  XSPerfAccumulate("pre_pte_hit",base_valid_access_1 && io.resp.bits.hit)
721
722  XSPerfAccumulate("pre_l1_hit_pre", base_valid_access_1 && resp_l1_pre && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
723  XSPerfAccumulate("pre_l2_hit_pre", base_valid_access_1 && resp_l2_pre && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
724  XSPerfAccumulate("pre_l3_hit_pre", base_valid_access_1 && resp_l3_pre && resp_l3)
725  XSPerfAccumulate("pre_sp_hit_pre", base_valid_access_1 && resp_sp_pre && resp_sp)
726  XSPerfAccumulate("pre_pte_hit_pre",base_valid_access_1 && (resp_l3_pre && resp_l3 || resp_sp_pre && resp_sp) && io.resp.bits.hit)
727
728  val base_valid_access_2 = stageResp.bits.isFirst && !from_pre(io.resp.bits.req_info.source) && io.resp.fire
729  XSPerfAccumulate("access_first", base_valid_access_2)
730  XSPerfAccumulate("l1_hit_first", base_valid_access_2 && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
731  XSPerfAccumulate("l2_hit_first", base_valid_access_2 && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
732  XSPerfAccumulate("l3_hit_first", base_valid_access_2 && resp_l3)
733  XSPerfAccumulate("sp_hit_first", base_valid_access_2 && resp_sp)
734  XSPerfAccumulate("pte_hit_first",base_valid_access_2 && io.resp.bits.hit)
735
736  XSPerfAccumulate("l1_hit_pre_first", base_valid_access_2 && resp_l1_pre && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
737  XSPerfAccumulate("l2_hit_pre_first", base_valid_access_2 && resp_l2_pre && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
738  XSPerfAccumulate("l3_hit_pre_first", base_valid_access_2 && resp_l3_pre && resp_l3)
739  XSPerfAccumulate("sp_hit_pre_first", base_valid_access_2 && resp_sp_pre && resp_sp)
740  XSPerfAccumulate("pte_hit_pre_first",base_valid_access_2 && (resp_l3_pre && resp_l3 || resp_sp_pre && resp_sp) && io.resp.bits.hit)
741
742  val base_valid_access_3 = stageResp.bits.isFirst && from_pre(io.resp.bits.req_info.source) && io.resp.fire
743  XSPerfAccumulate("pre_access_first", base_valid_access_3)
744  XSPerfAccumulate("pre_l1_hit_first", base_valid_access_3 && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
745  XSPerfAccumulate("pre_l2_hit_first", base_valid_access_3 && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
746  XSPerfAccumulate("pre_l3_hit_first", base_valid_access_3 && resp_l3)
747  XSPerfAccumulate("pre_sp_hit_first", base_valid_access_3 && resp_sp)
748  XSPerfAccumulate("pre_pte_hit_first", base_valid_access_3 && io.resp.bits.hit)
749
750  XSPerfAccumulate("pre_l1_hit_pre_first", base_valid_access_3 && resp_l1_pre && io.resp.bits.toFsm.l1Hit && !io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
751  XSPerfAccumulate("pre_l2_hit_pre_first", base_valid_access_3 && resp_l2_pre && io.resp.bits.toFsm.l2Hit && !io.resp.bits.hit)
752  XSPerfAccumulate("pre_l3_hit_pre_first", base_valid_access_3 && resp_l3_pre && resp_l3)
753  XSPerfAccumulate("pre_sp_hit_pre_first", base_valid_access_3 && resp_sp_pre && resp_sp)
754  XSPerfAccumulate("pre_pte_hit_pre_first",base_valid_access_3 && (resp_l3_pre && resp_l3 || resp_sp_pre && resp_sp) && io.resp.bits.hit)
755
756  XSPerfAccumulate("rwHarzad", io.req.valid && !io.req.ready)
757  XSPerfAccumulate("out_blocked", io.resp.valid && !io.resp.ready)
758  l1AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L1AccessIndex${i}", l) }
759  l2AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L2AccessIndex${i}", l) }
760  l3AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L3AccessIndex${i}", l) }
761  spAccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"SPAccessIndex${i}", l) }
762  l1RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L1RefillIndex${i}", l) }
763  l2RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L2RefillIndex${i}", l) }
764  l3RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L3RefillIndex${i}", l) }
765  spRefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"SPRefillIndex${i}", l) }
766
767  XSPerfAccumulate("l1Refill", Cat(l1RefillPerf).orR)
768  XSPerfAccumulate("l2Refill", Cat(l2RefillPerf).orR)
769  XSPerfAccumulate("l3Refill", Cat(l3RefillPerf).orR)
770  XSPerfAccumulate("spRefill", Cat(spRefillPerf).orR)
771  XSPerfAccumulate("l1Refill_pre", Cat(l1RefillPerf).orR && refill_prefetch_dup(0))
772  XSPerfAccumulate("l2Refill_pre", Cat(l2RefillPerf).orR && refill_prefetch_dup(0))
773  XSPerfAccumulate("l3Refill_pre", Cat(l3RefillPerf).orR && refill_prefetch_dup(0))
774  XSPerfAccumulate("spRefill_pre", Cat(spRefillPerf).orR && refill_prefetch_dup(0))
775
776  // debug
777  XSDebug(sfence_dup(0).valid, p"[sfence] original v and g vector:\n")
778  XSDebug(sfence_dup(0).valid, p"[sfence] l1v:${Binary(l1v)}\n")
779  XSDebug(sfence_dup(0).valid, p"[sfence] l2v:${Binary(l2v)}\n")
780  XSDebug(sfence_dup(0).valid, p"[sfence] l3v:${Binary(l3v)}\n")
781  XSDebug(sfence_dup(0).valid, p"[sfence] l3g:${Binary(l3g)}\n")
782  XSDebug(sfence_dup(0).valid, p"[sfence] spv:${Binary(spv)}\n")
783  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] new v and g vector:\n")
784  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] l1v:${Binary(l1v)}\n")
785  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] l2v:${Binary(l2v)}\n")
786  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] l3v:${Binary(l3v)}\n")
787  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] l3g:${Binary(l3g)}\n")
788  XSDebug(RegNext(sfence_dup(0).valid), p"[sfence] spv:${Binary(spv)}\n")
789
790  val perfEvents = Seq(
791    ("access           ", base_valid_access_0             ),
792    ("l1_hit           ", l1Hit                           ),
793    ("l2_hit           ", l2Hit                           ),
794    ("l3_hit           ", l3Hit                           ),
795    ("sp_hit           ", spHit                           ),
796    ("pte_hit          ", l3Hit || spHit                  ),
797    ("rwHarzad         ",  io.req.valid && !io.req.ready  ),
798    ("out_blocked      ",  io.resp.valid && !io.resp.ready),
799  )
800  generatePerfEvent()
801}
802