xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/PageTableCache.scala (revision f320e0f01bd645f0a3045a8a740e60dd770734a9)
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 chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import xiangshan.cache.{HasDCacheParameters, MemoryOpConstants}
24import utils._
25import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
26import freechips.rocketchip.tilelink._
27
28/* ptw cache caches the page table of all the three layers
29 * ptw cache resp at next cycle
30 * the cache should not be blocked
31 * when miss queue if full, just block req outside
32 */
33class PtwCacheIO()(implicit p: Parameters) extends PtwBundle {
34  val req = Flipped(DecoupledIO(new Bundle {
35    val vpn = UInt(vpnLen.W)
36    val source = UInt(bPtwWidth.W)
37    val isReplay = Bool()
38  }))
39  val resp = DecoupledIO(new Bundle {
40    val source = UInt(bPtwWidth.W)
41    val vpn = UInt(vpnLen.W)
42    val isReplay = Bool()
43    val hit = Bool()
44    val toFsm = new Bundle {
45      val l1Hit = Bool()
46      val l2Hit = Bool()
47      val ppn = UInt(ppnLen.W)
48    }
49    val toTlb = new PtwEntry(tagLen = vpnLen, hasPerm = true, hasLevel = true)
50  })
51  val refill = Flipped(ValidIO(new Bundle {
52    val ptes = UInt(MemBandWidth.W)
53    val vpn = UInt(vpnLen.W)
54    val level = UInt(log2Up(Level).W)
55    val memAddr = Input(UInt(PAddrBits.W))
56  }))
57  val sfence = Input(new SfenceBundle)
58  val refuseRefill = Input(Bool())
59}
60
61class PtwCache()(implicit p: Parameters) extends XSModule with HasPtwConst {
62  val io = IO(new PtwCacheIO)
63
64  // TODO: four caches make the codes dirty, think about how to deal with it
65
66  val sfence = io.sfence
67  val refuseRefill = io.refuseRefill
68  val refill = io.refill.bits
69
70  val first_valid = io.req.valid
71  val first_fire = first_valid && io.req.ready
72  val first_req = io.req.bits
73  val second_ready = Wire(Bool())
74  val second_valid = ValidHold(first_fire, io.resp.fire(), sfence.valid)
75  val second_req = RegEnable(first_req, first_fire)
76  // NOTE: if ptw cache resp may be blocked, hard to handle refill
77  // when miss queue is full, please to block itlb and dtlb input
78
79  // when refill, refuce to accept new req
80  val rwHarzad = if (SramSinglePort) io.refill.valid else false.B
81  io.req.ready := !rwHarzad && (second_ready || io.req.bits.isReplay)
82  // NOTE: when write, don't ready, whe
83  //       when replay, just come in, out make sure resp.fire()
84
85  // l1: level 0 non-leaf pte
86  val l1 = Reg(Vec(PtwL1EntrySize, new PtwEntry(tagLen = PtwL1TagLen)))
87  val l1v = RegInit(0.U(PtwL1EntrySize.W))
88  val l1g = Reg(UInt(PtwL1EntrySize.W))
89
90  // l2: level 1 non-leaf pte
91  val l2 = Module(new SRAMTemplate(
92    new PtwEntries(num = PtwL2SectorSize, tagLen = PtwL2TagLen, level = 1, hasPerm = false),
93    set = PtwL2LineNum,
94    way = PtwL2WayNum,
95    singlePort = SramSinglePort
96  ))
97  val l2v = RegInit(0.U((PtwL2LineNum * PtwL2WayNum).W))
98  val l2g = Reg(UInt((PtwL2LineNum * PtwL2WayNum).W))
99  def getl2vSet(vpn: UInt) = {
100    require(log2Up(PtwL2WayNum) == log2Down(PtwL2WayNum))
101    val set = genPtwL2SetIdx(vpn)
102    require(set.getWidth == log2Up(PtwL2LineNum))
103    val l2vVec = l2v.asTypeOf(Vec(PtwL2LineNum, UInt(PtwL2WayNum.W)))
104    l2vVec(set)
105  }
106
107  // l3: level 2 leaf pte of 4KB pages
108  val l3 = Module(new SRAMTemplate(
109    new PtwEntries(num = PtwL3SectorSize, tagLen = PtwL3TagLen, level = 2, hasPerm = true),
110    set = PtwL3LineNum,
111    way = PtwL3WayNum,
112    singlePort = SramSinglePort
113  ))
114  val l3v = RegInit(0.U((PtwL3LineNum * PtwL3WayNum).W))
115  val l3g = Reg(UInt((PtwL3LineNum * PtwL3WayNum).W))
116  def getl3vSet(vpn: UInt) = {
117    require(log2Up(PtwL3WayNum) == log2Down(PtwL3WayNum))
118    val set = genPtwL3SetIdx(vpn)
119    require(set.getWidth == log2Up(PtwL3LineNum))
120    val l3vVec = l3v.asTypeOf(Vec(PtwL3LineNum, UInt(PtwL3WayNum.W)))
121    l3vVec(set)
122  }
123
124  // sp: level 0/1 leaf pte of 1GB/2MB super pages
125  val sp = Reg(Vec(PtwSPEntrySize, new PtwEntry(tagLen = SPTagLen, hasPerm = true, hasLevel = true)))
126  val spv = RegInit(0.U(PtwSPEntrySize.W))
127  val spg = Reg(UInt(PtwSPEntrySize.W))
128
129  // Access Perf
130  val l1AccessPerf = Wire(Vec(PtwL1EntrySize, Bool()))
131  val l2AccessPerf = Wire(Vec(PtwL2WayNum, Bool()))
132  val l3AccessPerf = Wire(Vec(PtwL3WayNum, Bool()))
133  val spAccessPerf = Wire(Vec(PtwSPEntrySize, Bool()))
134  l1AccessPerf.map(_ := false.B)
135  l2AccessPerf.map(_ := false.B)
136  l3AccessPerf.map(_ := false.B)
137  spAccessPerf.map(_ := false.B)
138
139  // l1
140  val ptwl1replace = ReplacementPolicy.fromString(ptwl1Replacer, PtwL1EntrySize)
141  val (l1Hit, l1HitPPN) = {
142    val hitVecT = l1.zipWithIndex.map { case (e, i) => e.hit(first_req.vpn) && l1v(i) }
143    val hitVec = hitVecT.map(RegEnable(_, first_fire))
144    val hitPPN = ParallelPriorityMux(hitVec zip l1.map(_.ppn))
145    val hit = ParallelOR(hitVec) && second_valid
146
147    when (hit) { ptwl1replace.access(OHToUInt(hitVec)) }
148
149    l1AccessPerf.zip(hitVec).map{ case (l, h) => l := h && RegNext(first_fire)}
150    for (i <- 0 until PtwL1EntrySize) {
151      XSDebug(first_fire, p"[l1] l1(${i.U}) ${l1(i)} hit:${l1(i).hit(first_req.vpn)}\n")
152    }
153    XSDebug(first_fire, p"[l1] l1v:${Binary(l1v)} hitVecT:${Binary(VecInit(hitVecT).asUInt)}\n")
154    XSDebug(second_valid, p"[l1] l1Hit:${hit} l1HitPPN:0x${Hexadecimal(hitPPN)} hitVec:${VecInit(hitVec).asUInt}\n")
155
156    VecInit(hitVecT).suggestName(s"l1_hitVecT")
157    VecInit(hitVec).suggestName(s"l1_hitVec")
158
159    (hit, hitPPN)
160  }
161
162  // l2
163  val ptwl2replace = ReplacementPolicy.fromString(ptwl2Replacer,PtwL2WayNum,PtwL2LineNum)
164  val (l2Hit, l2HitPPN) = {
165    val ridx = genPtwL2SetIdx(first_req.vpn)
166    val vidx = RegEnable(VecInit(getl2vSet(first_req.vpn).asBools), first_fire)
167    l2.io.r.req.valid := first_fire
168    l2.io.r.req.bits.apply(setIdx = ridx)
169    val ramDatas = l2.io.r.resp.data
170    // val hitVec = VecInit(ramDatas.map{wayData => wayData.hit(first_req.vpn) })
171    val hitVec = VecInit(ramDatas.zip(vidx).map { case (wayData, v) => wayData.hit(second_req.vpn) && v })
172    val hitWayData = ParallelPriorityMux(hitVec zip ramDatas)
173    val hit = ParallelOR(hitVec) && second_valid
174    val hitWay = ParallelPriorityMux(hitVec zip (0 until PtwL2WayNum).map(_.U))
175
176    ridx.suggestName(s"l2_ridx")
177    vidx.suggestName(s"l2_vidx")
178    ramDatas.suggestName(s"l2_ramDatas")
179    hitVec.suggestName(s"l2_hitVec")
180    hitWayData.suggestName(s"l2_hitWayData")
181    hitWay.suggestName(s"l2_hitWay")
182
183    when (hit) { ptwl2replace.access(genPtwL2SetIdx(second_req.vpn), hitWay) }
184
185    l2AccessPerf.zip(hitVec).map{ case (l, h) => l := h && RegNext(first_fire) }
186    XSDebug(first_fire, p"[l2] ridx:0x${Hexadecimal(ridx)}\n")
187    for (i <- 0 until PtwL2WayNum) {
188      XSDebug(RegNext(first_fire), p"[l2] ramDatas(${i.U}) ${ramDatas(i)}  l2v:${vidx(i)}  hit:${ramDatas(i).hit(second_req.vpn)}\n")
189    }
190    XSDebug(second_valid, p"[l2] l2Hit:${hit} l2HitPPN:0x${Hexadecimal(hitWayData.ppns(genPtwL2SectorIdx(second_req.vpn)))} hitVec:${Binary(hitVec.asUInt)} hitWay:${hitWay} vidx:${Binary(vidx.asUInt)}\n")
191
192    (hit, hitWayData.ppns(genPtwL2SectorIdx(second_req.vpn)))
193  }
194
195  // l3
196  val ptwl3replace = ReplacementPolicy.fromString(ptwl3Replacer,PtwL3WayNum,PtwL3LineNum)
197  val (l3Hit, l3HitData) = {
198    val ridx = genPtwL3SetIdx(first_req.vpn)
199    val vidx = RegEnable(VecInit(getl3vSet(first_req.vpn).asBools), first_fire)
200    l3.io.r.req.valid := first_fire
201    l3.io.r.req.bits.apply(setIdx = ridx)
202    val ramDatas = l3.io.r.resp.data
203    val hitVec = VecInit(ramDatas.zip(vidx).map{ case (wayData, v) => wayData.hit(second_req.vpn) && v })
204    val hitWayData = ParallelPriorityMux(hitVec zip ramDatas)
205    val hit = ParallelOR(hitVec) && second_valid
206    val hitWay = ParallelPriorityMux(hitVec zip (0 until PtwL3WayNum).map(_.U))
207
208    when (hit) { ptwl3replace.access(genPtwL3SetIdx(second_req.vpn), hitWay) }
209
210    l3AccessPerf.zip(hitVec).map{ case (l, h) => l := h && RegNext(first_fire) }
211    XSDebug(first_fire, p"[l3] ridx:0x${Hexadecimal(ridx)}\n")
212    for (i <- 0 until PtwL3WayNum) {
213      XSDebug(RegNext(first_fire), p"[l3] ramDatas(${i.U}) ${ramDatas(i)}  l3v:${vidx(i)}  hit:${ramDatas(i).hit(second_req.vpn)}\n")
214    }
215    XSDebug(second_valid, p"[l3] l3Hit:${hit} l3HitData:${hitWayData} hitVec:${Binary(hitVec.asUInt)} hitWay:${hitWay} vidx:${Binary(vidx.asUInt)}\n")
216
217    ridx.suggestName(s"l3_ridx")
218    vidx.suggestName(s"l3_vidx")
219    ramDatas.suggestName(s"l3_ramDatas")
220    hitVec.suggestName(s"l3_hitVec")
221    hitWay.suggestName(s"l3_hitWay")
222
223    (hit, hitWayData)
224  }
225  val l3HitPPN = l3HitData.ppns(genPtwL3SectorIdx(second_req.vpn))
226  val l3HitPerm = l3HitData.perms.getOrElse(0.U.asTypeOf(Vec(PtwL3SectorSize, new PtePermBundle)))(genPtwL3SectorIdx(second_req.vpn))
227
228  // super page
229  val spreplace = ReplacementPolicy.fromString(spReplacer, PtwSPEntrySize)
230  val (spHit, spHitData) = {
231    val hitVecT = sp.zipWithIndex.map { case (e, i) => e.hit(first_req.vpn) && spv(i) }
232    val hitVec = hitVecT.map(RegEnable(_, first_fire))
233    val hitData = ParallelPriorityMux(hitVec zip sp)
234    val hit = ParallelOR(hitVec) && second_valid
235
236    when (hit) { spreplace.access(OHToUInt(hitVec)) }
237
238    spAccessPerf.zip(hitVec).map{ case (s, h) => s := h && RegNext(first_fire) }
239    for (i <- 0 until PtwSPEntrySize) {
240      XSDebug(first_fire, p"[sp] sp(${i.U}) ${sp(i)} hit:${sp(i).hit(first_req.vpn)} spv:${spv(i)}\n")
241    }
242    XSDebug(second_valid, p"[sp] spHit:${hit} spHitData:${hitData} hitVec:${Binary(VecInit(hitVec).asUInt)}\n")
243
244    VecInit(hitVecT).suggestName(s"sp_hitVecT")
245    VecInit(hitVec).suggestName(s"sp_hitVec")
246
247    (hit, hitData)
248  }
249  val spHitPerm = spHitData.perm.getOrElse(0.U.asTypeOf(new PtePermBundle))
250  val spHitLevel = spHitData.level.getOrElse(0.U)
251
252  val resp = Wire(io.resp.bits.cloneType)
253  val resp_latch = RegEnable(resp, io.resp.valid && !io.resp.ready)
254  val resp_latch_valid = ValidHold(io.resp.valid && !io.resp.ready, io.resp.ready, sfence.valid)
255  second_ready := !(second_valid || resp_latch_valid) || io.resp.fire()
256  resp.source   := second_req.source
257  resp.vpn      := second_req.vpn
258  resp.isReplay := second_req.isReplay
259  resp.hit      := l3Hit || spHit
260  resp.toFsm.l1Hit := l1Hit
261  resp.toFsm.l2Hit := l2Hit
262  resp.toFsm.ppn   := Mux(l2Hit, l2HitPPN, l1HitPPN)
263  resp.toTlb.tag   := second_req.vpn
264  resp.toTlb.ppn   := Mux(l3Hit, l3HitPPN, spHitData.ppn)
265  resp.toTlb.perm.map(_ := Mux(l3Hit, l3HitPerm, spHitPerm))
266  resp.toTlb.level.map(_ := Mux(l3Hit, 2.U, spHitLevel))
267
268  io.resp.valid := second_valid
269  io.resp.bits := Mux(resp_latch_valid, resp_latch, resp)
270  assert(!(l3Hit && spHit), "normal page and super page both hit")
271
272  // refill Perf
273  val l1RefillPerf = Wire(Vec(PtwL1EntrySize, Bool()))
274  val l2RefillPerf = Wire(Vec(PtwL2WayNum, Bool()))
275  val l3RefillPerf = Wire(Vec(PtwL3WayNum, Bool()))
276  val spRefillPerf = Wire(Vec(PtwSPEntrySize, Bool()))
277  l1RefillPerf.map(_ := false.B)
278  l2RefillPerf.map(_ := false.B)
279  l3RefillPerf.map(_ := false.B)
280  spRefillPerf.map(_ := false.B)
281
282  // refill
283  l2.io.w.req <> DontCare
284  l3.io.w.req <> DontCare
285  l2.io.w.req.valid := false.B
286  l3.io.w.req.valid := false.B
287
288  val memRdata = refill.ptes
289  val memSelData = memRdata.asTypeOf(Vec(MemBandWidth/XLEN, UInt(XLEN.W)))(refill.memAddr(log2Up(l1BusDataWidth/8) - 1, log2Up(XLEN/8)))
290  val memPtes = (0 until PtwL3SectorSize).map(i => memRdata((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle))
291  val memPte = memSelData.asTypeOf(new PteBundle)
292
293  // TODO: handle sfenceLatch outsize
294  when (io.refill.valid && !memPte.isPf(refill.level) && !(sfence.valid || refuseRefill)) {
295    when (refill.level === 0.U && !memPte.isLeaf()) {
296      // val refillIdx = LFSR64()(log2Up(PtwL1EntrySize)-1,0) // TODO: may be LRU
297      val refillIdx = replaceWrapper(l1v, ptwl1replace.way)
298      refillIdx.suggestName(s"PtwL1RefillIdx")
299      val rfOH = UIntToOH(refillIdx)
300      l1(refillIdx).refill(refill.vpn, memSelData)
301      ptwl1replace.access(refillIdx)
302      l1v := l1v | rfOH
303      l1g := (l1g & ~rfOH) | Mux(memPte.perm.g, rfOH, 0.U)
304
305      for (i <- 0 until PtwL1EntrySize) {
306        l1RefillPerf(i) := i.U === refillIdx
307      }
308
309      XSDebug(p"[l1 refill] refillIdx:${refillIdx} refillEntry:${l1(refillIdx).genPtwEntry(refill.vpn, memSelData)}\n")
310      XSDebug(p"[l1 refill] l1v:${Binary(l1v)}->${Binary(l1v | rfOH)} l1g:${Binary(l1g)}->${Binary((l1g & ~rfOH) | Mux(memPte.perm.g, rfOH, 0.U))}\n")
311
312      refillIdx.suggestName(s"l1_refillIdx")
313      rfOH.suggestName(s"l1_rfOH")
314    }
315
316    when (refill.level === 1.U && !memPte.isLeaf()) {
317      val refillIdx = genPtwL2SetIdx(refill.vpn)
318      val victimWay = replaceWrapper(RegEnable(VecInit(getl2vSet(refill.vpn).asBools).asUInt, first_fire), ptwl2replace.way(refillIdx))
319      val victimWayOH = UIntToOH(victimWay)
320      val rfvOH = UIntToOH(Cat(refillIdx, victimWay))
321      l2.io.w.apply(
322        valid = true.B,
323        setIdx = refillIdx,
324        data = (new PtwEntries(num = PtwL2SectorSize, tagLen = PtwL2TagLen, level = 1, hasPerm = false)).genEntries(
325          vpn = refill.vpn, data = memRdata, levelUInt = 1.U
326        ),
327        waymask = victimWayOH
328      )
329      ptwl2replace.access(refillIdx, victimWay)
330      l2v := l2v | rfvOH
331      l2g := l2g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U)
332
333      for (i <- 0 until PtwL2WayNum) {
334        l2RefillPerf(i) := i.U === victimWay
335      }
336
337      XSDebug(p"[l2 refill] refillIdx:0x${Hexadecimal(refillIdx)} victimWay:${victimWay} victimWayOH:${Binary(victimWayOH)} rfvOH(in UInt):${Cat(refillIdx, victimWay)}\n")
338      XSDebug(p"[l2 refill] refilldata:0x${
339        (new PtwEntries(num = PtwL2SectorSize, tagLen = PtwL2TagLen, level = 1, hasPerm = false)).genEntries(
340          vpn = refill.vpn, data = memRdata, levelUInt = 1.U)
341      }\n")
342      XSDebug(p"[l2 refill] l2v:${Binary(l2v)} -> ${Binary(l2v | rfvOH)}\n")
343      XSDebug(p"[l2 refill] l2g:${Binary(l2g)} -> ${Binary(l2g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U))}\n")
344
345      refillIdx.suggestName(s"l2_refillIdx")
346      victimWay.suggestName(s"l2_victimWay")
347      victimWayOH.suggestName(s"l2_victimWayOH")
348      rfvOH.suggestName(s"l2_rfvOH")
349    }
350
351    when (refill.level === 2.U && memPte.isLeaf()) {
352      val refillIdx = genPtwL3SetIdx(refill.vpn)
353      val victimWay = replaceWrapper(RegEnable(VecInit(getl3vSet(refill.vpn).asBools).asUInt, first_fire), ptwl3replace.way(refillIdx))
354      val victimWayOH = UIntToOH(victimWay)
355      val rfvOH = UIntToOH(Cat(refillIdx, victimWay))
356      l3.io.w.apply(
357        valid = true.B,
358        setIdx = refillIdx,
359        data = (new PtwEntries(num = PtwL3SectorSize, tagLen = PtwL3TagLen, level = 2, hasPerm = true)).genEntries(
360          vpn = refill.vpn, data = memRdata, levelUInt = 2.U
361        ),
362        waymask = victimWayOH
363      )
364      ptwl3replace.access(refillIdx, victimWay)
365      l3v := l3v | rfvOH
366      l3g := l3g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U)
367
368        for (i <- 0 until PtwL3WayNum) {
369          l3RefillPerf(i) := i.U === victimWay
370        }
371
372      XSDebug(p"[l3 refill] refillIdx:0x${Hexadecimal(refillIdx)} victimWay:${victimWay} victimWayOH:${Binary(victimWayOH)} rfvOH(in UInt):${Cat(refillIdx, victimWay)}\n")
373      XSDebug(p"[l3 refill] refilldata:0x${
374        (new PtwEntries(num = PtwL3SectorSize, tagLen = PtwL3TagLen, level = 2, hasPerm = true)).genEntries(
375          vpn = refill.vpn, data = memRdata, levelUInt = 2.U)
376      }\n")
377      XSDebug(p"[l3 refill] l3v:${Binary(l3v)} -> ${Binary(l3v | rfvOH)}\n")
378      XSDebug(p"[l3 refill] l3g:${Binary(l3g)} -> ${Binary(l3g & ~rfvOH | Mux(Cat(memPtes.map(_.perm.g)).andR, rfvOH, 0.U))}\n")
379
380      refillIdx.suggestName(s"l3_refillIdx")
381      victimWay.suggestName(s"l3_victimWay")
382      victimWayOH.suggestName(s"l3_victimWayOH")
383      rfvOH.suggestName(s"l3_rfvOH")
384    }
385
386    when ((refill.level === 0.U || refill.level === 1.U) && memPte.isLeaf()) {
387      val refillIdx = spreplace.way// LFSR64()(log2Up(PtwSPEntrySize)-1,0) // TODO: may be LRU
388      val rfOH = UIntToOH(refillIdx)
389      sp(refillIdx).refill(refill.vpn, memSelData, refill.level)
390      spreplace.access(refillIdx)
391      spv := spv | rfOH
392      spg := spg & ~rfOH | Mux(memPte.perm.g, rfOH, 0.U)
393
394      for (i <- 0 until PtwSPEntrySize) {
395        spRefillPerf(i) := i.U === refillIdx
396      }
397
398      XSDebug(p"[sp refill] refillIdx:${refillIdx} refillEntry:${sp(refillIdx).genPtwEntry(refill.vpn, memSelData, refill.level)}\n")
399      XSDebug(p"[sp refill] spv:${Binary(spv)}->${Binary(spv | rfOH)} spg:${Binary(spg)}->${Binary(spg & ~rfOH | Mux(memPte.perm.g, rfOH, 0.U))}\n")
400
401      refillIdx.suggestName(s"sp_refillIdx")
402      rfOH.suggestName(s"sp_rfOH")
403    }
404  }
405
406  // sfence
407  when (sfence.valid) {
408    when (sfence.bits.rs1/*va*/) {
409      when (sfence.bits.rs2) {
410        // all va && all asid
411        l1v := 0.U
412        l2v := 0.U
413        l3v := 0.U
414        spv := 0.U
415      } .otherwise {
416        // all va && specific asid except global
417        l1v := l1v & l1g
418        l2v := l2v & l2g
419        l3v := l3v & l3g
420        spv := spv & spg
421      }
422    } .otherwise {
423      // val flushMask = UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
424      val flushSetIdxOH = UIntToOH(genPtwL3SetIdx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
425      // val flushMask = VecInit(flushSetIdxOH.asBools.map(Fill(PtwL3WayNum, _.asUInt))).asUInt
426      val flushMask = VecInit(flushSetIdxOH.asBools.map { a => Fill(PtwL3WayNum, a.asUInt) }).asUInt
427      flushSetIdxOH.suggestName(s"sfence_nrs1_flushSetIdxOH")
428      flushMask.suggestName(s"sfence_nrs1_flushMask")
429      when (sfence.bits.rs2) {
430        // specific leaf of addr && all asid
431        l3v := l3v & ~flushMask
432        l3g := l3g & ~flushMask
433      } .otherwise {
434        // specific leaf of addr && specific asid
435        l3v := l3v & (~flushMask | l3g)
436      }
437      spv := 0.U
438    }
439  }
440
441  // Perf Count
442  XSPerfAccumulate("access", second_valid)
443  XSPerfAccumulate("l1_hit", l1Hit)
444  XSPerfAccumulate("l2_hit", l2Hit)
445  XSPerfAccumulate("l3_hit", l3Hit)
446  XSPerfAccumulate("sp_hit", spHit)
447  XSPerfAccumulate("pte_hit", l3Hit || spHit)
448  XSPerfAccumulate("rwHarzad", io.req.valid && !io.req.ready)
449  XSPerfAccumulate("out_blocked", io.resp.valid && !io.resp.ready)
450  l1AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L1AccessIndex${i}", l) }
451  l2AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L2AccessIndex${i}", l) }
452  l3AccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L3AccessIndex${i}", l) }
453  spAccessPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"SPAccessIndex${i}", l) }
454  l1RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L1RefillIndex${i}", l) }
455  l2RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L2RefillIndex${i}", l) }
456  l3RefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"L3RefillIndex${i}", l) }
457  spRefillPerf.zipWithIndex.map{ case (l, i) => XSPerfAccumulate(s"SPRefillIndex${i}", l) }
458
459  // debug
460  XSDebug(sfence.valid, p"[sfence] original v and g vector:\n")
461  XSDebug(sfence.valid, p"[sfence] l1v:${Binary(l1v)}\n")
462  XSDebug(sfence.valid, p"[sfence] l2v:${Binary(l2v)}\n")
463  XSDebug(sfence.valid, p"[sfence] l3v:${Binary(l3v)}\n")
464  XSDebug(sfence.valid, p"[sfence] l3g:${Binary(l3g)}\n")
465  XSDebug(sfence.valid, p"[sfence] spv:${Binary(spv)}\n")
466  XSDebug(RegNext(sfence.valid), p"[sfence] new v and g vector:\n")
467  XSDebug(RegNext(sfence.valid), p"[sfence] l1v:${Binary(l1v)}\n")
468  XSDebug(RegNext(sfence.valid), p"[sfence] l2v:${Binary(l2v)}\n")
469  XSDebug(RegNext(sfence.valid), p"[sfence] l3v:${Binary(l3v)}\n")
470  XSDebug(RegNext(sfence.valid), p"[sfence] l3g:${Binary(l3g)}\n")
471  XSDebug(RegNext(sfence.valid), p"[sfence] spv:${Binary(spv)}\n")
472}