Rob.scala 54.3 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))
Y
Yinan Xu 已提交
52 53
  val isXRet     = Input(Bool())
  val wfiEvent   = Input(Bool())
Y
Yinan Xu 已提交
54

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

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

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

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

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

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

  // for exceptions (flushPipe included) and interrupts:
  // only consider the first instruction
Y
Yinan Xu 已提交
104
  val intrEnable = io.intrBitSetReg && !io.hasNoSpecExec && io.interrupt_safe
105
  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 已提交
106 107 108 109
  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 已提交
110
  val commit_exception = io.exception_state.valid && !isAfter(io.exception_state.bits.robIdx, deqPtrVec.last)
Y
Yinan Xu 已提交
111
  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 已提交
112
  val normalCommitCnt = PriorityEncoder(canCommit.map(c => !c) :+ true.B)
113 114
  // when io.intrBitSetReg or there're possible exceptions in these instructions,
  // only one instruction is allowed to commit
115
  val allowOnlyOne = commit_exception || io.intrBitSetReg
116
  val commitCnt = Mux(allowOnlyOne, canCommit(0), normalCommitCnt)
Y
Yinan Xu 已提交
117

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

  deqPtrVec := deqPtrVec_next

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

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

}

Y
Yinan Xu 已提交
132
class RobEnqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
Y
Yinan Xu 已提交
133 134 135 136 137 138 139
  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 已提交
140
    val out = Output(new RobPtr)
Y
Yinan Xu 已提交
141 142
  })

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

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

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

  io.out := enqPtr

Y
Yinan Xu 已提交
157 158
}

Y
Yinan Xu 已提交
159
class RobExceptionInfo(implicit p: Parameters) extends XSBundle {
160
  // val valid = Bool()
Y
Yinan Xu 已提交
161
  val robIdx = new RobPtr
162 163
  val exceptionVec = ExceptionVec()
  val flushPipe = Bool()
W
William Wang 已提交
164
  val replayInst = Bool() // redirect to that inst itself
L
Li Qianruo 已提交
165
  val singleStep = Bool() // TODO add frontend hit beneath
166
  val crossPageIPFFix = Bool()
167 168
  val trigger = new TriggerCf

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

177
class ExceptionGen(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
178 179 180
  val io = IO(new Bundle {
    val redirect = Input(Valid(new Redirect))
    val flush = Input(Bool())
Y
Yinan Xu 已提交
181
    val enq = Vec(RenameWidth, Flipped(ValidIO(new RobExceptionInfo)))
182
    val wb = Vec(1 + LoadPipelineWidth + StorePipelineWidth, Flipped(ValidIO(new RobExceptionInfo)))
Y
Yinan Xu 已提交
183 184
    val out = ValidIO(new RobExceptionInfo)
    val state = ValidIO(new RobExceptionInfo)
185 186
  })

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  def getOldest(valid: Seq[Bool], bits: Seq[RobExceptionInfo]): (Seq[Bool], Seq[RobExceptionInfo]) = {
    assert(valid.length == bits.length)
    assert(isPow2(valid.length))
    if (valid.length == 1) {
      (valid, bits)
    } else if (valid.length == 2) {
      val res = Seq.fill(2)(Wire(ValidIO(chiselTypeOf(bits(0)))))
      for (i <- res.indices) {
        res(i).valid := valid(i)
        res(i).bits := bits(i)
      }
      val oldest = Mux(!valid(1) || valid(0) && isAfter(bits(1).robIdx, bits(0).robIdx), res(0), res(1))
      (Seq(oldest.valid), Seq(oldest.bits))
    } else {
      val left = getOldest(valid.take(valid.length / 2), bits.take(valid.length / 2))
      val right = getOldest(valid.takeRight(valid.length / 2), bits.takeRight(valid.length / 2))
      getOldest(left._1 ++ right._1, left._2 ++ right._2)
    }
  }

Y
Yinan Xu 已提交
207
  val current = Reg(Valid(new RobExceptionInfo))
208 209

  // orR the exceptionVec
210 211 212
  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)
213

214
  // s0: compare wb(1)~wb(LoadPipelineWidth) and wb(1 + LoadPipelineWidth)~wb(LoadPipelineWidth + StorePipelineWidth)
215
  val wb_valid = in_wb_valid.zip(io.wb.map(_.bits)).map{ case (v, bits) => v && !(bits.robIdx.needFlush(io.redirect) || io.flush) }
216
  val csr_wb_bits = io.wb(0).bits
217 218 219
  val load_wb_bits = getOldest(in_wb_valid.slice(1, 1 + LoadPipelineWidth), io.wb.map(_.bits).slice(1, 1 + LoadPipelineWidth))._2(0)
  val store_wb_bits = getOldest(in_wb_valid.slice(1 + LoadPipelineWidth, 1 + LoadPipelineWidth + StorePipelineWidth), io.wb.map(_.bits).slice(1 + LoadPipelineWidth, 1 + LoadPipelineWidth + StorePipelineWidth))._2(0)
  val s0_out_valid = RegNext(VecInit(Seq(wb_valid(0), wb_valid.slice(1, 1 + LoadPipelineWidth).reduce(_ || _), wb_valid.slice(1 + LoadPipelineWidth, 1 + LoadPipelineWidth + StorePipelineWidth).reduce(_ || _))))
220 221 222
  val s0_out_bits = RegNext(VecInit(Seq(csr_wb_bits, load_wb_bits, store_wb_bits)))

  // s1: compare last four and current flush
223
  val s1_valid = VecInit(s0_out_valid.zip(s0_out_bits).map{ case (v, b) => v && !(b.robIdx.needFlush(io.redirect) || io.flush) })
224
  val compare_01_valid = s0_out_valid(0) || s0_out_valid(1)
Y
Yinan Xu 已提交
225 226
  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))
227 228 229
  val s1_out_bits = RegNext(compare_bits)
  val s1_out_valid = RegNext(s1_valid.asUInt.orR)

230
  val enq_valid = RegNext(in_enq_valid.asUInt.orR && !io.redirect.valid && !io.flush)
231 232 233 234 235 236 237
  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
238 239
  val current_flush = current.bits.robIdx.needFlush(io.redirect) || io.flush
  val s1_flush = s1_out_bits.robIdx.needFlush(io.redirect) || io.flush
240 241 242 243 244 245 246
  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 已提交
247
      when (isAfter(current.bits.robIdx, s1_out_bits.robIdx)) {
248
        current.bits := s1_out_bits
Y
Yinan Xu 已提交
249
      }.elsewhen (current.bits.robIdx === s1_out_bits.robIdx) {
250 251
        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 已提交
252
        current.bits.replayInst := s1_out_bits.replayInst || current.bits.replayInst
253
        current.bits.singleStep := s1_out_bits.singleStep || current.bits.singleStep
L
Li Qianruo 已提交
254
        current.bits.trigger := (s1_out_bits.trigger.asUInt | current.bits.trigger.asUInt).asTypeOf(new TriggerCf)
255 256 257 258 259 260 261 262 263 264 265 266 267 268
      }
    }
  }.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

269 270
}

Y
Yinan Xu 已提交
271
class RobFlushInfo(implicit p: Parameters) extends XSBundle {
272
  val ftqIdx = new FtqPtr
273
  val robIdx = new RobPtr
274
  val ftqOffset = UInt(log2Up(PredictWidth).W)
W
William Wang 已提交
275
  val replayInst = Bool()
276 277
}

278 279 280 281 282 283 284 285 286 287 288 289 290 291
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)
292
  with HasXSParameter with HasCircularQueuePtrHelper with HasPerfEvents {
293 294 295
  val wbExuConfigs = outer.writebackSinksParams.map(_.exuConfigs)
  val numWbPorts = wbExuConfigs.map(_.length)

296
  val io = IO(new Bundle() {
J
Jiawei Lin 已提交
297
    val hartId = Input(UInt(8.W))
298
    val redirect = Input(Valid(new Redirect))
Y
Yinan Xu 已提交
299
    val enq = new RobEnqIO
300
    val flushOut = ValidIO(new Redirect)
301
    val exception = ValidIO(new ExceptionInfo)
L
LinJiawei 已提交
302
    // exu + brq
303
    val writeback = MixedVec(numWbPorts.map(num => Vec(num, Flipped(ValidIO(new ExuOutput)))))
Y
Yinan Xu 已提交
304 305
    val commits = new RobCommitIO
    val lsq = new RobLsqIO
306
    val bcommit = Output(UInt(log2Up(CommitWidth + 1).W))
Y
Yinan Xu 已提交
307 308 309
    val robDeqPtr = Output(new RobPtr)
    val csr = new RobCSRIO
    val robFull = Output(Bool())
Y
Yinan Xu 已提交
310
    val cpu_halt = Output(Bool())
311
  })
W
William Wang 已提交
312

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
  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)
331

332
  // instvalid field
Y
Yinan Xu 已提交
333
  val valid = Mem(RobSize, Bool())
334
  // writeback status
Y
Yinan Xu 已提交
335 336
  val writebacked = Mem(RobSize, Bool())
  val store_data_writebacked = Mem(RobSize, Bool())
337
  // data for redirect, exception, etc.
Y
Yinan Xu 已提交
338
  val flagBkup = Mem(RobSize, Bool())
Y
Yinan Xu 已提交
339 340 341
  // 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())
342

343
  // data for debug
344
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
345 346 347
  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 已提交
348

349 350
  // pointers
  // For enqueue ptr, we don't duplicate it since only enqueue needs it.
Y
Yinan Xu 已提交
351 352
  val enqPtr = Wire(new RobPtr)
  val deqPtrVec = Wire(Vec(CommitWidth, new RobPtr))
Y
Yinan Xu 已提交
353

Y
Yinan Xu 已提交
354 355
  val walkPtrVec = Reg(Vec(CommitWidth, new RobPtr))
  val validCounter = RegInit(0.U(log2Ceil(RobSize + 1).W))
356
  val allowEnqueue = RegInit(true.B)
357 358 359 360

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

362
  val isEmpty = enqPtr === deqPtr
363
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
364

365
  /**
Y
Yinan Xu 已提交
366
    * states of Rob
367
    */
W
William Wang 已提交
368
  val s_idle :: s_walk :: s_extrawalk :: Nil = Enum(3)
W
William Wang 已提交
369 370
  val state = RegInit(s_idle)

Y
Yinan Xu 已提交
371
  /**
372 373 374 375
    * Data Modules
    *
    * CommitDataModule: data from dispatch
    * (1) read: commits/walk/exception
Y
Yinan Xu 已提交
376
    * (2) write: enqueue
377 378 379 380
    *
    * WritebackData: data from writeback
    * (1) read: commits/walk/exception
    * (2) write: write back from exe units
Y
Yinan Xu 已提交
381
    */
Y
Yinan Xu 已提交
382
  val dispatchData = Module(new SyncDataModuleTemplate(new RobDispatchData, RobSize, CommitWidth, RenameWidth))
Y
Yinan Xu 已提交
383 384
  val dispatchDataRead = dispatchData.io.rdata

385 386
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
387
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
388

Y
Yinan Xu 已提交
389
  io.robDeqPtr := deqPtr
390

Y
Yinan Xu 已提交
391 392 393 394
  /**
    * Enqueue (from dispatch)
    */
  // special cases
395 396
  val hasBlockBackward = RegInit(false.B)
  val hasNoSpecExec = RegInit(false.B)
H
happy-lx 已提交
397
  val doingSvinval = RegInit(false.B)
Y
Yinan Xu 已提交
398
  // When blockBackward instruction leaves Rob (commit or walk), hasBlockBackward should be set to false.B
399
  // To reduce registers usage, for hasBlockBackward cases, we allow enqueue after ROB is empty.
Y
Yinan Xu 已提交
400
  when (isEmpty) { hasBlockBackward:= false.B }
401
  // When any instruction commits, hasNoSpecExec should be set to false.B
402
  when (io.commits.valid.asUInt.orR  && state =/= s_extrawalk) { hasNoSpecExec:= false.B }
Y
Yinan Xu 已提交
403 404 405 406 407 408 409 410

  // The wait-for-interrupt (WFI) instruction waits in the ROB until an interrupt might need servicing.
  // io.csr.wfiEvent will be asserted if the WFI can resume execution, and we change the state to s_wfi_idle.
  // It does not affect how interrupts are serviced. Note that WFI is noSpecExec and it does not trigger interrupts.
  val hasWFI = RegInit(false.B)
  io.cpu_halt := hasWFI
  when (RegNext(RegNext(io.csr.wfiEvent))) {
    hasWFI := false.B
Y
Yinan Xu 已提交
411
  }
L
Opt roq  
LinJiawei 已提交
412

413
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
414
  io.enq.resp      := enqPtrVec
415
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
416
  val timer = GTimer()
Y
Yinan Xu 已提交
417
  for (i <- 0 until RenameWidth) {
418 419
    // we don't check whether io.redirect is valid here since redirect has higher priority
    when (canEnqueue(i)) {
420
      val enqUop = io.enq.req(i).bits
421
      // store uop in data module and debug_microOp Vec
422
      debug_microOp(enqPtrVec(i).value) := enqUop
423 424 425 426 427
      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
428
      when (enqUop.ctrl.blockBackward) {
429 430
        hasBlockBackward := true.B
      }
431
      when (enqUop.ctrl.noSpecExec) {
432 433
        hasNoSpecExec := true.B
      }
434
      val enqHasTriggerHit = io.enq.req(i).bits.cf.trigger.getHitFrontend
435
      val enqHasException = ExceptionNO.selectFrontend(enqUop.cf.exceptionVec).asUInt.orR
H
happy-lx 已提交
436
      // the begin instruction of Svinval enqs so mark doingSvinval as true to indicate this process
437
      when(!enqHasTriggerHit && !enqHasException && FuType.isSvinvalBegin(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe))
H
happy-lx 已提交
438 439 440
      {
        doingSvinval := true.B
      }
441
      // the end instruction of Svinval enqs so clear doingSvinval
442
      when(!enqHasTriggerHit && !enqHasException && FuType.isSvinvalEnd(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe))
H
happy-lx 已提交
443 444 445 446
      {
        doingSvinval := false.B
      }
      // when we are in the process of Svinval software code area , only Svinval.vma and end instruction of Svinval can appear
447 448
      assert(!doingSvinval || (FuType.isSvinval(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe) ||
        FuType.isSvinvalEnd(enqUop.ctrl.fuType, enqUop.ctrl.fuOpType, enqUop.ctrl.flushPipe)))
449
      when (enqUop.ctrl.isWFI && !enqHasException && !enqHasTriggerHit) {
Y
Yinan Xu 已提交
450
        hasWFI := true.B
Y
Yinan Xu 已提交
451
      }
W
William Wang 已提交
452 453
    }
  }
454 455
  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 已提交
456

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

W
William Wang 已提交
461

Y
Yinan Xu 已提交
462 463 464
  /**
    * Writeback (from execution units)
    */
465 466 467 468 469 470 471 472 473
  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 已提交
474

475
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
476
      XSInfo(true.B,
477
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
478 479
        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"
480
      )
W
William Wang 已提交
481 482
    }
  }
483
  val writebackNum = PopCount(exuWriteback.map(_.valid))
484 485
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
486

Y
Yinan Xu 已提交
487
  /**
488
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
489
    */
Y
Yinan Xu 已提交
490
  val deqDispatchData = dispatchDataRead(0)
491 492
  val debug_deqUop = debug_microOp(deqPtr.value)

Y
Yinan Xu 已提交
493
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
Y
Yinan Xu 已提交
494
  val intrEnable = intrBitSetReg && !hasNoSpecExec && interrupt_safe(deqPtr.value)
Y
Yinan Xu 已提交
495
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
L
Li Qianruo 已提交
496
  val deqHasException = deqHasExceptionOrFlush && (exceptionDataRead.bits.exceptionVec.asUInt.orR ||
L
Li Qianruo 已提交
497
    exceptionDataRead.bits.singleStep || exceptionDataRead.bits.trigger.hit)
498
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
499
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
L
Li Qianruo 已提交
500 501 502
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException

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

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

508 509 510 511 512 513 514
  // 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
515 516
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
L
Li Qianruo 已提交
517
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter) // TODO use this to implement "exception next"
518
  io.flushOut.bits.interrupt := true.B
519 520 521 522
  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)
523

524
  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable) && !lastCycleFlush
525 526 527
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
528
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
529
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
530
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(exceptionDataRead.bits.crossPageIPFFix, exceptionHappen)
531
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
L
Li Qianruo 已提交
532
  io.exception.bits.uop.cf.trigger := RegEnable(exceptionDataRead.bits.trigger, exceptionHappen)
533 534 535

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

539

Y
Yinan Xu 已提交
540 541 542 543
  /**
    * Commits (and walk)
    * They share the same width.
    */
544
  val walkCounter = Reg(UInt(log2Up(RobSize + 1).W))
545
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
546
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
547

Y
Yinan Xu 已提交
548
  // extra space is used when rob has no enough space, but mispredict recovery needs such info to walk regmap
Y
Yinan Xu 已提交
549
  require(RenameWidth <= CommitWidth)
Y
Yinan Xu 已提交
550
  val extraSpaceForMPR = Reg(Vec(RenameWidth, new RobDispatchData))
W
William Wang 已提交
551
  val usedSpaceForMPR = Reg(Vec(RenameWidth, Bool()))
Y
Yinan Xu 已提交
552 553 554
  when (io.enq.needAlloc.asUInt.orR && io.redirect.valid) {
    usedSpaceForMPR := io.enq.needAlloc
    extraSpaceForMPR := dispatchData.io.wdata
Y
Yinan Xu 已提交
555
    XSDebug("rob full, switched to s_extrawalk. needExtraSpaceForMPR: %b\n", io.enq.needAlloc.asUInt)
Y
Yinan Xu 已提交
556
  }
W
William Wang 已提交
557

L
linjiawei 已提交
558
  // wiring to csr
559 560 561 562 563 564 565
  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())
566
  fflags.bits := wflags.zip(fflagsDataRead).map({
567 568 569
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
570

W
William Wang 已提交
571
  // when mispredict branches writeback, stop commit in the next 2 cycles
L
LinJiawei 已提交
572
  // TODO: don't check all exu write back
573 574
  val misPredWb = Cat(VecInit(exuWriteback.map(wb =>
    wb.bits.redirect.cfiUpdate.isMisPred && wb.bits.redirectValid
L
LinJiawei 已提交
575
  ))).orR()
576
  val misPredBlockCounter = Reg(UInt(3.W))
L
LinJiawei 已提交
577
  misPredBlockCounter := Mux(misPredWb,
578
    "b111".U,
W
William Wang 已提交
579 580 581 582
    misPredBlockCounter >> 1.U
  )
  val misPredBlock = misPredBlockCounter(0)

Y
Yinan Xu 已提交
583
  io.commits.isWalk := state =/= s_idle
584
  val commit_v = Mux(state === s_idle, VecInit(deqPtrVec.map(ptr => valid(ptr.value))), VecInit(walkPtrVec.map(ptr => valid(ptr.value))))
Y
Yinan Xu 已提交
585
  // store will be commited iff both sta & std have been writebacked
586
  val commit_w = VecInit(deqPtrVec.map(ptr => writebacked(ptr.value) && store_data_writebacked(ptr.value)))
Y
Yinan Xu 已提交
587
  val commit_exception = exceptionDataRead.valid && !isAfter(exceptionDataRead.bits.robIdx, deqPtrVec.last)
588
  val commit_block = VecInit((0 until CommitWidth).map(i => !commit_w(i)))
589
  val allowOnlyOneCommit = commit_exception || intrBitSetReg
590
  // for instructions that may block others, we don't allow them to commit
Y
Yinan Xu 已提交
591
  for (i <- 0 until CommitWidth) {
592
    // defaults: state === s_idle and instructions commit
593
    // when intrBitSetReg, allow only one instruction to commit at each clock cycle
594
    val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || deqHasException || deqHasReplayInst
Y
Yinan Xu 已提交
595
    io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked && !misPredBlock && !isReplaying && !lastCycleFlush && !hasWFI
Y
Yinan Xu 已提交
596
    io.commits.info(i)  := dispatchDataRead(i)
W
William Wang 已提交
597

598 599 600
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
601 602
      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 已提交
603
    }
604 605 606 607 608 609 610 611 612

    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),
613
      fflagsDataRead(i)
614 615 616 617 618 619 620 621 622 623 624
    )
    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 已提交
625
  }
626
  if (env.EnableDifftest) {
627
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
628
  }
W
William Wang 已提交
629

630
  // sync fflags/dirty_fs to csr
L
Li Qianruo 已提交
631 632
  io.csr.fflags := RegNext(fflags)
  io.csr.dirty_fs := RegNext(dirty_fs)
633

634 635 636
  // 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 已提交
637

638 639 640
  // 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))
641 642 643 644 645
  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))
646 647 648

  /**
    * state changes
Y
Yinan Xu 已提交
649 650 651 652
    * (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
653
    */
654 655 656 657 658
  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 已提交
659 660 661
    )
  )
  state := state_next
662

663
  /**
664
    * pointers and counters
665
    */
Y
Yinan Xu 已提交
666
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
667 668 669
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
670
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
671 672
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
Y
Yinan Xu 已提交
673
  deqPtrGenModule.io.interrupt_safe := interrupt_safe(deqPtr.value)
L
LinJiawei 已提交
674
  deqPtrGenModule.io.misPredBlock := misPredBlock
675
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
676
  deqPtrGenModule.io.hasWFI := hasWFI
Y
Yinan Xu 已提交
677
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
678
  val deqPtrVec_next = deqPtrGenModule.io.next_out
679

Y
Yinan Xu 已提交
680
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
681 682 683 684 685
  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
686 687

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
688 689 690 691 692
  // 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,
693 694
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
695 696 697 698
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
699

700
  val lastCycleRedirect = RegNext(io.redirect.valid)
701
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
702
  val commitCnt = PopCount(io.commits.valid)
703 704 705
  validCounter := Mux(state === s_idle,
    (validCounter - commitCnt) + dispatchNum,
    trueValidCounter
706 707
  )

708 709 710
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
711 712
  )

713
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
714
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
715 716
  when (io.redirect.valid) {
    walkCounter := Mux(state === s_walk,
717 718 719 720 721 722 723 724 725 726
      // 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()
727 728 729 730
    )
  }.elsewhen (state === s_walk) {
    walkCounter := walkCounter - commitCnt
    XSInfo(p"rolling back: $enqPtr $deqPtr walk $walkPtr walkcnt $walkCounter\n")
731 732
  }

733

Y
Yinan Xu 已提交
734 735
  /**
    * States
736
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
737

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

743 744
  // enqueue logic writes 6 valid
  for (i <- 0 until RenameWidth) {
745
    when (canEnqueue(i) && !io.redirect.valid) {
Y
Yinan Xu 已提交
746
      valid(enqPtrVec(i).value) := true.B
747 748 749
    }
  }
  // dequeue/walk logic writes 6 valid, dequeue and walk will not happen at the same time
750 751 752
  for (i <- 0 until CommitWidth) {
    when (io.commits.valid(i) && state =/= s_extrawalk) {
      valid(commitReadAddr(i)) := false.B
753 754
    }
  }
755
  // reset: when exception, reset all valid to false
Y
Yinan Xu 已提交
756
  when (reset.asBool) {
Y
Yinan Xu 已提交
757
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
758 759
      valid(i) := false.B
    }
760
  }
761

762 763 764
  // status field: writebacked
  // enqueue logic set 6 writebacked to false
  for (i <- 0 until RenameWidth) {
765
    when (canEnqueue(i)) {
766 767
      val enqHasException = ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec).asUInt.orR
      val enqHasTriggerHit = io.enq.req(i).bits.cf.trigger.getHitFrontend
768
      val enqIsWritebacked = io.enq.req(i).bits.eliminatedMove
Y
Yinan Xu 已提交
769
      writebacked(enqPtrVec(i).value) := enqIsWritebacked && !enqHasException && !enqHasTriggerHit
770 771
      val isStu = io.enq.req(i).bits.ctrl.fuType === FuType.stu
      store_data_writebacked(enqPtrVec(i).value) := !isStu
772 773
    }
  }
774
  when (exceptionGen.io.out.valid) {
Y
Yinan Xu 已提交
775
    val wbIdx = exceptionGen.io.out.bits.robIdx.value
776
    writebacked(wbIdx) := true.B
777
    store_data_writebacked(wbIdx) := true.B
778
  }
Y
Yinan Xu 已提交
779
  // writeback logic set numWbPorts writebacked to true
780 781 782 783
  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
784
      val wbHasTriggerHit = wb.bits.uop.cf.trigger.getHitBackend
785 786
      val wbHasFlushPipe = cfgs.exists(_.flushPipe).B && wb.bits.uop.ctrl.flushPipe
      val wbHasReplayInst = cfgs.exists(_.replayInst).B && wb.bits.uop.ctrl.replayInst
787
      val block_wb = wbHasException || wbHasFlushPipe || wbHasReplayInst || wbHasTriggerHit
788
      writebacked(wbIdx) := !block_wb
789 790
    }
  }
791
  // store data writeback logic mark store as data_writebacked
792 793 794
  for (wb <- stdWriteback) {
    when(RegNext(wb.valid)) {
      store_data_writebacked(RegNext(wb.bits.uop.robIdx.value)) := true.B
795 796
    }
  }
797 798 799 800

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
801
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
802
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
803 804 805
    }
  }

Y
Yinan Xu 已提交
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
  // 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 已提交
821 822 823 824 825 826 827 828 829 830

  /**
    * 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)
831
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
832 833 834 835 836 837 838
    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 已提交
839 840
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
841 842 843 844
    wdata.pc := req.cf.pc
  }
  dispatchData.io.raddr := commitReadAddr_next

845 846 847 848
  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 已提交
849
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
850
    exceptionGen.io.enq(i).bits.exceptionVec := ExceptionNO.selectFrontend(io.enq.req(i).bits.cf.exceptionVec)
851
    exceptionGen.io.enq(i).bits.flushPipe := io.enq.req(i).bits.ctrl.flushPipe
852
    exceptionGen.io.enq(i).bits.replayInst := false.B
853
    XSError(canEnqueue(i) && io.enq.req(i).bits.ctrl.replayInst, "enq should not set replayInst")
854
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
855
    exceptionGen.io.enq(i).bits.crossPageIPFFix := io.enq.req(i).bits.cf.crossPageIPFFix
856 857
    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 已提交
858
  }
859

860 861 862 863 864 865 866 867 868 869 870 871
  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
872 873
    exc_wb.bits.trigger.clear()
    exc_wb.bits.trigger.backendHit := wb.bits.uop.cf.trigger.backendHit
874 875 876
    println(s"  [$i] ${configs.map(_.name)}: exception ${exceptionCases(i)}, " +
      s"flushPipe ${configs.exists(_.flushPipe)}, " +
      s"replayInst ${configs.exists(_.replayInst)}")
877
  }
Y
Yinan Xu 已提交
878

879
  val fflags_wb = fflagsPorts.map(_._2)
880
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
881
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
882 883 884
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
885
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
886
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
887 888 889 890 891
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


892
  val instrCnt = RegInit(0.U(64.W))
893
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && CommitType.isFused(i.commitType) })
894 895 896 897
  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 已提交
898
  io.robFull := !allowEnqueue
899

900 901 902
  /**
    * debug info
    */
903
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
904
  XSDebug("")
Y
Yinan Xu 已提交
905
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
906 907 908
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
909
  }
Y
Yinan Xu 已提交
910 911
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
912
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
913
    if(i % 4 == 0) XSDebug("")
914
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
915 916 917 918
    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 已提交
919
  }
W
William Wang 已提交
920

921 922 923
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

  val commitDebugUop = deqPtrVec.map(_.value).map(debug_microOp(_))
924
  XSPerfAccumulate("clock_cycle", 1.U)
Y
Yinan Xu 已提交
925
  QueuePerf(RobSize, PopCount((0 until RobSize).map(valid(_))), !allowEnqueue)
926 927 928 929
  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 })))
930 931
  val commitMoveElim = commitDebugUop.map(_.debugInfo.eliminatedMove)
  XSPerfAccumulate("commitInstrMoveElim", ifCommit(PopCount(io.commits.valid zip commitMoveElim map { case (v, e) => v && e })))
932
  XSPerfAccumulate("commitInstrFused", ifCommit(fuseCommitCnt))
933 934
  val commitIsLoad = io.commits.info.map(_.commitType).map(_ === CommitType.LOAD)
  val commitLoadValid = io.commits.valid.zip(commitIsLoad).map{ case (v, t) => v && t }
935
  XSPerfAccumulate("commitInstrLoad", ifCommit(PopCount(commitLoadValid)))
W
William Wang 已提交
936 937 938
  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)))
939 940
  val commitLoadWaitBit = commitDebugUop.map(_.cf.loadWaitBit)
  XSPerfAccumulate("commitInstrLoadWait", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w })))
941
  val commitIsStore = io.commits.info.map(_.commitType).map(_ === CommitType.STORE)
942
  XSPerfAccumulate("commitInstrStore", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t })))
Y
Yinan Xu 已提交
943
  XSPerfAccumulate("writeback", PopCount((0 until RobSize).map(i => valid(i) && writebacked(i))))
944 945
  // XSPerfAccumulate("enqInstr", PopCount(io.dp1Req.map(_.fire())))
  // XSPerfAccumulate("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
946 947
  XSPerfAccumulate("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
  XSPerfAccumulate("walkCycle", state === s_walk || state === s_extrawalk)
948 949
  val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
  val deqUopCommitType = io.commits.info(0).commitType
950 951 952 953
  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 已提交
954
  XSPerfAccumulate("robHeadPC", io.commits.info(0).pc)
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
  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 已提交
983

984 985 986 987 988
  //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)))
989

990 991 992
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
993
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
994
  }
995
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
996 997
  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)
998

999
  if (env.EnableDifftest) {
1000 1001 1002
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
J
Jiawei Lin 已提交
1003
      difftest.io.coreid   := io.hartId
1004 1005 1006
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
1007
      val uop = commitDebugUop(i)
1008 1009
      val exuOut = debug_exuDebug(ptr)
      val exuData = debug_exuData(ptr)
1010 1011 1012 1013
      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))))
1014 1015
      // when committing an eliminated move instruction,
      // we must make sure that skip is properly set to false (output from EXU is random value)
1016 1017
      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 已提交
1018 1019
      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)))
1020 1021
      difftest.io.wpdest   := RegNext(RegNext(RegNext(io.commits.info(i).pdest)))
      difftest.io.wdest    := RegNext(RegNext(RegNext(io.commits.info(i).ldest)))
1022

1023 1024 1025 1026 1027 1028 1029 1030 1031
      // // runahead commit hint
      // val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      // runahead_commit.io.clock := clock
      // runahead_commit.io.coreid := io.hartId
      // 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
1032 1033
    }
  }
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
  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
      }
    }
1045 1046 1047 1048
    for (wb <- exuWriteback) {
      when (wb.valid) {
        val wbIdx = wb.bits.uop.robIdx.value
        dt_exuDebug(wbIdx) := wb.bits.debug
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
      }
    }
    // 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 已提交
1061
      difftest.io.coreid  := io.hartId
1062
      difftest.io.index   := i.U
1063 1064 1065 1066
      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 已提交
1067 1068
      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)))
1069 1070
      difftest.io.wpdest  := RegNext(RegNext(RegNext(commitInfo.pdest)))
      difftest.io.wdest   := RegNext(RegNext(RegNext(commitInfo.ldest)))
1071 1072
    }
  }
1073

1074
  if (env.EnableDifftest) {
1075 1076 1077
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
J
Jiawei Lin 已提交
1078
      difftest.io.coreid := io.hartId
1079 1080 1081
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
1082
      val uop = commitDebugUop(i)
1083
      val exuOut = debug_exuDebug(ptr)
1084 1085 1086 1087
      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)))
1088 1089 1090
    }
  }

1091
  // Always instantiate basic difftest modules.
1092
  if (env.EnableDifftest) {
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
    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)
1103 1104
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
J
Jiawei Lin 已提交
1105
    difftest.io.coreid   := io.hartId
1106 1107 1108
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1109
    difftest.io.cycleCnt := timer
1110
    difftest.io.instrCnt := instrCnt
1111
    difftest.io.hasWFI   := hasWFI
1112
  }
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
  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 已提交
1124
    difftest.io.coreid   := io.hartId
1125 1126 1127 1128
    difftest.io.valid    := hitTrap
    difftest.io.cycleCnt := timer
    difftest.io.instrCnt := instrCnt
  }
1129

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
  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)                                                                                       ),
1145 1146 1147 1148
    ("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))                                                                 ),
1149
  )
1150
  generatePerfEvent()
1151
}