xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueUncache.scala (revision c41f725a91c55e75c95c55b4bb0d2649f43e4c83)
1/***************************************************************************************
2 * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3 * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
4 * Copyright (c) 2020-2021 Peng Cheng Laboratory
5 *
6 * XiangShan is licensed under Mulan PSL v2.
7 * You can use this software according to the terms and conditions of the Mulan PSL v2.
8 * You may obtain a copy of Mulan PSL v2 at:
9 *          http://license.coscl.org.cn/MulanPSL2
10 *
11 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14 *
15 * See the Mulan PSL v2 for more details.
16 ***************************************************************************************/
17package xiangshan.mem
18
19import org.chipsalliance.cde.config._
20import chisel3._
21import chisel3.util._
22import utils._
23import utility._
24import xiangshan._
25import xiangshan.ExceptionNO._
26import xiangshan.backend.rob.{RobPtr, RobLsqIO}
27import xiangshan.backend.Bundles
28import xiangshan.backend.Bundles.{DynInst, MemExuOutput}
29import xiangshan.backend.fu.FuConfig.LduCfg
30import xiangshan.mem.Bundles._
31import xiangshan.cache._
32
33class UncacheEntry(entryIndex: Int)(implicit p: Parameters) extends XSModule
34  with HasCircularQueuePtrHelper
35  with HasLoadHelper
36{
37  val io = IO(new Bundle() {
38    /* control */
39    val redirect = Flipped(Valid(new Redirect))
40    // redirect flush
41    val flush = Output(Bool())
42    // mmio commit
43    val rob = Flipped(new RobLsqIO)
44    // mmio select
45    val mmioSelect = Output(Bool())
46    // slaveId
47    val slaveId = ValidIO(UInt(UncacheBufferIndexWidth.W))
48
49    /* transaction */
50    // from ldu
51    val req = Flipped(Valid(new LqWriteBundle))
52    // to ldu: mmio, data
53    val mmioOut = DecoupledIO(new MemExuOutput)
54    val mmioRawData = Output(new LoadDataFromLQBundle)
55    // to ldu: nc with data
56    val ncOut = DecoupledIO(new LsPipelineBundle)
57    // <=> uncache
58    val uncache = new UncacheWordIO
59    // exception generated by outer bus
60    val exception = Valid(new LqWriteBundle)
61  })
62
63  val req_valid = RegInit(false.B)
64  val req = Reg(new LqWriteBundle)
65  val slaveAccept = RegInit(false.B)
66  val slaveId = Reg(UInt(UncacheBufferIndexWidth.W))
67
68  val s_idle :: s_req :: s_resp :: s_wait :: Nil = Enum(4)
69  val uncacheState = RegInit(s_idle)
70  val uncacheData = Reg(io.uncache.resp.bits.data.cloneType)
71  val nderr = RegInit(false.B)
72
73  val writeback = Mux(req.nc, io.ncOut.fire, io.mmioOut.fire)
74  val slaveAck = req_valid && io.uncache.idResp.valid && io.uncache.idResp.bits.mid === entryIndex.U
75
76  /**
77    * Flush
78    *
79    * 1. direct flush during idle
80    * 2. otherwise delayed flush until receiving uncache resp
81    */
82  val needFlushReg = RegInit(false.B)
83  val needFlush = req_valid && req.uop.robIdx.needFlush(io.redirect)
84  val flush = (needFlush && uncacheState===s_idle) || (io.uncache.resp.fire && needFlushReg)
85  when(flush){
86    needFlushReg := false.B
87  }.elsewhen(needFlush){
88    needFlushReg := true.B
89  }
90
91  /* enter req */
92  when (flush) {
93    req_valid := false.B
94    slaveAccept := false.B
95  } .elsewhen (io.req.valid) {
96    req_valid := true.B
97    slaveAccept := false.B
98    req := io.req.bits
99    nderr := false.B
100  } .elsewhen(slaveAck) {
101    slaveAccept := true.B
102    slaveId := io.uncache.idResp.bits.sid
103  } .elsewhen (writeback) {
104    req_valid := false.B
105    slaveAccept := false.B
106  }
107  XSError(!flush && io.req.valid && req_valid, p"LoadQueueUncache: You can not write an valid entry: $entryIndex")
108
109  /**
110    * Memory mapped IO / NC operations
111    *
112    * States:
113    * (1) s_idle: wait for mmio reaching ROB's head / nc req valid from loadunit
114    * (2) s_req: wait to be sent to uncache channel until req selected and uncache ready
115    * (3) s_resp: wait for response from uncache channel
116    * (4) s_wait: wait for loadunit to receive writeback req
117    */
118  val pendingld = GatedValidRegNext(io.rob.pendingMMIOld)
119  val pendingPtr = GatedRegNext(io.rob.pendingPtr)
120  val canSendReq = req_valid && !needFlush && Mux(
121    req.nc, true.B,
122    pendingld && req.uop.robIdx === pendingPtr
123  )
124  switch (uncacheState) {
125    is (s_idle) {
126      when (canSendReq) {
127        uncacheState := s_req
128      }
129    }
130    is (s_req) {
131      when (io.uncache.req.fire) {
132        uncacheState := s_resp
133      }
134    }
135    is (s_resp) {
136      when (io.uncache.resp.fire) {
137        when (needFlushReg) {
138          uncacheState := s_idle
139        }.otherwise{
140          uncacheState := s_wait
141        }
142      }
143    }
144    is (s_wait) {
145      when (writeback) {
146        uncacheState := s_idle
147      }
148    }
149  }
150
151  /* control */
152  io.flush := flush
153  io.rob.mmio := DontCare
154  io.rob.uop := DontCare
155  io.mmioSelect := (uncacheState =/= s_idle) && req.mmio
156  io.slaveId.valid := slaveAccept
157  io.slaveId.bits := slaveId
158
159  /* uncahce req */
160  io.uncache.req.valid     := uncacheState === s_req
161  io.uncache.req.bits      := DontCare
162  io.uncache.req.bits.cmd  := MemoryOpConstants.M_XRD
163  io.uncache.req.bits.data := DontCare
164  io.uncache.req.bits.addr := req.paddr
165  io.uncache.req.bits.vaddr:= req.vaddr
166  io.uncache.req.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
167  io.uncache.req.bits.id   := entryIndex.U
168  io.uncache.req.bits.instrtype := DontCare
169  io.uncache.req.bits.replayCarry := DontCare
170  io.uncache.req.bits.atomic := req.atomic
171  io.uncache.req.bits.nc := req.nc
172  io.uncache.req.bits.memBackTypeMM := req.memBackTypeMM
173
174  io.uncache.resp.ready := true.B
175
176  /* uncahce resp */
177  when (io.uncache.resp.fire) {
178    uncacheData := io.uncache.resp.bits.data
179    nderr := io.uncache.resp.bits.nderr
180  }
181
182  /* uncahce writeback */
183  val selUop = req.uop
184  val func = selUop.fuOpType
185  val raddr = req.paddr
186  val rdataSel = LookupTree(raddr(2, 0), List(
187      "b000".U -> uncacheData(63,  0),
188      "b001".U -> uncacheData(63,  8),
189      "b010".U -> uncacheData(63, 16),
190      "b011".U -> uncacheData(63, 24),
191      "b100".U -> uncacheData(63, 32),
192      "b101".U -> uncacheData(63, 40),
193      "b110".U -> uncacheData(63, 48),
194      "b111".U -> uncacheData(63, 56)
195    ))
196  val rdataPartialLoad = rdataHelper(selUop, rdataSel)
197
198  io.mmioOut.valid := false.B
199  io.mmioOut.bits := DontCare
200  io.mmioRawData := DontCare
201  io.ncOut.valid := false.B
202  io.ncOut.bits := DontCare
203
204  when(req.nc){
205    io.ncOut.valid := (uncacheState === s_wait)
206    io.ncOut.bits := DontCare
207    io.ncOut.bits.uop := selUop
208    io.ncOut.bits.uop.lqIdx := req.uop.lqIdx
209    io.ncOut.bits.uop.exceptionVec(loadAccessFault) := nderr
210    io.ncOut.bits.data := rdataPartialLoad
211    io.ncOut.bits.paddr := req.paddr
212    io.ncOut.bits.vaddr := req.vaddr
213    io.ncOut.bits.nc := true.B
214    io.ncOut.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
215    io.ncOut.bits.schedIndex := req.schedIndex
216    io.ncOut.bits.isvec := req.isvec
217    io.ncOut.bits.is128bit := req.is128bit
218    io.ncOut.bits.vecActive := req.vecActive
219  }.otherwise{
220    io.mmioOut.valid := (uncacheState === s_wait)
221    io.mmioOut.bits := DontCare
222    io.mmioOut.bits.uop := selUop
223    io.mmioOut.bits.uop.lqIdx := req.uop.lqIdx
224    io.mmioOut.bits.uop.exceptionVec(loadAccessFault) := nderr
225    io.mmioOut.bits.data := rdataPartialLoad
226    io.mmioOut.bits.debug.isMMIO := true.B
227    io.mmioOut.bits.debug.isNC := false.B
228    io.mmioOut.bits.debug.paddr := req.paddr
229    io.mmioOut.bits.debug.vaddr := req.vaddr
230    io.mmioRawData.lqData := uncacheData
231    io.mmioRawData.uop := req.uop
232    io.mmioRawData.addrOffset := req.paddr
233  }
234
235  io.exception.valid := writeback
236  io.exception.bits := req
237  io.exception.bits.uop.exceptionVec(loadAccessFault) := nderr
238
239  /* debug log */
240  XSDebug(io.uncache.req.fire,
241    "uncache req: pc %x addr %x data %x op %x mask %x\n",
242    req.uop.pc,
243    io.uncache.req.bits.addr,
244    io.uncache.req.bits.data,
245    io.uncache.req.bits.cmd,
246    io.uncache.req.bits.mask
247  )
248  XSInfo(io.ncOut.fire,
249    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
250    io.ncOut.bits.uop.robIdx.asUInt,
251    io.ncOut.bits.uop.lqIdx.asUInt,
252    io.ncOut.bits.uop.pc,
253    true.B
254  )
255  XSInfo(io.mmioOut.fire,
256    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
257    io.mmioOut.bits.uop.robIdx.asUInt,
258    io.mmioOut.bits.uop.lqIdx.asUInt,
259    io.mmioOut.bits.uop.pc,
260    true.B
261  )
262
263}
264
265class LoadQueueUncache(implicit p: Parameters) extends XSModule
266  with HasCircularQueuePtrHelper
267  with HasMemBlockParameters
268{
269  val io = IO(new Bundle() {
270    /* control */
271    val redirect = Flipped(Valid(new Redirect))
272    // mmio commit
273    val rob = Flipped(new RobLsqIO)
274
275    /* transaction */
276    // enqueue: from ldu s3
277    val req = Vec(LoadPipelineWidth, Flipped(Decoupled(new LqWriteBundle)))
278    // writeback: mmio to ldu s0, s3
279    val mmioOut = Vec(LoadPipelineWidth, DecoupledIO(new MemExuOutput))
280    val mmioRawData = Vec(LoadPipelineWidth, Output(new LoadDataFromLQBundle))
281    // writeback: nc to ldu s0--s3
282    val ncOut = Vec(LoadPipelineWidth, Decoupled(new LsPipelineBundle))
283    // <=>uncache
284    val uncache = new UncacheWordIO
285
286    /* except */
287    // rollback from frontend when buffer is full
288    val rollback = Output(Valid(new Redirect))
289    // exception generated by outer bus
290    val exception = Valid(new LqWriteBundle)
291  })
292
293  /******************************************************************
294   * Structure
295   ******************************************************************/
296  val entries = Seq.tabulate(LoadUncacheBufferSize)(i => Module(new UncacheEntry(i)))
297
298  val freeList = Module(new FreeList(
299    size = LoadUncacheBufferSize,
300    allocWidth = LoadPipelineWidth,
301    freeWidth = 4,
302    enablePreAlloc = true,
303    moduleName = "LoadQueueUncache freelist"
304  ))
305  freeList.io := DontCare
306
307  // set default IO
308  entries.foreach {
309    case (e) =>
310      e.io.req.valid := false.B
311      e.io.req.bits := DontCare
312      e.io.uncache.req.ready := false.B
313      e.io.uncache.idResp.valid := false.B
314      e.io.uncache.idResp.bits := DontCare
315      e.io.uncache.resp.valid := false.B
316      e.io.uncache.resp.bits := DontCare
317      e.io.ncOut.ready := false.B
318      e.io.mmioOut.ready := false.B
319  }
320  io.uncache.req.valid := false.B
321  io.uncache.req.bits := DontCare
322  io.uncache.resp.ready := false.B
323  for (w <- 0 until LoadPipelineWidth) {
324    io.mmioOut(w).valid := false.B
325    io.mmioOut(w).bits := DontCare
326    io.mmioRawData(w) := DontCare
327    io.ncOut(w).valid := false.B
328    io.ncOut(w).bits := DontCare
329  }
330
331
332  /******************************************************************
333   * Enqueue
334   *
335   * s1: hold
336   * s2: confirm enqueue and write entry
337   *    valid: no redirect, no exception, no replay, is mmio/nc
338   *    ready: freelist can allocate
339   ******************************************************************/
340
341  val s1_sortedVec = HwSort(VecInit(io.req.map { case x => DataWithPtr(x.valid, x.bits, x.bits.uop.robIdx) }))
342  val s1_req = VecInit(s1_sortedVec.map(_.bits))
343  val s1_valid = VecInit(s1_sortedVec.map(_.valid))
344  val s2_enqueue = Wire(Vec(LoadPipelineWidth, Bool()))
345  io.req.zipWithIndex.foreach{ case (r, i) =>
346    r.ready := true.B
347  }
348
349  // s2: enqueue
350  val s2_req = (0 until LoadPipelineWidth).map(i => {RegEnable(s1_req(i), s1_valid(i))})
351  val s2_valid = (0 until LoadPipelineWidth).map(i => {
352    RegNext(s1_valid(i)) &&
353    !s2_req(i).uop.robIdx.needFlush(RegNext(io.redirect)) &&
354    !s2_req(i).uop.robIdx.needFlush(io.redirect)
355  })
356  val s2_has_exception = s2_req.map(x => ExceptionNO.selectByFu(x.uop.exceptionVec, LduCfg).asUInt.orR)
357  val s2_need_replay = s2_req.map(_.rep_info.need_rep)
358
359  for (w <- 0 until LoadPipelineWidth) {
360    s2_enqueue(w) := s2_valid(w) && !s2_has_exception(w) && !s2_need_replay(w) && (s2_req(w).mmio || s2_req(w).nc)
361  }
362
363  val s2_enqValidVec = Wire(Vec(LoadPipelineWidth, Bool()))
364  val s2_enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt()))
365
366  for (w <- 0 until LoadPipelineWidth) {
367    freeList.io.allocateReq(w) := true.B
368  }
369
370  // freeList real-allocate
371  for (w <- 0 until LoadPipelineWidth) {
372    freeList.io.doAllocate(w) := s2_enqValidVec(w)
373  }
374
375  for (w <- 0 until LoadPipelineWidth) {
376    val offset = PopCount(s2_enqueue.take(w))
377    s2_enqValidVec(w) := s2_enqueue(w) && freeList.io.canAllocate(offset)
378    s2_enqIndexVec(w) := freeList.io.allocateSlot(offset)
379  }
380
381
382  /******************************************************************
383   * Uncache Transaction
384   *
385   * 1. uncache req
386   * 2. uncache resp
387   * 3. writeback
388   ******************************************************************/
389  private val NC_WB_MOD = NCWBPorts.length
390
391  val uncacheReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
392  val mmioSelect = entries.map(e => e.io.mmioSelect).reduce(_ || _)
393  val mmioReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
394  // TODO lyq: It's best to choose in robIdx order / the order in which they enter
395  val ncReqArb = Module(new RRArbiterInit(io.uncache.req.bits.cloneType, LoadUncacheBufferSize))
396
397  val mmioOut = Wire(DecoupledIO(io.mmioOut(0).bits.cloneType))
398  val mmioRawData = Wire(io.mmioRawData(0).cloneType)
399  val ncOut = Wire(chiselTypeOf(io.ncOut))
400  val ncOutValidVec = VecInit(entries.map(e => e.io.ncOut.valid))
401  val ncOutValidVecRem = SubVec.getMaskRem(ncOutValidVec, NC_WB_MOD)
402
403  // init
404  uncacheReq.valid := false.B
405  uncacheReq.bits  := DontCare
406  mmioReq.valid := false.B
407  mmioReq.bits := DontCare
408  mmioOut.valid := false.B
409  mmioOut.bits := DontCare
410  mmioRawData := DontCare
411  for (i <- 0 until LoadUncacheBufferSize) {
412    ncReqArb.io.in(i).valid := false.B
413    ncReqArb.io.in(i).bits := DontCare
414  }
415  for (i <- 0 until LoadPipelineWidth) {
416    ncOut(i).valid := false.B
417    ncOut(i).bits := DontCare
418  }
419
420  entries.zipWithIndex.foreach {
421    case (e, i) =>
422      // enqueue
423      for (w <- 0 until LoadPipelineWidth) {
424        when (s2_enqValidVec(w) && (i.U === s2_enqIndexVec(w))) {
425          e.io.req.valid := true.B
426          e.io.req.bits := s2_req(w)
427        }
428      }
429
430      // control
431      e.io.redirect <> io.redirect
432      e.io.rob <> io.rob
433
434      // uncache req, writeback
435      when (e.io.mmioSelect) {
436        mmioReq.valid := e.io.uncache.req.valid
437        mmioReq.bits := e.io.uncache.req.bits
438        e.io.uncache.req.ready := mmioReq.ready
439
440        e.io.mmioOut.ready := mmioOut.ready
441        mmioOut.valid := e.io.mmioOut.valid
442        mmioOut.bits := e.io.mmioOut.bits
443        mmioRawData := e.io.mmioRawData
444
445      }.otherwise{
446        ncReqArb.io.in(i).valid := e.io.uncache.req.valid
447        ncReqArb.io.in(i).bits := e.io.uncache.req.bits
448        e.io.uncache.req.ready := ncReqArb.io.in(i).ready
449
450        (0 until NC_WB_MOD).map { w =>
451          val (idx, ncOutValid) = PriorityEncoderWithFlag(ncOutValidVecRem(w))
452          val port = NCWBPorts(w)
453          when((i.U === idx) && ncOutValid) {
454            ncOut(port).valid := ncOutValid
455            ncOut(port).bits := e.io.ncOut.bits
456            e.io.ncOut.ready := ncOut(port).ready
457          }
458        }
459
460      }
461
462      // uncache idResp
463      when(i.U === io.uncache.idResp.bits.mid) {
464        e.io.uncache.idResp <> io.uncache.idResp
465      }
466
467      // uncache resp
468      when (e.io.slaveId.valid && e.io.slaveId.bits === io.uncache.resp.bits.id) {
469        e.io.uncache.resp <> io.uncache.resp
470      }
471
472  }
473
474  mmioReq.ready := false.B
475  ncReqArb.io.out.ready := false.B
476  when(mmioSelect){
477    uncacheReq <> mmioReq
478  }.otherwise{
479    uncacheReq <> ncReqArb.io.out
480  }
481
482  // uncache Request
483  AddPipelineReg(uncacheReq, io.uncache.req, false.B)
484
485  // uncache Writeback
486  AddPipelineReg(mmioOut, io.mmioOut(UncacheWBPort), false.B)
487  io.mmioRawData(UncacheWBPort) := RegEnable(mmioRawData, mmioOut.fire)
488
489  (0 until LoadPipelineWidth).foreach { i => AddPipelineReg(ncOut(i), io.ncOut(i), false.B) }
490
491  // uncache exception
492  io.exception.valid := Cat(entries.map(_.io.exception.valid)).orR
493  io.exception.bits := ParallelPriorityMux(entries.map(e =>
494    (e.io.exception.valid, e.io.exception.bits)
495  ))
496
497  // rob
498  for (i <- 0 until LoadPipelineWidth) {
499    io.rob.mmio(i) := RegNext(s1_valid(i) && s1_req(i).mmio)
500    io.rob.uop(i) := RegEnable(s1_req(i).uop, s1_valid(i))
501  }
502
503
504  /******************************************************************
505   * Deallocate
506   ******************************************************************/
507  // UncacheBuffer deallocate
508  val freeMaskVec = Wire(Vec(LoadUncacheBufferSize, Bool()))
509
510  // init
511  freeMaskVec.map(e => e := false.B)
512
513  // dealloc logic
514  entries.zipWithIndex.foreach {
515    case (e, i) =>
516      when ((e.io.mmioSelect && e.io.mmioOut.fire) || e.io.ncOut.fire || e.io.flush) {
517        freeMaskVec(i) := true.B
518      }
519  }
520
521  freeList.io.free := freeMaskVec.asUInt
522
523
524  /******************************************************************
525   * Uncache rollback detection
526   *
527   * When uncache loads enqueue, it searches uncache loads, They can not enqueue and need re-execution.
528   *
529   * Cycle 0: uncache enqueue.
530   * Cycle 1: Select oldest uncache loads.
531   * Cycle 2: Redirect Fire.
532   *   Choose the oldest load from LoadPipelineWidth oldest loads.
533   *   Prepare redirect request according to the detected rejection.
534   *   Fire redirect request (if valid)
535   *
536   *               Load_S3  .... Load_S3
537   * stage 0:        lq            lq
538   *                 |             | (can not enqueue)
539   * stage 1:        lq            lq
540   *                 |             |
541   *                 ---------------
542   *                        |
543   * stage 2:               lq
544   *                        |
545   *                     rollback req
546   *
547   ******************************************************************/
548  def selectOldestRedirect(xs: Seq[Valid[Redirect]]): Vec[Bool] = {
549    val compareVec = (0 until xs.length).map(i => (0 until i).map(j => isAfter(xs(j).bits.robIdx, xs(i).bits.robIdx)))
550    val resultOnehot = VecInit((0 until xs.length).map(i => Cat((0 until xs.length).map(j =>
551      (if (j < i) !xs(j).valid || compareVec(i)(j)
552      else if (j == i) xs(i).valid
553      else !xs(j).valid || !compareVec(j)(i))
554    )).andR))
555    resultOnehot
556  }
557  val reqNeedCheck = VecInit((0 until LoadPipelineWidth).map(w =>
558    s2_enqueue(w) && !s2_enqValidVec(w)
559  ))
560  val reqSelUops = VecInit(s2_req.map(_.uop))
561  val allRedirect = (0 until LoadPipelineWidth).map(i => {
562    val redirect = Wire(Valid(new Redirect))
563    redirect.valid := reqNeedCheck(i)
564    redirect.bits             := DontCare
565    redirect.bits.isRVC       := reqSelUops(i).preDecodeInfo.isRVC
566    redirect.bits.robIdx      := reqSelUops(i).robIdx
567    redirect.bits.ftqIdx      := reqSelUops(i).ftqPtr
568    redirect.bits.ftqOffset   := reqSelUops(i).ftqOffset
569    redirect.bits.level       := RedirectLevel.flush
570    redirect.bits.cfiUpdate.target := reqSelUops(i).pc // TODO: check if need pc
571    redirect.bits.debug_runahead_checkpoint_id := reqSelUops(i).debugInfo.runahead_checkpoint_id
572    redirect
573  })
574  val oldestOneHot = selectOldestRedirect(allRedirect)
575  val oldestRedirect = Mux1H(oldestOneHot, allRedirect)
576  val lastCycleRedirect = Wire(Valid(new Redirect))
577  lastCycleRedirect.valid := RegNext(io.redirect.valid)
578  lastCycleRedirect.bits := RegEnable(io.redirect.bits, io.redirect.valid)
579  val lastLastCycleRedirect = Wire(Valid(new Redirect))
580  lastLastCycleRedirect.valid := RegNext(lastCycleRedirect.valid)
581  lastLastCycleRedirect.bits := RegEnable(lastCycleRedirect.bits, lastCycleRedirect.valid)
582  io.rollback.valid := GatedValidRegNext(oldestRedirect.valid &&
583                      !oldestRedirect.bits.robIdx.needFlush(io.redirect) &&
584                      !oldestRedirect.bits.robIdx.needFlush(lastCycleRedirect) &&
585                      !oldestRedirect.bits.robIdx.needFlush(lastLastCycleRedirect))
586  io.rollback.bits := RegEnable(oldestRedirect.bits, oldestRedirect.valid)
587
588
589  /******************************************************************
590   * Perf Counter
591   ******************************************************************/
592  val validCount = freeList.io.validCount
593  val allowEnqueue = !freeList.io.empty
594  QueuePerf(LoadUncacheBufferSize, validCount, !allowEnqueue)
595
596  XSPerfAccumulate("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc)
597  XSPerfAccumulate("mmio_writeback_success", io.mmioOut(0).fire)
598  XSPerfAccumulate("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready)
599  XSPerfAccumulate("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc)
600  XSPerfAccumulate("nc_writeback_success", io.ncOut(0).fire)
601  XSPerfAccumulate("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready)
602  XSPerfAccumulate("uncache_full_rollback", io.rollback.valid)
603
604  val perfEvents: Seq[(String, UInt)] = Seq(
605    ("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc),
606    ("mmio_writeback_success", io.mmioOut(0).fire),
607    ("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready),
608    ("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc),
609    ("nc_writeback_success", io.ncOut(0).fire),
610    ("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready),
611    ("uncache_full_rollback", io.rollback.valid)
612  )
613  // end
614}
615