Rob.scala 52.8 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 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 67 68
  val pendingld = Output(Bool())
  val pendingst = Output(Bool())
  val commit = Output(Bool())
}

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

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

Y
Yinan Xu 已提交
80
class RobDeqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
Y
Yinan Xu 已提交
81
  val io = IO(new Bundle {
Y
Yinan Xu 已提交
82 83 84 85
    // 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 已提交
86
    val exception_state = Flipped(ValidIO(new RobExceptionInfo))
Y
Yinan Xu 已提交
87 88 89
    // for flush: when exception occurs, reset deqPtrs to range(0, CommitWidth)
    val intrBitSetReg = Input(Bool())
    val hasNoSpecExec = Input(Bool())
Y
Yinan Xu 已提交
90
    val interrupt_safe = Input(Bool())
L
LinJiawei 已提交
91
    val misPredBlock = Input(Bool())
92
    val isReplaying = Input(Bool())
Y
Yinan Xu 已提交
93
    val hasWFI = 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) || io.hasWFI)
104
  val exceptionEnable = io.deq_w(0) && io.exception_state.valid && io.exception_state.bits.not_commit && 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)
Y
Yinan Xu 已提交
110
  val canCommit = VecInit((0 until CommitWidth).map(i => io.deq_v(i) && io.deq_w(i) && !io.misPredBlock && !io.isReplaying && !io.hasWFI))
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
L
Li Qianruo 已提交
164
  val singleStep = Bool() // TODO add frontend hit beneath
165
  val crossPageIPFFix = Bool()
166 167
  val trigger = new TriggerCf

L
Li Qianruo 已提交
168 169
//  def trigger_before = !trigger.getTimingBackend && trigger.getHitBackend
//  def trigger_after = trigger.getTimingBackend && trigger.getHitBackend
L
Li Qianruo 已提交
170
  def has_exception = exceptionVec.asUInt.orR || flushPipe || singleStep || replayInst || trigger.hit
171
  def not_commit = exceptionVec.asUInt.orR || singleStep || replayInst || trigger.hit
172
  // only exceptions are allowed to writeback when enqueue
L
Li Qianruo 已提交
173
  def can_writeback = exceptionVec.asUInt.orR || singleStep || trigger.hit
174 175
}

176
class ExceptionGen(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
177 178 179
  val io = IO(new Bundle {
    val redirect = Input(Valid(new Redirect))
    val flush = Input(Bool())
Y
Yinan Xu 已提交
180 181 182 183
    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)
184 185
  })

Y
Yinan Xu 已提交
186
  val current = Reg(Valid(new RobExceptionInfo))
187 188

  // orR the exceptionVec
189 190 191
  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)
192 193

  // s0: compare wb(1),wb(2) and wb(3),wb(4)
194
  val wb_valid = in_wb_valid.zip(io.wb.map(_.bits)).map{ case (v, bits) => v && !(bits.robIdx.needFlush(io.redirect) || io.flush) }
195
  val csr_wb_bits = io.wb(0).bits
Y
Yinan Xu 已提交
196 197
  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)
198 199 200 201
  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
202
  val s1_valid = VecInit(s0_out_valid.zip(s0_out_bits).map{ case (v, b) => v && !(b.robIdx.needFlush(io.redirect) || io.flush) })
203
  val compare_01_valid = s0_out_valid(0) || s0_out_valid(1)
Y
Yinan Xu 已提交
204 205
  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))
206 207 208
  val s1_out_bits = RegNext(compare_bits)
  val s1_out_valid = RegNext(s1_valid.asUInt.orR)

209
  val enq_valid = RegNext(in_enq_valid.asUInt.orR && !io.redirect.valid && !io.flush)
210 211 212 213 214 215 216
  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
217 218
  val current_flush = current.bits.robIdx.needFlush(io.redirect) || io.flush
  val s1_flush = s1_out_bits.robIdx.needFlush(io.redirect) || io.flush
219 220 221 222 223 224 225
  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 已提交
226
      when (isAfter(current.bits.robIdx, s1_out_bits.robIdx)) {
227
        current.bits := s1_out_bits
Y
Yinan Xu 已提交
228
      }.elsewhen (current.bits.robIdx === s1_out_bits.robIdx) {
229 230
        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 已提交
231
        current.bits.replayInst := s1_out_bits.replayInst || current.bits.replayInst
232
        current.bits.singleStep := s1_out_bits.singleStep || current.bits.singleStep
L
Li Qianruo 已提交
233
        current.bits.trigger := (s1_out_bits.trigger.asUInt | current.bits.trigger.asUInt).asTypeOf(new TriggerCf)
234 235 236 237 238 239 240 241 242 243 244 245 246 247
      }
    }
  }.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

248 249
}

Y
Yinan Xu 已提交
250
class RobFlushInfo(implicit p: Parameters) extends XSBundle {
251
  val ftqIdx = new FtqPtr
252
  val robIdx = new RobPtr
253
  val ftqOffset = UInt(log2Up(PredictWidth).W)
W
William Wang 已提交
254
  val replayInst = Bool()
255 256
}

257 258 259 260 261 262 263 264 265 266 267 268 269 270
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)
271
  with HasXSParameter with HasCircularQueuePtrHelper with HasPerfEvents {
272 273 274
  val wbExuConfigs = outer.writebackSinksParams.map(_.exuConfigs)
  val numWbPorts = wbExuConfigs.map(_.length)

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

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
  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)
310

311
  // instvalid field
Y
Yinan Xu 已提交
312
  val valid = Mem(RobSize, Bool())
313
  // writeback status
Y
Yinan Xu 已提交
314 315
  val writebacked = Mem(RobSize, Bool())
  val store_data_writebacked = Mem(RobSize, Bool())
316
  // data for redirect, exception, etc.
Y
Yinan Xu 已提交
317
  val flagBkup = Mem(RobSize, Bool())
Y
Yinan Xu 已提交
318 319 320
  // 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())
321

322
  // data for debug
323
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
324 325 326
  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 已提交
327

328 329
  // pointers
  // For enqueue ptr, we don't duplicate it since only enqueue needs it.
Y
Yinan Xu 已提交
330 331
  val enqPtr = Wire(new RobPtr)
  val deqPtrVec = Wire(Vec(CommitWidth, new RobPtr))
Y
Yinan Xu 已提交
332

Y
Yinan Xu 已提交
333 334
  val walkPtrVec = Reg(Vec(CommitWidth, new RobPtr))
  val validCounter = RegInit(0.U(log2Ceil(RobSize + 1).W))
335
  val allowEnqueue = RegInit(true.B)
336 337 338 339

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

341
  val isEmpty = enqPtr === deqPtr
342
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
343

344
  /**
Y
Yinan Xu 已提交
345
    * states of Rob
346
    */
W
William Wang 已提交
347
  val s_idle :: s_walk :: s_extrawalk :: Nil = Enum(3)
W
William Wang 已提交
348 349
  val state = RegInit(s_idle)

Y
Yinan Xu 已提交
350
  /**
351 352 353 354
    * Data Modules
    *
    * CommitDataModule: data from dispatch
    * (1) read: commits/walk/exception
Y
Yinan Xu 已提交
355
    * (2) write: enqueue
356 357 358 359
    *
    * WritebackData: data from writeback
    * (1) read: commits/walk/exception
    * (2) write: write back from exe units
Y
Yinan Xu 已提交
360
    */
Y
Yinan Xu 已提交
361
  val dispatchData = Module(new SyncDataModuleTemplate(new RobDispatchData, RobSize, CommitWidth, RenameWidth))
Y
Yinan Xu 已提交
362 363
  val dispatchDataRead = dispatchData.io.rdata

364 365
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
366
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
367

Y
Yinan Xu 已提交
368
  io.robDeqPtr := deqPtr
369

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

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

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

W
William Wang 已提交
439

Y
Yinan Xu 已提交
440 441 442
  /**
    * Writeback (from execution units)
    */
443 444 445 446 447 448 449 450 451
  for (wb <- exuWriteback) {
    when (wb.valid) {
      val wbIdx = wb.bits.uop.robIdx.value
      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 已提交
452

453
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
454
      XSInfo(true.B,
455
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
456 457
        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"
458
      )
W
William Wang 已提交
459 460
    }
  }
461
  val writebackNum = PopCount(exuWriteback.map(_.valid))
462 463
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
464

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

Y
Yinan Xu 已提交
471
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
Y
Yinan Xu 已提交
472
  val intrEnable = intrBitSetReg && ((!hasNoSpecExec && interrupt_safe(deqPtr.value)) || hasWFI)
Y
Yinan Xu 已提交
473
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
L
Li Qianruo 已提交
474
  val deqHasException = deqHasExceptionOrFlush && (exceptionDataRead.bits.exceptionVec.asUInt.orR ||
L
Li Qianruo 已提交
475
    exceptionDataRead.bits.singleStep || exceptionDataRead.bits.trigger.hit)
476
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
477
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
L
Li Qianruo 已提交
478 479 480
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException

  XSDebug(deqHasException && exceptionDataRead.bits.singleStep, "Debug Mode: Deq has singlestep exception\n")
L
Li Qianruo 已提交
481
  XSDebug(deqHasException && exceptionDataRead.bits.trigger.getHitFrontend, "Debug Mode: Deq has frontend trigger exception\n")
L
Li Qianruo 已提交
482
  XSDebug(deqHasException && exceptionDataRead.bits.trigger.getHitBackend, "Debug Mode: Deq has backend trigger exception\n")
483

L
Li Qianruo 已提交
484
  val isFlushPipe = writebacked(deqPtr.value) && (deqHasFlushPipe || deqHasReplayInst)
485

486 487 488 489 490 491 492
  // 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
493 494
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
L
Li Qianruo 已提交
495
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter) // TODO use this to implement "exception next"
496
  io.flushOut.bits.interrupt := true.B
497 498 499 500
  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)
501

502
  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable) && !lastCycleFlush
503 504 505
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
506
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
507
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
508
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(exceptionDataRead.bits.crossPageIPFFix, exceptionHappen)
509
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
L
Li Qianruo 已提交
510
  io.exception.bits.uop.cf.trigger := RegEnable(exceptionDataRead.bits.trigger, exceptionHappen)
511 512 513

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

517

Y
Yinan Xu 已提交
518 519 520 521
  /**
    * Commits (and walk)
    * They share the same width.
    */
522
  val walkCounter = Reg(UInt(log2Up(RobSize + 1).W))
523
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
524
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
525

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

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

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

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

576 577 578
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
579 580
      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 已提交
581
    }
582 583 584 585 586 587 588 589 590

    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),
591
      fflagsDataRead(i)
592 593 594 595 596 597 598 599 600 601 602
    )
    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 已提交
603
  }
604
  if (env.EnableDifftest) {
605
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
606
  }
W
William Wang 已提交
607

608
  // sync fflags/dirty_fs to csr
L
Li Qianruo 已提交
609 610
  io.csr.fflags := RegNext(fflags)
  io.csr.dirty_fs := RegNext(dirty_fs)
611

612 613 614
  // 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 已提交
615

616 617 618
  // 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))
619 620 621 622 623
  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))
624 625 626

  /**
    * state changes
Y
Yinan Xu 已提交
627 628 629 630
    * (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
631
    */
632 633 634 635 636
  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 已提交
637 638 639
    )
  )
  state := state_next
640

641
  /**
642
    * pointers and counters
643
    */
Y
Yinan Xu 已提交
644
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
645 646 647
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
648
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
649 650
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
Y
Yinan Xu 已提交
651
  deqPtrGenModule.io.interrupt_safe := interrupt_safe(deqPtr.value)
L
LinJiawei 已提交
652
  deqPtrGenModule.io.misPredBlock := misPredBlock
653
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
654
  deqPtrGenModule.io.hasWFI := hasWFI
Y
Yinan Xu 已提交
655
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
656
  val deqPtrVec_next = deqPtrGenModule.io.next_out
657

Y
Yinan Xu 已提交
658
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
659 660 661 662 663
  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
664 665

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

678
  val lastCycleRedirect = RegNext(io.redirect.valid)
679
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
680
  val commitCnt = PopCount(io.commits.valid)
681 682 683
  validCounter := Mux(state === s_idle,
    (validCounter - commitCnt) + dispatchNum,
    trueValidCounter
684 685
  )

686 687 688
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
689 690
  )

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

711

Y
Yinan Xu 已提交
712 713
  /**
    * States
714
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
715

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

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

740 741 742
  // status field: writebacked
  // enqueue logic set 6 writebacked to false
  for (i <- 0 until RenameWidth) {
743
    when (canEnqueue(i)) {
744 745
      val enqHasException = ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec).asUInt.orR
      val enqHasTriggerHit = io.enq.req(i).bits.cf.trigger.getHitFrontend
Y
Yinan Xu 已提交
746 747
      val enqIsWritebacked = io.enq.req(i).bits.eliminatedMove || io.enq.req(i).bits.ctrl.isWFI
      writebacked(enqPtrVec(i).value) := enqIsWritebacked && !enqHasException && !enqHasTriggerHit
748 749
      val isStu = io.enq.req(i).bits.ctrl.fuType === FuType.stu
      store_data_writebacked(enqPtrVec(i).value) := !isStu
750 751
    }
  }
752
  when (exceptionGen.io.out.valid) {
Y
Yinan Xu 已提交
753
    val wbIdx = exceptionGen.io.out.bits.robIdx.value
754
    writebacked(wbIdx) := true.B
755
    store_data_writebacked(wbIdx) := true.B
756
  }
Y
Yinan Xu 已提交
757
  // writeback logic set numWbPorts writebacked to true
758 759 760 761
  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
762
      val wbHasTriggerHit = wb.bits.uop.cf.trigger.getHitBackend
763 764
      val wbHasFlushPipe = cfgs.exists(_.flushPipe).B && wb.bits.uop.ctrl.flushPipe
      val wbHasReplayInst = cfgs.exists(_.replayInst).B && wb.bits.uop.ctrl.replayInst
765
      val block_wb = wbHasException || wbHasFlushPipe || wbHasReplayInst || wbHasTriggerHit
766
      writebacked(wbIdx) := !block_wb
767 768
    }
  }
769
  // store data writeback logic mark store as data_writebacked
770 771 772
  for (wb <- stdWriteback) {
    when(RegNext(wb.valid)) {
      store_data_writebacked(RegNext(wb.bits.uop.robIdx.value)) := true.B
773 774
    }
  }
775 776 777 778

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
779
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
780
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
781 782 783
    }
  }

Y
Yinan Xu 已提交
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
  // 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 已提交
799 800 801 802 803 804 805 806 807 808

  /**
    * 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)
809
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
810 811 812 813 814 815 816
    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 已提交
817 818
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
819 820 821 822
    wdata.pc := req.cf.pc
  }
  dispatchData.io.raddr := commitReadAddr_next

823 824 825 826
  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 已提交
827
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
828
    exceptionGen.io.enq(i).bits.exceptionVec := ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec)
829
    exceptionGen.io.enq(i).bits.flushPipe := io.enq.req(i).bits.ctrl.flushPipe
830 831
    exceptionGen.io.enq(i).bits.replayInst := false.B
    assert(io.enq.req(i).bits.ctrl.replayInst === false.B)
832
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
833
    exceptionGen.io.enq(i).bits.crossPageIPFFix := io.enq.req(i).bits.cf.crossPageIPFFix
834 835
    exceptionGen.io.enq(i).bits.trigger.clear()
    exceptionGen.io.enq(i).bits.trigger.frontendHit := io.enq.req(i).bits.cf.trigger.frontendHit
Y
Yinan Xu 已提交
836
  }
837

838 839 840 841 842 843 844 845 846 847 848 849
  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
850 851
    exc_wb.bits.trigger.clear()
    exc_wb.bits.trigger.backendHit := wb.bits.uop.cf.trigger.backendHit
852 853 854
    println(s"  [$i] ${configs.map(_.name)}: exception ${exceptionCases(i)}, " +
      s"flushPipe ${configs.exists(_.flushPipe)}, " +
      s"replayInst ${configs.exists(_.replayInst)}")
855
  }
Y
Yinan Xu 已提交
856

857
  val fflags_wb = fflagsPorts.map(_._2)
858
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
859
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
860 861 862
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
863
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
864
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
865 866 867 868 869
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


870
  val instrCnt = RegInit(0.U(64.W))
871
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && CommitType.isFused(i.commitType) })
872 873 874 875
  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 已提交
876
  io.robFull := !allowEnqueue
877

878 879 880
  /**
    * debug info
    */
881
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
882
  XSDebug("")
Y
Yinan Xu 已提交
883
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
884 885 886
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
887
  }
Y
Yinan Xu 已提交
888 889
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
890
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
891
    if(i % 4 == 0) XSDebug("")
892
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
893 894 895 896
    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 已提交
897
  }
W
William Wang 已提交
898

899 900 901
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

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

962 963 964 965 966
  //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)))
967

968 969 970
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
971
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
972
  }
973
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
974 975
  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)
976

977
  if (env.EnableDifftest) {
978 979 980
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
J
Jiawei Lin 已提交
981
      difftest.io.coreid   := io.hartId
982 983 984
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
985
      val uop = commitDebugUop(i)
986 987
      val exuOut = debug_exuDebug(ptr)
      val exuData = debug_exuData(ptr)
988 989 990 991
      difftest.io.valid    := RegNext(RegNext(RegNext(io.commits.valid(i) && !io.commits.isWalk)))
      difftest.io.pc       := RegNext(RegNext(RegNext(SignExt(uop.cf.pc, XLEN))))
      difftest.io.instr    := RegNext(RegNext(RegNext(uop.cf.instr)))
      difftest.io.special  := RegNext(RegNext(RegNext(CommitType.isFused(io.commits.info(i).commitType))))
992 993
      // when committing an eliminated move instruction,
      // we must make sure that skip is properly set to false (output from EXU is random value)
994 995
      difftest.io.skip     := RegNext(RegNext(RegNext(Mux(uop.eliminatedMove, false.B, exuOut.isMMIO || exuOut.isPerfCnt))))
      difftest.io.isRVC    := RegNext(RegNext(RegNext(uop.cf.pd.isRVC)))
W
wakafa 已提交
996 997
      difftest.io.rfwen    := RegNext(RegNext(RegNext(io.commits.valid(i) && io.commits.info(i).rfWen && io.commits.info(i).ldest =/= 0.U)))
      difftest.io.fpwen    := RegNext(RegNext(RegNext(io.commits.valid(i) && io.commits.info(i).fpWen)))
998 999
      difftest.io.wpdest   := RegNext(RegNext(RegNext(io.commits.info(i).pdest)))
      difftest.io.wdest    := RegNext(RegNext(RegNext(io.commits.info(i).ldest)))
1000

W
William Wang 已提交
1001 1002 1003
      // runahead commit hint
      val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      runahead_commit.io.clock := clock
J
Jiawei Lin 已提交
1004
      runahead_commit.io.coreid := io.hartId
W
William Wang 已提交
1005 1006 1007 1008 1009
      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
1010 1011
    }
  }
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
  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
      }
    }
1023 1024 1025 1026
    for (wb <- exuWriteback) {
      when (wb.valid) {
        val wbIdx = wb.bits.uop.robIdx.value
        dt_exuDebug(wbIdx) := wb.bits.debug
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
      }
    }
    // 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 已提交
1039
      difftest.io.coreid  := io.hartId
1040
      difftest.io.index   := i.U
1041 1042 1043 1044
      difftest.io.valid   := RegNext(RegNext(RegNext(io.commits.valid(i) && !io.commits.isWalk)))
      difftest.io.special := RegNext(RegNext(RegNext(CommitType.isFused(commitInfo.commitType))))
      difftest.io.skip    := RegNext(RegNext(RegNext(Mux(eliminatedMove, false.B, exuOut.isMMIO || exuOut.isPerfCnt))))
      difftest.io.isRVC   := RegNext(RegNext(RegNext(isRVC)))
W
wakafa 已提交
1045 1046
      difftest.io.rfwen   := RegNext(RegNext(RegNext(io.commits.valid(i) && commitInfo.rfWen && commitInfo.ldest =/= 0.U)))
      difftest.io.fpwen   := RegNext(RegNext(RegNext(io.commits.valid(i) && commitInfo.fpWen)))
1047 1048
      difftest.io.wpdest  := RegNext(RegNext(RegNext(commitInfo.pdest)))
      difftest.io.wdest   := RegNext(RegNext(RegNext(commitInfo.ldest)))
1049 1050
    }
  }
1051

1052
  if (env.EnableDifftest) {
1053 1054 1055
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
J
Jiawei Lin 已提交
1056
      difftest.io.coreid := io.hartId
1057 1058 1059
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
1060
      val uop = commitDebugUop(i)
1061
      val exuOut = debug_exuDebug(ptr)
1062 1063 1064 1065
      difftest.io.valid  := RegNext(RegNext(RegNext(io.commits.valid(i) && !io.commits.isWalk)))
      difftest.io.paddr  := RegNext(RegNext(RegNext(exuOut.paddr)))
      difftest.io.opType := RegNext(RegNext(RegNext(uop.ctrl.fuOpType)))
      difftest.io.fuType := RegNext(RegNext(RegNext(uop.ctrl.fuType)))
1066 1067 1068
    }
  }

1069
  // Always instantiate basic difftest modules.
1070
  if (env.EnableDifftest) {
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
    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)
1081 1082
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1083
    difftest.io.coreid   := io.hartId
1084 1085 1086
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1087
    difftest.io.cycleCnt := timer
1088
    difftest.io.instrCnt := instrCnt
1089
  }
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
  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 已提交
1101
    difftest.io.coreid   := io.hartId
1102 1103 1104 1105
    difftest.io.valid    := hitTrap
    difftest.io.cycleCnt := timer
    difftest.io.instrCnt := instrCnt
  }
1106

1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
  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)                                                                                       ),
1122 1123 1124 1125
    ("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))                                                                 ),
1126
  )
1127
  generatePerfEvent()
1128
}