Rob.scala 51.6 KB
Newer Older
L
Lemover 已提交
1 2
/***************************************************************************************
* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
Y
Yinan Xu 已提交
3
* Copyright (c) 2020-2021 Peng Cheng Laboratory
L
Lemover 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16
*
* XiangShan is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

Y
Yinan Xu 已提交
17
package xiangshan.backend.rob
18

19
import chipsalliance.rocketchip.config.Parameters
20
import chisel3.ExcitingUtils._
21 22 23
import chisel3._
import chisel3.util._
import xiangshan._
L
LinJiawei 已提交
24
import utils._
L
Lingrui98 已提交
25
import xiangshan.frontend.FtqPtr
26
import difftest._
27

Y
Yinan Xu 已提交
28 29
class RobPtr(implicit p: Parameters) extends CircularQueuePtr[RobPtr](
  p => p(XSCoreParamsKey).RobSize
30 31
) with HasCircularQueuePtrHelper {

32
  def needFlush(redirect: Valid[Redirect]): Bool = {
Y
Yinan Xu 已提交
33
    val flushItself = redirect.bits.flushItself() && this === redirect.bits.robIdx
34
    redirect.valid && (flushItself || isAfter(this, redirect.bits.robIdx))
Y
Yinan Xu 已提交
35
  }
36

Y
Yinan Xu 已提交
37
  override def cloneType = (new RobPtr).asInstanceOf[this.type]
Y
Yinan Xu 已提交
38 39
}

Y
Yinan Xu 已提交
40 41 42
object RobPtr {
  def apply(f: Bool, v: UInt)(implicit p: Parameters): RobPtr = {
    val ptr = Wire(new RobPtr)
Y
Yinan Xu 已提交
43 44 45 46 47 48
    ptr.flag := f
    ptr.value := v
    ptr
  }
}

Y
Yinan Xu 已提交
49
class RobCSRIO(implicit p: Parameters) extends XSBundle {
50 51
  val intrBitSet = Input(Bool())
  val trapTarget = Input(UInt(VAddrBits.W))
L
LinJiawei 已提交
52
  val isXRet = Input(Bool())
Y
Yinan Xu 已提交
53

54
  val fflags = Output(Valid(UInt(5.W)))
55
  val dirty_fs = Output(Bool())
56 57 58
  val perfinfo = new Bundle {
    val retiredInstr = Output(UInt(3.W))
  }
59
}
Y
Yinan Xu 已提交
60

Y
Yinan Xu 已提交
61
class RobLsqIO(implicit p: Parameters) extends XSBundle {
62 63
  val lcommit = Output(UInt(log2Up(CommitWidth + 1).W))
  val scommit = Output(UInt(log2Up(CommitWidth + 1).W))
64 65 66
  val pendingld = Output(Bool())
  val pendingst = Output(Bool())
  val commit = Output(Bool())
Y
Yinan Xu 已提交
67
  val storeDataRobWb = Input(Vec(StorePipelineWidth, Valid(new RobPtr)))
68 69
}

Y
Yinan Xu 已提交
70
class RobEnqIO(implicit p: Parameters) extends XSBundle {
Y
Yinan Xu 已提交
71 72
  val canAccept = Output(Bool())
  val isEmpty = Output(Bool())
Y
Yinan Xu 已提交
73
  // valid vector, for robIdx gen and walk
Y
Yinan Xu 已提交
74 75
  val needAlloc = Vec(RenameWidth, Input(Bool()))
  val req = Vec(RenameWidth, Flipped(ValidIO(new MicroOp)))
Y
Yinan Xu 已提交
76
  val resp = Vec(RenameWidth, Output(new RobPtr))
Y
Yinan Xu 已提交
77 78
}

79
class RobDispatchData(implicit p: Parameters) extends RobCommitInfo
Y
Yinan Xu 已提交
80

Y
Yinan Xu 已提交
81
class RobDeqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
Y
Yinan Xu 已提交
82
  val io = IO(new Bundle {
Y
Yinan Xu 已提交
83 84 85 86
    // for commits/flush
    val state = Input(UInt(2.W))
    val deq_v = Vec(CommitWidth, Input(Bool()))
    val deq_w = Vec(CommitWidth, Input(Bool()))
Y
Yinan Xu 已提交
87
    val exception_state = Flipped(ValidIO(new RobExceptionInfo))
Y
Yinan Xu 已提交
88 89 90 91
    // for flush: when exception occurs, reset deqPtrs to range(0, CommitWidth)
    val intrBitSetReg = Input(Bool())
    val hasNoSpecExec = Input(Bool())
    val commitType = Input(CommitType())
L
LinJiawei 已提交
92
    val misPredBlock = Input(Bool())
93
    val isReplaying = Input(Bool())
Y
Yinan Xu 已提交
94
    // output: the CommitWidth deqPtr
Y
Yinan Xu 已提交
95 96
    val out = Vec(CommitWidth, Output(new RobPtr))
    val next_out = Vec(CommitWidth, Output(new RobPtr))
Y
Yinan Xu 已提交
97 98
  })

Y
Yinan Xu 已提交
99
  val deqPtrVec = RegInit(VecInit((0 until CommitWidth).map(_.U.asTypeOf(new RobPtr))))
Y
Yinan Xu 已提交
100 101 102 103

  // for exceptions (flushPipe included) and interrupts:
  // only consider the first instruction
  val intrEnable = io.intrBitSetReg && !io.hasNoSpecExec && !CommitType.isLoadStore(io.commitType)
104
  val exceptionEnable = io.deq_w(0) && io.exception_state.valid && !io.exception_state.bits.flushPipe && io.exception_state.bits.robIdx === deqPtrVec(0)
Y
Yinan Xu 已提交
105 106 107 108
  val redirectOutValid = io.state === 0.U && io.deq_v(0) && (intrEnable || exceptionEnable)

  // for normal commits: only to consider when there're no exceptions
  // we don't need to consider whether the first instruction has exceptions since it wil trigger exceptions.
Y
Yinan Xu 已提交
109
  val commit_exception = io.exception_state.valid && !isAfter(io.exception_state.bits.robIdx, deqPtrVec.last)
110
  val canCommit = VecInit((0 until CommitWidth).map(i => io.deq_v(i) && io.deq_w(i) && !io.misPredBlock && !io.isReplaying))
Y
Yinan Xu 已提交
111
  val normalCommitCnt = PriorityEncoder(canCommit.map(c => !c) :+ true.B)
112 113
  // when io.intrBitSetReg or there're possible exceptions in these instructions,
  // only one instruction is allowed to commit
114
  val allowOnlyOne = commit_exception || io.intrBitSetReg
115
  val commitCnt = Mux(allowOnlyOne, canCommit(0), normalCommitCnt)
Y
Yinan Xu 已提交
116

Y
Yinan Xu 已提交
117
  val commitDeqPtrVec = VecInit(deqPtrVec.map(_ + commitCnt))
118
  val deqPtrVec_next = Mux(io.state === 0.U && !redirectOutValid, commitDeqPtrVec, deqPtrVec)
Y
Yinan Xu 已提交
119 120 121 122 123 124 125

  deqPtrVec := deqPtrVec_next

  io.next_out := deqPtrVec_next
  io.out      := deqPtrVec

  when (io.state === 0.U) {
Y
Yinan Xu 已提交
126
    XSInfo(io.state === 0.U && commitCnt > 0.U, "retired %d insts\n", commitCnt)
Y
Yinan Xu 已提交
127
  }
Y
Yinan Xu 已提交
128 129 130

}

Y
Yinan Xu 已提交
131
class RobEnqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
Y
Yinan Xu 已提交
132 133 134 135 136 137 138
  val io = IO(new Bundle {
    // for input redirect
    val redirect = Input(Valid(new Redirect))
    // for enqueue
    val allowEnqueue = Input(Bool())
    val hasBlockBackward = Input(Bool())
    val enq = Vec(RenameWidth, Input(Bool()))
Y
Yinan Xu 已提交
139
    val out = Output(new RobPtr)
Y
Yinan Xu 已提交
140 141
  })

Y
Yinan Xu 已提交
142
  val enqPtr = RegInit(0.U.asTypeOf(new RobPtr))
Y
Yinan Xu 已提交
143 144 145

  // enqueue
  val canAccept = io.allowEnqueue && !io.hasBlockBackward
146
  val dispatchNum = Mux(canAccept, PopCount(io.enq), 0.U)
Y
Yinan Xu 已提交
147

148
  when (io.redirect.valid) {
Y
Yinan Xu 已提交
149
    enqPtr := io.redirect.bits.robIdx + Mux(io.redirect.bits.flushItself(), 0.U, 1.U)
Y
Yinan Xu 已提交
150 151
  }.otherwise {
    enqPtr := enqPtr + dispatchNum
Y
Yinan Xu 已提交
152
  }
Y
Yinan Xu 已提交
153 154 155

  io.out := enqPtr

Y
Yinan Xu 已提交
156 157
}

Y
Yinan Xu 已提交
158
class RobExceptionInfo(implicit p: Parameters) extends XSBundle {
159
  // val valid = Bool()
Y
Yinan Xu 已提交
160
  val robIdx = new RobPtr
161 162
  val exceptionVec = ExceptionVec()
  val flushPipe = Bool()
W
William Wang 已提交
163
  val replayInst = Bool() // redirect to that inst itself
164
  val singleStep = Bool()
165
  val crossPageIPFFix = Bool()
166 167 168 169 170 171 172 173 174 175 176 177 178
  val trigger = new TriggerCf

  // make sure chains are fired at same timing
  def trigger_vec_fix = VecInit(trigger.triggerHitVec.zipWithIndex.map{ case (hit, i) =>
    def chain = trigger.triggerChainVec(i / 2)
    if (i % 2 == 0)
      Mux(chain, (trigger.triggerHitVec(i ) && trigger.triggerHitVec(i + 1)), trigger.triggerHitVec(i))
    else
      Mux(chain, (trigger.triggerHitVec(i ) && trigger.triggerHitVec(i - 1)), trigger.triggerHitVec(i))
  })

  def trigger_before = trigger_vec_fix.zip(trigger.triggerTiming).map{ case (hit, timing) => hit && !timing}.reduce(_ | _)
  def trigger_after = trigger_vec_fix.zip(trigger.triggerTiming).map{ case (hit, timing) => hit && timing}.reduce(_ | _)
179

180
  def has_exception = exceptionVec.asUInt.orR || flushPipe || singleStep || replayInst || trigger_vec_fix.asUInt.orR
181
  // only exceptions are allowed to writeback when enqueue
182
  def can_writeback = exceptionVec.asUInt.orR || singleStep || trigger_before
183 184
}

185
class ExceptionGen(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
186 187 188
  val io = IO(new Bundle {
    val redirect = Input(Valid(new Redirect))
    val flush = Input(Bool())
Y
Yinan Xu 已提交
189 190 191 192
    val enq = Vec(RenameWidth, Flipped(ValidIO(new RobExceptionInfo)))
    val wb = Vec(5, Flipped(ValidIO(new RobExceptionInfo)))
    val out = ValidIO(new RobExceptionInfo)
    val state = ValidIO(new RobExceptionInfo)
193 194
  })

Y
Yinan Xu 已提交
195
  val current = Reg(Valid(new RobExceptionInfo))
196 197

  // orR the exceptionVec
198 199 200
  val lastCycleFlush = RegNext(io.flush)
  val in_enq_valid = VecInit(io.enq.map(e => e.valid && e.bits.has_exception && !lastCycleFlush))
  val in_wb_valid = io.wb.map(w => w.valid && w.bits.has_exception && !lastCycleFlush)
201 202

  // s0: compare wb(1),wb(2) and wb(3),wb(4)
203
  val wb_valid = in_wb_valid.zip(io.wb.map(_.bits)).map{ case (v, bits) => v && !(bits.robIdx.needFlush(io.redirect) || io.flush) }
204
  val csr_wb_bits = io.wb(0).bits
Y
Yinan Xu 已提交
205 206
  val load_wb_bits = Mux(!in_wb_valid(2) || in_wb_valid(1) && isAfter(io.wb(2).bits.robIdx, io.wb(1).bits.robIdx), io.wb(1).bits, io.wb(2).bits)
  val store_wb_bits = Mux(!in_wb_valid(4) || in_wb_valid(3) && isAfter(io.wb(4).bits.robIdx, io.wb(3).bits.robIdx), io.wb(3).bits, io.wb(4).bits)
207 208 209 210
  val s0_out_valid = RegNext(VecInit(Seq(wb_valid(0), wb_valid(1) || wb_valid(2), wb_valid(3) || wb_valid(4))))
  val s0_out_bits = RegNext(VecInit(Seq(csr_wb_bits, load_wb_bits, store_wb_bits)))

  // s1: compare last four and current flush
211
  val s1_valid = VecInit(s0_out_valid.zip(s0_out_bits).map{ case (v, b) => v && !(b.robIdx.needFlush(io.redirect) || io.flush) })
212
  val compare_01_valid = s0_out_valid(0) || s0_out_valid(1)
Y
Yinan Xu 已提交
213 214
  val compare_01_bits = Mux(!s0_out_valid(0) || s0_out_valid(1) && isAfter(s0_out_bits(0).robIdx, s0_out_bits(1).robIdx), s0_out_bits(1), s0_out_bits(0))
  val compare_bits = Mux(!s0_out_valid(2) || compare_01_valid && isAfter(s0_out_bits(2).robIdx, compare_01_bits.robIdx), compare_01_bits, s0_out_bits(2))
215 216 217
  val s1_out_bits = RegNext(compare_bits)
  val s1_out_valid = RegNext(s1_valid.asUInt.orR)

218
  val enq_valid = RegNext(in_enq_valid.asUInt.orR && !io.redirect.valid && !io.flush)
219 220 221 222 223 224 225
  val enq_bits = RegNext(ParallelPriorityMux(in_enq_valid, io.enq.map(_.bits)))

  // s2: compare the input exception with the current one
  // priorities:
  // (1) system reset
  // (2) current is valid: flush, remain, merge, update
  // (3) current is not valid: s1 or enq
226 227
  val current_flush = current.bits.robIdx.needFlush(io.redirect) || io.flush
  val s1_flush = s1_out_bits.robIdx.needFlush(io.redirect) || io.flush
228 229 230 231 232 233 234
  when (reset.asBool) {
    current.valid := false.B
  }.elsewhen (current.valid) {
    when (current_flush) {
      current.valid := Mux(s1_flush, false.B, s1_out_valid)
    }
    when (s1_out_valid && !s1_flush) {
Y
Yinan Xu 已提交
235
      when (isAfter(current.bits.robIdx, s1_out_bits.robIdx)) {
236
        current.bits := s1_out_bits
Y
Yinan Xu 已提交
237
      }.elsewhen (current.bits.robIdx === s1_out_bits.robIdx) {
238 239
        current.bits.exceptionVec := (s1_out_bits.exceptionVec.asUInt | current.bits.exceptionVec.asUInt).asTypeOf(ExceptionVec())
        current.bits.flushPipe := s1_out_bits.flushPipe || current.bits.flushPipe
W
William Wang 已提交
240
        current.bits.replayInst := s1_out_bits.replayInst || current.bits.replayInst
241
        current.bits.singleStep := s1_out_bits.singleStep || current.bits.singleStep
242
//        current.bits.trigger := (s1_out_bits.trigger.asUInt | current.bits.trigger.asUInt).asTypeOf(new TriggerCf)
243 244 245 246 247 248 249 250 251 252 253 254 255 256
      }
    }
  }.elsewhen (s1_out_valid && !s1_flush) {
    current.valid := true.B
    current.bits := s1_out_bits
  }.elsewhen (enq_valid && !(io.redirect.valid || io.flush)) {
    current.valid := true.B
    current.bits := enq_bits
  }

  io.out.valid := s1_out_valid || enq_valid && enq_bits.can_writeback
  io.out.bits := Mux(s1_out_valid, s1_out_bits, enq_bits)
  io.state := current

257 258
}

Y
Yinan Xu 已提交
259
class RobFlushInfo(implicit p: Parameters) extends XSBundle {
260
  val ftqIdx = new FtqPtr
261
  val robIdx = new RobPtr
262
  val ftqOffset = UInt(log2Up(PredictWidth).W)
W
William Wang 已提交
263
  val replayInst = Bool()
264 265
}

Y
Yinan Xu 已提交
266
class Rob(numWbPorts: Int)(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
267
  val io = IO(new Bundle() {
J
Jiawei Lin 已提交
268
    val hartId = Input(UInt(8.W))
269
    val redirect = Input(Valid(new Redirect))
Y
Yinan Xu 已提交
270
    val enq = new RobEnqIO
271
    val flushOut = ValidIO(new Redirect)
272
    val exception = ValidIO(new ExceptionInfo)
L
LinJiawei 已提交
273
    // exu + brq
274
    val exeWbResults = Vec(numWbPorts, Flipped(ValidIO(new ExuOutput)))
Y
Yinan Xu 已提交
275 276
    val commits = new RobCommitIO
    val lsq = new RobLsqIO
277
    val bcommit = Output(UInt(log2Up(CommitWidth + 1).W))
Y
Yinan Xu 已提交
278 279 280
    val robDeqPtr = Output(new RobPtr)
    val csr = new RobCSRIO
    val robFull = Output(Bool())
281
  })
W
William Wang 已提交
282

Y
Yinan Xu 已提交
283
  println("Rob: size:" + RobSize + " wbports:" + numWbPorts  + " commitwidth:" + CommitWidth)
284

285
  // instvalid field
Y
Yinan Xu 已提交
286 287
  // val valid = RegInit(VecInit(List.fill(RobSize)(false.B)))
  val valid = Mem(RobSize, Bool())
288
  // writeback status
Y
Yinan Xu 已提交
289 290 291
  // val writebacked = Reg(Vec(RobSize, Bool()))
  val writebacked = Mem(RobSize, Bool())
  val store_data_writebacked = Mem(RobSize, Bool())
292
  // data for redirect, exception, etc.
Y
Yinan Xu 已提交
293 294
  // val flagBkup = RegInit(VecInit(List.fill(RobSize)(false.B)))
  val flagBkup = Mem(RobSize, Bool())
295

296
  // data for debug
297
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
298 299 300
  val debug_microOp = Mem(RobSize, new MicroOp)
  val debug_exuData = Reg(Vec(RobSize, UInt(XLEN.W)))//for debug
  val debug_exuDebug = Reg(Vec(RobSize, new DebugBundle))//for debug
W
William Wang 已提交
301

302 303
  // pointers
  // For enqueue ptr, we don't duplicate it since only enqueue needs it.
Y
Yinan Xu 已提交
304 305
  val enqPtr = Wire(new RobPtr)
  val deqPtrVec = Wire(Vec(CommitWidth, new RobPtr))
Y
Yinan Xu 已提交
306

Y
Yinan Xu 已提交
307 308
  val walkPtrVec = Reg(Vec(CommitWidth, new RobPtr))
  val validCounter = RegInit(0.U(log2Ceil(RobSize + 1).W))
309
  val allowEnqueue = RegInit(true.B)
310 311 312 313

  val enqPtrVec = VecInit((0 until RenameWidth).map(i => enqPtr + PopCount(io.enq.needAlloc.take(i))))
  val deqPtr = deqPtrVec(0)
  val walkPtr = walkPtrVec(0)
W
William Wang 已提交
314

315
  val isEmpty = enqPtr === deqPtr
316
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
317

318
  /**
Y
Yinan Xu 已提交
319
    * states of Rob
320
    */
W
William Wang 已提交
321
  val s_idle :: s_walk :: s_extrawalk :: Nil = Enum(3)
W
William Wang 已提交
322 323
  val state = RegInit(s_idle)

Y
Yinan Xu 已提交
324
  /**
325 326 327 328
    * Data Modules
    *
    * CommitDataModule: data from dispatch
    * (1) read: commits/walk/exception
Y
Yinan Xu 已提交
329
    * (2) write: enqueue
330 331 332 333
    *
    * WritebackData: data from writeback
    * (1) read: commits/walk/exception
    * (2) write: write back from exe units
Y
Yinan Xu 已提交
334
    */
Y
Yinan Xu 已提交
335
  val dispatchData = Module(new SyncDataModuleTemplate(new RobDispatchData, RobSize, CommitWidth, RenameWidth))
Y
Yinan Xu 已提交
336 337
  val dispatchDataRead = dispatchData.io.rdata

338 339
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
340
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
341

Y
Yinan Xu 已提交
342
  io.robDeqPtr := deqPtr
343

Y
Yinan Xu 已提交
344 345 346 347
  /**
    * Enqueue (from dispatch)
    */
  // special cases
348 349
  val hasBlockBackward = RegInit(false.B)
  val hasNoSpecExec = RegInit(false.B)
H
happy-lx 已提交
350
  val doingSvinval = RegInit(false.B)
Y
Yinan Xu 已提交
351
  // When blockBackward instruction leaves Rob (commit or walk), hasBlockBackward should be set to false.B
352
  // To reduce registers usage, for hasBlockBackward cases, we allow enqueue after ROB is empty.
Y
Yinan Xu 已提交
353
  when (isEmpty) { hasBlockBackward:= false.B }
354
  // When any instruction commits, hasNoSpecExec should be set to false.B
355
  when (io.commits.valid.asUInt.orR  && state =/= s_extrawalk) { hasNoSpecExec:= false.B }
L
Opt roq  
LinJiawei 已提交
356

357
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
358
  io.enq.resp      := enqPtrVec
359
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
360
  val timer = GTimer()
Y
Yinan Xu 已提交
361
  for (i <- 0 until RenameWidth) {
362 363 364 365
    // we don't check whether io.redirect is valid here since redirect has higher priority
    when (canEnqueue(i)) {
      // store uop in data module and debug_microOp Vec
      debug_microOp(enqPtrVec(i).value) := io.enq.req(i).bits
366 367 368 369 370
      debug_microOp(enqPtrVec(i).value).debugInfo.dispatchTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.enqRsTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.selectTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.issueTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.writebackTime := timer
371
      when (io.enq.req(i).bits.ctrl.blockBackward) {
372 373
        hasBlockBackward := true.B
      }
374
      when (io.enq.req(i).bits.ctrl.noSpecExec) {
375 376
        hasNoSpecExec := true.B
      }
H
happy-lx 已提交
377 378 379 380 381 382 383 384 385 386 387 388
      // the begin instruction of Svinval enqs so mark doingSvinval as true to indicate this process
      when(!Cat(io.enq.req(i).bits.cf.exceptionVec).orR && FuType.isSvinvalBegin(io.enq.req(i).bits.ctrl.fuType,io.enq.req(i).bits.ctrl.fuOpType,io.enq.req(i).bits.ctrl.flushPipe))
      {
        doingSvinval := true.B
      }
      // the end instruction of Svinval enqs so clear doingSvinval 
      when(!Cat(io.enq.req(i).bits.cf.exceptionVec).orR && FuType.isSvinvalEnd(io.enq.req(i).bits.ctrl.fuType,io.enq.req(i).bits.ctrl.fuOpType,io.enq.req(i).bits.ctrl.flushPipe))
      {
        doingSvinval := false.B
      }
      // when we are in the process of Svinval software code area , only Svinval.vma and end instruction of Svinval can appear
      assert( !doingSvinval || (FuType.isSvinval(io.enq.req(i).bits.ctrl.fuType,io.enq.req(i).bits.ctrl.fuOpType,io.enq.req(i).bits.ctrl.flushPipe) || FuType.isSvinvalEnd(io.enq.req(i).bits.ctrl.fuType,io.enq.req(i).bits.ctrl.fuOpType,io.enq.req(i).bits.ctrl.flushPipe)))
W
William Wang 已提交
389 390
    }
  }
391 392
  val dispatchNum = Mux(io.enq.canAccept, PopCount(Cat(io.enq.req.map(_.valid))), 0.U)
  io.enq.isEmpty   := RegNext(isEmpty && dispatchNum === 0.U)
W
William Wang 已提交
393

394
  // debug info for enqueue (dispatch)
Y
Yinan Xu 已提交
395
  XSDebug(p"(ready, valid): ${io.enq.canAccept}, ${Binary(Cat(io.enq.req.map(_.valid)))}\n")
396 397
  XSInfo(dispatchNum =/= 0.U, p"dispatched $dispatchNum insts\n")

W
William Wang 已提交
398

Y
Yinan Xu 已提交
399 400 401
  /**
    * Writeback (from execution units)
    */
402 403
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
404
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
405 406
      debug_microOp(wbIdx).cf.exceptionVec := io.exeWbResults(i).bits.uop.cf.exceptionVec
      debug_microOp(wbIdx).ctrl.flushPipe := io.exeWbResults(i).bits.uop.ctrl.flushPipe
407
      debug_microOp(wbIdx).ctrl.replayInst := io.exeWbResults(i).bits.uop.ctrl.replayInst
408
      debug_microOp(wbIdx).diffTestDebugLrScValid := io.exeWbResults(i).bits.uop.diffTestDebugLrScValid
409 410
      debug_exuData(wbIdx) := io.exeWbResults(i).bits.data
      debug_exuDebug(wbIdx) := io.exeWbResults(i).bits.debug
411 412
      debug_microOp(wbIdx).debugInfo.enqRsTime := io.exeWbResults(i).bits.uop.debugInfo.enqRsTime
      debug_microOp(wbIdx).debugInfo.selectTime := io.exeWbResults(i).bits.uop.debugInfo.selectTime
413 414
      debug_microOp(wbIdx).debugInfo.issueTime := io.exeWbResults(i).bits.uop.debugInfo.issueTime
      debug_microOp(wbIdx).debugInfo.writebackTime := io.exeWbResults(i).bits.uop.debugInfo.writebackTime
L
Opt roq  
LinJiawei 已提交
415

416
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
417
      XSInfo(true.B,
418
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
Y
Yinan Xu 已提交
419
        p"data 0x${Hexadecimal(io.exeWbResults(i).bits.data)} ldst ${debug_Uop.ctrl.ldest} pdst ${debug_Uop.pdest} " +
Y
Yinan Xu 已提交
420
        p"skip ${io.exeWbResults(i).bits.debug.isMMIO} robIdx: ${io.exeWbResults(i).bits.uop.robIdx}\n"
421
      )
W
William Wang 已提交
422 423
    }
  }
424 425 426
  val writebackNum = PopCount(io.exeWbResults.map(_.valid))
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
427

Y
Yinan Xu 已提交
428
  /**
429
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
430
    */
Y
Yinan Xu 已提交
431
  val deqDispatchData = dispatchDataRead(0)
432 433 434 435 436
  val debug_deqUop = debug_microOp(deqPtr.value)

  // For MMIO instructions, they should not trigger interrupts since they may be sent to lower level before it writes back.
  // However, we cannot determine whether a load/store instruction is MMIO.
  // Thus, we don't allow load/store instructions to trigger an interrupt.
Y
Yinan Xu 已提交
437
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
438
  val intrEnable = intrBitSetReg && !hasNoSpecExec && !CommitType.isLoadStore(deqDispatchData.commitType)
Y
Yinan Xu 已提交
439
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
440 441
  val triggerBefore = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_before
  val triggerAfter = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_after && !exceptionDataRead.bits.trigger_before
442
  val deqHasException = deqHasExceptionOrFlush && exceptionDataRead.bits.exceptionVec.asUInt.orR
443
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
444
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
445 446 447
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException// && triggerBefore

  val isFlushPipe = writebacked(deqPtr.value) && (deqHasFlushPipe || deqHasReplayInst || triggerAfter)
448

449 450 451 452 453 454 455
  // io.flushOut will trigger redirect at the next cycle.
  // Block any redirect or commit at the next cycle.
  val lastCycleFlush = RegNext(io.flushOut.valid)

  io.flushOut.valid := (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable || isFlushPipe) && !lastCycleFlush
  io.flushOut.bits := DontCare
  io.flushOut.bits.robIdx := deqPtr
456 457
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
458 459
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter)
  io.flushOut.bits.interrupt := true.B
460 461 462 463
  XSPerfAccumulate("interrupt_num", io.flushOut.valid && intrEnable)
  XSPerfAccumulate("exception_num", io.flushOut.valid && exceptionEnable)
  XSPerfAccumulate("flush_pipe_num", io.flushOut.valid && isFlushPipe)
  XSPerfAccumulate("replay_inst_num", io.flushOut.valid && isFlushPipe && deqHasReplayInst)
464

465
  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable) && !lastCycleFlush
466 467 468
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
469
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
470
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
471
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(exceptionDataRead.bits.crossPageIPFFix, exceptionHappen)
472
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
473
  io.exception.bits.uop.cf.trigger.triggerHitVec := RegEnable(exceptionDataRead.bits.trigger_vec_fix, exceptionHappen)
474 475 476

  XSDebug(io.flushOut.valid,
    p"generate redirect: pc 0x${Hexadecimal(io.exception.bits.uop.cf.pc)} intr $intrEnable " +
477
    p"excp $exceptionEnable flushPipe $isFlushPipe " +
478
    p"Trap_target 0x${Hexadecimal(io.csr.trapTarget)} exceptionVec ${Binary(exceptionDataRead.bits.exceptionVec.asUInt)}\n")
479

480

Y
Yinan Xu 已提交
481 482 483 484
  /**
    * Commits (and walk)
    * They share the same width.
    */
485
  val walkCounter = Reg(UInt(log2Up(RobSize + 1).W))
486
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
487
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
488

Y
Yinan Xu 已提交
489
  // extra space is used when rob has no enough space, but mispredict recovery needs such info to walk regmap
Y
Yinan Xu 已提交
490
  require(RenameWidth <= CommitWidth)
Y
Yinan Xu 已提交
491
  val extraSpaceForMPR = Reg(Vec(RenameWidth, new RobDispatchData))
W
William Wang 已提交
492
  val usedSpaceForMPR = Reg(Vec(RenameWidth, Bool()))
Y
Yinan Xu 已提交
493 494 495
  when (io.enq.needAlloc.asUInt.orR && io.redirect.valid) {
    usedSpaceForMPR := io.enq.needAlloc
    extraSpaceForMPR := dispatchData.io.wdata
Y
Yinan Xu 已提交
496
    XSDebug("rob full, switched to s_extrawalk. needExtraSpaceForMPR: %b\n", io.enq.needAlloc.asUInt)
Y
Yinan Xu 已提交
497
  }
W
William Wang 已提交
498

L
linjiawei 已提交
499
  // wiring to csr
500 501 502 503 504 505 506
  val (wflags, fpWen) = (0 until CommitWidth).map(i => {
    val v = io.commits.valid(i)
    val info = io.commits.info(i)
    (v & info.wflags, v & info.fpWen)
  }).unzip
  val fflags = Wire(Valid(UInt(5.W)))
  fflags.valid := Mux(io.commits.isWalk, false.B, Cat(wflags).orR())
507
  fflags.bits := wflags.zip(fflagsDataRead).map({
508 509 510
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
511

W
William Wang 已提交
512
  // when mispredict branches writeback, stop commit in the next 2 cycles
L
LinJiawei 已提交
513
  // TODO: don't check all exu write back
L
LinJiawei 已提交
514
  val misPredWb = Cat(VecInit((0 until numWbPorts).map(i =>
L
LinJiawei 已提交
515
    io.exeWbResults(i).bits.redirect.cfiUpdate.isMisPred && io.exeWbResults(i).bits.redirectValid
L
LinJiawei 已提交
516
  ))).orR()
517
  val misPredBlockCounter = Reg(UInt(3.W))
L
LinJiawei 已提交
518
  misPredBlockCounter := Mux(misPredWb,
519
    "b111".U,
W
William Wang 已提交
520 521 522 523
    misPredBlockCounter >> 1.U
  )
  val misPredBlock = misPredBlockCounter(0)

Y
Yinan Xu 已提交
524
  io.commits.isWalk := state =/= s_idle
525
  val commit_v = Mux(state === s_idle, VecInit(deqPtrVec.map(ptr => valid(ptr.value))), VecInit(walkPtrVec.map(ptr => valid(ptr.value))))
Y
Yinan Xu 已提交
526
  // store will be commited iff both sta & std have been writebacked
527
  val commit_w = VecInit(deqPtrVec.map(ptr => writebacked(ptr.value) && store_data_writebacked(ptr.value)))
Y
Yinan Xu 已提交
528
  val commit_exception = exceptionDataRead.valid && !isAfter(exceptionDataRead.bits.robIdx, deqPtrVec.last)
529
  val commit_block = VecInit((0 until CommitWidth).map(i => !commit_w(i)))
530
  val allowOnlyOneCommit = commit_exception || intrBitSetReg
531
  // for instructions that may block others, we don't allow them to commit
Y
Yinan Xu 已提交
532
  for (i <- 0 until CommitWidth) {
533
    // defaults: state === s_idle and instructions commit
534
    // when intrBitSetReg, allow only one instruction to commit at each clock cycle
535
    val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || deqHasException || deqHasReplayInst
536
    io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked && !misPredBlock && !isReplaying && !lastCycleFlush
Y
Yinan Xu 已提交
537
    io.commits.info(i)  := dispatchDataRead(i)
W
William Wang 已提交
538

539 540 541
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
542 543
      io.commits.valid(i) := (if (i < RenameWidth) usedSpaceForMPR(RenameWidth-i-1) else false.B)
      io.commits.info(i)  := (if (i < RenameWidth) extraSpaceForMPR(RenameWidth-i-1) else DontCare)
W
William Wang 已提交
544
    }
545 546 547 548 549 550 551 552 553

    XSInfo(state === s_idle && io.commits.valid(i),
      "retired pc %x wen %d ldest %d pdest %x old_pdest %x data %x fflags: %b\n",
      debug_microOp(deqPtrVec(i).value).cf.pc,
      io.commits.info(i).rfWen,
      io.commits.info(i).ldest,
      io.commits.info(i).pdest,
      io.commits.info(i).old_pdest,
      debug_exuData(deqPtrVec(i).value),
554
      fflagsDataRead(i)
555 556 557 558 559 560 561 562 563 564 565
    )
    XSInfo(state === s_walk && io.commits.valid(i), "walked pc %x wen %d ldst %d data %x\n",
      debug_microOp(walkPtrVec(i).value).cf.pc,
      io.commits.info(i).rfWen,
      io.commits.info(i).ldest,
      debug_exuData(walkPtrVec(i).value)
    )
    XSInfo(state === s_extrawalk && io.commits.valid(i), "use extra space walked wen %d ldst %d\n",
      io.commits.info(i).rfWen,
      io.commits.info(i).ldest
    )
W
William Wang 已提交
566
  }
567
  if (env.EnableDifftest) {
568
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
569
  }
W
William Wang 已提交
570

571
  // sync fflags/dirty_fs to csr
572 573
  io.csr.fflags := fflags
  io.csr.dirty_fs := dirty_fs
574

575 576 577
  // commit branch to brq
  val cfiCommitVec = VecInit(io.commits.valid.zip(io.commits.info.map(_.commitType)).map{case(v, t) => v && CommitType.isBranch(t)})
  io.bcommit := Mux(io.commits.isWalk, 0.U, PopCount(cfiCommitVec))
L
linjiawei 已提交
578

579 580 581
  // commit load/store to lsq
  val ldCommitVec = VecInit((0 until CommitWidth).map(i => io.commits.valid(i) && io.commits.info(i).commitType === CommitType.LOAD))
  val stCommitVec = VecInit((0 until CommitWidth).map(i => io.commits.valid(i) && io.commits.info(i).commitType === CommitType.STORE))
582 583 584 585 586
  io.lsq.lcommit := RegNext(Mux(io.commits.isWalk, 0.U, PopCount(ldCommitVec)))
  io.lsq.scommit := RegNext(Mux(io.commits.isWalk, 0.U, PopCount(stCommitVec)))
  io.lsq.pendingld := RegNext(!io.commits.isWalk && io.commits.info(0).commitType === CommitType.LOAD && valid(deqPtr.value))
  io.lsq.pendingst := RegNext(!io.commits.isWalk && io.commits.info(0).commitType === CommitType.STORE && valid(deqPtr.value))
  io.lsq.commit := RegNext(!io.commits.isWalk && io.commits.valid(0))
587 588 589

  /**
    * state changes
Y
Yinan Xu 已提交
590 591 592 593
    * (1) exceptions: when exception occurs, cancels all and switch to s_idle
    * (2) redirect: switch to s_walk or s_extrawalk (depends on whether there're pending instructions in dispatch1)
    * (3) walk: when walking comes to the end, switch to s_walk
    * (4) s_extrawalk to s_walk
594
    */
595 596 597 598 599
  val state_next = Mux(io.redirect.valid,
    Mux(io.enq.needAlloc.asUInt.orR, s_extrawalk, s_walk),
    Mux(state === s_walk && walkFinished,
      s_idle,
      Mux(state === s_extrawalk, s_walk, state)
Y
Yinan Xu 已提交
600 601 602
    )
  )
  state := state_next
603

604
  /**
605
    * pointers and counters
606
    */
Y
Yinan Xu 已提交
607
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
608 609 610
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
611
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
612 613 614
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
  deqPtrGenModule.io.commitType := deqDispatchData.commitType
L
LinJiawei 已提交
615 616

  deqPtrGenModule.io.misPredBlock := misPredBlock
617
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
618
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
619
  val deqPtrVec_next = deqPtrGenModule.io.next_out
620

Y
Yinan Xu 已提交
621
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
622 623 624 625 626
  enqPtrGenModule.io.redirect := io.redirect
  enqPtrGenModule.io.allowEnqueue := allowEnqueue
  enqPtrGenModule.io.hasBlockBackward := hasBlockBackward
  enqPtrGenModule.io.enq := VecInit(io.enq.req.map(_.valid))
  enqPtr := enqPtrGenModule.io.out
627 628

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
629 630 631 632 633
  // next walkPtrVec:
  // (1) redirect occurs: update according to state
  // (2) walk: move backwards
  val walkPtrVec_next = Mux(io.redirect.valid && state =/= s_extrawalk,
    Mux(state === s_walk,
634 635
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
636 637 638 639
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
640

641
  val lastCycleRedirect = RegNext(io.redirect.valid)
642
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
643
  val commitCnt = PopCount(io.commits.valid)
644 645 646
  validCounter := Mux(state === s_idle,
    (validCounter - commitCnt) + dispatchNum,
    trueValidCounter
647 648
  )

649 650 651
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
652 653
  )

654
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
655
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
656 657
  when (io.redirect.valid) {
    walkCounter := Mux(state === s_walk,
658 659 660 661 662 663 664 665 666 667
      // NOTE: +& is used here because:
      // When rob is full and the head instruction causes an exception,
      // the redirect robIdx is the deqPtr. In this case, currentWalkPtr is
      // enqPtr - 1.U and redirectWalkDistance is RobSize - 1.
      // Since exceptions flush the instruction itself, flushItSelf is true.B.
      // Previously we use `+` to count the walk distance and it causes overflows
      // when RobSize is power of 2. We change it to `+&` to allow walkCounter to be RobSize.
      // The width of walkCounter also needs to be changed.
      redirectWalkDistance +& io.redirect.bits.flushItself() - commitCnt,
      redirectWalkDistance +& io.redirect.bits.flushItself()
668 669 670 671
    )
  }.elsewhen (state === s_walk) {
    walkCounter := walkCounter - commitCnt
    XSInfo(p"rolling back: $enqPtr $deqPtr walk $walkPtr walkcnt $walkCounter\n")
672 673
  }

674

Y
Yinan Xu 已提交
675 676
  /**
    * States
677
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
678

Y
Yinan Xu 已提交
679
    * All events: (1) enqueue (dispatch); (2) writeback; (3) cancel; (4) dequeue (commit);
680
    * All states: (1) valid; (2) writebacked; (3) flagBkup
Y
Yinan Xu 已提交
681
    */
Y
Yinan Xu 已提交
682 683
  val commitReadAddr = Mux(state === s_idle, VecInit(deqPtrVec.map(_.value)), VecInit(walkPtrVec.map(_.value)))

684 685
  // enqueue logic writes 6 valid
  for (i <- 0 until RenameWidth) {
686
    when (canEnqueue(i) && !io.redirect.valid) {
Y
Yinan Xu 已提交
687
      valid(enqPtrVec(i).value) := true.B
688 689 690
    }
  }
  // dequeue/walk logic writes 6 valid, dequeue and walk will not happen at the same time
691 692 693
  for (i <- 0 until CommitWidth) {
    when (io.commits.valid(i) && state =/= s_extrawalk) {
      valid(commitReadAddr(i)) := false.B
694 695
    }
  }
696
  // reset: when exception, reset all valid to false
Y
Yinan Xu 已提交
697
  when (reset.asBool) {
Y
Yinan Xu 已提交
698
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
699 700
      valid(i) := false.B
    }
701
  }
702

703 704 705
  // status field: writebacked
  // enqueue logic set 6 writebacked to false
  for (i <- 0 until RenameWidth) {
706
    when (canEnqueue(i)) {
707
      writebacked(enqPtrVec(i).value) := io.enq.req(i).bits.eliminatedMove && !io.enq.req(i).bits.cf.exceptionVec.asUInt.orR
708 709
      val isStu = io.enq.req(i).bits.ctrl.fuType === FuType.stu
      store_data_writebacked(enqPtrVec(i).value) := !isStu
710 711
    }
  }
712
  when (exceptionGen.io.out.valid) {
Y
Yinan Xu 已提交
713
    val wbIdx = exceptionGen.io.out.bits.robIdx.value
714
    writebacked(wbIdx) := true.B
715
    store_data_writebacked(wbIdx) := true.B
716
  }
Y
Yinan Xu 已提交
717
  // writeback logic set numWbPorts writebacked to true
718 719
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
720 721 722
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
      val block_wb =
        selectAll(io.exeWbResults(i).bits.uop.cf.exceptionVec, false, true).asUInt.orR ||
W
William Wang 已提交
723
        io.exeWbResults(i).bits.uop.ctrl.flushPipe ||
724
        io.exeWbResults(i).bits.uop.ctrl.replayInst
725
      writebacked(wbIdx) := !block_wb
726 727
    }
  }
728 729
  // store data writeback logic mark store as data_writebacked
  for (i <- 0 until StorePipelineWidth) {
730 731
    when(RegNext(io.lsq.storeDataRobWb(i).valid)) {
      store_data_writebacked(RegNext(io.lsq.storeDataRobWb(i).bits.value)) := true.B
732 733
    }
  }
734 735 736 737

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
738
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
739
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
740 741 742
    }
  }

Y
Yinan Xu 已提交
743 744 745 746 747 748 749 750 751 752

  /**
    * read and write of data modules
    */
  val commitReadAddr_next = Mux(state_next === s_idle,
    VecInit(deqPtrVec_next.map(_.value)),
    VecInit(walkPtrVec_next.map(_.value))
  )
  dispatchData.io.wen := canEnqueue
  dispatchData.io.waddr := enqPtrVec.map(_.value)
753
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
754 755 756 757 758 759 760
    wdata.ldest := req.ctrl.ldest
    wdata.rfWen := req.ctrl.rfWen
    wdata.fpWen := req.ctrl.fpWen
    wdata.wflags := req.ctrl.fpu.wflags
    wdata.commitType := req.ctrl.commitType
    wdata.pdest := req.pdest
    wdata.old_pdest := req.old_pdest
L
Lingrui98 已提交
761 762
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
763 764 765 766
    wdata.pc := req.cf.pc
  }
  dispatchData.io.raddr := commitReadAddr_next

767 768 769 770
  exceptionGen.io.redirect <> io.redirect
  exceptionGen.io.flush := io.flushOut.valid
  for (i <- 0 until RenameWidth) {
    exceptionGen.io.enq(i).valid := canEnqueue(i)
Y
Yinan Xu 已提交
771
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
772 773
    exceptionGen.io.enq(i).bits.exceptionVec := selectFrontend(io.enq.req(i).bits.cf.exceptionVec, false, true)
    exceptionGen.io.enq(i).bits.flushPipe := io.enq.req(i).bits.ctrl.flushPipe
774
    exceptionGen.io.enq(i).bits.replayInst := io.enq.req(i).bits.ctrl.replayInst
W
William Wang 已提交
775
    assert(exceptionGen.io.enq(i).bits.replayInst === false.B)
776
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
777
    exceptionGen.io.enq(i).bits.crossPageIPFFix := io.enq.req(i).bits.cf.crossPageIPFFix
778
    exceptionGen.io.enq(i).bits.trigger := io.enq.req(i).bits.cf.trigger
Y
Yinan Xu 已提交
779
  }
780 781

  // TODO: don't hard code these idxes
782
  val numIntWbPorts = exuParameters.AluCnt + exuParameters.LduCnt + exuParameters.MduCnt
783 784 785 786
  // CSR is after Alu and Load
  def csr_wb_idx = exuParameters.AluCnt + exuParameters.LduCnt
  def atomic_wb_idx = exuParameters.AluCnt // first port for load
  def load_wb_idxes = Seq(exuParameters.AluCnt + 1) // second port for load
787
  def store_wb_idxes = io.exeWbResults.indices.takeRight(2)
788
  val all_exception_possibilities = Seq(csr_wb_idx, atomic_wb_idx) ++ load_wb_idxes ++ store_wb_idxes
789
  all_exception_possibilities.zipWithIndex.foreach{ case (p, i) => connect_exception(i, p) }
790 791
  def connect_exception(index: Int, wb_index: Int) = {
    exceptionGen.io.wb(index).valid             := io.exeWbResults(wb_index).valid
Y
Yinan Xu 已提交
792
    exceptionGen.io.wb(index).bits.robIdx       := io.exeWbResults(wb_index).bits.uop.robIdx
793 794 795 796 797 798 799
    val selectFunc = if (wb_index == csr_wb_idx) selectCSR _
    else if (wb_index == atomic_wb_idx) selectAtomics _
    else if (load_wb_idxes.contains(wb_index)) selectLoad _
    else {
      assert(store_wb_idxes.contains(wb_index))
      selectStore _
    }
800 801 802 803 804
    exceptionGen.io.wb(index).bits.exceptionVec    := selectFunc(io.exeWbResults(wb_index).bits.uop.cf.exceptionVec, false, true)
    exceptionGen.io.wb(index).bits.flushPipe       := io.exeWbResults(wb_index).bits.uop.ctrl.flushPipe
    exceptionGen.io.wb(index).bits.replayInst      := io.exeWbResults(wb_index).bits.uop.ctrl.replayInst
    exceptionGen.io.wb(index).bits.singleStep      := false.B
    exceptionGen.io.wb(index).bits.crossPageIPFFix := false.B
805
    exceptionGen.io.wb(index).bits.trigger := io.exeWbResults(wb_index).bits.uop.cf.trigger
806
  }
Y
Yinan Xu 已提交
807

808
  // 4 fmac + 2 fmisc + 1 i2f
809
  val fmacWb = (0 until exuParameters.FmacCnt).map(_ + numIntWbPorts)
810
  val fmiscWb = (0 until exuParameters.FmiscCnt).map(_ + numIntWbPorts + exuParameters.FmacCnt)
811
  val i2fWb = Seq(numIntWbPorts - 1) // last port in int
812
  val fflags_wb = io.exeWbResults.zipWithIndex.filter(w => {
813
    (fmacWb ++ fmiscWb ++ i2fWb).contains(w._2)
814 815
  }).map(_._1)
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
816
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
817 818 819
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
820
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
821
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
822 823 824 825 826
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


827
  val instrCnt = RegInit(0.U(64.W))
828
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && CommitType.isFused(i.commitType) })
829 830 831 832
  val trueCommitCnt = commitCnt +& fuseCommitCnt
  val retireCounter = Mux(state === s_idle, trueCommitCnt, 0.U)
  instrCnt := instrCnt + retireCounter
  io.csr.perfinfo.retiredInstr := RegNext(retireCounter)
Y
Yinan Xu 已提交
833
  io.robFull := !allowEnqueue
834

835 836 837
  /**
    * debug info
    */
838
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
839
  XSDebug("")
Y
Yinan Xu 已提交
840
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
841 842 843
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
844
  }
Y
Yinan Xu 已提交
845 846
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
847
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
848
    if(i % 4 == 0) XSDebug("")
849
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
850 851 852 853
    XSDebug(false, !valid(i), "- ")
    XSDebug(false, valid(i) && writebacked(i), "w ")
    XSDebug(false, valid(i) && !writebacked(i), "v ")
    if(i % 4 == 3) XSDebug(false, true.B, "\n")
W
William Wang 已提交
854
  }
W
William Wang 已提交
855

856 857 858
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

  val commitDebugUop = deqPtrVec.map(_.value).map(debug_microOp(_))
859
  XSPerfAccumulate("clock_cycle", 1.U)
Y
Yinan Xu 已提交
860
  QueuePerf(RobSize, PopCount((0 until RobSize).map(valid(_))), !allowEnqueue)
861 862 863 864
  XSPerfAccumulate("commitUop", ifCommit(commitCnt))
  XSPerfAccumulate("commitInstr", ifCommit(trueCommitCnt))
  val commitIsMove = commitDebugUop.map(_.ctrl.isMove)
  XSPerfAccumulate("commitInstrMove", ifCommit(PopCount(io.commits.valid.zip(commitIsMove).map{ case (v, m) => v && m })))
865 866
  val commitMoveElim = commitDebugUop.map(_.debugInfo.eliminatedMove)
  XSPerfAccumulate("commitInstrMoveElim", ifCommit(PopCount(io.commits.valid zip commitMoveElim map { case (v, e) => v && e })))
867
  XSPerfAccumulate("commitInstrFused", ifCommit(fuseCommitCnt))
868 869
  val commitIsLoad = io.commits.info.map(_.commitType).map(_ === CommitType.LOAD)
  val commitLoadValid = io.commits.valid.zip(commitIsLoad).map{ case (v, t) => v && t }
870
  XSPerfAccumulate("commitInstrLoad", ifCommit(PopCount(commitLoadValid)))
W
William Wang 已提交
871 872 873
  val commitIsBranch = io.commits.info.map(_.commitType).map(_ === CommitType.BRANCH)
  val commitBranchValid = io.commits.valid.zip(commitIsBranch).map{ case (v, t) => v && t }
  XSPerfAccumulate("commitInstrBranch", ifCommit(PopCount(commitBranchValid)))
874 875
  val commitLoadWaitBit = commitDebugUop.map(_.cf.loadWaitBit)
  XSPerfAccumulate("commitInstrLoadWait", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w })))
876
  val commitIsStore = io.commits.info.map(_.commitType).map(_ === CommitType.STORE)
877
  XSPerfAccumulate("commitInstrStore", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t })))
Y
Yinan Xu 已提交
878
  XSPerfAccumulate("writeback", PopCount((0 until RobSize).map(i => valid(i) && writebacked(i))))
879 880
  // XSPerfAccumulate("enqInstr", PopCount(io.dp1Req.map(_.fire())))
  // XSPerfAccumulate("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
881 882
  XSPerfAccumulate("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
  XSPerfAccumulate("walkCycle", state === s_walk || state === s_extrawalk)
883 884
  val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
  val deqUopCommitType = io.commits.info(0).commitType
885 886 887 888
  XSPerfAccumulate("waitNormalCycle", deqNotWritebacked && deqUopCommitType === CommitType.NORMAL)
  XSPerfAccumulate("waitBranchCycle", deqNotWritebacked && deqUopCommitType === CommitType.BRANCH)
  XSPerfAccumulate("waitLoadCycle", deqNotWritebacked && deqUopCommitType === CommitType.LOAD)
  XSPerfAccumulate("waitStoreCycle", deqNotWritebacked && deqUopCommitType === CommitType.STORE)
Y
Yinan Xu 已提交
889
  XSPerfAccumulate("robHeadPC", io.commits.info(0).pc)
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
  val dispatchLatency = commitDebugUop.map(uop => uop.debugInfo.dispatchTime - uop.debugInfo.renameTime)
  val enqRsLatency = commitDebugUop.map(uop => uop.debugInfo.enqRsTime - uop.debugInfo.dispatchTime)
  val selectLatency = commitDebugUop.map(uop => uop.debugInfo.selectTime - uop.debugInfo.enqRsTime)
  val issueLatency = commitDebugUop.map(uop => uop.debugInfo.issueTime - uop.debugInfo.selectTime)
  val executeLatency = commitDebugUop.map(uop => uop.debugInfo.writebackTime - uop.debugInfo.issueTime)
  val rsFuLatency = commitDebugUop.map(uop => uop.debugInfo.writebackTime - uop.debugInfo.enqRsTime)
  val commitLatency = commitDebugUop.map(uop => timer - uop.debugInfo.writebackTime)
  def latencySum(cond: Seq[Bool], latency: Seq[UInt]): UInt = {
    cond.zip(latency).map(x => Mux(x._1, x._2, 0.U)).reduce(_ +& _)
  }
  for (fuType <- FuType.functionNameMap.keys) {
    val fuName = FuType.functionNameMap(fuType)
    val commitIsFuType = io.commits.valid.zip(commitDebugUop).map(x => x._1 && x._2.ctrl.fuType === fuType.U )
    XSPerfAccumulate(s"${fuName}_instr_cnt", ifCommit(PopCount(commitIsFuType)))
    XSPerfAccumulate(s"${fuName}_latency_dispatch", ifCommit(latencySum(commitIsFuType, dispatchLatency)))
    XSPerfAccumulate(s"${fuName}_latency_enq_rs", ifCommit(latencySum(commitIsFuType, enqRsLatency)))
    XSPerfAccumulate(s"${fuName}_latency_select", ifCommit(latencySum(commitIsFuType, selectLatency)))
    XSPerfAccumulate(s"${fuName}_latency_issue", ifCommit(latencySum(commitIsFuType, issueLatency)))
    XSPerfAccumulate(s"${fuName}_latency_execute", ifCommit(latencySum(commitIsFuType, executeLatency)))
    XSPerfAccumulate(s"${fuName}_latency_enq_rs_execute", ifCommit(latencySum(commitIsFuType, rsFuLatency)))
    XSPerfAccumulate(s"${fuName}_latency_commit", ifCommit(latencySum(commitIsFuType, commitLatency)))
    if (fuType == FuType.fmac.litValue()) {
      val commitIsFma = commitIsFuType.zip(commitDebugUop).map(x => x._1 && x._2.ctrl.fpu.ren3 )
      XSPerfAccumulate(s"${fuName}_instr_cnt_fma", ifCommit(PopCount(commitIsFma)))
      XSPerfAccumulate(s"${fuName}_latency_enq_rs_execute_fma", ifCommit(latencySum(commitIsFma, rsFuLatency)))
      XSPerfAccumulate(s"${fuName}_latency_execute_fma", ifCommit(latencySum(commitIsFma, executeLatency)))
    }
  }
Y
Yinan Xu 已提交
918

919 920 921 922 923
  //difftest signals
  val firstValidCommit = (deqPtr + PriorityMux(io.commits.valid, VecInit(List.tabulate(CommitWidth)(_.U)))).value

  val wdata = Wire(Vec(CommitWidth, UInt(XLEN.W)))
  val wpc = Wire(Vec(CommitWidth, UInt(XLEN.W)))
924

925 926 927
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
928
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
929
  }
930
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
931 932
  val retirePCFix = SignExt(Mux(io.exception.valid, io.exception.bits.uop.cf.pc, debug_microOp(firstValidCommit).cf.pc), XLEN)
  val retireInstFix = Mux(io.exception.valid, io.exception.bits.uop.cf.instr, debug_microOp(firstValidCommit).cf.instr)
933

934
  if (env.EnableDifftest) {
935 936 937
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
J
Jiawei Lin 已提交
938
      difftest.io.coreid   := io.hartId
939 940 941
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
942
      val uop = commitDebugUop(i)
943 944 945 946 947
      val exuOut = debug_exuDebug(ptr)
      val exuData = debug_exuData(ptr)
      difftest.io.valid    := RegNext(io.commits.valid(i) && !io.commits.isWalk)
      difftest.io.pc       := RegNext(SignExt(uop.cf.pc, XLEN))
      difftest.io.instr    := RegNext(uop.cf.instr)
948
      difftest.io.special  := RegNext(CommitType.isFused(io.commits.info(i).commitType))
949 950 951
      // when committing an eliminated move instruction,
      // we must make sure that skip is properly set to false (output from EXU is random value)
      difftest.io.skip     := RegNext(Mux(uop.eliminatedMove, false.B, exuOut.isMMIO || exuOut.isPerfCnt))
952 953 954 955
      difftest.io.isRVC    := RegNext(uop.cf.pd.isRVC)
      difftest.io.scFailed := RegNext(!uop.diffTestDebugLrScValid &&
        uop.ctrl.fuType === FuType.mou &&
        (uop.ctrl.fuOpType === LSUOpType.sc_d || uop.ctrl.fuOpType === LSUOpType.sc_w))
956 957
      difftest.io.wen      := RegNext(io.commits.valid(i) && io.commits.info(i).rfWen && io.commits.info(i).ldest =/= 0.U)
      difftest.io.wpdest   := RegNext(io.commits.info(i).pdest)
J
Jiawei Lin 已提交
958
      difftest.io.wdest    := RegNext(io.commits.info(i).ldest)
959

W
William Wang 已提交
960 961 962
      // runahead commit hint
      val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      runahead_commit.io.clock := clock
J
Jiawei Lin 已提交
963
      runahead_commit.io.coreid := io.hartId
W
William Wang 已提交
964 965 966 967 968
      runahead_commit.io.index := i.U
      runahead_commit.io.valid := difftest.io.valid && 
        (commitBranchValid(i) || commitIsStore(i))
      // TODO: is branch or store
      runahead_commit.io.pc    := difftest.io.pc
969 970
    }
  }
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
  else if (env.AlwaysBasicDiff) {
    // These are the structures used by difftest only and should be optimized after synthesis.
    val dt_eliminatedMove = Mem(RobSize, Bool())
    val dt_isRVC = Mem(RobSize, Bool())
    val dt_exuDebug = Reg(Vec(RobSize, new DebugBundle))
    for (i <- 0 until RenameWidth) {
      when (canEnqueue(i)) {
        dt_eliminatedMove(enqPtrVec(i).value) := io.enq.req(i).bits.eliminatedMove
        dt_isRVC(enqPtrVec(i).value) := io.enq.req(i).bits.cf.pd.isRVC
      }
    }
    for (i <- 0 until numWbPorts) {
      when (io.exeWbResults(i).valid) {
        val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
        dt_exuDebug(wbIdx) := io.exeWbResults(i).bits.debug
      }
    }
    // Always instantiate basic difftest modules.
    for (i <- 0 until CommitWidth) {
      val commitInfo = io.commits.info(i)
      val ptr = deqPtrVec(i).value
      val exuOut = dt_exuDebug(ptr)
      val eliminatedMove = dt_eliminatedMove(ptr)
      val isRVC = dt_isRVC(ptr)

      val difftest = Module(new DifftestBasicInstrCommit)
      difftest.io.clock   := clock
J
Jiawei Lin 已提交
998
      difftest.io.coreid  := io.hartId
999 1000 1001 1002 1003 1004 1005 1006 1007 1008
      difftest.io.index   := i.U
      difftest.io.valid   := RegNext(io.commits.valid(i) && !io.commits.isWalk)
      difftest.io.special := RegNext(CommitType.isFused(commitInfo.commitType))
      difftest.io.skip    := RegNext(Mux(eliminatedMove, false.B, exuOut.isMMIO || exuOut.isPerfCnt))
      difftest.io.isRVC   := RegNext(isRVC)
      difftest.io.wen     := RegNext(io.commits.valid(i) && commitInfo.rfWen && commitInfo.ldest =/= 0.U)
      difftest.io.wpdest  := RegNext(commitInfo.pdest)
      difftest.io.wdest   := RegNext(commitInfo.ldest)
    }
  }
1009

1010
  if (env.EnableDifftest) {
1011 1012 1013
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
J
Jiawei Lin 已提交
1014
      difftest.io.coreid := io.hartId
1015 1016 1017
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
1018
      val uop = commitDebugUop(i)
1019
      val exuOut = debug_exuDebug(ptr)
W
wakafa 已提交
1020 1021 1022 1023
      difftest.io.valid  := RegNext(io.commits.valid(i) && !io.commits.isWalk)
      difftest.io.paddr  := RegNext(exuOut.paddr)
      difftest.io.opType := RegNext(uop.ctrl.fuOpType)
      difftest.io.fuType := RegNext(uop.ctrl.fuType)
1024 1025 1026
    }
  }

1027
  // Always instantiate basic difftest modules.
1028
  if (env.EnableDifftest) {
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
    val dt_isXSTrap = Mem(RobSize, Bool())
    for (i <- 0 until RenameWidth) {
      when (canEnqueue(i)) {
        dt_isXSTrap(enqPtrVec(i).value) := io.enq.req(i).bits.ctrl.isXSTrap
      }
    }
    val trapVec = io.commits.valid.zip(deqPtrVec).map{ case (v, d) => state === s_idle && v && dt_isXSTrap(d.value) }
    val hitTrap = trapVec.reduce(_||_)
    val trapCode = PriorityMux(wdata.zip(trapVec).map(x => x._2 -> x._1))
    val trapPC = SignExt(PriorityMux(wpc.zip(trapVec).map(x => x._2 ->x._1)), XLEN)
1039 1040
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1041
    difftest.io.coreid   := io.hartId
1042 1043 1044
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1045
    difftest.io.cycleCnt := timer
1046
    difftest.io.instrCnt := instrCnt
1047
  }
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
  else if (env.AlwaysBasicDiff) {
    val dt_isXSTrap = Mem(RobSize, Bool())
    for (i <- 0 until RenameWidth) {
      when (canEnqueue(i)) {
        dt_isXSTrap(enqPtrVec(i).value) := io.enq.req(i).bits.ctrl.isXSTrap
      }
    }
    val trapVec = io.commits.valid.zip(deqPtrVec).map{ case (v, d) => state === s_idle && v && dt_isXSTrap(d.value) }
    val hitTrap = trapVec.reduce(_||_)
    val difftest = Module(new DifftestBasicTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1059
    difftest.io.coreid   := io.hartId
1060 1061 1062 1063
    difftest.io.valid    := hitTrap
    difftest.io.cycleCnt := timer
    difftest.io.instrCnt := instrCnt
  }
1064

1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
  val perfinfo = IO(new Bundle(){
    val perfEvents = Output(new PerfEventsBundle(18))
  })
  val perfEvents = Seq(
    ("rob_interrupt_num       ", io.flushOut.valid && intrEnable                                                                                                   ),
    ("rob_exception_num       ", io.flushOut.valid && exceptionEnable                                                                                              ),
    ("rob_flush_pipe_num      ", io.flushOut.valid && isFlushPipe                                                                                                  ),
    ("rob_replay_inst_num     ", io.flushOut.valid && isFlushPipe && deqHasReplayInst                                                                              ),
    ("rob_commitUop           ", ifCommit(commitCnt)                                                                                                               ),
    ("rob_commitInstr         ", ifCommit(trueCommitCnt)                                                                                                           ),
    ("rob_commitInstrMove     ", ifCommit(PopCount(io.commits.valid.zip(commitIsMove).map{ case (v, m) => v && m }))                                               ),
    ("rob_commitInstrFused    ", ifCommit(fuseCommitCnt)                                                                                                           ),
    ("rob_commitInstrLoad     ", ifCommit(PopCount(commitLoadValid))                                                                                               ),
    ("rob_commitInstrLoad     ", ifCommit(PopCount(commitBranchValid))                                                                                               ),
    ("rob_commitInstrLoadWait ", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w }))                                           ),
    ("rob_commitInstrStore    ", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t }))                                              ),
    ("rob_walkInstr           ", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U)                                                                           ),
    ("rob_walkCycle           ", (state === s_walk || state === s_extrawalk)                                                                                       ),
    ("rob_1/4_valid           ", (PopCount((0 until RobSize).map(valid(_))) < (RobSize.U/4.U))                                                                     ),
    ("rob_2/4_valid           ", (PopCount((0 until RobSize).map(valid(_))) > (RobSize.U/4.U)) & (PopCount((0 until RobSize).map(valid(_))) <= (RobSize.U/2.U))    ),
    ("rob_3/4_valid           ", (PopCount((0 until RobSize).map(valid(_))) > (RobSize.U/2.U)) & (PopCount((0 until RobSize).map(valid(_))) <= (RobSize.U*3.U/4.U))),
    ("rob_4/4_valid           ", (PopCount((0 until RobSize).map(valid(_))) > (RobSize.U*3.U/4.U))                                                                 ),
  )

  for (((perf_out,(perf_name,perf)),i) <- perfinfo.perfEvents.perf_events.zip(perfEvents).zipWithIndex) {
    perf_out.incr_step := RegNext(perf)
  }
1092
}