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
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
  val trigger = new TriggerCf

168 169 170 171
  // trigger vec fix obtains the triggers that actually hits after considering chain and timing
  // this might not fit into the csr and current exception mechanism so these functions are merely demos of how triggers work
  def trigger_timing_match(i, j): Bool = trigger.triggerTiming(i) === trigger.triggerTiming(j)

172 173 174
  def trigger_vec_fix = VecInit(trigger.triggerHitVec.zipWithIndex.map{ case (hit, i) =>
    def chain = trigger.triggerChainVec(i / 2)
    if (i % 2 == 0)
175
      Mux(chain, trigger.triggerHitVec(i) && trigger.triggerHitVec(i + 1) && trigger_timing_match(i, i + 1), trigger.triggerHitVec(i))
176
    else
177
      Mux(chain, trigger.triggerHitVec(i) && trigger.triggerHitVec(i + 1) && trigger_timing_match(i, i - 1), trigger.triggerHitVec(i))
178 179 180 181
  })

  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(_ | _)
182

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

188
class ExceptionGen(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
189 190 191
  val io = IO(new Bundle {
    val redirect = Input(Valid(new Redirect))
    val flush = Input(Bool())
Y
Yinan Xu 已提交
192 193 194 195
    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)
196 197
  })

Y
Yinan Xu 已提交
198
  val current = Reg(Valid(new RobExceptionInfo))
199 200

  // orR the exceptionVec
201 202 203
  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)
204 205

  // s0: compare wb(1),wb(2) and wb(3),wb(4)
206
  val wb_valid = in_wb_valid.zip(io.wb.map(_.bits)).map{ case (v, bits) => v && !(bits.robIdx.needFlush(io.redirect) || io.flush) }
207
  val csr_wb_bits = io.wb(0).bits
Y
Yinan Xu 已提交
208 209
  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)
210 211 212 213
  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
214
  val s1_valid = VecInit(s0_out_valid.zip(s0_out_bits).map{ case (v, b) => v && !(b.robIdx.needFlush(io.redirect) || io.flush) })
215
  val compare_01_valid = s0_out_valid(0) || s0_out_valid(1)
Y
Yinan Xu 已提交
216 217
  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))
218 219 220
  val s1_out_bits = RegNext(compare_bits)
  val s1_out_valid = RegNext(s1_valid.asUInt.orR)

221
  val enq_valid = RegNext(in_enq_valid.asUInt.orR && !io.redirect.valid && !io.flush)
222 223 224 225 226 227 228
  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
229 230
  val current_flush = current.bits.robIdx.needFlush(io.redirect) || io.flush
  val s1_flush = s1_out_bits.robIdx.needFlush(io.redirect) || io.flush
231 232 233 234 235 236 237
  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 已提交
238
      when (isAfter(current.bits.robIdx, s1_out_bits.robIdx)) {
239
        current.bits := s1_out_bits
Y
Yinan Xu 已提交
240
      }.elsewhen (current.bits.robIdx === s1_out_bits.robIdx) {
241 242
        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 已提交
243
        current.bits.replayInst := s1_out_bits.replayInst || current.bits.replayInst
244
        current.bits.singleStep := s1_out_bits.singleStep || current.bits.singleStep
245
//        current.bits.trigger := (s1_out_bits.trigger.asUInt | current.bits.trigger.asUInt).asTypeOf(new TriggerCf)
246 247 248 249 250 251 252 253 254 255 256 257 258 259
      }
    }
  }.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

260 261
}

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

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

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

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

299
  // data for debug
300
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
301 302 303
  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 已提交
304

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

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

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

318
  val isEmpty = enqPtr === deqPtr
319
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
320

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

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

341 342
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
343
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
344

Y
Yinan Xu 已提交
345
  io.robDeqPtr := deqPtr
346

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

360
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
361
  io.enq.resp      := enqPtrVec
362
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
363
  val timer = GTimer()
Y
Yinan Xu 已提交
364
  for (i <- 0 until RenameWidth) {
365 366 367 368
    // 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
369 370 371 372 373
      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
374
      when (io.enq.req(i).bits.ctrl.blockBackward) {
375 376
        hasBlockBackward := true.B
      }
377
      when (io.enq.req(i).bits.ctrl.noSpecExec) {
378 379
        hasNoSpecExec := true.B
      }
H
happy-lx 已提交
380 381 382 383 384 385 386 387 388 389 390 391
      // 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 已提交
392 393
    }
  }
394 395
  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 已提交
396

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

W
William Wang 已提交
401

Y
Yinan Xu 已提交
402 403 404
  /**
    * Writeback (from execution units)
    */
405 406
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
407
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
408 409
      debug_microOp(wbIdx).cf.exceptionVec := io.exeWbResults(i).bits.uop.cf.exceptionVec
      debug_microOp(wbIdx).ctrl.flushPipe := io.exeWbResults(i).bits.uop.ctrl.flushPipe
410
      debug_microOp(wbIdx).ctrl.replayInst := io.exeWbResults(i).bits.uop.ctrl.replayInst
411
      debug_microOp(wbIdx).diffTestDebugLrScValid := io.exeWbResults(i).bits.uop.diffTestDebugLrScValid
412 413
      debug_exuData(wbIdx) := io.exeWbResults(i).bits.data
      debug_exuDebug(wbIdx) := io.exeWbResults(i).bits.debug
414 415
      debug_microOp(wbIdx).debugInfo.enqRsTime := io.exeWbResults(i).bits.uop.debugInfo.enqRsTime
      debug_microOp(wbIdx).debugInfo.selectTime := io.exeWbResults(i).bits.uop.debugInfo.selectTime
416 417
      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 已提交
418

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

W
William Wang 已提交
430

Y
Yinan Xu 已提交
431
  /**
432
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
433
    */
Y
Yinan Xu 已提交
434
  val deqDispatchData = dispatchDataRead(0)
435 436 437 438 439
  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 已提交
440
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
441
  val intrEnable = intrBitSetReg && !hasNoSpecExec && !CommitType.isLoadStore(deqDispatchData.commitType)
Y
Yinan Xu 已提交
442
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
443 444
  val triggerBefore = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_before
  val triggerAfter = deqHasExceptionOrFlush && exceptionDataRead.bits.trigger_after && !exceptionDataRead.bits.trigger_before
445
  val deqHasException = deqHasExceptionOrFlush && exceptionDataRead.bits.exceptionVec.asUInt.orR
446
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
447
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
448 449 450
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException// && triggerBefore

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

452 453 454 455 456 457 458
  // 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
459 460
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
461 462
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter)
  io.flushOut.bits.interrupt := true.B
463 464 465 466
  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)
467

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

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

483

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

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

L
linjiawei 已提交
502
  // wiring to csr
503 504 505 506 507 508 509
  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())
510
  fflags.bits := wflags.zip(fflagsDataRead).map({
511 512 513
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
514

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

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

542 543 544
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
545 546
      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 已提交
547
    }
548 549 550 551 552 553 554 555 556

    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),
557
      fflagsDataRead(i)
558 559 560 561 562 563 564 565 566 567 568
    )
    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 已提交
569
  }
570
  if (env.EnableDifftest) {
571
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
572
  }
W
William Wang 已提交
573

574
  // sync fflags/dirty_fs to csr
575 576
  io.csr.fflags := fflags
  io.csr.dirty_fs := dirty_fs
577

578 579 580
  // 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 已提交
581

582 583 584
  // 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))
585 586 587 588 589
  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))
590 591 592

  /**
    * state changes
Y
Yinan Xu 已提交
593 594 595 596
    * (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
597
    */
598 599 600 601 602
  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 已提交
603 604 605
    )
  )
  state := state_next
606

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

  deqPtrGenModule.io.misPredBlock := misPredBlock
620
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
621
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
622
  val deqPtrVec_next = deqPtrGenModule.io.next_out
623

Y
Yinan Xu 已提交
624
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
625 626 627 628 629
  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
630 631

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
632 633 634 635 636
  // 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,
637 638
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
639 640 641 642
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
643

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

652 653 654
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
655 656
  )

657
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
658
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
659 660
  when (io.redirect.valid) {
    walkCounter := Mux(state === s_walk,
661 662 663 664 665 666 667 668 669 670
      // 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()
671 672 673 674
    )
  }.elsewhen (state === s_walk) {
    walkCounter := walkCounter - commitCnt
    XSInfo(p"rolling back: $enqPtr $deqPtr walk $walkPtr walkcnt $walkCounter\n")
675 676
  }

677

Y
Yinan Xu 已提交
678 679
  /**
    * States
680
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
681

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

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

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

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

Y
Yinan Xu 已提交
746 747 748 749 750 751 752 753 754 755

  /**
    * 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)
756
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
757 758 759 760 761 762 763
    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 已提交
764 765
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
766 767 768 769
    wdata.pc := req.cf.pc
  }
  dispatchData.io.raddr := commitReadAddr_next

770 771 772 773
  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 已提交
774
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
775 776
    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
777
    exceptionGen.io.enq(i).bits.replayInst := io.enq.req(i).bits.ctrl.replayInst
W
William Wang 已提交
778
    assert(exceptionGen.io.enq(i).bits.replayInst === false.B)
779
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
780
    exceptionGen.io.enq(i).bits.crossPageIPFFix := io.enq.req(i).bits.cf.crossPageIPFFix
781
    exceptionGen.io.enq(i).bits.trigger := io.enq.req(i).bits.cf.trigger
Y
Yinan Xu 已提交
782
  }
783 784

  // TODO: don't hard code these idxes
785
  val numIntWbPorts = exuParameters.AluCnt + exuParameters.LduCnt + exuParameters.MduCnt
786 787 788 789
  // 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
790
  def store_wb_idxes = io.exeWbResults.indices.takeRight(2)
791
  val all_exception_possibilities = Seq(csr_wb_idx, atomic_wb_idx) ++ load_wb_idxes ++ store_wb_idxes
792
  all_exception_possibilities.zipWithIndex.foreach{ case (p, i) => connect_exception(i, p) }
793 794
  def connect_exception(index: Int, wb_index: Int) = {
    exceptionGen.io.wb(index).valid             := io.exeWbResults(wb_index).valid
795 796 797 798 799 800 801
    // A temporary fix for float load writeback
    // TODO: let int/fp load use the same two wb ports
    if (wb_index == atomic_wb_idx || load_wb_idxes.contains(wb_index)) {
      when (io.exeWbResults(wb_index - exuParameters.AluCnt + numIntWbPorts + exuParameters.FmacCnt).valid) {
        exceptionGen.io.wb(index).valid := true.B
      }
    }
Y
Yinan Xu 已提交
802
    exceptionGen.io.wb(index).bits.robIdx       := io.exeWbResults(wb_index).bits.uop.robIdx
803 804 805 806 807 808 809
    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 _
    }
810 811 812 813 814
    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
815
    exceptionGen.io.wb(index).bits.trigger := io.exeWbResults(wb_index).bits.uop.cf.trigger
816
  }
Y
Yinan Xu 已提交
817

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


837
  val instrCnt = RegInit(0.U(64.W))
838
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && CommitType.isFused(i.commitType) })
839 840 841 842
  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 已提交
843
  io.robFull := !allowEnqueue
844

845 846 847
  /**
    * debug info
    */
848
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
849
  XSDebug("")
Y
Yinan Xu 已提交
850
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
851 852 853
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
854
  }
Y
Yinan Xu 已提交
855 856
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
857
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
858
    if(i % 4 == 0) XSDebug("")
859
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
860 861 862 863
    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 已提交
864
  }
W
William Wang 已提交
865

866 867 868
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

  val commitDebugUop = deqPtrVec.map(_.value).map(debug_microOp(_))
869
  XSPerfAccumulate("clock_cycle", 1.U)
Y
Yinan Xu 已提交
870
  QueuePerf(RobSize, PopCount((0 until RobSize).map(valid(_))), !allowEnqueue)
871 872 873 874
  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 })))
875 876
  val commitMoveElim = commitDebugUop.map(_.debugInfo.eliminatedMove)
  XSPerfAccumulate("commitInstrMoveElim", ifCommit(PopCount(io.commits.valid zip commitMoveElim map { case (v, e) => v && e })))
877
  XSPerfAccumulate("commitInstrFused", ifCommit(fuseCommitCnt))
878 879
  val commitIsLoad = io.commits.info.map(_.commitType).map(_ === CommitType.LOAD)
  val commitLoadValid = io.commits.valid.zip(commitIsLoad).map{ case (v, t) => v && t }
880
  XSPerfAccumulate("commitInstrLoad", ifCommit(PopCount(commitLoadValid)))
W
William Wang 已提交
881 882 883
  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)))
884 885
  val commitLoadWaitBit = commitDebugUop.map(_.cf.loadWaitBit)
  XSPerfAccumulate("commitInstrLoadWait", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w })))
886
  val commitIsStore = io.commits.info.map(_.commitType).map(_ === CommitType.STORE)
887
  XSPerfAccumulate("commitInstrStore", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t })))
Y
Yinan Xu 已提交
888
  XSPerfAccumulate("writeback", PopCount((0 until RobSize).map(i => valid(i) && writebacked(i))))
889 890
  // XSPerfAccumulate("enqInstr", PopCount(io.dp1Req.map(_.fire())))
  // XSPerfAccumulate("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
891 892
  XSPerfAccumulate("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
  XSPerfAccumulate("walkCycle", state === s_walk || state === s_extrawalk)
893 894
  val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
  val deqUopCommitType = io.commits.info(0).commitType
895 896 897 898
  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 已提交
899
  XSPerfAccumulate("robHeadPC", io.commits.info(0).pc)
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
  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 已提交
928

929 930 931 932 933
  //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)))
934

935 936 937
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
938
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
939
  }
940
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
941 942
  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)
943

944
  if (env.EnableDifftest) {
945 946 947
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
J
Jiawei Lin 已提交
948
      difftest.io.coreid   := io.hartId
949 950 951
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
952
      val uop = commitDebugUop(i)
953 954 955 956 957
      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)
958
      difftest.io.special  := RegNext(CommitType.isFused(io.commits.info(i).commitType))
959 960 961
      // 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))
962 963 964 965
      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))
966 967
      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 已提交
968
      difftest.io.wdest    := RegNext(io.commits.info(i).ldest)
969

W
William Wang 已提交
970 971 972
      // runahead commit hint
      val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      runahead_commit.io.clock := clock
J
Jiawei Lin 已提交
973
      runahead_commit.io.coreid := io.hartId
W
William Wang 已提交
974 975 976 977 978
      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
979 980
    }
  }
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
  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 已提交
1008
      difftest.io.coreid  := io.hartId
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
      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)
    }
  }
1019

1020
  if (env.EnableDifftest) {
1021 1022 1023
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
J
Jiawei Lin 已提交
1024
      difftest.io.coreid := io.hartId
1025 1026 1027
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
1028
      val uop = commitDebugUop(i)
1029
      val exuOut = debug_exuDebug(ptr)
W
wakafa 已提交
1030 1031 1032 1033
      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)
1034 1035 1036
    }
  }

1037
  // Always instantiate basic difftest modules.
1038
  if (env.EnableDifftest) {
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    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)
1049 1050
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1051
    difftest.io.coreid   := io.hartId
1052 1053 1054
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1055
    difftest.io.cycleCnt := timer
1056
    difftest.io.instrCnt := instrCnt
1057
  }
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
  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 已提交
1069
    difftest.io.coreid   := io.hartId
1070 1071 1072 1073
    difftest.io.valid    := hitTrap
    difftest.io.cycleCnt := timer
    difftest.io.instrCnt := instrCnt
  }
1074

1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
  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)
  }
1102
}