Rob.scala 52.2 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 21
import chisel3._
import chisel3.util._
22 23
import difftest._
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
L
LinJiawei 已提交
24
import utils._
25 26
import xiangshan._
import xiangshan.backend.exu.ExuConfig
L
Lingrui98 已提交
27
import xiangshan.frontend.FtqPtr
28

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

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

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

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

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

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

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

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
    // for flush: when exception occurs, reset deqPtrs to range(0, CommitWidth)
    val intrBitSetReg = Input(Bool())
    val hasNoSpecExec = Input(Bool())
Y
Yinan Xu 已提交
91
    val interrupt_safe = Input(Bool())
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

  // for exceptions (flushPipe included) and interrupts:
  // only consider the first instruction
Y
Yinan Xu 已提交
103
  val intrEnable = io.intrBitSetReg && !io.hasNoSpecExec && io.interrupt_safe
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
}

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
class Rob(implicit p: Parameters) extends LazyModule with HasWritebackSink with HasXSParameter {

  lazy val module = new RobImp(this)

  override def generateWritebackIO(
    thisMod: Option[HasWritebackSource] = None,
    thisModImp: Option[HasWritebackSourceImp] = None
  ): Unit = {
    val sources = writebackSinksImp(thisMod, thisModImp)
    module.io.writeback.zip(sources).foreach(x => x._1 := x._2)
  }
}

class RobImp(outer: Rob)(implicit p: Parameters) extends LazyModuleImp(outer)
  with HasXSParameter with HasCircularQueuePtrHelper {
  val wbExuConfigs = outer.writebackSinksParams.map(_.exuConfigs)
  val numWbPorts = wbExuConfigs.map(_.length)

284
  val io = IO(new Bundle() {
J
Jiawei Lin 已提交
285
    val hartId = Input(UInt(8.W))
286
    val redirect = Input(Valid(new Redirect))
Y
Yinan Xu 已提交
287
    val enq = new RobEnqIO
288
    val flushOut = ValidIO(new Redirect)
289
    val exception = ValidIO(new ExceptionInfo)
L
LinJiawei 已提交
290
    // exu + brq
291
    val writeback = MixedVec(numWbPorts.map(num => Vec(num, Flipped(ValidIO(new ExuOutput)))))
Y
Yinan Xu 已提交
292 293
    val commits = new RobCommitIO
    val lsq = new RobLsqIO
294
    val bcommit = Output(UInt(log2Up(CommitWidth + 1).W))
Y
Yinan Xu 已提交
295 296 297
    val robDeqPtr = Output(new RobPtr)
    val csr = new RobCSRIO
    val robFull = Output(Bool())
298
  })
W
William Wang 已提交
299

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  def selectWb(index: Int, func: Seq[ExuConfig] => Boolean): Seq[(Seq[ExuConfig], ValidIO[ExuOutput])] = {
    wbExuConfigs(index).zip(io.writeback(index)).filter(x => func(x._1))
  }
  val exeWbSel = outer.selWritebackSinks(_.exuConfigs.length)
  val fflagsWbSel = outer.selWritebackSinks(_.exuConfigs.count(_.exists(_.writeFflags)))
  val fflagsPorts = selectWb(fflagsWbSel, _.exists(_.writeFflags))
  val exceptionWbSel = outer.selWritebackSinks(_.exuConfigs.count(_.exists(_.needExceptionGen)))
  val exceptionPorts = selectWb(fflagsWbSel, _.exists(_.needExceptionGen))
  val exuWbPorts = selectWb(exeWbSel, _.forall(_ != StdExeUnitCfg))
  val stdWbPorts = selectWb(exeWbSel, _.contains(StdExeUnitCfg))
  println(s"Rob: size $RobSize, numWbPorts: $numWbPorts, commitwidth: $CommitWidth")
  println(s"exuPorts: ${exuWbPorts.map(_._1.map(_.name))}")
  println(s"stdPorts: ${stdWbPorts.map(_._1.map(_.name))}")
  println(s"fflags: ${fflagsPorts.map(_._1.map(_.name))}")


  val exuWriteback = exuWbPorts.map(_._2)
  val stdWriteback = stdWbPorts.map(_._2)
318

319
  // instvalid field
Y
Yinan Xu 已提交
320
  val valid = Mem(RobSize, Bool())
321
  // writeback status
Y
Yinan Xu 已提交
322 323
  val writebacked = Mem(RobSize, Bool())
  val store_data_writebacked = Mem(RobSize, Bool())
324
  // data for redirect, exception, etc.
Y
Yinan Xu 已提交
325
  val flagBkup = Mem(RobSize, Bool())
Y
Yinan Xu 已提交
326 327 328
  // some instructions are not allowed to trigger interrupts
  // They have side effects on the states of the processor before they write back
  val interrupt_safe = Mem(RobSize, Bool())
329

330
  // data for debug
331
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
332 333 334
  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 已提交
335

336 337
  // pointers
  // For enqueue ptr, we don't duplicate it since only enqueue needs it.
Y
Yinan Xu 已提交
338 339
  val enqPtr = Wire(new RobPtr)
  val deqPtrVec = Wire(Vec(CommitWidth, new RobPtr))
Y
Yinan Xu 已提交
340

Y
Yinan Xu 已提交
341 342
  val walkPtrVec = Reg(Vec(CommitWidth, new RobPtr))
  val validCounter = RegInit(0.U(log2Ceil(RobSize + 1).W))
343
  val allowEnqueue = RegInit(true.B)
344 345 346 347

  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 已提交
348

349
  val isEmpty = enqPtr === deqPtr
350
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
351

352
  /**
Y
Yinan Xu 已提交
353
    * states of Rob
354
    */
W
William Wang 已提交
355
  val s_idle :: s_walk :: s_extrawalk :: Nil = Enum(3)
W
William Wang 已提交
356 357
  val state = RegInit(s_idle)

Y
Yinan Xu 已提交
358
  /**
359 360 361 362
    * Data Modules
    *
    * CommitDataModule: data from dispatch
    * (1) read: commits/walk/exception
Y
Yinan Xu 已提交
363
    * (2) write: enqueue
364 365 366 367
    *
    * WritebackData: data from writeback
    * (1) read: commits/walk/exception
    * (2) write: write back from exe units
Y
Yinan Xu 已提交
368
    */
Y
Yinan Xu 已提交
369
  val dispatchData = Module(new SyncDataModuleTemplate(new RobDispatchData, RobSize, CommitWidth, RenameWidth))
Y
Yinan Xu 已提交
370 371
  val dispatchDataRead = dispatchData.io.rdata

372 373
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
374
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
375

Y
Yinan Xu 已提交
376
  io.robDeqPtr := deqPtr
377

Y
Yinan Xu 已提交
378 379 380 381
  /**
    * Enqueue (from dispatch)
    */
  // special cases
382 383
  val hasBlockBackward = RegInit(false.B)
  val hasNoSpecExec = RegInit(false.B)
H
happy-lx 已提交
384
  val doingSvinval = RegInit(false.B)
Y
Yinan Xu 已提交
385
  // When blockBackward instruction leaves Rob (commit or walk), hasBlockBackward should be set to false.B
386
  // To reduce registers usage, for hasBlockBackward cases, we allow enqueue after ROB is empty.
Y
Yinan Xu 已提交
387
  when (isEmpty) { hasBlockBackward:= false.B }
388
  // When any instruction commits, hasNoSpecExec should be set to false.B
389
  when (io.commits.valid.asUInt.orR  && state =/= s_extrawalk) { hasNoSpecExec:= false.B }
L
Opt roq  
LinJiawei 已提交
390

391
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
392
  io.enq.resp      := enqPtrVec
393
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
394
  val timer = GTimer()
Y
Yinan Xu 已提交
395
  for (i <- 0 until RenameWidth) {
396 397
    // we don't check whether io.redirect is valid here since redirect has higher priority
    when (canEnqueue(i)) {
398
      val enqUop = io.enq.req(i).bits
399
      // store uop in data module and debug_microOp Vec
400
      debug_microOp(enqPtrVec(i).value) := enqUop
401 402 403 404 405
      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
406
      when (enqUop.ctrl.blockBackward) {
407 408
        hasBlockBackward := true.B
      }
409
      when (enqUop.ctrl.noSpecExec) {
410 411
        hasNoSpecExec := true.B
      }
412
      val enqHasException = ExceptionNO.selectFrontend(enqUop.cf.exceptionVec).asUInt.orR
H
happy-lx 已提交
413
      // the begin instruction of Svinval enqs so mark doingSvinval as true to indicate this process
414
      when(!enqHasException && FuType.isSvinvalBegin(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe))
H
happy-lx 已提交
415 416 417 418
      {
        doingSvinval := true.B
      }
      // the end instruction of Svinval enqs so clear doingSvinval 
419
      when(!enqHasException && FuType.isSvinvalEnd(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe))
H
happy-lx 已提交
420 421 422 423
      {
        doingSvinval := false.B
      }
      // when we are in the process of Svinval software code area , only Svinval.vma and end instruction of Svinval can appear
424 425
      assert(!doingSvinval || (FuType.isSvinval(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe) ||
        FuType.isSvinvalEnd(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe)))
W
William Wang 已提交
426 427
    }
  }
428 429
  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 已提交
430

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

W
William Wang 已提交
435

Y
Yinan Xu 已提交
436 437 438
  /**
    * Writeback (from execution units)
    */
439 440 441 442 443 444 445 446 447 448
  for (wb <- exuWriteback) {
    when (wb.valid) {
      val wbIdx = wb.bits.uop.robIdx.value
      debug_microOp(wbIdx).diffTestDebugLrScValid := wb.bits.uop.diffTestDebugLrScValid
      debug_exuData(wbIdx) := wb.bits.data
      debug_exuDebug(wbIdx) := wb.bits.debug
      debug_microOp(wbIdx).debugInfo.enqRsTime := wb.bits.uop.debugInfo.enqRsTime
      debug_microOp(wbIdx).debugInfo.selectTime := wb.bits.uop.debugInfo.selectTime
      debug_microOp(wbIdx).debugInfo.issueTime := wb.bits.uop.debugInfo.issueTime
      debug_microOp(wbIdx).debugInfo.writebackTime := wb.bits.uop.debugInfo.writebackTime
L
Opt roq  
LinJiawei 已提交
449

450
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
451
      XSInfo(true.B,
452
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
453 454
        p"data 0x${Hexadecimal(wb.bits.data)} ldst ${debug_Uop.ctrl.ldest} pdst ${debug_Uop.pdest} " +
        p"skip ${wb.bits.debug.isMMIO} robIdx: ${wb.bits.uop.robIdx}\n"
455
      )
W
William Wang 已提交
456 457
    }
  }
458
  val writebackNum = PopCount(exuWriteback.map(_.valid))
459 460
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
461

Y
Yinan Xu 已提交
462
  /**
463
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
464
    */
Y
Yinan Xu 已提交
465
  val deqDispatchData = dispatchDataRead(0)
466 467
  val debug_deqUop = debug_microOp(deqPtr.value)

Y
Yinan Xu 已提交
468
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
Y
Yinan Xu 已提交
469
  val intrEnable = intrBitSetReg && !hasNoSpecExec && interrupt_safe(deqPtr.value)
Y
Yinan Xu 已提交
470
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
471 472
  val triggerBefore = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_before
  val triggerAfter = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_after && !exceptionDataRead.bits.trigger_before
473
  val deqHasException = deqHasExceptionOrFlush && exceptionDataRead.bits.exceptionVec.asUInt.orR
474
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
475
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
476 477 478
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException// && triggerBefore

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

480 481 482 483 484 485 486
  // 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
487 488
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
489 490
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter)
  io.flushOut.bits.interrupt := true.B
491 492 493 494
  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)
495

496
  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable) && !lastCycleFlush
497 498 499
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
500
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
501
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
502
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(exceptionDataRead.bits.crossPageIPFFix, exceptionHappen)
503
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
504
  io.exception.bits.uop.cf.trigger.triggerHitVec := RegEnable(exceptionDataRead.bits.trigger_vec_fix, exceptionHappen)
505 506 507

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

511

Y
Yinan Xu 已提交
512 513 514 515
  /**
    * Commits (and walk)
    * They share the same width.
    */
516
  val walkCounter = Reg(UInt(log2Up(RobSize + 1).W))
517
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
518
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
519

Y
Yinan Xu 已提交
520
  // extra space is used when rob has no enough space, but mispredict recovery needs such info to walk regmap
Y
Yinan Xu 已提交
521
  require(RenameWidth <= CommitWidth)
Y
Yinan Xu 已提交
522
  val extraSpaceForMPR = Reg(Vec(RenameWidth, new RobDispatchData))
W
William Wang 已提交
523
  val usedSpaceForMPR = Reg(Vec(RenameWidth, Bool()))
Y
Yinan Xu 已提交
524 525 526
  when (io.enq.needAlloc.asUInt.orR && io.redirect.valid) {
    usedSpaceForMPR := io.enq.needAlloc
    extraSpaceForMPR := dispatchData.io.wdata
Y
Yinan Xu 已提交
527
    XSDebug("rob full, switched to s_extrawalk. needExtraSpaceForMPR: %b\n", io.enq.needAlloc.asUInt)
Y
Yinan Xu 已提交
528
  }
W
William Wang 已提交
529

L
linjiawei 已提交
530
  // wiring to csr
531 532 533 534 535 536 537
  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())
538
  fflags.bits := wflags.zip(fflagsDataRead).map({
539 540 541
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
542

W
William Wang 已提交
543
  // when mispredict branches writeback, stop commit in the next 2 cycles
L
LinJiawei 已提交
544
  // TODO: don't check all exu write back
545 546
  val misPredWb = Cat(VecInit(exuWriteback.map(wb =>
    wb.bits.redirect.cfiUpdate.isMisPred && wb.bits.redirectValid
L
LinJiawei 已提交
547
  ))).orR()
548
  val misPredBlockCounter = Reg(UInt(3.W))
L
LinJiawei 已提交
549
  misPredBlockCounter := Mux(misPredWb,
550
    "b111".U,
W
William Wang 已提交
551 552 553 554
    misPredBlockCounter >> 1.U
  )
  val misPredBlock = misPredBlockCounter(0)

Y
Yinan Xu 已提交
555
  io.commits.isWalk := state =/= s_idle
556
  val commit_v = Mux(state === s_idle, VecInit(deqPtrVec.map(ptr => valid(ptr.value))), VecInit(walkPtrVec.map(ptr => valid(ptr.value))))
Y
Yinan Xu 已提交
557
  // store will be commited iff both sta & std have been writebacked
558
  val commit_w = VecInit(deqPtrVec.map(ptr => writebacked(ptr.value) && store_data_writebacked(ptr.value)))
Y
Yinan Xu 已提交
559
  val commit_exception = exceptionDataRead.valid && !isAfter(exceptionDataRead.bits.robIdx, deqPtrVec.last)
560
  val commit_block = VecInit((0 until CommitWidth).map(i => !commit_w(i)))
561
  val allowOnlyOneCommit = commit_exception || intrBitSetReg
562
  // for instructions that may block others, we don't allow them to commit
Y
Yinan Xu 已提交
563
  for (i <- 0 until CommitWidth) {
564
    // defaults: state === s_idle and instructions commit
565
    // when intrBitSetReg, allow only one instruction to commit at each clock cycle
566
    val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || deqHasException || deqHasReplayInst
567
    io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked && !misPredBlock && !isReplaying && !lastCycleFlush
Y
Yinan Xu 已提交
568
    io.commits.info(i)  := dispatchDataRead(i)
W
William Wang 已提交
569

570 571 572
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
573 574
      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 已提交
575
    }
576 577 578 579 580 581 582 583 584

    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),
585
      fflagsDataRead(i)
586 587 588 589 590 591 592 593 594 595 596
    )
    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 已提交
597
  }
598
  if (env.EnableDifftest) {
599
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
600
  }
W
William Wang 已提交
601

602
  // sync fflags/dirty_fs to csr
603 604
  io.csr.fflags := fflags
  io.csr.dirty_fs := dirty_fs
605

606 607 608
  // 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 已提交
609

610 611 612
  // 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))
613 614 615 616 617
  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))
618 619 620

  /**
    * state changes
Y
Yinan Xu 已提交
621 622 623 624
    * (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
625
    */
626 627 628 629 630
  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 已提交
631 632 633
    )
  )
  state := state_next
634

635
  /**
636
    * pointers and counters
637
    */
Y
Yinan Xu 已提交
638
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
639 640 641
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
642
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
643 644
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
Y
Yinan Xu 已提交
645
  deqPtrGenModule.io.interrupt_safe := interrupt_safe(deqPtr.value)
L
LinJiawei 已提交
646 647

  deqPtrGenModule.io.misPredBlock := misPredBlock
648
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
649
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
650
  val deqPtrVec_next = deqPtrGenModule.io.next_out
651

Y
Yinan Xu 已提交
652
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
653 654 655 656 657
  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
658 659

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
660 661 662 663 664
  // 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,
665 666
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
667 668 669 670
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
671

672
  val lastCycleRedirect = RegNext(io.redirect.valid)
673
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
674
  val commitCnt = PopCount(io.commits.valid)
675 676 677
  validCounter := Mux(state === s_idle,
    (validCounter - commitCnt) + dispatchNum,
    trueValidCounter
678 679
  )

680 681 682
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
683 684
  )

685
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
686
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
687 688
  when (io.redirect.valid) {
    walkCounter := Mux(state === s_walk,
689 690 691 692 693 694 695 696 697 698
      // 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()
699 700 701 702
    )
  }.elsewhen (state === s_walk) {
    walkCounter := walkCounter - commitCnt
    XSInfo(p"rolling back: $enqPtr $deqPtr walk $walkPtr walkcnt $walkCounter\n")
703 704
  }

705

Y
Yinan Xu 已提交
706 707
  /**
    * States
708
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
709

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

715 716
  // enqueue logic writes 6 valid
  for (i <- 0 until RenameWidth) {
717
    when (canEnqueue(i) && !io.redirect.valid) {
Y
Yinan Xu 已提交
718
      valid(enqPtrVec(i).value) := true.B
719 720 721
    }
  }
  // dequeue/walk logic writes 6 valid, dequeue and walk will not happen at the same time
722 723 724
  for (i <- 0 until CommitWidth) {
    when (io.commits.valid(i) && state =/= s_extrawalk) {
      valid(commitReadAddr(i)) := false.B
725 726
    }
  }
727
  // reset: when exception, reset all valid to false
Y
Yinan Xu 已提交
728
  when (reset.asBool) {
Y
Yinan Xu 已提交
729
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
730 731
      valid(i) := false.B
    }
732
  }
733

734 735 736
  // status field: writebacked
  // enqueue logic set 6 writebacked to false
  for (i <- 0 until RenameWidth) {
737
    when (canEnqueue(i)) {
738 739
      val enqHasException = ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec)
      writebacked(enqPtrVec(i).value) := io.enq.req(i).bits.eliminatedMove && !enqHasException.asUInt.orR
740 741
      val isStu = io.enq.req(i).bits.ctrl.fuType === FuType.stu
      store_data_writebacked(enqPtrVec(i).value) := !isStu
742 743
    }
  }
744
  when (exceptionGen.io.out.valid) {
Y
Yinan Xu 已提交
745
    val wbIdx = exceptionGen.io.out.bits.robIdx.value
746
    writebacked(wbIdx) := true.B
747
    store_data_writebacked(wbIdx) := true.B
748
  }
Y
Yinan Xu 已提交
749
  // writeback logic set numWbPorts writebacked to true
750 751 752 753 754 755 756
  for ((wb, cfgs) <- exuWriteback.zip(wbExuConfigs(exeWbSel))) {
    when (wb.valid) {
      val wbIdx = wb.bits.uop.robIdx.value
      val wbHasException = ExceptionNO.selectByExu(wb.bits.uop.cf.exceptionVec, cfgs).asUInt.orR
      val wbHasFlushPipe = cfgs.exists(_.flushPipe).B && wb.bits.uop.ctrl.flushPipe
      val wbHasReplayInst = cfgs.exists(_.replayInst).B && wb.bits.uop.ctrl.replayInst
      val block_wb = wbHasException || wbHasFlushPipe || wbHasReplayInst
757
      writebacked(wbIdx) := !block_wb
758 759
    }
  }
760
  // store data writeback logic mark store as data_writebacked
761 762 763
  for (wb <- stdWriteback) {
    when(RegNext(wb.valid)) {
      store_data_writebacked(RegNext(wb.bits.uop.robIdx.value)) := true.B
764 765
    }
  }
766 767 768 769

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
770
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
771
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
772 773 774
    }
  }

Y
Yinan Xu 已提交
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
  // interrupt_safe
  for (i <- 0 until RenameWidth) {
    // We RegNext the updates for better timing.
    // Note that instructions won't change the system's states in this cycle.
    when (RegNext(canEnqueue(i))) {
      // For now, we allow non-load-store instructions to trigger interrupts
      // 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.
      // TODO: support non-MMIO load-store instructions to trigger interrupts
      val allow_interrupts = !CommitType.isLoadStore(io.enq.req(i).bits.ctrl.commitType)
      interrupt_safe(RegNext(enqPtrVec(i).value)) := RegNext(allow_interrupts)
    }
  }
Y
Yinan Xu 已提交
790 791 792 793 794 795 796 797 798 799

  /**
    * 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)
800
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
801 802 803 804 805 806 807
    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 已提交
808 809
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
810 811 812 813
    wdata.pc := req.cf.pc
  }
  dispatchData.io.raddr := commitReadAddr_next

814 815 816 817
  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 已提交
818
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
819
    exceptionGen.io.enq(i).bits.exceptionVec := ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec)
820
    exceptionGen.io.enq(i).bits.flushPipe := io.enq.req(i).bits.ctrl.flushPipe
821
    exceptionGen.io.enq(i).bits.replayInst := io.enq.req(i).bits.ctrl.replayInst
W
William Wang 已提交
822
    assert(exceptionGen.io.enq(i).bits.replayInst === false.B)
823
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
824
    exceptionGen.io.enq(i).bits.crossPageIPFFix := io.enq.req(i).bits.cf.crossPageIPFFix
825
    exceptionGen.io.enq(i).bits.trigger := io.enq.req(i).bits.cf.trigger
Y
Yinan Xu 已提交
826
  }
827

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
  println(s"ExceptionGen:")
  val exceptionCases = exceptionPorts.map(_._1.flatMap(_.exceptionOut).distinct.sorted)
  require(exceptionCases.length == exceptionGen.io.wb.length)
  for ((((configs, wb), exc_wb), i) <- exceptionPorts.zip(exceptionGen.io.wb).zipWithIndex) {
    exc_wb.valid                := wb.valid
    exc_wb.bits.robIdx          := wb.bits.uop.robIdx
    exc_wb.bits.exceptionVec    := ExceptionNO.selectByExu(wb.bits.uop.cf.exceptionVec, configs)
    exc_wb.bits.flushPipe       := configs.exists(_.flushPipe).B && wb.bits.uop.ctrl.flushPipe
    exc_wb.bits.replayInst      := configs.exists(_.replayInst).B && wb.bits.uop.ctrl.replayInst
    exc_wb.bits.singleStep      := false.B
    exc_wb.bits.crossPageIPFFix := false.B
    // TODO: make trigger configurable
    exc_wb.bits.trigger         := wb.bits.uop.cf.trigger
    println(s"  [$i] ${configs.map(_.name)}: exception ${exceptionCases(i)}, " +
      s"flushPipe ${configs.exists(_.flushPipe)}, " +
      s"replayInst ${configs.exists(_.replayInst)}")
  }

  val fflags_wb = fflagsPorts.map(_._2)
847
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
848
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
849 850 851
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
852
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
853
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
854 855 856 857 858
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


859
  val instrCnt = RegInit(0.U(64.W))
860
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && CommitType.isFused(i.commitType) })
861 862 863 864
  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 已提交
865
  io.robFull := !allowEnqueue
866

867 868 869
  /**
    * debug info
    */
870
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
871
  XSDebug("")
Y
Yinan Xu 已提交
872
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
873 874 875
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
876
  }
Y
Yinan Xu 已提交
877 878
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
879
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
880
    if(i % 4 == 0) XSDebug("")
881
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
882 883 884 885
    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 已提交
886
  }
W
William Wang 已提交
887

888 889 890
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

  val commitDebugUop = deqPtrVec.map(_.value).map(debug_microOp(_))
891
  XSPerfAccumulate("clock_cycle", 1.U)
Y
Yinan Xu 已提交
892
  QueuePerf(RobSize, PopCount((0 until RobSize).map(valid(_))), !allowEnqueue)
893 894 895 896
  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 })))
897 898
  val commitMoveElim = commitDebugUop.map(_.debugInfo.eliminatedMove)
  XSPerfAccumulate("commitInstrMoveElim", ifCommit(PopCount(io.commits.valid zip commitMoveElim map { case (v, e) => v && e })))
899
  XSPerfAccumulate("commitInstrFused", ifCommit(fuseCommitCnt))
900 901
  val commitIsLoad = io.commits.info.map(_.commitType).map(_ === CommitType.LOAD)
  val commitLoadValid = io.commits.valid.zip(commitIsLoad).map{ case (v, t) => v && t }
902
  XSPerfAccumulate("commitInstrLoad", ifCommit(PopCount(commitLoadValid)))
W
William Wang 已提交
903 904 905
  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)))
906 907
  val commitLoadWaitBit = commitDebugUop.map(_.cf.loadWaitBit)
  XSPerfAccumulate("commitInstrLoadWait", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w })))
908
  val commitIsStore = io.commits.info.map(_.commitType).map(_ === CommitType.STORE)
909
  XSPerfAccumulate("commitInstrStore", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t })))
Y
Yinan Xu 已提交
910
  XSPerfAccumulate("writeback", PopCount((0 until RobSize).map(i => valid(i) && writebacked(i))))
911 912
  // XSPerfAccumulate("enqInstr", PopCount(io.dp1Req.map(_.fire())))
  // XSPerfAccumulate("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
913 914
  XSPerfAccumulate("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
  XSPerfAccumulate("walkCycle", state === s_walk || state === s_extrawalk)
915 916
  val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
  val deqUopCommitType = io.commits.info(0).commitType
917 918 919 920
  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 已提交
921
  XSPerfAccumulate("robHeadPC", io.commits.info(0).pc)
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
  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 已提交
950

951 952 953 954 955
  //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)))
956

957 958 959
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
960
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
961
  }
962
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
963 964
  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)
965

966
  if (env.EnableDifftest) {
967 968 969
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
J
Jiawei Lin 已提交
970
      difftest.io.coreid   := io.hartId
971 972 973
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
974
      val uop = commitDebugUop(i)
975 976 977 978 979
      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)
980
      difftest.io.special  := RegNext(CommitType.isFused(io.commits.info(i).commitType))
981 982 983
      // 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))
984 985 986 987
      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))
988 989
      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 已提交
990
      difftest.io.wdest    := RegNext(io.commits.info(i).ldest)
991

W
William Wang 已提交
992 993 994
      // runahead commit hint
      val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      runahead_commit.io.clock := clock
J
Jiawei Lin 已提交
995
      runahead_commit.io.coreid := io.hartId
W
William Wang 已提交
996 997 998 999 1000
      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
1001 1002
    }
  }
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
  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
      }
    }
1014 1015 1016 1017
    for (wb <- exuWriteback) {
      when (wb.valid) {
        val wbIdx = wb.bits.uop.robIdx.value
        dt_exuDebug(wbIdx) := wb.bits.debug
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
      }
    }
    // 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 已提交
1030
      difftest.io.coreid  := io.hartId
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
      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)
    }
  }
1041

1042
  if (env.EnableDifftest) {
1043 1044 1045
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
J
Jiawei Lin 已提交
1046
      difftest.io.coreid := io.hartId
1047 1048 1049
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
1050
      val uop = commitDebugUop(i)
1051
      val exuOut = debug_exuDebug(ptr)
W
wakafa 已提交
1052 1053 1054 1055
      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)
1056 1057 1058
    }
  }

1059
  // Always instantiate basic difftest modules.
1060
  if (env.EnableDifftest) {
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    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)
1071 1072
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1073
    difftest.io.coreid   := io.hartId
1074 1075 1076
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1077
    difftest.io.cycleCnt := timer
1078
    difftest.io.instrCnt := instrCnt
1079
  }
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
  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 已提交
1091
    difftest.io.coreid   := io.hartId
1092 1093 1094 1095
    difftest.io.valid    := hitTrap
    difftest.io.cycleCnt := timer
    difftest.io.instrCnt := instrCnt
  }
1096

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
  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)
  }
1124
}