From ec2ac1dfc97e99caf8a2ebbd4b5b72f036cb8a6d Mon Sep 17 00:00:00 2001 From: ngc7331 Date: Tue, 3 Jun 2025 14:45:30 +0800 Subject: [PATCH] feat(Frontend): support hardware error exception --- .../scala/xiangshan/frontend/Bundles.scala | 84 +++++++--- .../xiangshan/frontend/ibuffer/Bundles.scala | 157 +++++++----------- .../xiangshan/frontend/icache/Bundles.scala | 1 + .../frontend/icache/ICacheMainPipe.scala | 15 +- .../frontend/icache/ICacheMissUnit.scala | 15 +- .../scala/xiangshan/frontend/ifu/Ifu.scala | 27 ++- .../frontend/ifu/IfuUncacheUnit.scala | 2 +- .../frontend/instruncache/Bundles.scala | 6 +- .../instruncache/InstrUncacheEntry.scala | 3 + 9 files changed, 169 insertions(+), 141 deletions(-) diff --git a/src/main/scala/xiangshan/frontend/Bundles.scala b/src/main/scala/xiangshan/frontend/Bundles.scala index 42a8c58a7..ad909968b 100644 --- a/src/main/scala/xiangshan/frontend/Bundles.scala +++ b/src/main/scala/xiangshan/frontend/Bundles.scala @@ -174,6 +174,8 @@ class ExceptionType extends Bundle { def isPf: Bool = value === ExceptionType.Value.Pf def isGpf: Bool = value === ExceptionType.Value.Gpf def isAf: Bool = value === ExceptionType.Value.Af + def isIll: Bool = value === ExceptionType.Value.Ill + def isHwe: Bool = value === ExceptionType.Value.Hwe def hasException: Bool = value =/= ExceptionType.Value.None @@ -191,11 +193,13 @@ class ExceptionType extends Bundle { } object ExceptionType { - private object Value extends EnumUInt(4) { + private object Value extends EnumUInt(6) { def None: UInt = 0.U(width.W) def Pf: UInt = 1.U(width.W) // instruction page fault def Gpf: UInt = 2.U(width.W) // instruction guest page fault def Af: UInt = 3.U(width.W) // instruction access fault + def Ill: UInt = 4.U(width.W) // illegal instruction + def Hwe: UInt = 5.U(width.W) // hardware error } def apply(that: UInt): ExceptionType = { @@ -209,14 +213,25 @@ object ExceptionType { def Pf: ExceptionType = apply(Value.Pf) def Gpf: ExceptionType = apply(Value.Gpf) def Af: ExceptionType = apply(Value.Af) + def Ill: ExceptionType = apply(Value.Ill) + def Hwe: ExceptionType = apply(Value.Hwe) - def apply(hasPf: Bool, hasGpf: Bool, hasAf: Bool): ExceptionType = { + def apply( + hasPf: Bool, + hasGpf: Bool, + hasAf: Bool, + hasIll: Bool, + hasHwe: Bool, + canAssert: Bool = true.B // prevent assert(x) + ): ExceptionType = { assert( - PopCount(VecInit(hasPf, hasGpf, hasAf)) <= 1.U, - "ExceptionType receives input that is not one-hot: pf=%d, gpf=%d, af=%d", + !canAssert || PopCount(VecInit(hasPf, hasGpf, hasAf, hasIll, hasHwe)) <= 1.U, + "ExceptionType receives input that is not one-hot: pf=%d, gpf=%d, af=%d, ill=%d, hwe=%d", hasPf, hasGpf, - hasAf + hasAf, + hasIll, + hasHwe ) // input is at-most-one-hot encoded, so we don't worry about priority here. MuxCase( @@ -224,38 +239,60 @@ object ExceptionType { Seq( hasPf -> Pf, hasGpf -> Gpf, - hasAf -> Af + hasAf -> Af, + hasIll -> Ill, + hasHwe -> Hwe ) ) } // only af is used most frequently (pmp / ecc / tilelink), so we define a shortcut // we cannot use default parameter in apply(), as it is overloaded and scala won't allow - def apply(hasAf: Bool): ExceptionType = - apply(hasPf = false.B, hasGpf = false.B, hasAf = hasAf) + def hasAf(hasAf: Bool, canAssert: Bool = true.B): ExceptionType = + apply(false.B, false.B, hasAf, false.B, false.B, canAssert) // raise pf/gpf/af according to backend redirect request (tlb pre-check) - def fromBackend(redirect: Redirect): ExceptionType = + def fromBackend(redirect: Redirect, canAssert: Bool = true.B): ExceptionType = apply( - hasPf = redirect.backendIPF, - hasGpf = redirect.backendIGPF, - hasAf = redirect.backendIAF + redirect.backendIPF, + redirect.backendIGPF, + redirect.backendIAF, + false.B, + false.B, + canAssert ) // raise pf/gpf/af according to itlb response - def fromTlbResp(resp: TlbResp, useDup: Int = 0): ExceptionType = { + def fromTlbResp(resp: TlbResp, canAssert: Bool = true.B, useDup: Int = 0): ExceptionType = { require(useDup >= 0 && useDup < resp.excp.length) // itlb is guaranteed to respond at most one exception apply( - hasPf = resp.excp(useDup).pf.instr, - hasGpf = resp.excp(useDup).gpf.instr, - hasAf = resp.excp(useDup).af.instr + resp.excp(useDup).pf.instr, + resp.excp(useDup).gpf.instr, + resp.excp(useDup).af.instr, + false.B, + false.B, + canAssert ) } // raise af if pmp check failed - def fromPmpResp(resp: PMPRespBundle): ExceptionType = - apply(hasAf = resp.instr) + def fromPmpResp(resp: PMPRespBundle, canAssert: Bool = true.B): ExceptionType = + hasAf(resp.instr, canAssert) + + // raise af / hwe according to tilelink response + def fromTileLink(corrupt: Bool, denied: Bool, canAssert: Bool = true.B): ExceptionType = { + // corrupt && denied -> access fault + // corrupt && !denied -> hardware error + // !corrupt && !denied -> no exception + // !corrupt && denied -> violates tilelink specification, should not happen + assert(!canAssert || !(denied && !corrupt), "TileLink response should not be denied but !corrupt") + apply(false.B, false.B, denied, false.B, corrupt && !denied, canAssert) + } + + // raise ill according to rvc expander + def fromRvcExpander(ill: Bool, canAssert: Bool = true.B): ExceptionType = + apply(false.B, false.B, false.B, ill, false.B, canAssert) } object BrType extends EnumUInt(4) { @@ -297,12 +334,11 @@ class FetchToIBuffer(implicit p: Parameters) extends FrontendBundle { val foldpc: Vec[UInt] = Vec(IBufferEnqueueWidth, UInt(MemPredPCWidth.W)) val instrEndOffset: Vec[InstrEndOffset] = Vec(IBufferEnqueueWidth, new InstrEndOffset) // val ftqPcOffset: Vec[Valid[FtqPcOffset]] = Vec(IBufferEnqueueWidth, Valid(new FtqPcOffset)) - val backendException: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) - val exceptionType: Vec[ExceptionType] = Vec(IBufferEnqueueWidth, new ExceptionType) - val crossPageIPFFix: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) - val illegalInstr: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) - val triggered: Vec[UInt] = Vec(IBufferEnqueueWidth, TriggerAction()) - val isLastInFtqEntry: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) + val isBackendException: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) + val exceptionType: Vec[ExceptionType] = Vec(IBufferEnqueueWidth, new ExceptionType) + val exceptionCrossPage: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) + val triggered: Vec[UInt] = Vec(IBufferEnqueueWidth, TriggerAction()) + val isLastInFtqEntry: Vec[Bool] = Vec(IBufferEnqueueWidth, Bool()) val pc: Vec[PrunedAddr] = Vec(IBufferEnqueueWidth, PrunedAddr(VAddrBits)) val prevIBufEnqPtr: IBufPtr = new IBufPtr diff --git a/src/main/scala/xiangshan/frontend/ibuffer/Bundles.scala b/src/main/scala/xiangshan/frontend/ibuffer/Bundles.scala index 946248645..3ed934a0a 100644 --- a/src/main/scala/xiangshan/frontend/ibuffer/Bundles.scala +++ b/src/main/scala/xiangshan/frontend/ibuffer/Bundles.scala @@ -47,94 +47,57 @@ class IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr]( p(XSCoreParamsKey).frontendParameters.ibufferParameters.NumReadBank ) {} -// FIXME: this is to encode cross-page & ill into 3 bits, remove this when we support ill & hwe in ExceptionType -object IBufferExceptionType extends EnumUInt(8) { - def None: UInt = "b000".U(width.W) - def NonCrossPF: UInt = "b001".U(width.W) - def NonCrossGPF: UInt = "b010".U(width.W) - def NonCrossAF: UInt = "b011".U(width.W) - def RvcII: UInt = "b100".U(width.W) // illegal instruction - def CrossPF: UInt = "b101".U(width.W) - def CrossGPF: UInt = "b110".U(width.W) - def CrossAF: UInt = "b111".U(width.W) - - def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: ExceptionType, crossPage: Bool, rvcIll: Bool): UInt = - MuxCase( - 0.U, - Seq( - crossPage -> Cat(1.U(1.W), fetchExcp.value), - fetchExcp.hasException -> fetchExcp.value, - rvcIll -> this.RvcII - ) - ) - - def isRVCII(uint: UInt): Bool = { - this.checkInputWidth(uint) - uint(2) && uint(1, 0) === 0.U - } - - def isCrossPage(uint: UInt): Bool = { - this.checkInputWidth(uint) - uint(2) && uint(1, 0) =/= 0.U - } - - def isPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0) - def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0) - def isAF(uint: UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0) -} - class IBufEntry(implicit p: Parameters) extends IBufferBundle { - val inst: UInt = UInt(32.W) - val pc: PrunedAddr = PrunedAddr(VAddrBits) - val foldpc: UInt = UInt(MemPredPCWidth.W) - val pd: PreDecodeInfo = new PreDecodeInfo - val predTaken: Bool = Bool() - val identifiedCfi: Bool = Bool() - val ftqPtr: FtqPtr = new FtqPtr - val instrEndOffset: UInt = UInt(FetchBlockInstOffsetWidth.W) - val exceptionType: UInt = IBufferExceptionType() - val backendException: Bool = Bool() - val triggered: UInt = TriggerAction() - val isLastInFtqEntry: Bool = Bool() + val inst: UInt = UInt(32.W) + val pc: PrunedAddr = PrunedAddr(VAddrBits) + val foldpc: UInt = UInt(MemPredPCWidth.W) + val pd: PreDecodeInfo = new PreDecodeInfo + val predTaken: Bool = Bool() + val identifiedCfi: Bool = Bool() + val ftqPtr: FtqPtr = new FtqPtr + val instrEndOffset: UInt = UInt(FetchBlockInstOffsetWidth.W) + val exceptionType: ExceptionType = new ExceptionType + val exceptionCrossPage: Bool = Bool() + val isBackendException: Bool = Bool() + val triggered: UInt = TriggerAction() + val isLastInFtqEntry: Bool = Bool() val debug_seqNum: UInt = InstSeqNum() def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = { - inst := fetch.instrs(i) - pc := fetch.pc(i) - foldpc := fetch.foldpc(i) - pd := fetch.pd(i) - predTaken := fetch.instrEndOffset(i).taken - identifiedCfi := fetch.identifiedCfi(i) - ftqPtr := fetch.ftqPtr - instrEndOffset := fetch.instrEndOffset(i).offset - exceptionType := IBufferExceptionType.cvtFromFetchExcpAndCrossPageAndRVCII( - fetch.exceptionType(i), - fetch.crossPageIPFFix(i), - fetch.illegalInstr(i) - ) - backendException := fetch.backendException(i) - triggered := fetch.triggered(i) - isLastInFtqEntry := fetch.isLastInFtqEntry(i) - debug_seqNum := fetch.debug_seqNum(i) + inst := fetch.instrs(i) + pc := fetch.pc(i) + foldpc := fetch.foldpc(i) + pd := fetch.pd(i) + predTaken := fetch.instrEndOffset(i).taken + identifiedCfi := fetch.identifiedCfi(i) + ftqPtr := fetch.ftqPtr + instrEndOffset := fetch.instrEndOffset(i).offset + exceptionType := fetch.exceptionType(i) + exceptionCrossPage := fetch.exceptionCrossPage(i) + isBackendException := fetch.isBackendException(i) + triggered := fetch.triggered(i) + isLastInFtqEntry := fetch.isLastInFtqEntry(i) + debug_seqNum := fetch.debug_seqNum(i) this } def toIBufOutEntry: IBufOutEntry = { val result = Wire(new IBufOutEntry) - result.inst := inst - result.pc := pc - result.foldpc := foldpc - result.pd := pd - result.predTaken := predTaken - result.identifiedCfi := identifiedCfi - result.ftqPtr := ftqPtr - result.exceptionType := exceptionType - result.backendException := backendException - result.triggered := triggered - result.isLastInFtqEntry := isLastInFtqEntry - result.debug_seqNum := debug_seqNum - result.instrEndOffset := instrEndOffset + result.inst := inst + result.pc := pc + result.foldpc := foldpc + result.pd := pd + result.predTaken := predTaken + result.identifiedCfi := identifiedCfi + result.ftqPtr := ftqPtr + result.exceptionType := exceptionType + result.exceptionCrossPage := exceptionCrossPage + result.isBackendException := isBackendException + result.triggered := triggered + result.isLastInFtqEntry := isLastInFtqEntry + result.debug_seqNum := debug_seqNum + result.instrEndOffset := instrEndOffset result } } @@ -143,18 +106,19 @@ class IBufEntry(implicit p: Parameters) extends IBufferBundle { // In the future, the backend will perform certain computations // in the IBuffer, which will be differentiated from IBufEntry. class IBufOutEntry(implicit p: Parameters) extends IBufferBundle { - val inst: UInt = UInt(32.W) - val pc: PrunedAddr = PrunedAddr(VAddrBits) - val foldpc: UInt = UInt(MemPredPCWidth.W) - val pd: PreDecodeInfo = new PreDecodeInfo - val predTaken: Bool = Bool() - val identifiedCfi: Bool = Bool() - val ftqPtr: FtqPtr = new FtqPtr - val exceptionType: UInt = IBufferExceptionType() - val backendException: Bool = Bool() - val triggered: UInt = TriggerAction() - val isLastInFtqEntry: Bool = Bool() - val instrEndOffset: UInt = UInt(FetchBlockInstOffsetWidth.W) + val inst: UInt = UInt(32.W) + val pc: PrunedAddr = PrunedAddr(VAddrBits) + val foldpc: UInt = UInt(MemPredPCWidth.W) + val pd: PreDecodeInfo = new PreDecodeInfo + val predTaken: Bool = Bool() + val identifiedCfi: Bool = Bool() + val ftqPtr: FtqPtr = new FtqPtr + val exceptionType: ExceptionType = new ExceptionType + val exceptionCrossPage: Bool = Bool() + val isBackendException: Bool = Bool() + val triggered: UInt = TriggerAction() + val isLastInFtqEntry: Bool = Bool() + val instrEndOffset: UInt = UInt(FetchBlockInstOffsetWidth.W) val debug_seqNum: UInt = InstSeqNum() @@ -164,16 +128,17 @@ class IBufOutEntry(implicit p: Parameters) extends IBufferBundle { cf.pc := pc.toUInt cf.foldpc := foldpc cf.exceptionVec := 0.U.asTypeOf(ExceptionVec()) - cf.exceptionVec(ExceptionNO.instrPageFault) := IBufferExceptionType.isPF(exceptionType) - cf.exceptionVec(ExceptionNO.instrGuestPageFault) := IBufferExceptionType.isGPF(exceptionType) - cf.exceptionVec(ExceptionNO.instrAccessFault) := IBufferExceptionType.isAF(exceptionType) - cf.exceptionVec(ExceptionNO.illegalInstr) := IBufferExceptionType.isRVCII(exceptionType) - cf.backendException := backendException + cf.exceptionVec(ExceptionNO.instrPageFault) := exceptionType.isPf + cf.exceptionVec(ExceptionNO.instrGuestPageFault) := exceptionType.isGpf + cf.exceptionVec(ExceptionNO.instrAccessFault) := exceptionType.isAf + cf.exceptionVec(ExceptionNO.illegalInstr) := exceptionType.isIll + cf.exceptionVec(ExceptionNO.hardwareError) := exceptionType.isHwe + cf.backendException := isBackendException cf.trigger := triggered cf.pd := pd cf.pred_taken := predTaken cf.identifiedCfi := identifiedCfi - cf.crossPageIPFFix := IBufferExceptionType.isCrossPage(exceptionType) + cf.crossPageIPFFix := exceptionCrossPage cf.storeSetHit := DontCare cf.waitForRobIdx := DontCare cf.loadWaitBit := DontCare diff --git a/src/main/scala/xiangshan/frontend/icache/Bundles.scala b/src/main/scala/xiangshan/frontend/icache/Bundles.scala index 05a3a35c3..a22bba61f 100644 --- a/src/main/scala/xiangshan/frontend/icache/Bundles.scala +++ b/src/main/scala/xiangshan/frontend/icache/Bundles.scala @@ -265,6 +265,7 @@ class MissRespBundle(implicit p: Parameters) extends ICacheBundle { val waymask: UInt = UInt(nWays.W) val data: UInt = UInt(blockBits.W) val corrupt: Bool = Bool() + val denied: Bool = Bool() } /* ***** Mshr ***** */ diff --git a/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala b/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala index c504db942..900478f90 100644 --- a/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala +++ b/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala @@ -232,13 +232,20 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule ) }) - private val s1_l2Corrupt = VecInit((0 until PortNumber).map { i => + private val s1_tlCorrupt = VecInit((0 until PortNumber).map { i => DataHoldBypass( s1_mshrHits(i) && fromMiss.bits.corrupt, s1_mshrHits(i) || RegNext(s0_fire) ) }) + private val s1_tlDenied = VecInit((0 until PortNumber).map { i => + DataHoldBypass( + s1_mshrHits(i) && fromMiss.bits.denied, + s1_mshrHits(i) || RegNext(s0_fire) + ) + }) + /* *** Update replacer *** */ (0 until PortNumber).foreach { i => io.replacerTouch.req(i).bits.vSetIdx := s1_vSetIdx(i) @@ -358,11 +365,13 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule private val s1_fetchFinish = !s1_shouldFetch.reduce(_ || _) // also raise af if l2 corrupt is detected - private val s1_l2Exception = ExceptionType(hasAf = s1_l2Corrupt.reduce(_ || _)) + private val s1_tlException = (s1_tlCorrupt zip s1_tlDenied).map { case (corrupt, denied) => + ExceptionType.fromTileLink(corrupt, denied, s1_valid) // s1_valid used only for assertion + }.reduce(_ || _) // NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2 // merge s2 exceptions, itlb/pmp has the highest priority, then l2 - private val s1_exceptionOut = s1_exception || s1_l2Exception + private val s1_exceptionOut = s1_exception || s1_tlException /* *** send response to IFU *** */ toIfu.valid := s1_fire diff --git a/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala b/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala index 882372019..bdceab0cc 100644 --- a/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala +++ b/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala @@ -182,19 +182,20 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModu private val lastFireNext = RegNext(lastFire) private val idNext = RegNext(io.memGrant.bits.source) - // if any beat is corrupt, the whole response (to mainPipe/metaArray/dataArray) is corrupt private val corruptReg = RegInit(false.B) - when(io.memGrant.fire && edge.hasData(io.memGrant.bits) && io.memGrant.bits.corrupt) { - // Set corruptReg when any beat is corrupt - // This is actually when(xxx.fire && xxx.hasData) { corruptReg := corruptReg || io.mem_grant.bits.corrupt } - corruptReg := true.B + private val deniedReg = RegInit(false.B) + when(io.memGrant.fire && edge.hasData(io.memGrant.bits)) { + // Set corruptReg / deniedReg when any beat is corrupt / denied + corruptReg := corruptReg || io.memGrant.bits.corrupt + deniedReg := deniedReg || io.memGrant.bits.denied }.elsewhen(lastFireNext) { - // Clear corruptReg when response it sent to mainPipe + // Clear corruptReg / deniedReg when response it sent to mainPipe // This used to be io.resp.valid (lastFireNext && mshrValid) but when mshr is flushed by io.flush/fencei, // mshrValid is false.B and corruptReg will never be cleared, that's not correct // so we remove mshrValid here, and the condition leftover is lastFireNext // or, actually, io.resp.valid || (lastFireNext && !mshrValid) corruptReg := false.B + deniedReg := false.B } /** @@ -225,6 +226,7 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModu // unnecessary response will be dropped by mainPipe/prefetchPipe/wayLookup since their sx_valid is set to false private val respValid = mshrValid && lastFireNext // NOTE: but we should not write meta/dataArray when flush/fencei + // NOTE: tilelink spec asks corrupt to be set when denied is set, so we don't need to check deniedReg here private val writeSramValid = respValid && !corruptReg && !io.flush && !io.fencei // write SRAM @@ -253,6 +255,7 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModu io.resp.bits.waymask := waymask io.resp.bits.data := respDataReg.asUInt io.resp.bits.corrupt := corruptReg + io.resp.bits.denied := deniedReg // we are safe to enter wfi if all entries have no pending response from L2 io.wfi.wfiSafe := allMshr.map(_.io.wfi.wfiSafe).reduce(_ && _) diff --git a/src/main/scala/xiangshan/frontend/ifu/Ifu.scala b/src/main/scala/xiangshan/frontend/ifu/Ifu.scala index d1a4a92ec..ae0b4b4c0 100644 --- a/src/main/scala/xiangshan/frontend/ifu/Ifu.scala +++ b/src/main/scala/xiangshan/frontend/ifu/Ifu.scala @@ -509,7 +509,9 @@ class Ifu(implicit p: Parameters) extends IfuModule private val s4_alignExpdInstr = VecInit(rvcExpanders.map { expander: RvcExpander => Mux(expander.io.ill, expander.io.in, expander.io.out.bits) }) - private val s4_alignIll = VecInit(rvcExpanders.map(_.io.ill)) + private val s4_alignRvcException = VecInit(rvcExpanders.map { expander: RvcExpander => + ExceptionType.fromRvcExpander(expander.io.ill) + }) private val s4_alignPdWire = RegEnable(s3_alignPd, s3_fire) private val s4_alignPds = WireInit(s4_alignPdWire) @@ -678,19 +680,23 @@ class Ifu(implicit p: Parameters) extends IfuModule // mark the exception only on first instruction // TODO: store only the first exception in IBuffer, instead of store in every entry io.toIBuffer.bits.exceptionType := (0 until IBufferEnqueueWidth).map { - i => Mux(i.U === s4_prevIBufEnqPtr.value(1, 0), s4_icacheMeta(0).exception, ExceptionType.None) + i => + Mux( + i.U === s4_prevIBufEnqPtr.value(1, 0), + s4_icacheMeta(0).exception, + ExceptionType.None + ) || s4_alignRvcException(i) } // backendException only needs to be set for the first instruction. // Other instructions in the same block may have pf or af set, // which is a side effect of the first instruction and actually not necessary. - io.toIBuffer.bits.backendException := (0 until IBufferEnqueueWidth).map { + io.toIBuffer.bits.isBackendException := (0 until IBufferEnqueueWidth).map { i => i.U === s4_prevIBufEnqPtr.value(1, 0) && s4_icacheMeta(0).isBackendException } // if we have last half RV-I instruction, and has exception, we need to tell backend to caculate the correct pc - io.toIBuffer.bits.crossPageIPFFix := (0 until IBufferEnqueueWidth).map { + io.toIBuffer.bits.exceptionCrossPage := (0 until IBufferEnqueueWidth).map { i => i.U === s4_prevIBufEnqPtr.value(1, 0) && s4_icacheMeta(0).exception.hasException && s4_prevLastIsHalfRvi } - io.toIBuffer.bits.illegalInstr := s4_alignIll io.toIBuffer.bits.triggered := s4_alignTriggered io.toIBuffer.bits.identifiedCfi := s4_alignCompactInfo.identifiedCfi @@ -742,6 +748,9 @@ class Ifu(implicit p: Parameters) extends IfuModule when(s4_reqIsUncache) { val inst = s4_uncacheData val (brType, isCall, isRet) = getBrInfo(inst) + + val uncacheRvcException = ExceptionType.fromRvcExpander(uncacheRvcExpander.io.ill) + io.toIBuffer.bits.instrs(s4_shiftNum) := Mux( uncacheRvcExpander.io.ill, uncacheRvcExpander.io.in, @@ -756,11 +765,11 @@ class Ifu(implicit p: Parameters) extends IfuModule io.toIBuffer.bits.pd(s4_shiftNum).isRet := isRet io.toIBuffer.bits.instrEndOffset(s4_shiftNum).offset := Mux(prevUncacheCrossPage || uncacheIsRvc, 0.U, 1.U) - io.toIBuffer.bits.exceptionType(s4_shiftNum) := uncacheException + io.toIBuffer.bits.exceptionType(s4_shiftNum) := uncacheException || uncacheRvcException // execption can happen in next page only when cross page. - io.toIBuffer.bits.crossPageIPFFix(s4_shiftNum) := prevUncacheCrossPage && uncacheException.hasException - io.toIBuffer.bits.illegalInstr(s4_shiftNum) := uncacheRvcExpander.io.ill - io.toIBuffer.bits.enqEnable := s4_alignBlockStartPos.asUInt + io.toIBuffer.bits.exceptionCrossPage(s4_shiftNum) := prevUncacheCrossPage && uncacheException.hasException + + io.toIBuffer.bits.enqEnable := s4_alignBlockStartPos.asUInt uncacheFlushWb.bits.isRVC := uncacheIsRvc uncacheFlushWb.bits.attribute := BranchAttribute(brType, Cat(isCall, isRet)) diff --git a/src/main/scala/xiangshan/frontend/ifu/IfuUncacheUnit.scala b/src/main/scala/xiangshan/frontend/ifu/IfuUncacheUnit.scala index f5a6dd95a..6bd6d9023 100644 --- a/src/main/scala/xiangshan/frontend/ifu/IfuUncacheUnit.scala +++ b/src/main/scala/xiangshan/frontend/ifu/IfuUncacheUnit.scala @@ -114,7 +114,7 @@ class IfuUncacheUnit(implicit p: Parameters) extends IfuModule with IfuHelper { is(UncacheFsmState.WaitResp) { when(fromUncache.fire) { - val exception = ExceptionType(hasAf = fromUncache.bits.corrupt) + val exception = ExceptionType.fromTileLink(fromUncache.bits.corrupt, fromUncache.bits.denied) val crossPage = fromUncache.bits.incomplete uncacheState := UncacheFsmState.Idle uncacheException := exception diff --git a/src/main/scala/xiangshan/frontend/instruncache/Bundles.scala b/src/main/scala/xiangshan/frontend/instruncache/Bundles.scala index a27b8c793..a1d17341a 100644 --- a/src/main/scala/xiangshan/frontend/instruncache/Bundles.scala +++ b/src/main/scala/xiangshan/frontend/instruncache/Bundles.scala @@ -26,7 +26,9 @@ class InstrUncacheReq(implicit p: Parameters) extends InstrUncacheBundle { } class InstrUncacheResp(implicit p: Parameters) extends InstrUncacheBundle { - val data: UInt = UInt(32.W) // TODO: add a const for InstrLen, maybe in XSParameters, and use it all over the repo - val corrupt: Bool = Bool() + // TODO: add a const for InstrLen, maybe in XSParameters, and use it all over the repo, remove magic number 32 + val data: UInt = UInt(32.W) + val corrupt: Bool = Bool() + val denied: Bool = Bool() val incomplete: Bool = Bool() // whether this.data is incomplete (e.g. crossing a page boundary) } diff --git a/src/main/scala/xiangshan/frontend/instruncache/InstrUncacheEntry.scala b/src/main/scala/xiangshan/frontend/instruncache/InstrUncacheEntry.scala index cba1446a0..a27ace2ac 100644 --- a/src/main/scala/xiangshan/frontend/instruncache/InstrUncacheEntry.scala +++ b/src/main/scala/xiangshan/frontend/instruncache/InstrUncacheEntry.scala @@ -94,11 +94,13 @@ class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUn private val respDataReg = RegInit(VecInit.fill(2)(0.U(16.W))) // FIXME: 2 * rvc, how to avoid magic number? private val respCorruptReg = RegInit(false.B) + private val respDeniedReg = RegInit(false.B) // send response to InstrUncache io.resp.valid := state === State.SendResp && !needFlush io.resp.bits.data := respDataReg.asUInt io.resp.bits.corrupt := respCorruptReg + io.resp.bits.denied := respDeniedReg io.resp.bits.incomplete := crossPageBoundary // state transfer @@ -149,6 +151,7 @@ class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUn respDataReg(1) := shiftedBusData(31, 16) } respCorruptReg := io.mmioGrant.bits.corrupt + respDeniedReg := io.mmioGrant.bits.denied } }