Skip to content

Commit

Permalink
Rob: fix bug of exception (#3161)
Browse files Browse the repository at this point in the history
1.when writeback exception, rob may commit next cycle. 2.when fulshOut,
rob commit info to ftq may 4 cycle after redirect but redirect info to
ftq need 5 cycle.
  • Loading branch information
xiaofeibao-xjtu authored Jul 9, 2024
1 parent 6bb8be2 commit 571677c
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 45 deletions.
6 changes: 6 additions & 0 deletions src/main/scala/xiangshan/backend/CtrlBlock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ class CtrlBlockImp(
delayed.bits.debugInfo.writebackTime := GTimer()
delayed
}).toSeq
val delayedNotFlushedWriteBackNeedFlush = Wire(Vec(params.allExuParams.filter(_.needExceptionGen).length, Bool()))
delayedNotFlushedWriteBackNeedFlush := delayedNotFlushedWriteBack.filter(_.bits.params.needExceptionGen).map{ x =>
x.bits.exceptionVec.get.asUInt.orR || x.bits.flushPipe.getOrElse(false.B) || x.bits.replay.getOrElse(false.B) ||
(if (x.bits.trigger.nonEmpty) x.bits.trigger.get.getBackendCanFire else false.B)
}

val wbDataNoStd = io.fromWB.wbData.filter(!_.bits.params.hasStdFu)
val intScheWbData = io.fromWB.wbData.filter(_.bits.params.schdType.isInstanceOf[IntScheduler])
Expand Down Expand Up @@ -535,6 +540,7 @@ class CtrlBlockImp(
rob.io.redirect := s1_s3_redirect
rob.io.writeback := delayedNotFlushedWriteBack
rob.io.writebackNums := VecInit(delayedNotFlushedWriteBackNums)
rob.io.writebackNeedFlush := delayedNotFlushedWriteBackNeedFlush
rob.io.readGPAMemData := gpaMem.io.exceptionReadData

io.redirect := s1_s3_redirect
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/xiangshan/backend/rename/Rename.scala
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ class Rename(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHe

uops(i).robIdx := robIdxHead + PopCount(io.in.zip(needRobFlags).take(i).map{ case(in, needRobFlag) => in.valid && in.bits.lastUop && needRobFlag})
uops(i).instrSize := instrSizesVec(i)
when(isMove(i)) {
val hasExceptionExceptFlushPipe = Cat(selectFrontend(uops(i).exceptionVec) :+ uops(i).exceptionVec(illegalInstr) :+ uops(i).exceptionVec(virtualInstr)).orR || uops(i).trigger.getFrontendCanFire
when(isMove(i) || hasExceptionExceptFlushPipe) {
uops(i).numUops := 0.U
uops(i).numWB := 0.U
}
Expand Down
107 changes: 64 additions & 43 deletions src/main/scala/xiangshan/backend/rob/Rob.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
// exu + brq
val writeback: MixedVec[ValidIO[ExuOutput]] = Flipped(params.genWrite2CtrlBundles)
val writebackNums = Flipped(Vec(writeback.size - params.StdCnt, ValidIO(UInt(writeback.size.U.getWidth.W))))
val writebackNeedFlush = Input(Vec(params.allExuParams.filter(_.needExceptionGen).length, Bool()))
val commits = Output(new RobCommitIO)
val rabCommits = Output(new RabCommitIO)
val diffCommits = if (backendParams.debugEn) Some(Output(new DiffCommitIO)) else None
Expand Down Expand Up @@ -475,43 +476,46 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
val deqDispatchData = robEntries(deqPtr.value)
val debug_deqUop = debug_microOp(deqPtr.value)

val deqPtrEntry = robDeqGroup(deqPtr.value(bankAddrWidth-1,0))
val deqPtrEntryValid = deqPtrEntry.commit_v
val intrBitSetReg = RegNext(io.csr.intrBitSet)
val intrEnable = intrBitSetReg && !hasWaitForward && robDeqGroup(deqPtr.value(bankAddrWidth-1,0)).interrupt_safe
val deqHasExceptionOrFlush = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
val deqHasException = deqHasExceptionOrFlush && (exceptionDataRead.bits.exceptionVec.asUInt.orR ||
exceptionDataRead.bits.singleStep || exceptionDataRead.bits.trigger.canFire)
val deqHasFlushPipe = deqHasExceptionOrFlush && exceptionDataRead.bits.flushPipe
val deqHasReplayInst = deqHasExceptionOrFlush && exceptionDataRead.bits.replayInst
val exceptionEnable = robEntries(deqPtr.value).isWritebacked && deqHasException
val intrEnable = intrBitSetReg && !hasWaitForward && deqPtrEntry.interrupt_safe
val deqNeedFlush = deqPtrEntry.needFlush && deqPtrEntry.commit_v && deqPtrEntry.commit_w
val deqHitExceptionGenState = exceptionDataRead.valid && exceptionDataRead.bits.robIdx === deqPtr
val deqNeedFlushAndHitExceptionGenState = deqNeedFlush && deqHitExceptionGenState
val exceptionGenStateIsException = exceptionDataRead.bits.exceptionVec.asUInt.orR || exceptionDataRead.bits.singleStep || exceptionDataRead.bits.trigger.canFire
val deqHasException = deqNeedFlushAndHitExceptionGenState && exceptionGenStateIsException
val deqHasFlushPipe = deqNeedFlushAndHitExceptionGenState && exceptionDataRead.bits.flushPipe
val deqHasReplayInst = deqNeedFlushAndHitExceptionGenState && exceptionDataRead.bits.replayInst

XSDebug(deqHasException && exceptionDataRead.bits.singleStep, "Debug Mode: Deq has singlestep exception\n")
XSDebug(deqHasException && exceptionDataRead.bits.trigger.getFrontendCanFire, "Debug Mode: Deq has frontend trigger exception\n")
XSDebug(deqHasException && exceptionDataRead.bits.trigger.getBackendCanFire, "Debug Mode: Deq has backend trigger exception\n")

val isFlushPipe = robEntries(deqPtr.value).isWritebacked && (deqHasFlushPipe || deqHasReplayInst)
val isFlushPipe = deqPtrEntry.commit_w && (deqHasFlushPipe || deqHasReplayInst)

val isVsetFlushPipe = robEntries(deqPtr.value).isWritebacked && deqHasFlushPipe && exceptionDataRead.bits.isVset
val isVsetFlushPipe = deqPtrEntry.commit_w && deqHasFlushPipe && exceptionDataRead.bits.isVset
// val needModifyFtqIdxOffset = isVsetFlushPipe && (vsetvlState === vs_waitFlush)
val needModifyFtqIdxOffset = false.B
io.isVsetFlushPipe := isVsetFlushPipe
// 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) && robEntries(deqPtr.value).valid && (intrEnable || exceptionEnable || isFlushPipe) && !lastCycleFlush
io.flushOut.valid := (state === s_idle) && deqPtrEntryValid && (intrEnable || deqHasException || isFlushPipe) && !lastCycleFlush
io.flushOut.bits := DontCare
io.flushOut.bits.isRVC := deqDispatchData.isRVC
io.flushOut.bits.robIdx := Mux(needModifyFtqIdxOffset, firstVInstrRobIdx, deqPtr)
io.flushOut.bits.ftqIdx := Mux(needModifyFtqIdxOffset, firstVInstrFtqPtr, deqDispatchData.ftqIdx)
io.flushOut.bits.ftqOffset := Mux(needModifyFtqIdxOffset, firstVInstrFtqOffset, deqDispatchData.ftqOffset)
io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || exceptionEnable || needModifyFtqIdxOffset, RedirectLevel.flush, RedirectLevel.flushAfter) // TODO use this to implement "exception next"
io.flushOut.bits.level := Mux(deqHasReplayInst || intrEnable || deqHasException || needModifyFtqIdxOffset, RedirectLevel.flush, RedirectLevel.flushAfter) // TODO use this to implement "exception next"
io.flushOut.bits.interrupt := true.B
XSPerfAccumulate("interrupt_num", io.flushOut.valid && intrEnable)
XSPerfAccumulate("exception_num", io.flushOut.valid && exceptionEnable)
XSPerfAccumulate("exception_num", io.flushOut.valid && deqHasException)
XSPerfAccumulate("flush_pipe_num", io.flushOut.valid && isFlushPipe)
XSPerfAccumulate("replay_inst_num", io.flushOut.valid && isFlushPipe && deqHasReplayInst)

val exceptionHappen = (state === s_idle) && robEntries(deqPtr.value).valid && (intrEnable || exceptionEnable) && !lastCycleFlush
val exceptionHappen = (state === s_idle) && deqPtrEntryValid && (intrEnable || deqHasException) && !lastCycleFlush
io.exception.valid := RegNext(exceptionHappen)
io.exception.bits.pc := RegEnable(debug_deqUop.pc, exceptionHappen)
io.exception.bits.gpaddr := io.readGPAMemData
Expand All @@ -532,7 +536,7 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP

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


Expand Down Expand Up @@ -599,7 +603,21 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
misPredBlockCounter >> 1.U
)
val misPredBlock = misPredBlockCounter(0)
val blockCommit = misPredBlock || lastCycleFlush || hasWFI || io.redirect.valid
val deqFlushBlockCounter = Reg(UInt(3.W))
val deqFlushBlock = deqFlushBlockCounter(0)
val deqHasFlushed = Reg(Bool())
val deqHitRedirectReg = RegNext(io.redirect.valid && io.redirect.bits.robIdx === deqPtr)
when(deqNeedFlush && deqHitRedirectReg){
deqFlushBlockCounter := "b111".U
}.otherwise{
deqFlushBlockCounter := deqFlushBlockCounter >> 1.U
}
when(deqNeedFlush && io.flushOut.valid){
deqHasFlushed := true.B
}.elsewhen(!deqNeedFlush){
deqHasFlushed := false.B
}
val blockCommit = misPredBlock || lastCycleFlush || hasWFI || io.redirect.valid || (deqNeedFlush && !deqHasFlushed && !deqHasFlushPipe) || deqFlushBlock

io.commits.isWalk := state === s_walk
io.commits.isCommit := state === s_idle && !blockCommit
Expand All @@ -608,15 +626,15 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
val commit_vDeqGroup = VecInit(robDeqGroup.map(_.commit_v))
val commit_wDeqGroup = VecInit(robDeqGroup.map(_.commit_w))
val realCommitLast = deqPtrVec(0).lineHeadPtr + Fill(bankAddrWidth, 1.U)
val commit_exception = exceptionDataRead.valid && !isAfter(exceptionDataRead.bits.robIdx, realCommitLast)
val commit_block = VecInit((0 until CommitWidth).map(i => !commit_wDeqGroup(i) && !hasCommitted(i)))
val allowOnlyOneCommit = commit_exception || intrBitSetReg
val allowOnlyOneCommit = VecInit(robDeqGroup.map(x => x.commit_v && x.needFlush)).asUInt.orR || intrBitSetReg
// for instructions that may block others, we don't allow them to commit
io.commits.commitValid := PriorityMux(commitValidThisLine, (0 until CommitWidth).map(i => (commitValidThisLine.asUInt >> i).asUInt.asTypeOf(io.commits.commitValid)))

for (i <- 0 until CommitWidth) {
// defaults: state === s_idle and instructions commit
// when intrBitSetReg, allow only one instruction to commit at each clock cycle
val isBlocked = intrEnable || deqHasException || deqHasReplayInst
val isBlocked = intrEnable || (deqNeedFlush && !deqHasFlushed && !deqHasFlushPipe)
val isBlockedByOlder = if (i != 0) commit_block.asUInt(i, 0).orR || allowOnlyOneCommit && !hasCommitted.asUInt(i - 1, 0).andR else false.B
commitValidThisLine(i) := commit_vDeqGroup(i) && commit_wDeqGroup(i) && !isBlocked && !isBlockedByOlder && !hasCommitted(i)
io.commits.info(i) := commitInfo(i)
Expand Down Expand Up @@ -698,6 +716,7 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
deqPtrGenModule.io.exception_state := exceptionDataRead
deqPtrGenModule.io.intrBitSetReg := intrBitSetReg
deqPtrGenModule.io.hasNoSpecExec := hasWaitForward
deqPtrGenModule.io.allowOnlyOneCommit := allowOnlyOneCommit
deqPtrGenModule.io.interrupt_safe := robDeqGroup(deqPtr.value(bankAddrWidth-1,0)).interrupt_safe
deqPtrGenModule.io.blockCommit := blockCommit
deqPtrGenModule.io.hasCommitted := hasCommitted
Expand Down Expand Up @@ -873,19 +892,19 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
val canWbSeq = exuWBs.map(writeback => writeback.valid && writeback.bits.robIdx.value === i.U)
val canWbNoBlockSeq = canWbSeq.zip(blockWbSeq).map { case (canWb, blockWb) => canWb && !blockWb }
val canStdWbSeq = VecInit(stdWBs.map(writeback => writeback.valid && writeback.bits.robIdx.value === i.U))
val wbCnt = Mux1H(canWbNoBlockSeq, io.writebackNums.map(_.bits))

val exceptionHas = RegInit(false.B)
val exceptionHasWire = Wire(Bool())
exceptionHasWire := MuxCase(exceptionHas, Seq(
(robEntries(i).valid && exceptionGen.io.out.valid && exceptionGen.io.out.bits.robIdx.value === i.U) -> true.B,
!robEntries(i).valid -> false.B
))
exceptionHas := exceptionHasWire
val wbCnt = Mux1H(canWbSeq, io.writebackNums.map(_.bits))

val canWbExceptionSeq = exceptionWBs.map(writeback => writeback.valid && writeback.bits.robIdx.value === i.U)
val needFlush = robEntries(i).needFlush
val needFlushWriteBack = Wire(Bool())
needFlushWriteBack := Mux1H(canWbExceptionSeq, io.writebackNeedFlush)
when(robEntries(i).valid){
needFlush := needFlush || needFlushWriteBack
}

when(exceptionHas || exceptionHasWire) {
when(robEntries(i).valid && (needFlush || needFlushWriteBack)) {
// exception flush
robEntries(i).uopNum := 0.U
robEntries(i).uopNum := robEntries(i).uopNum - wbCnt
robEntries(i).stdWritebacked := true.B
}.elsewhen(!robEntries(i).valid && instCanEnqFlag) {
// enq set num of uops
Expand Down Expand Up @@ -933,20 +952,19 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
val canWbSeq = exuWBs.map(writeback => writeback.valid && writeback.bits.robIdx.value === needUpdateRobIdx(i))
val canWbNoBlockSeq = canWbSeq.zip(blockWbSeq).map { case (canWb, blockWb) => canWb && !blockWb }
val canStdWbSeq = VecInit(stdWBs.map(writeback => writeback.valid && writeback.bits.robIdx.value === needUpdateRobIdx(i)))
val wbCnt = Mux1H(canWbNoBlockSeq, io.writebackNums.map(_.bits))

val exceptionHas = RegInit(false.B)
val exceptionHasWire = Wire(Bool())
exceptionHasWire := MuxCase(exceptionHas, Seq(
// allCommitted has high priority, because the robidx in exceptionHas before maybe different from the current one
(!needUpdate(i).valid || allCommitted) -> false.B,
(needUpdate(i).valid && exceptionGen.io.out.valid && exceptionGen.io.out.bits.robIdx.value === needUpdateRobIdx(i)) -> true.B
))
exceptionHas := exceptionHasWire

when(exceptionHas || exceptionHasWire) {
val wbCnt = Mux1H(canWbSeq, io.writebackNums.map(_.bits))

val canWbExceptionSeq = exceptionWBs.map(writeback => writeback.valid && (writeback.bits.robIdx.value === needUpdateRobIdx(i)))
val needFlush = robBanksRdata(i).needFlush
val needFlushWriteBack = Wire(Bool())
needFlushWriteBack := Mux1H(canWbExceptionSeq, io.writebackNeedFlush)
when(needUpdate(i).valid) {
needUpdate(i).needFlush := needFlush || needFlushWriteBack
}

when(needUpdate(i).valid && (needFlush || needFlushWriteBack)) {
// exception flush
needUpdate(i).uopNum := 0.U
needUpdate(i).uopNum := robBanksRdata(i).uopNum - wbCnt
needUpdate(i).stdWritebacked := true.B
}.elsewhen(!needUpdate(i).valid && instCanEnqFlag) {
// enq set num of uops
Expand Down Expand Up @@ -1329,7 +1347,7 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
val commitStoreVec = VecInit(io.commits.commitValid.zip(commitIsStore).map { case (v, t) => v && t })
val perfEvents = Seq(
("rob_interrupt_num ", io.flushOut.valid && intrEnable),
("rob_exception_num ", io.flushOut.valid && exceptionEnable),
("rob_exception_num ", io.flushOut.valid && deqHasException),
("rob_flush_pipe_num ", io.flushOut.valid && isFlushPipe),
("rob_replay_inst_num ", io.flushOut.valid && isFlushPipe && deqHasReplayInst),
("rob_commitUop ", ifCommit(commitCnt)),
Expand Down Expand Up @@ -1362,6 +1380,9 @@ class RobImp(override val wrapper: Rob)(implicit p: Parameters, params: BackendP
dontTouch(robBanksRdataNextLine)
dontTouch(robBanksRdataThisLineUpdate)
dontTouch(robBanksRdataNextLineUpdate)
dontTouch(needUpdate)
val exceptionWBsVec = MixedVecInit(exceptionWBs)
dontTouch(exceptionWBsVec)
dontTouch(commit_wDeqGroup)
dontTouch(commit_vDeqGroup)
dontTouch(commitSizeSumSeq)
Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/xiangshan/backend/rob/RobBundles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ object RobBundles extends HasCircularQueuePtrHelper {
val realDestSize = UInt(log2Up(MaxUopSize + 1).W)
val uopNum = UInt(log2Up(MaxUopSize + 1).W)
val commitTrigger = Bool()
val needFlush = Bool()
// status end

// debug_begin
Expand Down Expand Up @@ -107,6 +108,7 @@ object RobBundles extends HasCircularQueuePtrHelper {
val rfWen = Bool()
val loadWaitBit = Bool() // for perfEvents
val isMove = Bool() // for perfEvents
val needFlush = Bool()
// debug_begin
val debug_pc = OptionWrapper(backendParams.debugEn, UInt(VAddrBits.W))
val debug_instr = OptionWrapper(backendParams.debugEn, UInt(32.W))
Expand All @@ -132,6 +134,8 @@ object RobBundles extends HasCircularQueuePtrHelper {
robEntry.dirtyVs := robEnq.dirtyVs
robEntry.loadWaitBit := robEnq.loadWaitBit
robEntry.eliminatedMove := robEnq.eliminatedMove
// flushPipe needFlush but not exception
robEntry.needFlush := robEnq.hasException || robEnq.flushPipe
robEntry.debug_pc.foreach(_ := robEnq.pc)
robEntry.debug_instr.foreach(_ := robEnq.instr)
robEntry.debug_ldest.foreach(_ := robEnq.ldest)
Expand Down Expand Up @@ -160,6 +164,7 @@ object RobBundles extends HasCircularQueuePtrHelper {
robCommitEntry.loadWaitBit := robEntry.loadWaitBit
robCommitEntry.isMove := robEntry.eliminatedMove
robCommitEntry.dirtyVs := robEntry.dirtyVs
robCommitEntry.needFlush := robEntry.needFlush
robCommitEntry.debug_pc.foreach(_ := robEntry.debug_pc.get)
robCommitEntry.debug_instr.foreach(_ := robEntry.debug_instr.get)
robCommitEntry.debug_ldest.foreach(_ := robEntry.debug_ldest.get)
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/xiangshan/backend/rob/RobDeqPtrWrapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class NewRobDeqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircu
val exception_state = Flipped(ValidIO(new RobExceptionInfo))
// for flush: when exception occurs, reset deqPtrs to range(0, CommitWidth)
val intrBitSetReg = Input(Bool())
val allowOnlyOneCommit = Input(Bool())
val hasNoSpecExec = Input(Bool())
val interrupt_safe = Input(Bool())
val blockCommit = Input(Bool())
Expand Down Expand Up @@ -74,7 +75,7 @@ class NewRobDeqPtrWrapper(implicit p: Parameters) extends XSModule with HasCircu
val normalCommitCnt = PriorityEncoder(canCommit.map(c => !c) :+ true.B) - PopCount(io.hasCommitted)
// when io.intrBitSetReg or there're possible exceptions in these instructions,
// only one instruction is allowed to commit
val allowOnlyOne = commit_exception || io.intrBitSetReg
val allowOnlyOne = io.allowOnlyOneCommit
val commitCnt = Mux(allowOnlyOne, canCommit(realCommitLast.value), normalCommitCnt)
val allowOnlyOneCond = Wire(chiselTypeOf(io.canCommitPriorityCond))
allowOnlyOneCond.zipWithIndex.map{ case (value,i) => {
Expand Down

0 comments on commit 571677c

Please sign in to comment.