Rob.scala 44.6 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], flush: Bool): Bool = {
Y
Yinan Xu 已提交
33 34
    val flushItself = redirect.bits.flushItself() && this === redirect.bits.robIdx
    flush || (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)
Y
Yinan Xu 已提交
106
  val exceptionEnable = io.deq_w(0) && io.exception_state.valid && 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
  // 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 resetDeqPtrVec = VecInit((0 until CommitWidth).map(_.U.asTypeOf(new RobPtr)))
Y
Yinan Xu 已提交
119 120 121 122 123 124 125 126 127
  val commitDeqPtrVec = VecInit(deqPtrVec.map(_ + commitCnt))
  val deqPtrVec_next = Mux(redirectOutValid, resetDeqPtrVec, Mux(io.state === 0.U, commitDeqPtrVec, deqPtrVec))

  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
  val io = IO(new Bundle {
    // for exceptions and interrupts
    val state = Input(UInt(2.W))
    val deq_v = Input(Bool())
    val deq_w = Input(Bool())
Y
Yinan Xu 已提交
139 140
    val deqPtr = Input(new RobPtr)
    val exception_state = Flipped(ValidIO(new RobExceptionInfo))
Y
Yinan Xu 已提交
141 142 143 144 145 146 147 148 149
    val intrBitSetReg = Input(Bool())
    val hasNoSpecExec = Input(Bool())
    val commitType = Input(CommitType())
    // 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 已提交
150
    val out = Output(new RobPtr)
Y
Yinan Xu 已提交
151 152
  })

Y
Yinan Xu 已提交
153
  val enqPtr = RegInit(0.U.asTypeOf(new RobPtr))
Y
Yinan Xu 已提交
154 155 156 157

  // for exceptions (flushPipe included) and interrupts:
  // only consider the first instruction
  val intrEnable = io.intrBitSetReg && !io.hasNoSpecExec && !CommitType.isLoadStore(io.commitType)
Y
Yinan Xu 已提交
158
  val exceptionEnable = io.deq_w(0) && io.exception_state.valid && io.exception_state.bits.robIdx === io.deqPtr
Y
Yinan Xu 已提交
159 160 161 162
  val redirectOutValid = io.state === 0.U && io.deq_v && (intrEnable || exceptionEnable)

  // enqueue
  val canAccept = io.allowEnqueue && !io.hasBlockBackward
163
  val dispatchNum = Mux(canAccept && !RegNext(redirectOutValid), PopCount(io.enq), 0.U)
Y
Yinan Xu 已提交
164 165

  when (redirectOutValid) {
Y
Yinan Xu 已提交
166
    enqPtr := 0.U.asTypeOf(new RobPtr)
Y
Yinan Xu 已提交
167
  }.elsewhen (io.redirect.valid) {
Y
Yinan Xu 已提交
168
    enqPtr := io.redirect.bits.robIdx + Mux(io.redirect.bits.flushItself(), 0.U, 1.U)
Y
Yinan Xu 已提交
169 170
  }.otherwise {
    enqPtr := enqPtr + dispatchNum
Y
Yinan Xu 已提交
171
  }
Y
Yinan Xu 已提交
172 173 174

  io.out := enqPtr

Y
Yinan Xu 已提交
175 176
}

Y
Yinan Xu 已提交
177
class RobExceptionInfo(implicit p: Parameters) extends XSBundle {
178
  // val valid = Bool()
Y
Yinan Xu 已提交
179
  val robIdx = new RobPtr
180 181
  val exceptionVec = ExceptionVec()
  val flushPipe = Bool()
W
William Wang 已提交
182
  val replayInst = Bool() // redirect to that inst itself
183
  val singleStep = Bool()
184

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

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

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

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

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

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

261 262
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

360
  io.enq.canAccept := allowEnqueue && !hasBlockBackward
361
  io.enq.resp      := enqPtrVec
362
  val canEnqueue = VecInit(io.enq.req.map(_.valid && io.enq.canAccept))
363
  val timer = GTimer()
Y
Yinan Xu 已提交
364
  for (i <- 0 until RenameWidth) {
365 366 367 368
    // we don't check whether io.redirect is valid here since redirect has higher priority
    when (canEnqueue(i)) {
      // store uop in data module and debug_microOp Vec
      debug_microOp(enqPtrVec(i).value) := io.enq.req(i).bits
369 370 371 372 373
      debug_microOp(enqPtrVec(i).value).debugInfo.dispatchTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.enqRsTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.selectTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.issueTime := timer
      debug_microOp(enqPtrVec(i).value).debugInfo.writebackTime := timer
374
      when (io.enq.req(i).bits.ctrl.blockBackward) {
375 376
        hasBlockBackward := true.B
      }
377
      when (io.enq.req(i).bits.ctrl.noSpecExec) {
378 379
        hasNoSpecExec := true.B
      }
W
William Wang 已提交
380 381
    }
  }
382 383
  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 已提交
384

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

W
William Wang 已提交
389

Y
Yinan Xu 已提交
390 391 392
  /**
    * Writeback (from execution units)
    */
393 394
  for (i <- 0 until numWbPorts) {
    when (io.exeWbResults(i).valid) {
Y
Yinan Xu 已提交
395
      val wbIdx = io.exeWbResults(i).bits.uop.robIdx.value
396 397
      debug_microOp(wbIdx).cf.exceptionVec := io.exeWbResults(i).bits.uop.cf.exceptionVec
      debug_microOp(wbIdx).ctrl.flushPipe := io.exeWbResults(i).bits.uop.ctrl.flushPipe
398
      debug_microOp(wbIdx).ctrl.replayInst := io.exeWbResults(i).bits.uop.ctrl.replayInst
399
      debug_microOp(wbIdx).diffTestDebugLrScValid := io.exeWbResults(i).bits.uop.diffTestDebugLrScValid
400 401
      debug_exuData(wbIdx) := io.exeWbResults(i).bits.data
      debug_exuDebug(wbIdx) := io.exeWbResults(i).bits.debug
402 403
      debug_microOp(wbIdx).debugInfo.enqRsTime := io.exeWbResults(i).bits.uop.debugInfo.enqRsTime
      debug_microOp(wbIdx).debugInfo.selectTime := io.exeWbResults(i).bits.uop.debugInfo.selectTime
404 405
      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 已提交
406

407
      val debug_Uop = debug_microOp(wbIdx)
Y
Yinan Xu 已提交
408
      XSInfo(true.B,
409
        p"writebacked pc 0x${Hexadecimal(debug_Uop.cf.pc)} wen ${debug_Uop.ctrl.rfWen} " +
Y
Yinan Xu 已提交
410
        p"data 0x${Hexadecimal(io.exeWbResults(i).bits.data)} ldst ${debug_Uop.ctrl.ldest} pdst ${debug_Uop.pdest} " +
Y
Yinan Xu 已提交
411
        p"skip ${io.exeWbResults(i).bits.debug.isMMIO} robIdx: ${io.exeWbResults(i).bits.uop.robIdx}\n"
412
      )
W
William Wang 已提交
413 414
    }
  }
415 416 417
  val writebackNum = PopCount(io.exeWbResults.map(_.valid))
  XSInfo(writebackNum =/= 0.U, "writebacked %d insts\n", writebackNum)

W
William Wang 已提交
418

Y
Yinan Xu 已提交
419
  /**
420
    * RedirectOut: Interrupt and Exceptions
Y
Yinan Xu 已提交
421
    */
Y
Yinan Xu 已提交
422
  val deqDispatchData = dispatchDataRead(0)
423 424 425 426 427
  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 已提交
428
  val intrBitSetReg = RegNext(io.csr.intrBitSet)
429
  val intrEnable = intrBitSetReg && !hasNoSpecExec && !CommitType.isLoadStore(deqDispatchData.commitType)
Y
Yinan Xu 已提交
430
  val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
431
  val deqHasException = deqHasExceptionOrFlush && exceptionDataRead.bits.exceptionVec.asUInt.orR
432
  val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
W
William Wang 已提交
433
  val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
434
  val exceptionEnable = writebacked(deqPtr.value) && deqHasException
W
William Wang 已提交
435
  val isFlushPipe = writebacked(deqPtr.value) && (deqHasFlushPipe || deqHasReplayInst)
436

437
  io.flushOut.valid := (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable || isFlushPipe)
438 439
  io.flushOut.bits.ftqIdx := deqDispatchData.ftqIdx
  io.flushOut.bits.ftqOffset := deqDispatchData.ftqOffset
W
William Wang 已提交
440
  io.flushOut.bits.replayInst := deqHasReplayInst
441 442 443 444
  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)
445 446 447 448 449

  val exceptionHappen = (state === s_idle) && valid(deqPtr.value) && (intrEnable || exceptionEnable)
  io.exception.valid := RegNext(exceptionHappen)
  io.exception.bits.uop := RegEnable(debug_deqUop, exceptionHappen)
  io.exception.bits.uop.ctrl.commitType := RegEnable(deqDispatchData.commitType, exceptionHappen)
450
  io.exception.bits.uop.cf.exceptionVec := RegEnable(exceptionDataRead.bits.exceptionVec, exceptionHappen)
451
  io.exception.bits.uop.ctrl.singleStep := RegEnable(exceptionDataRead.bits.singleStep, exceptionHappen)
452 453
  io.exception.bits.uop.cf.crossPageIPFFix := RegEnable(deqDispatchData.crossPageIPFFix, exceptionHappen)
  io.exception.bits.isInterrupt := RegEnable(intrEnable, exceptionHappen)
454 455 456

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

460

Y
Yinan Xu 已提交
461 462 463 464
  /**
    * Commits (and walk)
    * They share the same width.
    */
Y
Yinan Xu 已提交
465
  val walkCounter = Reg(UInt(log2Up(RobSize).W))
466
  val shouldWalkVec = VecInit((0 until CommitWidth).map(_.U < walkCounter))
Y
Yinan Xu 已提交
467
  val walkFinished = walkCounter <= CommitWidth.U
W
William Wang 已提交
468

Y
Yinan Xu 已提交
469
  // extra space is used when rob has no enough space, but mispredict recovery needs such info to walk regmap
Y
Yinan Xu 已提交
470
  require(RenameWidth <= CommitWidth)
Y
Yinan Xu 已提交
471
  val extraSpaceForMPR = Reg(Vec(RenameWidth, new RobDispatchData))
W
William Wang 已提交
472
  val usedSpaceForMPR = Reg(Vec(RenameWidth, Bool()))
Y
Yinan Xu 已提交
473 474 475
  when (io.enq.needAlloc.asUInt.orR && io.redirect.valid) {
    usedSpaceForMPR := io.enq.needAlloc
    extraSpaceForMPR := dispatchData.io.wdata
Y
Yinan Xu 已提交
476
    XSDebug("rob full, switched to s_extrawalk. needExtraSpaceForMPR: %b\n", io.enq.needAlloc.asUInt)
Y
Yinan Xu 已提交
477
  }
W
William Wang 已提交
478

L
linjiawei 已提交
479
  // wiring to csr
480 481 482 483 484 485 486
  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())
487
  fflags.bits := wflags.zip(fflagsDataRead).map({
488 489 490
    case (w, f) => Mux(w, f, 0.U)
  }).reduce(_|_)
  val dirty_fs = Mux(io.commits.isWalk, false.B, Cat(fpWen).orR())
Y
Yinan Xu 已提交
491

W
William Wang 已提交
492
  // when mispredict branches writeback, stop commit in the next 2 cycles
L
LinJiawei 已提交
493
  // TODO: don't check all exu write back
L
LinJiawei 已提交
494
  val misPredWb = Cat(VecInit((0 until numWbPorts).map(i =>
L
LinJiawei 已提交
495
    io.exeWbResults(i).bits.redirect.cfiUpdate.isMisPred && io.exeWbResults(i).bits.redirectValid
L
LinJiawei 已提交
496
  ))).orR()
497
  val misPredBlockCounter = Reg(UInt(3.W))
L
LinJiawei 已提交
498
  misPredBlockCounter := Mux(misPredWb,
499
    "b111".U,
W
William Wang 已提交
500 501 502 503
    misPredBlockCounter >> 1.U
  )
  val misPredBlock = misPredBlockCounter(0)

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

519 520 521
    when (state === s_walk) {
      io.commits.valid(i) := commit_v(i) && shouldWalkVec(i)
    }.elsewhen(state === s_extrawalk) {
Y
Yinan Xu 已提交
522 523
      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 已提交
524
    }
525 526 527 528 529 530 531 532 533

    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),
534
      fflagsDataRead(i)
535 536 537 538 539 540 541 542 543 544 545
    )
    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 已提交
546
  }
547 548
  if (!env.FPGAPlatform) {
    io.commits.info.map(info => dontTouch(info.pc))
W
William Wang 已提交
549
  }
W
William Wang 已提交
550

551
  // sync fflags/dirty_fs to csr
552 553
  io.csr.fflags := fflags
  io.csr.dirty_fs := dirty_fs
554

555 556 557
  // 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 已提交
558

559 560 561 562 563 564 565 566
  // 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)
567 568 569

  /**
    * state changes
Y
Yinan Xu 已提交
570 571 572 573
    * (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
574
    */
575
  val state_next = Mux(io.flushOut.valid,
Y
Yinan Xu 已提交
576 577 578 579 580 581 582 583 584 585
    s_idle,
    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)
      )
    )
  )
  state := state_next
586

587
  /**
588
    * pointers and counters
589
    */
Y
Yinan Xu 已提交
590
  val deqPtrGenModule = Module(new RobDeqPtrWrapper)
Y
Yinan Xu 已提交
591 592 593
  deqPtrGenModule.io.state := state
  deqPtrGenModule.io.deq_v := commit_v
  deqPtrGenModule.io.deq_w := commit_w
594
  deqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
595 596 597
  deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  deqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
  deqPtrGenModule.io.commitType := deqDispatchData.commitType
L
LinJiawei 已提交
598 599

  deqPtrGenModule.io.misPredBlock := misPredBlock
600
  deqPtrGenModule.io.isReplaying := isReplaying
Y
Yinan Xu 已提交
601
  deqPtrVec := deqPtrGenModule.io.out
Y
Yinan Xu 已提交
602
  val deqPtrVec_next = deqPtrGenModule.io.next_out
603

Y
Yinan Xu 已提交
604
  val enqPtrGenModule = Module(new RobEnqPtrWrapper)
Y
Yinan Xu 已提交
605 606 607
  enqPtrGenModule.io.state := state
  enqPtrGenModule.io.deq_v := commit_v(0)
  enqPtrGenModule.io.deq_w := commit_w(0)
608 609
  enqPtrGenModule.io.deqPtr := deqPtr
  enqPtrGenModule.io.exception_state := exceptionDataRead
Y
Yinan Xu 已提交
610 611 612 613 614 615 616 617
  enqPtrGenModule.io.intrBitSetReg := intrBitSetReg
  enqPtrGenModule.io.hasNoSpecExec := hasNoSpecExec
  enqPtrGenModule.io.commitType := deqDispatchData.commitType
  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
618 619

  val thisCycleWalkCount = Mux(walkFinished, walkCounter, CommitWidth.U)
Y
Yinan Xu 已提交
620 621 622 623 624
  // 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,
625 626
      VecInit(walkPtrVec.map(_ - thisCycleWalkCount)),
      VecInit((0 until CommitWidth).map(i => enqPtr - (i+1).U))
Y
Yinan Xu 已提交
627 628 629 630
    ),
    Mux(state === s_walk, VecInit(walkPtrVec.map(_ - CommitWidth.U)), walkPtrVec)
  )
  walkPtrVec := walkPtrVec_next
W
William Wang 已提交
631

632
  val lastCycleRedirect = RegNext(io.redirect.valid)
633
  val trueValidCounter = Mux(lastCycleRedirect, distanceBetween(enqPtr, deqPtr), validCounter)
Y
Yinan Xu 已提交
634
  val commitCnt = PopCount(io.commits.valid)
635
  validCounter := Mux(io.flushOut.valid,
636
    0.U,
637
    Mux(state === s_idle,
638
      (validCounter - commitCnt) + dispatchNum,
639 640 641 642
      trueValidCounter
    )
  )

643
  allowEnqueue := Mux(io.flushOut.valid,
644 645
    true.B,
    Mux(state === s_idle,
Y
Yinan Xu 已提交
646 647
      validCounter + dispatchNum <= (RobSize - RenameWidth).U,
      trueValidCounter <= (RobSize - RenameWidth).U
648 649 650
    )
  )

651
  val currentWalkPtr = Mux(state === s_walk || state === s_extrawalk, walkPtr, enqPtr - 1.U)
Y
Yinan Xu 已提交
652
  val redirectWalkDistance = distanceBetween(currentWalkPtr, io.redirect.bits.robIdx)
653 654 655 656 657 658 659 660
  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")
661 662
  }

663

Y
Yinan Xu 已提交
664 665
  /**
    * States
666
    * We put all the stage bits changes here.
Y
Yinan Xu 已提交
667

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

673 674
  // enqueue logic writes 6 valid
  for (i <- 0 until RenameWidth) {
675
    when (canEnqueue(i) && !io.redirect.valid && !RegNext(io.flushOut.valid)) {
Y
Yinan Xu 已提交
676
      valid(enqPtrVec(i).value) := true.B
677 678 679
    }
  }
  // dequeue/walk logic writes 6 valid, dequeue and walk will not happen at the same time
680 681 682
  for (i <- 0 until CommitWidth) {
    when (io.commits.valid(i) && state =/= s_extrawalk) {
      valid(commitReadAddr(i)) := false.B
683 684
    }
  }
685
  // reset: when exception, reset all valid to false
686
  when (io.flushOut.valid) {
Y
Yinan Xu 已提交
687
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
688 689
      valid(i) := false.B
    }
690
  }
Y
Yinan Xu 已提交
691
  when (reset.asBool) {
Y
Yinan Xu 已提交
692
    for (i <- 0 until RobSize) {
Y
Yinan Xu 已提交
693 694
      valid(i) := false.B
    }
695
  }
696

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

  // flagBkup
  // enqueue logic set 6 flagBkup at most
  for (i <- 0 until RenameWidth) {
733
    when (canEnqueue(i)) {
Y
Yinan Xu 已提交
734
      flagBkup(enqPtrVec(i).value) := enqPtrVec(i).flag
735 736 737
    }
  }

Y
Yinan Xu 已提交
738 739 740 741 742 743 744 745 746 747

  /**
    * 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)
748
  dispatchData.io.wdata.zip(io.enq.req.map(_.bits)).foreach{ case (wdata, req) =>
Y
Yinan Xu 已提交
749 750 751 752 753
    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
754
    wdata.eliminatedMove := req.eliminatedMove
Y
Yinan Xu 已提交
755 756
    wdata.pdest := req.pdest
    wdata.old_pdest := req.old_pdest
L
Lingrui98 已提交
757 758
    wdata.ftqIdx := req.cf.ftqPtr
    wdata.ftqOffset := req.cf.ftqOffset
Y
Yinan Xu 已提交
759 760
    wdata.pc := req.cf.pc
    wdata.crossPageIPFFix := req.cf.crossPageIPFFix
761
    wdata.isFused := req.ctrl.isFused
762
    // wdata.exceptionVec := req.cf.exceptionVec
Y
Yinan Xu 已提交
763 764 765
  }
  dispatchData.io.raddr := commitReadAddr_next

766 767 768 769
  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 已提交
770
    exceptionGen.io.enq(i).bits.robIdx := io.enq.req(i).bits.robIdx
771 772
    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
773
    exceptionGen.io.enq(i).bits.replayInst := io.enq.req(i).bits.ctrl.replayInst
W
William Wang 已提交
774
    assert(exceptionGen.io.enq(i).bits.replayInst === false.B)
775
    exceptionGen.io.enq(i).bits.singleStep := io.enq.req(i).bits.ctrl.singleStep
Y
Yinan Xu 已提交
776
  }
777 778

  // TODO: don't hard code these idxes
779
  val numIntWbPorts = exuParameters.AluCnt + exuParameters.LduCnt + exuParameters.MduCnt
780 781 782 783
  // 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
784
  def store_wb_idxes = io.exeWbResults.indices.takeRight(2)
785 786
  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) }
787 788
  def connect_exception(index: Int, wb_index: Int) = {
    exceptionGen.io.wb(index).valid             := io.exeWbResults(wb_index).valid
789 790 791 792 793 794 795
    // 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 已提交
796
    exceptionGen.io.wb(index).bits.robIdx       := io.exeWbResults(wb_index).bits.uop.robIdx
797 798 799 800 801 802 803
    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 _
    }
804 805
    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
806
    exceptionGen.io.wb(index).bits.replayInst   := io.exeWbResults(wb_index).bits.uop.ctrl.replayInst
807
    exceptionGen.io.wb(index).bits.singleStep   := false.B
808
  }
Y
Yinan Xu 已提交
809

810
  // 4 fmac + 2 fmisc + 1 i2f
811 812 813
  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
814
  val fflags_wb = io.exeWbResults.zipWithIndex.filter(w => {
815
    (fmacWb ++ fmiscWb ++ i2fWb).contains(w._2)
816 817
  }).map(_._1)
  val fflagsDataModule = Module(new SyncDataModuleTemplate(
Y
Yinan Xu 已提交
818
    UInt(5.W), RobSize, CommitWidth, fflags_wb.size)
819 820 821
  )
  for(i <- fflags_wb.indices){
    fflagsDataModule.io.wen  (i) := fflags_wb(i).valid
Y
Yinan Xu 已提交
822
    fflagsDataModule.io.waddr(i) := fflags_wb(i).bits.uop.robIdx.value
823
    fflagsDataModule.io.wdata(i) := fflags_wb(i).bits.fflags
824 825 826 827 828
  }
  fflagsDataModule.io.raddr := VecInit(deqPtrVec_next.map(_.value))
  fflagsDataRead := fflagsDataModule.io.rdata


829 830 831 832 833 834
  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 已提交
835
  io.robFull := !allowEnqueue
836

837 838 839
  /**
    * debug info
    */
840
  XSDebug(p"enqPtr ${enqPtr} deqPtr ${deqPtr}\n")
W
William Wang 已提交
841
  XSDebug("")
Y
Yinan Xu 已提交
842
  for(i <- 0 until RobSize){
Y
Yinan Xu 已提交
843 844 845
    XSDebug(false, !valid(i), "-")
    XSDebug(false, valid(i) && writebacked(i), "w")
    XSDebug(false, valid(i) && !writebacked(i), "v")
W
William Wang 已提交
846
  }
Y
Yinan Xu 已提交
847 848
  XSDebug(false, true.B, "\n")

Y
Yinan Xu 已提交
849
  for(i <- 0 until RobSize) {
Y
Yinan Xu 已提交
850
    if(i % 4 == 0) XSDebug("")
851
    XSDebug(false, true.B, "%x ", debug_microOp(i).cf.pc)
Y
Yinan Xu 已提交
852 853 854 855
    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 已提交
856
  }
W
William Wang 已提交
857

858 859 860
  def ifCommit(counter: UInt): UInt = Mux(io.commits.isWalk, 0.U, counter)

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

Y
Yinan Xu 已提交
921

922 923 924 925 926 927 928 929 930
  //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)
931 932
    wpc(i) := SignExt(commitDebugUop(i).cf.pc, XLEN)
    trapVec(i) := io.commits.valid(i) && (state===s_idle) && commitDebugUop(i).ctrl.isXSTrap
933
  }
934
  val retireCounterFix = Mux(io.exception.valid, 1.U, retireCounter)
935 936
  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)
937

938 939 940 941
  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)

942
  if (!env.FPGAPlatform) {
943 944 945
    for (i <- 0 until CommitWidth) {
      val difftest = Module(new DifftestInstrCommit)
      difftest.io.clock    := clock
W
wakafa 已提交
946
      difftest.io.coreid   := hardId.U
947 948 949
      difftest.io.index    := i.U

      val ptr = deqPtrVec(i).value
950
      val uop = commitDebugUop(i)
951 952 953 954 955
      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)
956
      difftest.io.special  := RegNext(uop.ctrl.isFused =/= 0.U)
957 958 959
      // 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))
960 961 962 963 964 965 966
      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)
967 968

      // 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 已提交
969 970 971 972 973 974 975 976 977 978

      // 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
979 980 981 982 983 984 985
    }
  }

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

      val ptr = deqPtrVec(i).value
990
      val uop = commitDebugUop(i)
991
      val exuOut = debug_exuDebug(ptr)
W
wakafa 已提交
992 993 994 995
      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)
996 997 998 999 1000 1001
    }
  }

  if (!env.FPGAPlatform) {
    val difftest = Module(new DifftestTrapEvent)
    difftest.io.clock    := clock
W
wakafa 已提交
1002
    difftest.io.coreid   := hardId.U
1003 1004 1005
    difftest.io.valid    := hitTrap
    difftest.io.code     := trapCode
    difftest.io.pc       := trapPC
1006
    difftest.io.cycleCnt := timer
1007
    difftest.io.instrCnt := instrCnt
1008
  }
1009
}