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

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

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

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

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

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

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

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

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

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

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

Y
Yinan Xu 已提交
79
class RobDispatchData(implicit p: Parameters) extends RobCommitInfo {
80 81
  val crossPageIPFFix = Bool()
}
Y
Yinan Xu 已提交
82

Y
Yinan Xu 已提交
83
class RobDeqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
Y
Yinan Xu 已提交
84
  val io = IO(new Bundle {
Y
Yinan Xu 已提交
85 86 87 88
    // 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 已提交
89
    val exception_state = Flipped(ValidIO(new RobExceptionInfo))
Y
Yinan Xu 已提交
90 91 92 93
    // for flush: when exception occurs, reset deqPtrs to range(0, CommitWidth)
    val intrBitSetReg = Input(Bool())
    val hasNoSpecExec = Input(Bool())
    val commitType = Input(CommitType())
L
LinJiawei 已提交
94
    val misPredBlock = Input(Bool())
95
    val isReplaying = Input(Bool())
Y
Yinan Xu 已提交
96
    // output: the CommitWidth deqPtr
Y
Yinan Xu 已提交
97 98
    val out = Vec(CommitWidth, Output(new RobPtr))
    val next_out = Vec(CommitWidth, Output(new RobPtr))
Y
Yinan Xu 已提交
99 100
  })

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

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

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

  deqPtrVec := deqPtrVec_next

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

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

}

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

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

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

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

  io.out := enqPtr

Y
Yinan Xu 已提交
158 159
}

Y
Yinan Xu 已提交
160
class RobExceptionInfo(implicit p: Parameters) extends XSBundle {
161
  // val valid = Bool()
Y
Yinan Xu 已提交
162
  val robIdx = new RobPtr
163 164
  val exceptionVec = ExceptionVec()
  val flushPipe = Bool()
W
William Wang 已提交
165
  val replayInst = Bool() // redirect to that inst itself
166
  val singleStep = Bool()
167

168
  def has_exception = exceptionVec.asUInt.orR || flushPipe || singleStep || replayInst
169
  // only exceptions are allowed to writeback when enqueue
170
  def can_writeback = exceptionVec.asUInt.orR || singleStep
171 172
}

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

Y
Yinan Xu 已提交
183
  val current = Reg(Valid(new RobExceptionInfo))
184 185

  // orR the exceptionVec
186 187 188
  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)
189 190

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

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

244 245
}

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

Y
Yinan Xu 已提交
253
class Rob(numWbPorts: Int)(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
254
  val io = IO(new Bundle() {
255
    val redirect = Input(Valid(new Redirect))
Y
Yinan Xu 已提交
256
    val enq = new RobEnqIO
257
    val flushOut = ValidIO(new Redirect)
258
    val exception = ValidIO(new ExceptionInfo)
L
LinJiawei 已提交
259
    // exu + brq
260
    val exeWbResults = Vec(numWbPorts, Flipped(ValidIO(new ExuOutput)))
Y
Yinan Xu 已提交
261 262
    val commits = new RobCommitIO
    val lsq = new RobLsqIO
263
    val bcommit = Output(UInt(log2Up(CommitWidth + 1).W))
Y
Yinan Xu 已提交
264 265 266
    val robDeqPtr = Output(new RobPtr)
    val csr = new RobCSRIO
    val robFull = Output(Bool())
267
  })
W
William Wang 已提交
268

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

271
  // instvalid field
Y
Yinan Xu 已提交
272 273
  // val valid = RegInit(VecInit(List.fill(RobSize)(false.B)))
  val valid = Mem(RobSize, Bool())
274
  // writeback status
Y
Yinan Xu 已提交
275 276 277
  // val writebacked = Reg(Vec(RobSize, Bool()))
  val writebacked = Mem(RobSize, Bool())
  val store_data_writebacked = Mem(RobSize, Bool())
278
  // data for redirect, exception, etc.
Y
Yinan Xu 已提交
279 280
  // val flagBkup = RegInit(VecInit(List.fill(RobSize)(false.B)))
  val flagBkup = Mem(RobSize, Bool())
281
  // record move elimination info for each instruction
Y
Yinan Xu 已提交
282
  val eliminatedMove = Mem(RobSize, Bool())
283

284
  // data for debug
285
  // Warn: debug_* prefix should not exist in generated verilog.
Y
Yinan Xu 已提交
286 287 288
  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 已提交
289

290 291
  // pointers
  // For enqueue ptr, we don't duplicate it since only enqueue needs it.
Y
Yinan Xu 已提交
292 293
  val enqPtr = Wire(new RobPtr)
  val deqPtrVec = Wire(Vec(CommitWidth, new RobPtr))
Y
Yinan Xu 已提交
294

Y
Yinan Xu 已提交
295 296
  val walkPtrVec = Reg(Vec(CommitWidth, new RobPtr))
  val validCounter = RegInit(0.U(log2Ceil(RobSize + 1).W))
297
  val allowEnqueue = RegInit(true.B)
298 299 300 301

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

303
  val isEmpty = enqPtr === deqPtr
304
  val isReplaying = io.redirect.valid && RedirectLevel.flushItself(io.redirect.bits.level)
W
William Wang 已提交
305

306
  /**
Y
Yinan Xu 已提交
307
    * states of Rob
308
    */
W
William Wang 已提交
309
  val s_idle :: s_walk :: s_extrawalk :: Nil = Enum(3)
W
William Wang 已提交
310 311
  val state = RegInit(s_idle)

Y
Yinan Xu 已提交
312
  /**
313 314 315 316
    * Data Modules
    *
    * CommitDataModule: data from dispatch
    * (1) read: commits/walk/exception
Y
Yinan Xu 已提交
317
    * (2) write: enqueue
318 319 320 321
    *
    * WritebackData: data from writeback
    * (1) read: commits/walk/exception
    * (2) write: write back from exe units
Y
Yinan Xu 已提交
322
    */
Y
Yinan Xu 已提交
323
  val dispatchData = Module(new SyncDataModuleTemplate(new RobDispatchData, RobSize, CommitWidth, RenameWidth))
Y
Yinan Xu 已提交
324 325
  val dispatchDataRead = dispatchData.io.rdata

326 327
  val exceptionGen = Module(new ExceptionGen)
  val exceptionDataRead = exceptionGen.io.state
328
  val fflagsDataRead = Wire(Vec(CommitWidth, UInt(5.W)))
329

Y
Yinan Xu 已提交
330
  io.robDeqPtr := deqPtr
331

Y
Yinan Xu 已提交
332 333 334 335
  /**
    * Enqueue (from dispatch)
    */
  // special cases
336 337
  val hasBlockBackward = RegInit(false.B)
  val hasNoSpecExec = RegInit(false.B)
Y
Yinan Xu 已提交
338
  // When blockBackward instruction leaves Rob (commit or walk), hasBlockBackward should be set to false.B
339
  // To reduce registers usage, for hasBlockBackward cases, we allow enqueue after ROB is empty.
Y
Yinan Xu 已提交
340
  when (isEmpty) { hasBlockBackward:= false.B }
341
  // When any instruction commits, hasNoSpecExec should be set to false.B
342
  when (io.commits.valid.asUInt.orR  && state =/= s_extrawalk) { hasNoSpecExec:= false.B }
L
Opt roq  
LinJiawei 已提交
343

344
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
345
  io.enq.resp      := enqPtrVec
346
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
347
  val timer = GTimer()
Y
Yinan Xu 已提交
348
  for (i <- 0 until RenameWidth) {
349 350 351 352
    // we don't check whether io.redirect is valid here since redirect has higher priority
    when (canEnqueue(i)) {
      // store uop in data module and debug_microOp Vec
      debug_microOp(enqPtrVec(i).value) := io.enq.req(i).bits
353 354 355 356 357
      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
358
      when (io.enq.req(i).bits.ctrl.blockBackward) {
359 360
        hasBlockBackward := true.B
      }
361
      when (io.enq.req(i).bits.ctrl.noSpecExec) {
362 363
        hasNoSpecExec := true.B
      }
W
William Wang 已提交
364 365
    }
  }
366 367
  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 已提交
368

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

W
William Wang 已提交
373

Y
Yinan Xu 已提交
374 375 376
  /**
    * Writeback (from execution units)
    */
377 378
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
379
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
380 381
      debug_microOp(wbIdx).cf.exceptionVec := io.exeWbResults(i).bits.uop.cf.exceptionVec
      debug_microOp(wbIdx).ctrl.flushPipe := io.exeWbResults(i).bits.uop.ctrl.flushPipe
382
      debug_microOp(wbIdx).ctrl.replayInst := io.exeWbResults(i).bits.uop.ctrl.replayInst
383
      debug_microOp(wbIdx).diffTestDebugLrScValid := io.exeWbResults(i).bits.uop.diffTestDebugLrScValid
384 385
      debug_exuData(wbIdx) := io.exeWbResults(i).bits.data
      debug_exuDebug(wbIdx) := io.exeWbResults(i).bits.debug
386 387
      debug_microOp(wbIdx).debugInfo.enqRsTime := io.exeWbResults(i).bits.uop.debugInfo.enqRsTime
      debug_microOp(wbIdx).debugInfo.selectTime := io.exeWbResults(i).bits.uop.debugInfo.selectTime
388 389
      debug_microOp(wbIdx).debugInfo.issueTime := io.exeWbResults(i).bits.uop.debugInfo.issueTime
      debug_microOp(wbIdx).debugInfo.writebackTime := io.exeWbResults(i).bits.uop.debugInfo.writebackTime
L
Opt roq  
LinJiawei 已提交
390

391
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
392
      XSInfo(true.B,
393
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
Y
Yinan Xu 已提交
394
        p"data 0x${Hexadecimal(io.exeWbResults(i).bits.data)} ldst ${debug_Uop.ctrl.ldest} pdst ${debug_Uop.pdest} " +
Y
Yinan Xu 已提交
395
        p"skip ${io.exeWbResults(i).bits.debug.isMMIO} robIdx: ${io.exeWbResults(i).bits.uop.robIdx}\n"
396
      )
W
William Wang 已提交
397 398
    }
  }
399 400 401
  val writebackNum = PopCount(io.exeWbResults.map(_.valid))
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
402

Y
Yinan Xu 已提交
403
  /**
404
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
405
    */
Y
Yinan Xu 已提交
406
  val deqDispatchData = dispatchDataRead(0)
407 408 409 410 411
  val debug_deqUop = debug_microOp(deqPtr.value)

  // For MMIO instructions, they should not trigger interrupts since they may be sent to lower level before it writes back.
  // However, we cannot determine whether a load/store instruction is MMIO.
  // Thus, we don't allow load/store instructions to trigger an interrupt.
Y
Yinan Xu 已提交
412
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
413
  val intrEnable = intrBitSetReg && !hasNoSpecExec && !CommitType.isLoadStore(deqDispatchData.commitType)
Y
Yinan Xu 已提交
414
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
415
  val deqHasException = deqHasExceptionOrFlush && exceptionDataRead.bits.exceptionVec.asUInt.orR
416
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
417
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
418
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException
W
William Wang 已提交
419
  val isFlushPipe = writebacked(deqPtr.value) && (deqHasFlushPipe || deqHasReplayInst)
420

421 422 423 424 425 426 427
  // 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
428 429
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
430 431
  io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable, RedirectLevel.flush, RedirectLevel.flushAfter)
  io.flushOut.bits.interrupt := true.B
432 433 434 435
  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)
436

437
  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable) && !lastCycleFlush
438 439 440
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
441
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
442
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
443 444
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(deqDispatchData.crossPageIPFFix, exceptionHappen)
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
445 446 447

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

451

Y
Yinan Xu 已提交
452 453 454 455
  /**
    * Commits (and walk)
    * They share the same width.
    */
Y
Yinan Xu 已提交
456
  val walkCounter = Reg(UInt(log2Up(RobSize).W))
457
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
458
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
459

Y
Yinan Xu 已提交
460
  // extra space is used when rob has no enough space, but mispredict recovery needs such info to walk regmap
Y
Yinan Xu 已提交
461
  require(RenameWidth <= CommitWidth)
Y
Yinan Xu 已提交
462
  val extraSpaceForMPR = Reg(Vec(RenameWidth, new RobDispatchData))
W
William Wang 已提交
463
  val usedSpaceForMPR = Reg(Vec(RenameWidth, Bool()))
Y
Yinan Xu 已提交
464 465 466
  when (io.enq.needAlloc.asUInt.orR && io.redirect.valid) {
    usedSpaceForMPR := io.enq.needAlloc
    extraSpaceForMPR := dispatchData.io.wdata
Y
Yinan Xu 已提交
467
    XSDebug("rob full, switched to s_extrawalk. needExtraSpaceForMPR: %b\n", io.enq.needAlloc.asUInt)
Y
Yinan Xu 已提交
468
  }
W
William Wang 已提交
469

L
linjiawei 已提交
470
  // wiring to csr
471 472 473 474 475 476 477
  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())
478
  fflags.bits := wflags.zip(fflagsDataRead).map({
479 480 481
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
482

W
William Wang 已提交
483
  // when mispredict branches writeback, stop commit in the next 2 cycles
L
LinJiawei 已提交
484
  // TODO: don't check all exu write back
L
LinJiawei 已提交
485
  val misPredWb = Cat(VecInit((0 until numWbPorts).map(i =>
L
LinJiawei 已提交
486
    io.exeWbResults(i).bits.redirect.cfiUpdate.isMisPred && io.exeWbResults(i).bits.redirectValid
L
LinJiawei 已提交
487
  ))).orR()
488
  val misPredBlockCounter = Reg(UInt(3.W))
L
LinJiawei 已提交
489
  misPredBlockCounter := Mux(misPredWb,
490
    "b111".U,
W
William Wang 已提交
491 492 493 494
    misPredBlockCounter >> 1.U
  )
  val misPredBlock = misPredBlockCounter(0)

Y
Yinan Xu 已提交
495
  io.commits.isWalk := state =/= s_idle
496
  val commit_v = Mux(state === s_idle, VecInit(deqPtrVec.map(ptr => valid(ptr.value))), VecInit(walkPtrVec.map(ptr => valid(ptr.value))))
Y
Yinan Xu 已提交
497
  // store will be commited iff both sta & std have been writebacked
498
  val commit_w = VecInit(deqPtrVec.map(ptr => writebacked(ptr.value) && store_data_writebacked(ptr.value)))
Y
Yinan Xu 已提交
499
  val commit_exception = exceptionDataRead.valid && !isAfter(exceptionDataRead.bits.robIdx, deqPtrVec.last)
500
  val commit_block = VecInit((0 until CommitWidth).map(i => !commit_w(i)))
501
  val allowOnlyOneCommit = commit_exception || intrBitSetReg
502
  // for instructions that may block others, we don't allow them to commit
Y
Yinan Xu 已提交
503
  for (i <- 0 until CommitWidth) {
504
    // defaults: state === s_idle and instructions commit
505
    // when intrBitSetReg, allow only one instruction to commit at each clock cycle
506
    val isBlocked = if (i != 0) Cat(commit_block.take(i)).orR || allowOnlyOneCommit else intrEnable || deqHasException || deqHasReplayInst
507
    io.commits.valid(i) := commit_v(i) && commit_w(i) && !isBlocked && !misPredBlock && !isReplaying && !lastCycleFlush
Y
Yinan Xu 已提交
508
    io.commits.info(i)  := dispatchDataRead(i)
W
William Wang 已提交
509

510 511 512
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
513 514
      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 已提交
515
    }
516 517 518 519 520 521 522 523 524

    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),
525
      fflagsDataRead(i)
526 527 528 529 530 531 532 533 534 535 536
    )
    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 已提交
537
  }
538 539
  if (!env.FPGAPlatform) {
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
540
  }
W
William Wang 已提交
541

542
  // sync fflags/dirty_fs to csr
543 544
  io.csr.fflags := fflags
  io.csr.dirty_fs := dirty_fs
545

546 547 548
  // 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 已提交
549

550 551 552 553 554 555 556 557
  // 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))
  io.lsq.lcommit := Mux(io.commits.isWalk, 0.U, PopCount(ldCommitVec))
  io.lsq.scommit := Mux(io.commits.isWalk, 0.U, PopCount(stCommitVec))
  io.lsq.pendingld := !io.commits.isWalk && io.commits.info(0).commitType === CommitType.LOAD && valid(deqPtr.value)
  io.lsq.pendingst := !io.commits.isWalk && io.commits.info(0).commitType === CommitType.STORE && valid(deqPtr.value)
  io.lsq.commit := !io.commits.isWalk && io.commits.valid(0)
558 559 560

  /**
    * state changes
Y
Yinan Xu 已提交
561 562 563 564
    * (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
565
    */
566 567 568 569 570
  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 已提交
571 572 573
    )
  )
  state := state_next
574

575
  /**
576
    * pointers and counters
577
    */
Y
Yinan Xu 已提交
578
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
579 580 581
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
582
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
583 584 585
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
  deqPtrGenModule.io.commitType := deqDispatchData.commitType
L
LinJiawei 已提交
586 587

  deqPtrGenModule.io.misPredBlock := misPredBlock
588
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
589
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
590
  val deqPtrVec_next = deqPtrGenModule.io.next_out
591

Y
Yinan Xu 已提交
592
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
593 594 595 596 597
  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
598 599

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
600 601 602 603 604
  // 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,
605 606
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
607 608 609 610
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
611

612
  val lastCycleRedirect = RegNext(io.redirect.valid)
613
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
614
  val commitCnt = PopCount(io.commits.valid)
615 616 617
  validCounter := Mux(state === s_idle,
    (validCounter - commitCnt) + dispatchNum,
    trueValidCounter
618 619
  )

620 621 622
  allowEnqueue := Mux(state === s_idle,
    validCounter + dispatchNum <= (RobSize - RenameWidth).U,
    trueValidCounter <= (RobSize - RenameWidth).U
623 624
  )

625
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
626
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
627 628 629 630 631 632 633 634
  when (io.redirect.valid) {
    walkCounter := Mux(state === s_walk,
      redirectWalkDistance + io.redirect.bits.flushItself() - commitCnt,
      redirectWalkDistance + io.redirect.bits.flushItself()
    )
  }.elsewhen (state === s_walk) {
    walkCounter := walkCounter - commitCnt
    XSInfo(p"rolling back: $enqPtr $deqPtr walk $walkPtr walkcnt $walkCounter\n")
635 636
  }

637

Y
Yinan Xu 已提交
638 639
  /**
    * States
640
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
641

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

647 648
  // enqueue logic writes 6 valid
  for (i <- 0 until RenameWidth) {
649
    when (canEnqueue(i) && !io.redirect.valid) {
Y
Yinan Xu 已提交
650
      valid(enqPtrVec(i).value) := true.B
651 652 653
    }
  }
  // dequeue/walk logic writes 6 valid, dequeue and walk will not happen at the same time
654 655 656
  for (i <- 0 until CommitWidth) {
    when (io.commits.valid(i) && state =/= s_extrawalk) {
      valid(commitReadAddr(i)) := false.B
657 658
    }
  }
659
  // reset: when exception, reset all valid to false
Y
Yinan Xu 已提交
660
  when (reset.asBool) {
Y
Yinan Xu 已提交
661
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
662 663
      valid(i) := false.B
    }
664
  }
665

666 667 668
  // status field: writebacked
  // enqueue logic set 6 writebacked to false
  for (i <- 0 until RenameWidth) {
669
    when (canEnqueue(i)) {
670 671
      eliminatedMove(enqPtrVec(i).value) := io.enq.req(i).bits.eliminatedMove
      writebacked(enqPtrVec(i).value) := io.enq.req(i).bits.eliminatedMove && !io.enq.req(i).bits.cf.exceptionVec.asUInt.orR
672 673
      val isStu = io.enq.req(i).bits.ctrl.fuType === FuType.stu
      store_data_writebacked(enqPtrVec(i).value) := !isStu
674 675
    }
  }
676
  when (exceptionGen.io.out.valid) {
Y
Yinan Xu 已提交
677
    val wbIdx = exceptionGen.io.out.bits.robIdx.value
678
    writebacked(wbIdx) := true.B
679
    store_data_writebacked(wbIdx) := true.B
680
  }
Y
Yinan Xu 已提交
681
  // writeback logic set numWbPorts writebacked to true
682 683
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
684 685 686
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
      val block_wb =
        selectAll(io.exeWbResults(i).bits.uop.cf.exceptionVec, false, true).asUInt.orR ||
W
William Wang 已提交
687
        io.exeWbResults(i).bits.uop.ctrl.flushPipe ||
688
        io.exeWbResults(i).bits.uop.ctrl.replayInst
689
      writebacked(wbIdx) := !block_wb
690 691
    }
  }
692 693
  // store data writeback logic mark store as data_writebacked
  for (i <- 0 until StorePipelineWidth) {
Y
Yinan Xu 已提交
694 695
    when(io.lsq.storeDataRobWb(i).valid) {
      store_data_writebacked(io.lsq.storeDataRobWb(i).bits.value) := true.B
696 697
    }
  }
698 699 700 701

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
702
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
703
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
704 705 706
    }
  }

Y
Yinan Xu 已提交
707 708 709 710 711 712 713 714 715 716

  /**
    * 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)
717
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
718 719 720 721 722
    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
723
    wdata.eliminatedMove := req.eliminatedMove
Y
Yinan Xu 已提交
724 725
    wdata.pdest := req.pdest
    wdata.old_pdest := req.old_pdest
L
Lingrui98 已提交
726 727
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
728 729
    wdata.pc := req.cf.pc
    wdata.crossPageIPFFix := req.cf.crossPageIPFFix
730
    wdata.isFused := req.ctrl.isFused
731
    // wdata.exceptionVec := req.cf.exceptionVec
Y
Yinan Xu 已提交
732 733 734
  }
  dispatchData.io.raddr := commitReadAddr_next

735 736 737 738
  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 已提交
739
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
740 741
    exceptionGen.io.enq(i).bits.exceptionVec := selectFrontend(io.enq.req(i).bits.cf.exceptionVec, false, true)
    exceptionGen.io.enq(i).bits.flushPipe := io.enq.req(i).bits.ctrl.flushPipe
742
    exceptionGen.io.enq(i).bits.replayInst := io.enq.req(i).bits.ctrl.replayInst
W
William Wang 已提交
743
    assert(exceptionGen.io.enq(i).bits.replayInst === false.B)
744
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
Y
Yinan Xu 已提交
745
  }
746 747

  // TODO: don't hard code these idxes
748
  val numIntWbPorts = exuParameters.AluCnt + exuParameters.LduCnt + exuParameters.MduCnt
749 750 751 752
  // CSR is after Alu and Load
  def csr_wb_idx = exuParameters.AluCnt + exuParameters.LduCnt
  def atomic_wb_idx = exuParameters.AluCnt // first port for load
  def load_wb_idxes = Seq(exuParameters.AluCnt + 1) // second port for load
753
  def store_wb_idxes = io.exeWbResults.indices.takeRight(2)
754 755
  val all_exception_possibilities = Seq(csr_wb_idx, atomic_wb_idx) ++ load_wb_idxes ++ store_wb_idxes
  all_exception_possibilities.zipWithIndex.map{ case (p, i) => connect_exception(i, p) }
756 757
  def connect_exception(index: Int, wb_index: Int) = {
    exceptionGen.io.wb(index).valid             := io.exeWbResults(wb_index).valid
758 759 760 761 762 763 764
    // A temporary fix for float load writeback
    // TODO: let int/fp load use the same two wb ports
    if (wb_index == atomic_wb_idx || load_wb_idxes.contains(wb_index)) {
      when (io.exeWbResults(wb_index - exuParameters.AluCnt + numIntWbPorts + exuParameters.FmacCnt).valid) {
        exceptionGen.io.wb(index).valid := true.B
      }
    }
Y
Yinan Xu 已提交
765
    exceptionGen.io.wb(index).bits.robIdx       := io.exeWbResults(wb_index).bits.uop.robIdx
766 767 768 769 770 771 772
    val selectFunc = if (wb_index == csr_wb_idx) selectCSR _
    else if (wb_index == atomic_wb_idx) selectAtomics _
    else if (load_wb_idxes.contains(wb_index)) selectLoad _
    else {
      assert(store_wb_idxes.contains(wb_index))
      selectStore _
    }
773 774
    exceptionGen.io.wb(index).bits.exceptionVec := selectFunc(io.exeWbResults(wb_index).bits.uop.cf.exceptionVec, false, true)
    exceptionGen.io.wb(index).bits.flushPipe    := io.exeWbResults(wb_index).bits.uop.ctrl.flushPipe
775
    exceptionGen.io.wb(index).bits.replayInst   := io.exeWbResults(wb_index).bits.uop.ctrl.replayInst
776
    exceptionGen.io.wb(index).bits.singleStep   := false.B
777
  }
Y
Yinan Xu 已提交
778

779
  // 4 fmac + 2 fmisc + 1 i2f
780 781 782
  val fmacWb = (0 until exuParameters.FmacCnt).map(_ + numIntWbPorts)
  val fmiscWb = (0 until exuParameters.FmiscCnt).map(_ + numIntWbPorts + exuParameters.FmacCnt + 2)
  val i2fWb = Seq(numIntWbPorts - 1) // last port in int
783
  val fflags_wb = io.exeWbResults.zipWithIndex.filter(w => {
784
    (fmacWb ++ fmiscWb ++ i2fWb).contains(w._2)
785 786
  }).map(_._1)
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
787
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
788 789 790
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
791
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
792
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
793 794 795 796 797
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


798 799 800 801 802 803
  val instrCnt = RegInit(0.U(64.W))
  val fuseCommitCnt = PopCount(io.commits.valid.zip(io.commits.info).map{ case (v, i) => v && i.isFused =/= 0.U })
  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 已提交
804
  io.robFull := !allowEnqueue
805

806 807 808
  /**
    * debug info
    */
809
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
810
  XSDebug("")
Y
Yinan Xu 已提交
811
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
812 813 814
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
815
  }
Y
Yinan Xu 已提交
816 817
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
818
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
819
    if(i % 4 == 0) XSDebug("")
820
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
821 822 823 824
    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 已提交
825
  }
W
William Wang 已提交
826

827 828 829
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

  val commitDebugUop = deqPtrVec.map(_.value).map(debug_microOp(_))
830
  XSPerfAccumulate("clock_cycle", 1.U)
Y
Yinan Xu 已提交
831
  QueuePerf(RobSize, PopCount((0 until RobSize).map(valid(_))), !allowEnqueue)
832 833 834 835
  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 })))
836 837
  val commitMoveElim = commitDebugUop.map(_.debugInfo.eliminatedMove)
  XSPerfAccumulate("commitInstrMoveElim", ifCommit(PopCount(io.commits.valid zip commitMoveElim map { case (v, e) => v && e })))
838
  XSPerfAccumulate("commitInstrFused", ifCommit(fuseCommitCnt))
839 840
  val commitIsLoad = io.commits.info.map(_.commitType).map(_ === CommitType.LOAD)
  val commitLoadValid = io.commits.valid.zip(commitIsLoad).map{ case (v, t) => v && t }
841
  XSPerfAccumulate("commitInstrLoad", ifCommit(PopCount(commitLoadValid)))
W
William Wang 已提交
842 843 844
  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)))
845 846
  val commitLoadWaitBit = commitDebugUop.map(_.cf.loadWaitBit)
  XSPerfAccumulate("commitInstrLoadWait", ifCommit(PopCount(commitLoadValid.zip(commitLoadWaitBit).map{ case (v, w) => v && w })))
847
  val commitIsStore = io.commits.info.map(_.commitType).map(_ === CommitType.STORE)
848
  XSPerfAccumulate("commitInstrStore", ifCommit(PopCount(io.commits.valid.zip(commitIsStore).map{ case (v, t) => v && t })))
Y
Yinan Xu 已提交
849
  XSPerfAccumulate("writeback", PopCount((0 until RobSize).map(i => valid(i) && writebacked(i))))
850 851
  // XSPerfAccumulate("enqInstr", PopCount(io.dp1Req.map(_.fire())))
  // XSPerfAccumulate("d2rVnR", PopCount(io.dp1Req.map(p => p.valid && !p.ready)))
852 853
  XSPerfAccumulate("walkInstr", Mux(io.commits.isWalk, PopCount(io.commits.valid), 0.U))
  XSPerfAccumulate("walkCycle", state === s_walk || state === s_extrawalk)
854 855
  val deqNotWritebacked = valid(deqPtr.value) && !writebacked(deqPtr.value)
  val deqUopCommitType = io.commits.info(0).commitType
856 857 858 859
  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 已提交
860
  XSPerfAccumulate("robHeadPC", io.commits.info(0).pc)
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
  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 已提交
889

Y
Yinan Xu 已提交
890

891 892 893 894 895 896 897 898 899
  //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)))
  val trapVec = Wire(Vec(CommitWidth, Bool()))
  for(i <- 0 until CommitWidth) {
    val idx = deqPtrVec(i).value
    wdata(i) := debug_exuData(idx)
900 901
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
    trapVec(i) := io.commits.valid(i) && (state===s_idle) && commitDebugUop(i).ctrl.isXSTrap
902
  }
903
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
904 905
  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)
906

907 908 909 910
  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)

911
  if (!env.FPGAPlatform) {
912 913 914
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
W
wakafa 已提交
915
      difftest.io.coreid   := hardId.U
916 917 918
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
919
      val uop = commitDebugUop(i)
920 921 922 923 924
      val exuOut = debug_exuDebug(ptr)
      val exuData = debug_exuData(ptr)
      difftest.io.valid    := RegNext(io.commits.valid(i) && !io.commits.isWalk)
      difftest.io.pc       := RegNext(SignExt(uop.cf.pc, XLEN))
      difftest.io.instr    := RegNext(uop.cf.instr)
925
      difftest.io.special  := RegNext(uop.ctrl.isFused =/= 0.U)
926 927 928
      // when committing an eliminated move instruction,
      // we must make sure that skip is properly set to false (output from EXU is random value)
      difftest.io.skip     := RegNext(Mux(uop.eliminatedMove, false.B, exuOut.isMMIO || exuOut.isPerfCnt))
929 930 931 932 933 934 935
      difftest.io.isRVC    := RegNext(uop.cf.pd.isRVC)
      difftest.io.scFailed := RegNext(!uop.diffTestDebugLrScValid &&
        uop.ctrl.fuType === FuType.mou &&
        (uop.ctrl.fuOpType === LSUOpType.sc_d || uop.ctrl.fuOpType === LSUOpType.sc_w))
      difftest.io.wen      := RegNext(io.commits.valid(i) && uop.ctrl.rfWen && uop.ctrl.ldest =/= 0.U)
      difftest.io.wdata    := RegNext(exuData)
      difftest.io.wdest    := RegNext(uop.ctrl.ldest)
936 937

      // XSDebug(p"[difftest-instr-commit]valid:${difftest.io.valid},pc:${difftest.io.pc},instr:${difftest.io.instr},skip:${difftest.io.skip},isRVC:${difftest.io.isRVC},scFailed:${difftest.io.scFailed},wen:${difftest.io.wen},wdata:${difftest.io.wdata},wdest:${difftest.io.wdest}\n")
W
William Wang 已提交
938 939 940 941 942 943 944 945 946 947

      // runahead commit hint
      val runahead_commit = Module(new DifftestRunaheadCommitEvent)
      runahead_commit.io.clock := clock
      runahead_commit.io.coreid := hardId.U
      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
948 949 950 951 952 953 954
    }
  }

  if (!env.FPGAPlatform) {
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestLoadEvent)
      difftest.io.clock  := clock
W
wakafa 已提交
955
      difftest.io.coreid := hardId.U
956 957 958
      difftest.io.index  := i.U

      val ptr = deqPtrVec(i).value
959
      val uop = commitDebugUop(i)
960
      val exuOut = debug_exuDebug(ptr)
W
wakafa 已提交
961 962 963 964
      difftest.io.valid  := RegNext(io.commits.valid(i) && !io.commits.isWalk)
      difftest.io.paddr  := RegNext(exuOut.paddr)
      difftest.io.opType := RegNext(uop.ctrl.fuOpType)
      difftest.io.fuType := RegNext(uop.ctrl.fuType)
965 966 967 968 969 970
    }
  }

  if (!env.FPGAPlatform) {
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
W
wakafa 已提交
971
    difftest.io.coreid   := hardId.U
972 973 974
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
975
    difftest.io.cycleCnt := timer
976
    difftest.io.instrCnt := instrCnt
977
  }
978
}