xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueUncache.scala (revision afa1262c29a131f306a9ca1f6e157f360d97e8c4)
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 = WireInit(false.B)
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 (needFlush) {
127        uncacheState := s_idle
128        flush := true.B
129      }.elsewhen (canSendReq) {
130        uncacheState := s_req
131      }
132    }
133    is (s_req) {
134      when(needFlush){
135        uncacheState := s_idle
136        flush := true.B
137      }.elsewhen(io.uncache.req.fire) {
138        uncacheState := s_resp
139      }
140    }
141    is (s_resp) {
142      when (io.uncache.resp.fire) {
143        when (needFlush || needFlushReg) {
144          uncacheState := s_idle
145          flush := true.B
146        }.otherwise{
147          uncacheState := s_wait
148        }
149      }
150    }
151    is (s_wait) {
152      when (needFlush || writeback) {
153        uncacheState := s_idle
154        flush := true.B
155      }
156    }
157  }
158
159  /* control */
160  io.flush := flush
161  io.rob.mmio := DontCare
162  io.rob.uop := DontCare
163  io.mmioSelect := (uncacheState =/= s_idle) && req.mmio
164  io.slaveId.valid := slaveAccept
165  io.slaveId.bits := slaveId
166
167  /* uncahce req */
168  io.uncache.req.valid     := uncacheState === s_req && !needFlush
169  io.uncache.req.bits      := DontCare
170  io.uncache.req.bits.cmd  := MemoryOpConstants.M_XRD
171  io.uncache.req.bits.data := DontCare
172  io.uncache.req.bits.addr := req.paddr
173  io.uncache.req.bits.vaddr:= req.vaddr
174  io.uncache.req.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
175  io.uncache.req.bits.id   := entryIndex.U
176  io.uncache.req.bits.instrtype := DontCare
177  io.uncache.req.bits.replayCarry := DontCare
178  io.uncache.req.bits.atomic := req.atomic
179  io.uncache.req.bits.nc := req.nc
180  io.uncache.req.bits.memBackTypeMM := req.memBackTypeMM
181
182  io.uncache.resp.ready := true.B
183
184  /* uncahce resp */
185  when (io.uncache.resp.fire) {
186    uncacheData := io.uncache.resp.bits.data
187    nderr := io.uncache.resp.bits.nderr
188  }
189
190  /* uncahce writeback */
191  val selUop = req.uop
192  val func = selUop.fuOpType
193  val raddr = req.paddr
194  val rdataSel = LookupTree(raddr(2, 0), List(
195      "b000".U -> uncacheData(63,  0),
196      "b001".U -> uncacheData(63,  8),
197      "b010".U -> uncacheData(63, 16),
198      "b011".U -> uncacheData(63, 24),
199      "b100".U -> uncacheData(63, 32),
200      "b101".U -> uncacheData(63, 40),
201      "b110".U -> uncacheData(63, 48),
202      "b111".U -> uncacheData(63, 56)
203    ))
204  val rdataPartialLoad = rdataHelper(selUop, rdataSel)
205
206  io.mmioOut.valid := false.B
207  io.mmioOut.bits := DontCare
208  io.mmioRawData := DontCare
209  io.ncOut.valid := false.B
210  io.ncOut.bits := DontCare
211
212  when(req.nc){
213    io.ncOut.valid := (uncacheState === s_wait) && !needFlush
214    io.ncOut.bits := DontCare
215    io.ncOut.bits.uop := selUop
216    io.ncOut.bits.uop.lqIdx := req.uop.lqIdx
217    io.ncOut.bits.uop.exceptionVec(loadAccessFault) := nderr
218    io.ncOut.bits.data := rdataPartialLoad
219    io.ncOut.bits.paddr := req.paddr
220    io.ncOut.bits.vaddr := req.vaddr
221    io.ncOut.bits.nc := true.B
222    io.ncOut.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
223    io.ncOut.bits.schedIndex := req.schedIndex
224    io.ncOut.bits.isvec := req.isvec
225    io.ncOut.bits.is128bit := req.is128bit
226    io.ncOut.bits.vecActive := req.vecActive
227  }.otherwise{
228    io.mmioOut.valid := (uncacheState === s_wait) && !needFlush
229    io.mmioOut.bits := DontCare
230    io.mmioOut.bits.uop := selUop
231    io.mmioOut.bits.uop.lqIdx := req.uop.lqIdx
232    io.mmioOut.bits.uop.exceptionVec(loadAccessFault) := nderr
233    io.mmioOut.bits.data := rdataPartialLoad
234    io.mmioOut.bits.debug.isMMIO := true.B
235    io.mmioOut.bits.debug.isNC := false.B
236    io.mmioOut.bits.debug.paddr := req.paddr
237    io.mmioOut.bits.debug.vaddr := req.vaddr
238    io.mmioRawData.lqData := uncacheData
239    io.mmioRawData.uop := req.uop
240    io.mmioRawData.addrOffset := req.paddr
241  }
242
243  io.exception.valid := writeback
244  io.exception.bits := req
245  io.exception.bits.uop.exceptionVec(loadAccessFault) := nderr
246
247  /* debug log */
248  XSDebug(io.uncache.req.fire,
249    "uncache req: pc %x addr %x data %x op %x mask %x\n",
250    req.uop.pc,
251    io.uncache.req.bits.addr,
252    io.uncache.req.bits.data,
253    io.uncache.req.bits.cmd,
254    io.uncache.req.bits.mask
255  )
256  XSInfo(io.ncOut.fire,
257    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
258    io.ncOut.bits.uop.robIdx.asUInt,
259    io.ncOut.bits.uop.lqIdx.asUInt,
260    io.ncOut.bits.uop.pc,
261    true.B
262  )
263  XSInfo(io.mmioOut.fire,
264    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
265    io.mmioOut.bits.uop.robIdx.asUInt,
266    io.mmioOut.bits.uop.lqIdx.asUInt,
267    io.mmioOut.bits.uop.pc,
268    true.B
269  )
270
271}
272
273class LoadQueueUncache(implicit p: Parameters) extends XSModule
274  with HasCircularQueuePtrHelper
275  with HasMemBlockParameters
276{
277  val io = IO(new Bundle() {
278    /* control */
279    val redirect = Flipped(Valid(new Redirect))
280    // mmio commit
281    val rob = Flipped(new RobLsqIO)
282
283    /* transaction */
284    // enqueue: from ldu s3
285    val req = Vec(LoadPipelineWidth, Flipped(Decoupled(new LqWriteBundle)))
286    // writeback: mmio to ldu s0, s3
287    val mmioOut = Vec(LoadPipelineWidth, DecoupledIO(new MemExuOutput))
288    val mmioRawData = Vec(LoadPipelineWidth, Output(new LoadDataFromLQBundle))
289    // writeback: nc to ldu s0--s3
290    val ncOut = Vec(LoadPipelineWidth, Decoupled(new LsPipelineBundle))
291    // <=>uncache
292    val uncache = new UncacheWordIO
293
294    /* except */
295    // rollback from frontend when buffer is full
296    val rollback = Output(Valid(new Redirect))
297    // exception generated by outer bus
298    val exception = Valid(new LqWriteBundle)
299  })
300
301  /******************************************************************
302   * Structure
303   ******************************************************************/
304  val entries = Seq.tabulate(LoadUncacheBufferSize)(i => Module(new UncacheEntry(i)))
305
306  val freeList = Module(new FreeList(
307    size = LoadUncacheBufferSize,
308    allocWidth = LoadPipelineWidth,
309    freeWidth = 4,
310    enablePreAlloc = true,
311    moduleName = "LoadQueueUncache freelist"
312  ))
313  freeList.io := DontCare
314
315  // set default IO
316  entries.foreach {
317    case (e) =>
318      e.io.req.valid := false.B
319      e.io.req.bits := DontCare
320      e.io.uncache.req.ready := false.B
321      e.io.uncache.idResp.valid := false.B
322      e.io.uncache.idResp.bits := DontCare
323      e.io.uncache.resp.valid := false.B
324      e.io.uncache.resp.bits := DontCare
325      e.io.ncOut.ready := false.B
326      e.io.mmioOut.ready := false.B
327  }
328  io.uncache.req.valid := false.B
329  io.uncache.req.bits := DontCare
330  io.uncache.resp.ready := false.B
331  for (w <- 0 until LoadPipelineWidth) {
332    io.mmioOut(w).valid := false.B
333    io.mmioOut(w).bits := DontCare
334    io.mmioRawData(w) := DontCare
335    io.ncOut(w).valid := false.B
336    io.ncOut(w).bits := DontCare
337  }
338
339
340  /******************************************************************
341   * Enqueue
342   *
343   * s1: hold
344   * s2: confirm enqueue and write entry
345   *    valid: no redirect, no exception, no replay, is mmio/nc
346   *    ready: freelist can allocate
347   ******************************************************************/
348
349  val s1_sortedVec = HwSort(VecInit(io.req.map { case x => DataWithPtr(x.valid, x.bits, x.bits.uop.robIdx) }))
350  val s1_req = VecInit(s1_sortedVec.map(_.bits))
351  val s1_valid = VecInit(s1_sortedVec.map(_.valid))
352  val s2_enqueue = Wire(Vec(LoadPipelineWidth, Bool()))
353  io.req.zipWithIndex.foreach{ case (r, i) =>
354    r.ready := true.B
355  }
356
357  // s2: enqueue
358  val s2_req = (0 until LoadPipelineWidth).map(i => {RegEnable(s1_req(i), s1_valid(i))})
359  val s2_valid = (0 until LoadPipelineWidth).map(i => {
360    RegNext(s1_valid(i)) &&
361    !s2_req(i).uop.robIdx.needFlush(RegNext(io.redirect)) &&
362    !s2_req(i).uop.robIdx.needFlush(io.redirect)
363  })
364  val s2_has_exception = s2_req.map(x => ExceptionNO.selectByFu(x.uop.exceptionVec, LduCfg).asUInt.orR)
365  val s2_need_replay = s2_req.map(_.rep_info.need_rep)
366
367  for (w <- 0 until LoadPipelineWidth) {
368    s2_enqueue(w) := s2_valid(w) && !s2_has_exception(w) && !s2_need_replay(w) && (s2_req(w).mmio || s2_req(w).nc)
369  }
370
371  val s2_enqValidVec = Wire(Vec(LoadPipelineWidth, Bool()))
372  val s2_enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt()))
373
374  for (w <- 0 until LoadPipelineWidth) {
375    freeList.io.allocateReq(w) := true.B
376  }
377
378  // freeList real-allocate
379  for (w <- 0 until LoadPipelineWidth) {
380    freeList.io.doAllocate(w) := s2_enqValidVec(w)
381  }
382
383  for (w <- 0 until LoadPipelineWidth) {
384    val offset = PopCount(s2_enqueue.take(w))
385    s2_enqValidVec(w) := s2_enqueue(w) && freeList.io.canAllocate(offset)
386    s2_enqIndexVec(w) := freeList.io.allocateSlot(offset)
387  }
388
389
390  /******************************************************************
391   * Uncache Transaction
392   *
393   * 1. uncache req
394   * 2. uncache resp
395   * 3. writeback
396   ******************************************************************/
397  private val NC_WB_MOD = NCWBPorts.length
398
399  val uncacheReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
400  val mmioSelect = entries.map(e => e.io.mmioSelect).reduce(_ || _)
401  val mmioReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
402  // TODO lyq: It's best to choose in robIdx order / the order in which they enter
403  val ncReqArb = Module(new RRArbiterInit(io.uncache.req.bits.cloneType, LoadUncacheBufferSize))
404
405  val mmioOut = Wire(DecoupledIO(io.mmioOut(0).bits.cloneType))
406  val mmioRawData = Wire(io.mmioRawData(0).cloneType)
407  val ncOut = Wire(chiselTypeOf(io.ncOut))
408  val ncOutValidVec = VecInit(entries.map(e => e.io.ncOut.valid))
409  val ncOutValidVecRem = SubVec.getMaskRem(ncOutValidVec, NC_WB_MOD)
410
411  // init
412  uncacheReq.valid := false.B
413  uncacheReq.bits  := DontCare
414  mmioReq.valid := false.B
415  mmioReq.bits := DontCare
416  mmioOut.valid := false.B
417  mmioOut.bits := DontCare
418  mmioRawData := DontCare
419  for (i <- 0 until LoadUncacheBufferSize) {
420    ncReqArb.io.in(i).valid := false.B
421    ncReqArb.io.in(i).bits := DontCare
422  }
423  for (i <- 0 until LoadPipelineWidth) {
424    ncOut(i).valid := false.B
425    ncOut(i).bits := DontCare
426  }
427
428  entries.zipWithIndex.foreach {
429    case (e, i) =>
430      // enqueue
431      for (w <- 0 until LoadPipelineWidth) {
432        when (s2_enqValidVec(w) && (i.U === s2_enqIndexVec(w))) {
433          e.io.req.valid := true.B
434          e.io.req.bits := s2_req(w)
435        }
436      }
437
438      // control
439      e.io.redirect <> io.redirect
440      e.io.rob <> io.rob
441
442      // uncache req, writeback
443      when (e.io.mmioSelect) {
444        mmioReq.valid := e.io.uncache.req.valid
445        mmioReq.bits := e.io.uncache.req.bits
446        e.io.uncache.req.ready := mmioReq.ready
447
448        e.io.mmioOut.ready := mmioOut.ready
449        mmioOut.valid := e.io.mmioOut.valid
450        mmioOut.bits := e.io.mmioOut.bits
451        mmioRawData := e.io.mmioRawData
452
453      }.otherwise{
454        ncReqArb.io.in(i).valid := e.io.uncache.req.valid
455        ncReqArb.io.in(i).bits := e.io.uncache.req.bits
456        e.io.uncache.req.ready := ncReqArb.io.in(i).ready
457
458        (0 until NC_WB_MOD).map { w =>
459          val (idx, ncOutValid) = PriorityEncoderWithFlag(ncOutValidVecRem(w))
460          val port = NCWBPorts(w)
461          when((i.U === idx) && ncOutValid) {
462            ncOut(port).valid := ncOutValid
463            ncOut(port).bits := e.io.ncOut.bits
464            e.io.ncOut.ready := ncOut(port).ready
465          }
466        }
467
468      }
469
470      // uncache idResp
471      when(i.U === io.uncache.idResp.bits.mid) {
472        e.io.uncache.idResp <> io.uncache.idResp
473      }
474
475      // uncache resp
476      when (e.io.slaveId.valid && e.io.slaveId.bits === io.uncache.resp.bits.id) {
477        e.io.uncache.resp <> io.uncache.resp
478      }
479
480  }
481
482  mmioReq.ready := false.B
483  ncReqArb.io.out.ready := false.B
484  when(mmioSelect){
485    uncacheReq <> mmioReq
486  }.otherwise{
487    uncacheReq <> ncReqArb.io.out
488  }
489
490  // uncache Request
491  AddPipelineReg(uncacheReq, io.uncache.req, false.B)
492
493  // uncache Writeback
494  AddPipelineReg(mmioOut, io.mmioOut(UncacheWBPort), false.B)
495  io.mmioRawData(UncacheWBPort) := RegEnable(mmioRawData, mmioOut.fire)
496
497  (0 until LoadPipelineWidth).foreach { i => AddPipelineReg(ncOut(i), io.ncOut(i), false.B) }
498
499  // uncache exception
500  io.exception.valid := Cat(entries.map(_.io.exception.valid)).orR
501  io.exception.bits := ParallelPriorityMux(entries.map(e =>
502    (e.io.exception.valid, e.io.exception.bits)
503  ))
504
505  // rob
506  for (i <- 0 until LoadPipelineWidth) {
507    io.rob.mmio(i) := RegNext(s1_valid(i) && s1_req(i).mmio)
508    io.rob.uop(i) := RegEnable(s1_req(i).uop, s1_valid(i))
509  }
510
511
512  /******************************************************************
513   * Deallocate
514   ******************************************************************/
515  // UncacheBuffer deallocate
516  val freeMaskVec = Wire(Vec(LoadUncacheBufferSize, Bool()))
517
518  // init
519  freeMaskVec.map(e => e := false.B)
520
521  // dealloc logic
522  entries.zipWithIndex.foreach {
523    case (e, i) =>
524      when ((e.io.mmioSelect && e.io.mmioOut.fire) || e.io.ncOut.fire || e.io.flush) {
525        freeMaskVec(i) := true.B
526      }
527  }
528
529  freeList.io.free := freeMaskVec.asUInt
530
531
532  /******************************************************************
533   * Uncache rollback detection
534   *
535   * When uncache loads enqueue, it searches uncache loads, They can not enqueue and need re-execution.
536   *
537   * Cycle 0: uncache enqueue.
538   * Cycle 1: Select oldest uncache loads.
539   * Cycle 2: Redirect Fire.
540   *   Choose the oldest load from LoadPipelineWidth oldest loads.
541   *   Prepare redirect request according to the detected rejection.
542   *   Fire redirect request (if valid)
543   *
544   *               Load_S3  .... Load_S3
545   * stage 0:        lq            lq
546   *                 |             | (can not enqueue)
547   * stage 1:        lq            lq
548   *                 |             |
549   *                 ---------------
550   *                        |
551   * stage 2:               lq
552   *                        |
553   *                     rollback req
554   *
555   ******************************************************************/
556  def selectOldestRedirect(xs: Seq[Valid[Redirect]]): Vec[Bool] = {
557    val compareVec = (0 until xs.length).map(i => (0 until i).map(j => isAfter(xs(j).bits.robIdx, xs(i).bits.robIdx)))
558    val resultOnehot = VecInit((0 until xs.length).map(i => Cat((0 until xs.length).map(j =>
559      (if (j < i) !xs(j).valid || compareVec(i)(j)
560      else if (j == i) xs(i).valid
561      else !xs(j).valid || !compareVec(j)(i))
562    )).andR))
563    resultOnehot
564  }
565  val reqNeedCheck = VecInit((0 until LoadPipelineWidth).map(w =>
566    s2_enqueue(w) && !s2_enqValidVec(w)
567  ))
568  val reqSelUops = VecInit(s2_req.map(_.uop))
569  val allRedirect = (0 until LoadPipelineWidth).map(i => {
570    val redirect = Wire(Valid(new Redirect))
571    redirect.valid := reqNeedCheck(i)
572    redirect.bits             := DontCare
573    redirect.bits.isRVC       := reqSelUops(i).preDecodeInfo.isRVC
574    redirect.bits.robIdx      := reqSelUops(i).robIdx
575    redirect.bits.ftqIdx      := reqSelUops(i).ftqPtr
576    redirect.bits.ftqOffset   := reqSelUops(i).ftqOffset
577    redirect.bits.level       := RedirectLevel.flush
578    redirect.bits.cfiUpdate.target := reqSelUops(i).pc // TODO: check if need pc
579    redirect.bits.debug_runahead_checkpoint_id := reqSelUops(i).debugInfo.runahead_checkpoint_id
580    redirect
581  })
582  val oldestOneHot = selectOldestRedirect(allRedirect)
583  val oldestRedirect = Mux1H(oldestOneHot, allRedirect)
584  val lastCycleRedirect = Wire(Valid(new Redirect))
585  lastCycleRedirect.valid := RegNext(io.redirect.valid)
586  lastCycleRedirect.bits := RegEnable(io.redirect.bits, io.redirect.valid)
587  val lastLastCycleRedirect = Wire(Valid(new Redirect))
588  lastLastCycleRedirect.valid := RegNext(lastCycleRedirect.valid)
589  lastLastCycleRedirect.bits := RegEnable(lastCycleRedirect.bits, lastCycleRedirect.valid)
590  io.rollback.valid := GatedValidRegNext(oldestRedirect.valid &&
591                      !oldestRedirect.bits.robIdx.needFlush(io.redirect) &&
592                      !oldestRedirect.bits.robIdx.needFlush(lastCycleRedirect) &&
593                      !oldestRedirect.bits.robIdx.needFlush(lastLastCycleRedirect))
594  io.rollback.bits := RegEnable(oldestRedirect.bits, oldestRedirect.valid)
595
596
597  /******************************************************************
598   * Perf Counter
599   ******************************************************************/
600  val validCount = freeList.io.validCount
601  val allowEnqueue = !freeList.io.empty
602  QueuePerf(LoadUncacheBufferSize, validCount, !allowEnqueue)
603
604  XSPerfAccumulate("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc)
605  XSPerfAccumulate("mmio_writeback_success", io.mmioOut(0).fire)
606  XSPerfAccumulate("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready)
607  XSPerfAccumulate("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc)
608  XSPerfAccumulate("nc_writeback_success", io.ncOut(0).fire)
609  XSPerfAccumulate("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready)
610  XSPerfAccumulate("uncache_full_rollback", io.rollback.valid)
611
612  val perfEvents: Seq[(String, UInt)] = Seq(
613    ("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc),
614    ("mmio_writeback_success", io.mmioOut(0).fire),
615    ("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready),
616    ("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc),
617    ("nc_writeback_success", io.ncOut(0).fire),
618    ("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready),
619    ("uncache_full_rollback", io.rollback.valid)
620  )
621  // end
622}
623