refactor(Frontend): replace NamedUInt with EnumUInt (#4529)
EMU Test / Changes Detection (push) Has been cancelled Details
EMU Test / Generate Verilog (push) Has been cancelled Details
EMU Test / EMU - Basics (push) Has been cancelled Details
EMU Test / EMU - CHI (push) Has been cancelled Details
EMU Test / EMU - Performance (push) Has been cancelled Details
EMU Test / EMU - MC (push) Has been cancelled Details
EMU Test / SIMV - Basics (push) Has been cancelled Details
EMU Test / Upload Artifacts (push) Has been cancelled Details
EMU Test / Check Submodules (push) Has been cancelled Details
EMU Test / Check Format (push) Has been cancelled Details

Use EnumUInt introduced by #4528 to do some compile-time check.

Also:
- add `class ExceptionType` to replace `ExceptionType.hasException(xxx)`
with `xxx.hasException`, etc.
- apply CamelCase to `BrType`.
This commit is contained in:
xu_zh 2025-05-24 17:53:22 +08:00 committed by GitHub
parent 3bfc5a3c90
commit cbea99c932
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 247 additions and 317 deletions

View File

@ -33,12 +33,12 @@ object PreDecodeInst {
val brTable = Array( val brTable = Array(
// C_JAL -> List(BrType.jal), // C_JAL -> List(BrType.jal),
C_EBREAK -> List(BrType.notCFI), // c.ebreak should not be decoded as jalr, higher priority than c.jalr C_EBREAK -> List(BrType.NotCfi), // c.ebreak should not be decoded as jalr, higher priority than c.jalr
C_J -> List(BrType.jal), C_J -> List(BrType.Jal),
C_JALR -> List(BrType.jalr), C_JALR -> List(BrType.Jalr),
C_BRANCH -> List(BrType.branch), C_BRANCH -> List(BrType.Branch),
JAL -> List(BrType.jal), JAL -> List(BrType.Jal),
JALR -> List(BrType.jalr), JALR -> List(BrType.Jalr),
BRANCH -> List(BrType.branch) BRANCH -> List(BrType.Branch)
) )
} }

View File

@ -82,9 +82,9 @@ object Itype extends NamedUInt(4) {
def jumpTypeGen(brType: UInt, rd: OpRegType, rs: OpRegType): UInt = { def jumpTypeGen(brType: UInt, rd: OpRegType, rs: OpRegType): UInt = {
val isEqualRdRs = rd === rs val isEqualRdRs = rd === rs
val isJal = brType === BrType.jal val isJal = brType === BrType.Jal
val isJalr = brType === BrType.jalr val isJalr = brType === BrType.Jalr
val isBranch = brType === BrType.branch val isBranch = brType === BrType.Branch
// push to RAS when rd is link, pop from RAS when rs is link // push to RAS when rd is link, pop from RAS when rs is link
def isUninferableCall = isJalr && rd.isLink && (!rs.isLink || rs.isLink && isEqualRdRs) //8 push def isUninferableCall = isJalr && rd.isLink && (!rs.isLink || rs.isLink && isEqualRdRs) //8 push

View File

@ -24,7 +24,7 @@ import ftq.FtqRedirectSramEntry
import ftq.FtqRfComponents import ftq.FtqRfComponents
import org.chipsalliance.cde.config.Parameters import org.chipsalliance.cde.config.Parameters
import utility._ import utility._
import utils.NamedUInt import utils.EnumUInt
import xiangshan._ import xiangshan._
import xiangshan.backend.GPAMemEntry import xiangshan.backend.GPAMemEntry
import xiangshan.backend.fu.PMPRespBundle import xiangshan.backend.fu.PMPRespBundle
@ -88,7 +88,7 @@ class FtqICacheInfo(implicit p: Parameters) extends XSBundle with HasICacheParam
class FtqToPrefetchBundle(implicit p: Parameters) extends XSBundle { class FtqToPrefetchBundle(implicit p: Parameters) extends XSBundle {
val req: FtqICacheInfo = new FtqICacheInfo val req: FtqICacheInfo = new FtqICacheInfo
val backendException: UInt = ExceptionType() val backendException: ExceptionType = new ExceptionType
} }
class FtqToFetchBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters { class FtqToFetchBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters {
@ -152,138 +152,94 @@ class mmioCommitRead(implicit p: Parameters) extends XSBundle {
val mmioLastCommit = Input(Bool()) val mmioLastCommit = Input(Bool())
} }
object ExceptionType extends NamedUInt(2) { class ExceptionType extends Bundle {
def none: UInt = "b00".U(width.W) val value: UInt = ExceptionType.Value()
def pf: UInt = "b01".U(width.W) // instruction page fault
def gpf: UInt = "b10".U(width.W) // instruction guest page fault
def af: UInt = "b11".U(width.W) // instruction access fault
def hasException(e: UInt): Bool = e =/= none def isNone: Bool = value === ExceptionType.Value.None
def hasException(e: Vec[UInt]): Bool = e.map(_ =/= none).reduce(_ || _) def isPf: Bool = value === ExceptionType.Value.Pf
def hasException(e: IndexedSeq[UInt]): Bool = hasException(VecInit(e)) def isGpf: Bool = value === ExceptionType.Value.Gpf
def isAf: Bool = value === ExceptionType.Value.Af
def fromOH(has_pf: Bool, has_gpf: Bool, has_af: Bool): UInt = { def hasException: Bool = value =/= ExceptionType.Value.None
/** merge exception from multiple sources, the leftmost one has higher priority
* @example {{{
* val itlbException = ExceptionType(io.itlb.resp.bits)
* val pmpException = ExceptionType(io.pmp.resp)
*
* // itlb has higher priority than pmp, as when itlb has exception, pAddr is not valid
* val exception = itlbException || pmpException
* }}}
*/
def ||(that: ExceptionType): ExceptionType =
Mux(this.hasException, this, that)
}
object ExceptionType {
private object Value extends EnumUInt(4) {
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 apply(that: UInt): ExceptionType = {
Value.assertLegal(that)
val e = Wire(new ExceptionType)
e.value := that
e
}
def None: ExceptionType = apply(Value.None)
def Pf: ExceptionType = apply(Value.Pf)
def Gpf: ExceptionType = apply(Value.Gpf)
def Af: ExceptionType = apply(Value.Af)
def apply(hasPf: Bool, hasGpf: Bool, hasAf: Bool): ExceptionType = {
assert( assert(
PopCount(VecInit(has_pf, has_gpf, has_af)) <= 1.U, PopCount(VecInit(hasPf, hasGpf, hasAf)) <= 1.U,
"ExceptionType.fromOH receives input that is not one-hot: pf=%d, gpf=%d, af=%d", "ExceptionType receives input that is not one-hot: pf=%d, gpf=%d, af=%d",
has_pf, hasPf,
has_gpf, hasGpf,
has_af hasAf
) )
// input is at-most-one-hot encoded, so we don't worry about priority here. // input is at-most-one-hot encoded, so we don't worry about priority here.
MuxCase( MuxCase(
none, None,
Seq( Seq(
has_pf -> pf, hasPf -> Pf,
has_gpf -> gpf, hasGpf -> Gpf,
has_af -> af hasAf -> Af
) )
) )
} }
// 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)
// raise pf/gpf/af according to itlb response // raise pf/gpf/af according to itlb response
def fromTlbResp(resp: TlbResp, useDup: Int = 0): UInt = { def fromTlbResp(resp: TlbResp, useDup: Int = 0): ExceptionType = {
require(useDup >= 0 && useDup < resp.excp.length) require(useDup >= 0 && useDup < resp.excp.length)
// itlb is guaranteed to respond at most one exception // itlb is guaranteed to respond at most one exception
fromOH( apply(
resp.excp(useDup).pf.instr, hasPf = resp.excp(useDup).pf.instr,
resp.excp(useDup).gpf.instr, hasGpf = resp.excp(useDup).gpf.instr,
resp.excp(useDup).af.instr hasAf = resp.excp(useDup).af.instr
) )
} }
// raise af if pmp check failed // raise af if pmp check failed
def fromPMPResp(resp: PMPRespBundle): UInt = def fromPmpResp(resp: PMPRespBundle): ExceptionType =
Mux(resp.instr, af, none) apply(hasAf = resp.instr)
// raise af if meta/data array ecc check failed or l2 cache respond with tilelink corrupt
/* FIXME: RISC-V Machine ISA v1.13 (draft) introduced a "hardware error" exception, described as:
* > A Hardware Error exception is a synchronous exception triggered when corrupted or
* > uncorrectable data is accessed explicitly or implicitly by an instruction. In this context,
* > "data" encompasses all types of information used within a RISC-V hart. Upon a hardware
* > error exception, the xepc register is set to the address of the instruction that attempted to
* > access corrupted data, while the xtval register is set either to 0 or to the virtual address
* > of an instruction fetch, load, or store that attempted to access corrupted data. The priority
* > of Hardware Error exception is implementation-defined, but any given occurrence is
* > generally expected to be recognized at the point in the overall priority order at which the
* > hardware error is discovered.
* Maybe it's better to raise hardware error instead of access fault when ECC check failed.
* But it's draft and XiangShan backend does not implement this exception code yet, so we still raise af here.
*/
def fromECC(enable: Bool, corrupt: Bool): UInt =
Mux(enable && corrupt, af, none)
def fromTilelink(corrupt: Bool): UInt =
Mux(corrupt, af, none)
/**Generates exception mux tree
*
* Exceptions that are further to the left in the parameter list have higher priority
* @example
* {{{
* val itlb_exception = ExceptionType.fromTlbResp(io.itlb.resp.bits)
* // so as pmp_exception, meta_corrupt
* // ExceptionType.merge(itlb_exception, pmp_exception, meta_corrupt) is equivalent to:
* Mux(
* itlb_exception =/= none,
* itlb_exception,
* Mux(pmp_exception =/= none, pmp_exception, meta_corrupt)
* )
* }}}
*/
def merge(exceptions: UInt*): UInt = {
// // recursively generate mux tree
// if (exceptions.length == 1) {
// require(exceptions.head.getWidth == width)
// exceptions.head
// } else {
// Mux(exceptions.head =/= none, exceptions.head, merge(exceptions.tail: _*))
// }
// use MuxCase with default
exceptions.foreach(e => require(e.getWidth == width))
val mapping = exceptions.init.map(e => (e =/= none) -> e)
val default = exceptions.last
MuxCase(default, mapping)
}
/**Generates exception mux tree for multi-port exception vectors
*
* Exceptions that are further to the left in the parameter list have higher priority
* @example
* {{{
* val itlb_exception = VecInit((0 until PortNumber).map(i => ExceptionType.fromTlbResp(io.itlb(i).resp.bits)))
* // so as pmp_exception, meta_corrupt
* // ExceptionType.merge(itlb_exception, pmp_exception, meta_corrupt) is equivalent to:
* VecInit((0 until PortNumber).map(i => Mux(
* itlb_exception(i) =/= none,
* itlb_exception(i),
* Mux(pmp_exception(i) =/= none, pmp_exception(i), meta_corrupt(i))
* ))
* }}}
*/
def merge(exceptionVecs: Vec[UInt]*): Vec[UInt] = {
// // recursively generate mux tree
// if (exceptionVecs.length == 1) {
// exceptionVecs.head.foreach(e => require(e.getWidth == width))
// exceptionVecs.head
// } else {
// require(exceptionVecs.head.length == exceptionVecs.last.length)
// VecInit((exceptionVecs.head zip merge(exceptionVecs.tail: _*)).map{ case (high, low) =>
// Mux(high =/= none, high, low)
// })
// }
// merge port-by-port
val length = exceptionVecs.head.length
exceptionVecs.tail.foreach(vec => require(vec.length == length))
VecInit((0 until length).map(i => merge(exceptionVecs.map(_(i)): _*)))
}
} }
object BrType extends NamedUInt(2) { object BrType extends EnumUInt(4) {
def notCFI: UInt = "b00".U(width.W) def NotCfi: UInt = 0.U(width.W)
def branch: UInt = "b01".U(width.W) def Branch: UInt = 1.U(width.W)
def jal: UInt = "b10".U(width.W) def Jal: UInt = 2.U(width.W)
def jalr: UInt = "b11".U(width.W) def Jalr: UInt = 3.U(width.W)
} }
class PreDecodeInfo extends Bundle { // 8 bit class PreDecodeInfo extends Bundle { // 8 bit
@ -293,10 +249,10 @@ class PreDecodeInfo extends Bundle { // 8 bit
val isCall = Bool() val isCall = Bool()
val isRet = Bool() val isRet = Bool()
// val excType = UInt(3.W) // val excType = UInt(3.W)
def isBr = brType === BrType.branch def isBr = brType === BrType.Branch
def isJal = brType === BrType.jal def isJal = brType === BrType.Jal
def isJalr = brType === BrType.jalr def isJalr = brType === BrType.Jalr
def notCFI = brType === BrType.notCFI def notCFI = brType === BrType.NotCfi
} }
class FetchToIBuffer(implicit p: Parameters) extends XSBundle { class FetchToIBuffer(implicit p: Parameters) extends XSBundle {
@ -307,7 +263,7 @@ class FetchToIBuffer(implicit p: Parameters) extends XSBundle {
val foldpc = Vec(PredictWidth, UInt(MemPredPCWidth.W)) val foldpc = Vec(PredictWidth, UInt(MemPredPCWidth.W))
val ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) val ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
val backendException = Vec(PredictWidth, Bool()) val backendException = Vec(PredictWidth, Bool())
val exceptionType = Vec(PredictWidth, ExceptionType()) val exceptionType = Vec(PredictWidth, new ExceptionType)
val crossPageIPFFix = Vec(PredictWidth, Bool()) val crossPageIPFFix = Vec(PredictWidth, Bool())
val illegalInstr = Vec(PredictWidth, Bool()) val illegalInstr = Vec(PredictWidth, Bool())
val triggered = Vec(PredictWidth, TriggerAction()) val triggered = Vec(PredictWidth, TriggerAction())

View File

@ -49,6 +49,41 @@ class IBufferIO(implicit p: Parameters) extends XSBundle {
val stallReason = new StallReasonIO(DecodeWidth) val stallReason = new StallReasonIO(DecodeWidth)
} }
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 XSBundle { class IBufEntry(implicit p: Parameters) extends XSBundle {
val inst = UInt(32.W) val inst = UInt(32.W)
val pc = PrunedAddr(VAddrBits) val pc = PrunedAddr(VAddrBits)
@ -109,48 +144,6 @@ class IBufEntry(implicit p: Parameters) extends XSBundle {
cf.debug_seqNum := debug_seqNum cf.debug_seqNum := debug_seqNum
cf cf
} }
object IBufferExceptionType extends NamedUInt(3) {
def None = "b000".U
def NonCrossPF = "b001".U
def NonCrossGPF = "b010".U
def NonCrossAF = "b011".U
// illegal instruction
def rvcII = "b100".U
def CrossPF = "b101".U
def CrossGPF = "b110".U
def CrossAF = "b111".U
def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: UInt, crossPage: Bool, rvcIll: Bool): UInt = {
require(
fetchExcp.getWidth == ExceptionType.width,
s"The width(${fetchExcp.getWidth}) of fetchExcp should be equal to " +
s"the width(${ExceptionType.width}) of frontend.ExceptionType."
)
MuxCase(
0.U,
Seq(
crossPage -> Cat(1.U(1.W), fetchExcp),
fetchExcp.orR -> fetchExcp,
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 IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents { class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper with HasPerfEvents {

View File

@ -159,13 +159,13 @@ class Ftq(implicit p: Parameters) extends FtqModule
// raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write. // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write.
// Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this
// makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests. // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests.
val backendException = RegInit(ExceptionType.none) val backendException = RegInit(ExceptionType.None)
val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U)) val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U))
when(fromBackendRedirect.valid) { when(fromBackendRedirect.valid) {
backendException := ExceptionType.fromOH( backendException := ExceptionType(
has_pf = fromBackendRedirect.bits.cfiUpdate.backendIPF, hasPf = fromBackendRedirect.bits.cfiUpdate.backendIPF,
has_gpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF, hasGpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF,
has_af = fromBackendRedirect.bits.cfiUpdate.backendIAF hasAf = fromBackendRedirect.bits.cfiUpdate.backendIAF
) )
when( when(
fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF ||
@ -174,7 +174,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
backendPcFaultPtr := ifuWbPtr_write backendPcFaultPtr := ifuWbPtr_write
} }
}.elsewhen(ifuWbPtr =/= backendPcFaultPtr) { }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) {
backendException := ExceptionType.none backendException := ExceptionType.None
} }
// ********************************************************************** // **********************************************************************
@ -473,7 +473,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
copy.ftqIdx := ifuPtr copy.ftqIdx := ifuPtr
} }
io.toICache.fetchReq.bits.isBackendException := io.toICache.fetchReq.bits.isBackendException :=
ExceptionType.hasException(backendException) && backendPcFaultPtr === ifuPtr backendException.hasException && backendPcFaultPtr === ifuPtr
io.toICache.prefetchReq.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr io.toICache.prefetchReq.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
io.toICache.prefetchReq.bits.req.fromFtqPcBundle(toPrefetchPcBundle) io.toICache.prefetchReq.bits.req.fromFtqPcBundle(toPrefetchPcBundle)
@ -481,7 +481,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
io.toICache.prefetchReq.bits.backendException := Mux( io.toICache.prefetchReq.bits.backendException := Mux(
backendPcFaultPtr === pfPtr, backendPcFaultPtr === pfPtr,
backendException, backendException,
ExceptionType.none ExceptionType.None
) )
// io.toICache.fetchReq.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr // io.toICache.fetchReq.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
// io.toICache.fetchReq.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => // io.toICache.fetchReq.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>

View File

@ -161,14 +161,14 @@ class ReplacerVictimBundle(implicit p: Parameters) extends ICacheBundle {
/* ***** MainPipe ***** */ /* ***** MainPipe ***** */
// ICache(MainPipe) -> IFU // ICache(MainPipe) -> IFU
class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle { class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle {
val doubleline: Bool = Bool() val doubleline: Bool = Bool()
val vAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(VAddrBits)) val vAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(VAddrBits))
val data: UInt = UInt(blockBits.W) val data: UInt = UInt(blockBits.W)
val pAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(PAddrBits)) val pAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(PAddrBits))
val exception: Vec[UInt] = Vec(PortNumber, ExceptionType()) val exception: Vec[ExceptionType] = Vec(PortNumber, new ExceptionType)
val pmpMmio: Vec[Bool] = Vec(PortNumber, Bool()) val pmpMmio: Vec[Bool] = Vec(PortNumber, Bool())
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W)) val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
val isBackendException: Bool = Bool() val isBackendException: Bool = Bool()
/* NOTE: GPAddrBits(=50bit) is not enough for gpAddr here, refer to PR#3795 /* NOTE: GPAddrBits(=50bit) is not enough for gpAddr here, refer to PR#3795
* Sv48*4 only allows 50bit gpAddr, when software violates this requirement * Sv48*4 only allows 50bit gpAddr, when software violates this requirement
* it needs to fill the mtval2 register with the full XLEN(=64bit) gpAddr, * it needs to fill the mtval2 register with the full XLEN(=64bit) gpAddr,
@ -181,11 +181,11 @@ class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle {
/* ***** PrefetchPipe ***** */ /* ***** PrefetchPipe ***** */
class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle { class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle {
val startAddr: PrunedAddr = PrunedAddr(VAddrBits) val startAddr: PrunedAddr = PrunedAddr(VAddrBits)
val nextlineStart: PrunedAddr = PrunedAddr(VAddrBits) val nextlineStart: PrunedAddr = PrunedAddr(VAddrBits)
val ftqIdx: FtqPtr = new FtqPtr val ftqIdx: FtqPtr = new FtqPtr
val isSoftPrefetch: Bool = Bool() val isSoftPrefetch: Bool = Bool()
val backendException: UInt = ExceptionType() val backendException: ExceptionType = new ExceptionType
def crossCacheline: Bool = startAddr(blockOffBits - 1) === 1.U def crossCacheline: Bool = startAddr(blockOffBits - 1) === 1.U
@ -214,12 +214,12 @@ class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle {
* to save area, we separate those signals from WayLookupEntry and store only once. * to save area, we separate those signals from WayLookupEntry and store only once.
*/ */
class WayLookupEntry(implicit p: Parameters) extends ICacheBundle { class WayLookupEntry(implicit p: Parameters) extends ICacheBundle {
val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W)) val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W)) val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
val pTag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W)) val pTag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
val itlbException: Vec[UInt] = Vec(PortNumber, ExceptionType()) val itlbException: Vec[ExceptionType] = Vec(PortNumber, new ExceptionType)
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W)) val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
val metaCodes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W)) val metaCodes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
} }
class WayLookupGpfEntry(implicit p: Parameters) extends ICacheBundle { class WayLookupGpfEntry(implicit p: Parameters) extends ICacheBundle {
@ -233,14 +233,14 @@ class WayLookupBundle(implicit p: Parameters) extends ICacheBundle {
val gpf = new WayLookupGpfEntry val gpf = new WayLookupGpfEntry
// for compatibility // for compatibility
def vSetIdx: Vec[UInt] = entry.vSetIdx def vSetIdx: Vec[UInt] = entry.vSetIdx
def waymask: Vec[UInt] = entry.waymask def waymask: Vec[UInt] = entry.waymask
def pTag: Vec[UInt] = entry.pTag def pTag: Vec[UInt] = entry.pTag
def itlbException: Vec[UInt] = entry.itlbException def itlbException: Vec[ExceptionType] = entry.itlbException
def itlbPbmt: Vec[UInt] = entry.itlbPbmt def itlbPbmt: Vec[UInt] = entry.itlbPbmt
def metaCodes: Vec[UInt] = entry.metaCodes def metaCodes: Vec[UInt] = entry.metaCodes
def gpAddr: PrunedAddr = gpf.gpAddr def gpAddr: PrunedAddr = gpf.gpAddr
def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE
} }
/* ***** Miss ***** */ /* ***** Miss ***** */

View File

@ -27,7 +27,7 @@ import freechips.rocketchip.regmapper.RegReadFn
import freechips.rocketchip.regmapper.RegWriteFn import freechips.rocketchip.regmapper.RegWriteFn
import freechips.rocketchip.tilelink.TLRegisterNode import freechips.rocketchip.tilelink.TLRegisterNode
import org.chipsalliance.cde.config.Parameters import org.chipsalliance.cde.config.Parameters
import utils.NamedUInt import utils.EnumUInt
import xiangshan.frontend.PrunedAddrInit import xiangshan.frontend.PrunedAddrInit
// currently for ECC control only // currently for ECC control only
@ -61,7 +61,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
// eccCtrl.ierror: inject error code // eccCtrl.ierror: inject error code
private def nInjError: Int = 8 private def nInjError: Int = 8
private object EccCtrlInjError extends NamedUInt(log2Up(nInjError)) { private object EccCtrlInjError extends EnumUInt(nInjError) {
def NotEnabled: UInt = 0.U(width.W) // try to inject when ECC check is not enabled def NotEnabled: UInt = 0.U(width.W) // try to inject when ECC check is not enabled
def TargetInvalid: UInt = 1.U(width.W) // try to inject to invalid(rsvd) eccCtrl.itarget def TargetInvalid: UInt = 1.U(width.W) // try to inject to invalid(rsvd) eccCtrl.itarget
def NotFound: UInt = 2.U(width.W) // try to inject to eccIAddr.pAddr does not exist in ICache def NotFound: UInt = 2.U(width.W) // try to inject to eccIAddr.pAddr does not exist in ICache
@ -78,7 +78,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
} }
// eccCtrl.istatus: inject status // eccCtrl.istatus: inject status
private def nInjStatus: Int = 8 private def nInjStatus: Int = 8
private object EccCtrlInjStatus extends NamedUInt(log2Up(nInjStatus)) { private object EccCtrlInjStatus extends EnumUInt(nInjStatus) {
def Idle: UInt = 0.U(width.W) def Idle: UInt = 0.U(width.W)
def Working: UInt = 1.U(width.W) def Working: UInt = 1.U(width.W)
def Injected: UInt = 2.U(width.W) def Injected: UInt = 2.U(width.W)
@ -94,7 +94,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
} }
// eccCtrl.itarget: inject target // eccCtrl.itarget: inject target
private def nInjTarget: Int = 4 private def nInjTarget: Int = 4
private object EccCtrlInjTarget extends NamedUInt(log2Up(nInjTarget)) { private object EccCtrlInjTarget extends EnumUInt(nInjTarget) {
def MetaArray: UInt = 0.U(width.W) def MetaArray: UInt = 0.U(width.W)
def DataArray: UInt = 2.U(width.W) def DataArray: UInt = 2.U(width.W)
@unused @unused
@ -151,7 +151,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
// inject FSM // inject FSM
private def nInjectFsmState: Int = 5 private def nInjectFsmState: Int = 5
private object InjectFsmState extends NamedUInt(log2Up(nInjectFsmState)) { private object InjectFsmState extends EnumUInt(nInjectFsmState) {
// scala ask identifier that begins with uppercase cannot be used in pattern matching like `X :: Nil = Enum()` // scala ask identifier that begins with uppercase cannot be used in pattern matching like `X :: Nil = Enum()`
// but we want UpperCamelCase for constants for better readability, so we dont use Enum() here // but we want UpperCamelCase for constants for better readability, so we dont use Enum() here
def Idle: UInt = 0.U(width.W) def Idle: UInt = 0.U(width.W)

View File

@ -224,14 +224,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
p.bits.size := 3.U p.bits.size := 3.U
p.bits.cmd := TlbCmd.exec p.bits.cmd := TlbCmd.exec
} }
private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPMPResp)) private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPmpResp))
private val s1_pmpMmio = VecInit(fromPmp.map(_.mmio)) private val s1_pmpMmio = VecInit(fromPmp.map(_.mmio))
// merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next
private val s1_exceptionOut = ExceptionType.merge( private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p })
s1_itlbException,
s1_pmpException
)
/** /**
****************************************************************************** ******************************************************************************
@ -418,7 +415,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
private val s2_shouldFetch = VecInit((0 until PortNumber).map { i => private val s2_shouldFetch = VecInit((0 until PortNumber).map { i =>
(!s2_hits(i) || s2_corruptRefetch(i)) && (!s2_hits(i) || s2_corruptRefetch(i)) &&
(if (i == 0) true.B else s2_doubleline) && (if (i == 0) true.B else s2_doubleline) &&
!ExceptionType.hasException(s2_exception.take(i + 1)) && s2_exception.take(i + 1).map(_.isNone).reduce(_ && _) &&
s2_isMmio.take(i + 1).map(!_).reduce(_ && _) s2_isMmio.take(i + 1).map(!_).reduce(_ && _)
}) })
@ -446,14 +443,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
private val s2_fetchFinish = !s2_shouldFetch.reduce(_ || _) private val s2_fetchFinish = !s2_shouldFetch.reduce(_ || _)
// also raise af if l2 corrupt is detected // also raise af if l2 corrupt is detected
private val s2_l2Exception = VecInit(s2_l2Corrupt.map(ExceptionType.fromTilelink)) private val s2_l2Exception = VecInit(s2_l2Corrupt.map(corrupt => ExceptionType(hasAf = corrupt)))
// NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2 // NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2
// merge s2 exceptions, itlb has the highest priority, then l2 // merge s2 exceptions, itlb/pmp has the highest priority, then l2
private val s2_exceptionOut = ExceptionType.merge( private val s2_exceptionOut = VecInit((s2_exception zip s2_l2Exception).map { case (in, l2) => in || l2 })
s2_exception, // includes itlb/pmp exception
s2_l2Exception
)
/** /**
****************************************************************************** ******************************************************************************
@ -468,7 +462,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
toIfu.bits.pAddr := s2_pAddr toIfu.bits.pAddr := s2_pAddr
(0 until PortNumber).foreach { i => (0 until PortNumber).foreach { i =>
val needThisLine = if (i == 0) true.B else s2_doubleline val needThisLine = if (i == 0) true.B else s2_doubleline
toIfu.bits.exception(i) := Mux(needThisLine, s2_exceptionOut(i), ExceptionType.none) toIfu.bits.exception(i) := Mux(needThisLine, s2_exceptionOut(i), ExceptionType.None)
toIfu.bits.pmpMmio(i) := Mux(needThisLine, s2_pmpMmio(i), false.B) toIfu.bits.pmpMmio(i) := Mux(needThisLine, s2_pmpMmio(i), false.B)
toIfu.bits.itlbPbmt(i) := Mux(needThisLine, s2_itlbPbmt(i), Pbmt.pma) toIfu.bits.itlbPbmt(i) := Mux(needThisLine, s2_itlbPbmt(i), Pbmt.pma)
} }
@ -507,11 +501,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
io.perf.hit0Miss1 := s2_hits(0) && !s2_hits(1) && s2_doubleline io.perf.hit0Miss1 := s2_hits(0) && !s2_hits(1) && s2_doubleline
io.perf.miss0Hit1 := !s2_hits(0) && s2_hits(1) && s2_doubleline io.perf.miss0Hit1 := !s2_hits(0) && s2_hits(1) && s2_doubleline
io.perf.miss0Miss1 := !s2_hits(0) && !s2_hits(1) && s2_doubleline io.perf.miss0Miss1 := !s2_hits(0) && !s2_hits(1) && s2_doubleline
io.perf.hit0Except1 := s2_hits(0) && ExceptionType.hasException(s2_exception(1)) && s2_doubleline io.perf.hit0Except1 := s2_hits(0) && s2_exception(1).hasException && s2_doubleline
io.perf.miss0Except1 := !s2_hits(0) && ExceptionType.hasException(s2_exception(1)) && s2_doubleline io.perf.miss0Except1 := !s2_hits(0) && s2_exception(1).hasException && s2_doubleline
io.perf.bankHit(0) := s2_hits(0) io.perf.bankHit(0) := s2_hits(0)
io.perf.bankHit(1) := s2_hits(1) && s2_doubleline io.perf.bankHit(1) := s2_hits(1) && s2_doubleline
io.perf.except0 := ExceptionType.hasException(s2_exception(0)) io.perf.except0 := s2_exception(0).hasException
io.perf.hit := s2_hits(0) && (!s2_doubleline || s2_hits(1)) io.perf.hit := s2_hits(0) && (!s2_doubleline || s2_hits(1))
/** <PERF> fetch bubble generated by icache miss */ /** <PERF> fetch bubble generated by icache miss */
@ -553,7 +547,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
*/ */
if (env.EnableDifftest) { if (env.EnableDifftest) {
val discards = (0 until PortNumber).map { i => val discards = (0 until PortNumber).map { i =>
ExceptionType.hasException(toIfu.bits.exception(i)) || toIfu.bits.exception(i).hasException ||
toIfu.bits.pmpMmio(i) || toIfu.bits.pmpMmio(i) ||
Pbmt.isUncache(toIfu.bits.itlbPbmt(i)) Pbmt.isUncache(toIfu.bits.itlbPbmt(i))
} }

View File

@ -22,13 +22,12 @@ import utility.DataHoldBypass
import utility.PriorityMuxDefault import utility.PriorityMuxDefault
import utility.ValidHold import utility.ValidHold
import utility.XSPerfAccumulate import utility.XSPerfAccumulate
import utils.NamedUInt import utils.EnumUInt
import xiangshan.cache.mmu.Pbmt import xiangshan.cache.mmu.Pbmt
import xiangshan.cache.mmu.TlbCmd import xiangshan.cache.mmu.TlbCmd
import xiangshan.cache.mmu.TlbRequestIO import xiangshan.cache.mmu.TlbRequestIO
import xiangshan.cache.mmu.ValidHoldBypass // FIXME: should move this to utility? import xiangshan.cache.mmu.ValidHoldBypass // FIXME: should move this to utility?
import xiangshan.frontend.ExceptionType import xiangshan.frontend.ExceptionType
import xiangshan.frontend.PrunedAddr
import xiangshan.frontend.PrunedAddrInit import xiangshan.frontend.PrunedAddrInit
import xiangshan.frontend.ftq.BpuFlushInfo import xiangshan.frontend.ftq.BpuFlushInfo
@ -117,7 +116,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
private val s1_backendException = RegEnable(s0_backendException, 0.U.asTypeOf(s0_backendException), s0_fire) private val s1_backendException = RegEnable(s0_backendException, 0.U.asTypeOf(s0_backendException), s0_fire)
private def nS1FsmState: Int = 5 private def nS1FsmState: Int = 5
private object S1FsmState extends NamedUInt(log2Up(nS1FsmState)) { private object S1FsmState extends EnumUInt(nS1FsmState) {
def Idle: UInt = 0.U(width.W) def Idle: UInt = 0.U(width.W)
def ItlbResend: UInt = 1.U(width.W) def ItlbResend: UInt = 1.U(width.W)
def MetaResend: UInt = 2.U(width.W) def MetaResend: UInt = 2.U(width.W)
@ -185,7 +184,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
Mux(tlbValidPulse(i), s1_pAddrWire(i), s1_pAddrReg(i)) Mux(tlbValidPulse(i), s1_pAddrWire(i), s1_pAddrReg(i))
}) })
private val s1_itlbExceptionRaw = VecInit((0 until PortNumber).map { i => private val s1_itlbExceptionRaw = VecInit((0 until PortNumber).map { i =>
DataHoldBypass(ExceptionType.fromTlbResp(fromItlb(i).bits), 0.U(ExceptionType.width.W), tlbValidPulse(i)) DataHoldBypass(ExceptionType.fromTlbResp(fromItlb(i).bits), ExceptionType.None, tlbValidPulse(i))
}) })
private val s1_itlbPbmt = VecInit((0 until PortNumber).map { i => private val s1_itlbPbmt = VecInit((0 until PortNumber).map { i =>
DataHoldBypass(fromItlb(i).bits.pbmt(0), 0.U.asTypeOf(fromItlb(i).bits.pbmt(0)), tlbValidPulse(i)) DataHoldBypass(fromItlb(i).bits.pbmt(0), 0.U.asTypeOf(fromItlb(i).bits.pbmt(0)), tlbValidPulse(i))
@ -207,10 +206,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
// merge backend exception and itlb exception // merge backend exception and itlb exception
// for area concern, we don't have 64 bits vaddr in frontend, but spec asks page fault when high bits are not all 0/1 // for area concern, we don't have 64 bits vaddr in frontend, but spec asks page fault when high bits are not all 0/1
// this check is finished in backend, and passed to frontend with redirect, we see it as a part of itlb exception // this check is finished in backend, and passed to frontend with redirect, we see it as a part of itlb exception
private val s1_itlbException = ExceptionType.merge( private val s1_itlbException = VecInit((s1_backendException zip s1_itlbExceptionRaw).map { case (b, i) => b || i })
s1_backendException,
s1_itlbExceptionRaw
)
// debug // debug
dontTouch(s1_itlbExceptionRaw) dontTouch(s1_itlbExceptionRaw)
dontTouch(s1_itlbException) dontTouch(s1_itlbException)
@ -221,7 +217,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
* see GPAMem: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/backend/GPAMem.scala#L33-L34 * see GPAMem: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/backend/GPAMem.scala#L33-L34
* see also: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/frontend/IFU.scala#L374-L375 * see also: https://github.com/OpenXiangShan/XiangShan/blob/344cf5d55568dd40cd658a9ee66047a505eeb504/src/main/scala/xiangshan/frontend/IFU.scala#L374-L375
*/ */
private val s1_itlbExceptionIsGpf = VecInit(s1_itlbException.map(_ === ExceptionType.gpf)) private val s1_itlbExceptionIsGpf = VecInit(s1_itlbException.map(_.isGpf))
private val s1_gpAddr = PriorityMuxDefault( private val s1_gpAddr = PriorityMuxDefault(
s1_itlbExceptionIsGpf zip (0 until PortNumber).map(i => s1_gpAddrRaw(i) - (i << blockOffBits).U), s1_itlbExceptionIsGpf zip (0 until PortNumber).map(i => s1_gpAddrRaw(i) - (i << blockOffBits).U),
0.U.asTypeOf(s1_gpAddrRaw(0)) 0.U.asTypeOf(s1_gpAddrRaw(0))
@ -326,7 +322,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
toWayLookup.bits.itlbException(i) := Mux( toWayLookup.bits.itlbException(i) := Mux(
excpValid, excpValid,
s1_itlbException(i), // includes backend exception s1_itlbException(i), // includes backend exception
ExceptionType.none ExceptionType.None
) )
toWayLookup.bits.itlbPbmt(i) := Mux(excpValid, s1_itlbPbmt(i), Pbmt.pma) toWayLookup.bits.itlbPbmt(i) := Mux(excpValid, s1_itlbPbmt(i), Pbmt.pma)
} }
@ -359,15 +355,12 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
p.bits.size := 3.U p.bits.size := 3.U
p.bits.cmd := TlbCmd.exec p.bits.cmd := TlbCmd.exec
} }
private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPMPResp)) private val s1_pmpException = VecInit(fromPmp.map(ExceptionType.fromPmpResp))
private val s1_pmpMmio = VecInit(fromPmp.map(_.mmio)) private val s1_pmpMmio = VecInit(fromPmp.map(_.mmio))
// merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next
// for timing consideration, meta_corrupt is not merged, and it will NOT cancel prefetch // here, itlb exception includes backend exception
private val s1_exceptionOut = ExceptionType.merge( private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p })
s1_itlbException, // includes backend exception
s1_pmpException
)
// merge pmp mmio and itlb pbmt // merge pmp mmio and itlb pbmt
private val s1_isMmio = VecInit((s1_pmpMmio zip s1_itlbPbmt).map { case (mmio, pbmt) => private val s1_isMmio = VecInit((s1_pmpMmio zip s1_itlbPbmt).map { case (mmio, pbmt) =>
@ -503,7 +496,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
*/ */
private val s2_miss = VecInit((0 until PortNumber).map { i => private val s2_miss = VecInit((0 until PortNumber).map { i =>
!s2_hits(i) && (if (i == 0) true.B else s2_doubleline) && !s2_hits(i) && (if (i == 0) true.B else s2_doubleline) &&
!ExceptionType.hasException(s2_exception.take(i + 1)) && s2_exception.take(i + 1).map(_.isNone).reduce(_ && _) &&
s2_isMmio.take(i + 1).map(!_).reduce(_ && _) s2_isMmio.take(i + 1).map(!_).reduce(_ && _)
}) })

View File

@ -123,7 +123,7 @@ class ICacheWayLookup(implicit p: Parameters) extends ICacheModule with ICacheMi
io.write.ready := !full && !gpfStall io.write.ready := !full && !gpfStall
when(io.write.fire) { when(io.write.fire) {
entries(writePtr.value) := io.write.bits.entry entries(writePtr.value) := io.write.bits.entry
when(io.write.bits.itlbException.map(_ === ExceptionType.gpf).reduce(_ || _)) { when(io.write.bits.itlbException.map(_.isGpf).reduce(_ || _)) {
// if gpfEntry is bypassed, we don't need to save it // if gpfEntry is bypassed, we don't need to save it
// note this will override the read (L156) // note this will override the read (L156)
gpfEntry.valid := !(canBypass && io.read.fire) gpfEntry.valid := !(canBypass && io.read.fire)

View File

@ -18,7 +18,7 @@ package xiangshan.frontend.ifu
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import org.chipsalliance.cde.config.Parameters import org.chipsalliance.cde.config.Parameters
import utils.NamedUInt import utils.EnumUInt
import xiangshan.frontend.PrunedAddr import xiangshan.frontend.PrunedAddr
/* *** /* ***
@ -32,14 +32,14 @@ import xiangshan.frontend.PrunedAddr
* *** */ * *** */
/* ***** PreDecode ***** */ /* ***** PreDecode ***** */
object PreDecodeFaultType extends NamedUInt(3) { object PreDecodeFaultType extends EnumUInt(7) {
def noFault: UInt = "b000".U(width.W) def NoFault: UInt = 0.U(width.W)
def jalFault: UInt = "b001".U(width.W) // not CFI taken or invalid instruction taken def JalFault: UInt = 1.U(width.W) // not CFI taken or invalid instruction taken
def retFault: UInt = "b010".U(width.W) // not CFI taken or invalid instruction taken def RetFault: UInt = 2.U(width.W) // not CFI taken or invalid instruction taken
def targetFault: UInt = "b011".U(width.W) def TargetFault: UInt = 3.U(width.W)
def notCfiFault: UInt = "b100".U(width.W) // not CFI taken or invalid instruction taken def NotCfiFault: UInt = 4.U(width.W) // not CFI taken or invalid instruction taken
def invalidTaken: UInt = "b101".U(width.W) def InvalidTaken: UInt = 5.U(width.W)
def jalrFault: UInt = "b110".U(width.W) def JalrFault: UInt = 6.U(width.W)
} }
/* ***** Ifu last half ***** */ /* ***** Ifu last half ***** */

View File

@ -31,14 +31,14 @@ trait PreDecodeHelper extends HasXSParameter {
def isLink(reg: UInt): Bool = reg === 1.U || reg === 5.U def isLink(reg: UInt): Bool = reg === 1.U || reg === 5.U
def getBrType(inst: UInt): UInt = def getBrType(inst: UInt): UInt =
ListLookup(inst, List(BrType.notCFI), PreDecodeInst.brTable).head ListLookup(inst, List(BrType.NotCfi), PreDecodeInst.brTable).head
def getBrInfo(inst: UInt): (UInt, Bool, Bool) = { def getBrInfo(inst: UInt): (UInt, Bool, Bool) = {
val brType = getBrType(inst) val brType = getBrType(inst)
val rd = Mux(isRVC(inst), inst(12), inst(11, 7)) val rd = Mux(isRVC(inst), inst(12), inst(11, 7))
val rs = Mux(isRVC(inst), Mux(brType === BrType.jal, 0.U, inst(11, 7)), inst(19, 15)) val rs = Mux(isRVC(inst), Mux(brType === BrType.Jal, 0.U, inst(11, 7)), inst(19, 15))
val isCall = (brType === BrType.jal && !isRVC(inst) || brType === BrType.jalr) && isLink(rd) // Only for RV64 val isCall = (brType === BrType.Jal && !isRVC(inst) || brType === BrType.Jalr) && isLink(rd) // Only for RV64
val isRet = brType === BrType.jalr && isLink(rs) && !isCall val isRet = brType === BrType.Jalr && isLink(rs) && !isCall
(brType, isCall, isRet) (brType, isCall, isRet)
} }

View File

@ -32,7 +32,7 @@ import utility.XSDebug
import utility.XSError import utility.XSError
import utility.XSPerfAccumulate import utility.XSPerfAccumulate
import utility.XSPerfHistogram import utility.XSPerfHistogram
import utils.NamedUInt import utils.EnumUInt
import xiangshan.FrontendTdataDistributeIO import xiangshan.FrontendTdataDistributeIO
import xiangshan.RedirectLevel import xiangshan.RedirectLevel
import xiangshan.RobCommitInfo import xiangshan.RobCommitInfo
@ -331,21 +331,19 @@ class Ifu(implicit p: Parameters) extends IfuModule
// FIXME: raise af if one fetch block crosses the cacheable/un-cacheable boundary, might not correct // FIXME: raise af if one fetch block crosses the cacheable/un-cacheable boundary, might not correct
private val s2_mmioMismatchException = VecInit(Seq( private val s2_mmioMismatchException = VecInit(Seq(
ExceptionType.none, // mark the exception only on the second line ExceptionType.None, // mark the exception only on the second line
Mux( ExceptionType(hasAf =
// not double-line, skip check // if not double-line, skip check
!fromICache.bits.doubleline || ( fromICache.bits.doubleline && (
// is double-line, ask for consistent pmp_mmio and itlb_pbmt value // is double-line, ask for consistent pmp_mmio and itlb_pbmt value
fromICache.bits.pmpMmio(0) === fromICache.bits.pmpMmio(1) && fromICache.bits.pmpMmio(0) =/= fromICache.bits.pmpMmio(1) ||
fromICache.bits.itlbPbmt(0) === fromICache.bits.itlbPbmt(1) fromICache.bits.itlbPbmt(0) =/= fromICache.bits.itlbPbmt(1)
), )
ExceptionType.none,
ExceptionType.af
) )
)) ))
// merge exceptions // merge exceptions
private val s2_exception = ExceptionType.merge(s2_exceptionIn, s2_mmioMismatchException) private val s2_exception = VecInit((s2_exceptionIn zip s2_mmioMismatchException).map { case (in, m) => in || m })
// we need only the first port, as the second is asked to be the same // we need only the first port, as the second is asked to be the same
private val s2_pmpMmio = fromICache.bits.pmpMmio(0) private val s2_pmpMmio = fromICache.bits.pmpMmio(0)
@ -379,7 +377,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
private val s2_instrRange = s2_jumpRange & s2_ftrRange private val s2_instrRange = s2_jumpRange & s2_ftrRange
private val s2_exceptionVec = VecInit((0 until PredictWidth).map(i => private val s2_exceptionVec = VecInit((0 until PredictWidth).map(i =>
MuxCase( MuxCase(
ExceptionType.none, ExceptionType.None,
Seq( Seq(
!isNextLine(s2_pc(i), s2_ftqReq.startAddr) -> s2_exception(0), !isNextLine(s2_pc(i), s2_ftqReq.startAddr) -> s2_exception(0),
(isNextLine(s2_pc(i), s2_ftqReq.startAddr) && s2_doubleline) -> s2_exception(1) (isNextLine(s2_pc(i), s2_ftqReq.startAddr) && s2_doubleline) -> s2_exception(1)
@ -454,9 +452,9 @@ class Ifu(implicit p: Parameters) extends IfuModule
*/ */
private val s2_crossPageExceptionVec = VecInit((0 until PredictWidth).map { i => private val s2_crossPageExceptionVec = VecInit((0 until PredictWidth).map { i =>
Mux( Mux(
isLastInLine(s2_pc(i)) && !s2_pd(i).isRVC && s2_doubleline && !ExceptionType.hasException(s2_exception(0)), isLastInLine(s2_pc(i)) && !s2_pd(i).isRVC && s2_doubleline && s2_exception(0).isNone,
s2_exception(1), s2_exception(1),
ExceptionType.none ExceptionType.None
) )
}) })
XSPerfAccumulate("fetch_bubble_icache_not_resp", s2_valid && !icacheRespAllValid) XSPerfAccumulate("fetch_bubble_icache_not_resp", s2_valid && !icacheRespAllValid)
@ -563,7 +561,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
/* *** mmio *** */ /* *** mmio *** */
private def nMmioFsmState = 11 private def nMmioFsmState = 11
private object MmioFsmState extends NamedUInt(log2Up(nMmioFsmState)) { private object MmioFsmState extends EnumUInt(nMmioFsmState) {
def Idle: UInt = 0.U(width.W) def Idle: UInt = 0.U(width.W)
def WaitLastCommit: UInt = 1.U(width.W) def WaitLastCommit: UInt = 1.U(width.W)
def SendReq: UInt = 2.U(width.W) def SendReq: UInt = 2.U(width.W)
@ -580,7 +578,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
private val mmioState = RegInit(MmioFsmState.Idle) private val mmioState = RegInit(MmioFsmState.Idle)
private val mmioData = RegInit(VecInit(Seq.fill(2)(0.U(16.W)))) private val mmioData = RegInit(VecInit(Seq.fill(2)(0.U(16.W))))
private val mmioException = RegInit(0.U(ExceptionType.width.W)) private val mmioException = RegInit(ExceptionType.None)
private val mmioIsRvc = RegInit(false.B) private val mmioIsRvc = RegInit(false.B)
private val mmioHasResend = RegInit(false.B) private val mmioHasResend = RegInit(false.B)
private val mmioResendAddr = RegInit(PrunedAddrInit(0.U(PAddrBits.W))) private val mmioResendAddr = RegInit(PrunedAddrInit(0.U(PAddrBits.W)))
@ -591,7 +589,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
private def mmioReset(): Unit = { private def mmioReset(): Unit = {
mmioState := MmioFsmState.Idle mmioState := MmioFsmState.Idle
mmioData.foreach(_ := 0.U) mmioData.foreach(_ := 0.U)
mmioException := ExceptionType.none mmioException := ExceptionType.None
mmioIsRvc := false.B mmioIsRvc := false.B
mmioHasResend := false.B mmioHasResend := false.B
mmioResendAddr := PrunedAddrInit(0.U(PAddrBits.W)) mmioResendAddr := PrunedAddrInit(0.U(PAddrBits.W))
@ -607,7 +605,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
// do mmio fetch only when pmp/pbmt shows it is a un-cacheable address and no exception occurs // do mmio fetch only when pmp/pbmt shows it is a un-cacheable address and no exception occurs
private val s3_reqIsMmio = private val s3_reqIsMmio =
s3_valid && (s3_pmpMmio || Pbmt.isUncache(s3_itlbPbmt)) && !ExceptionType.hasException(s3_exception) s3_valid && (s3_pmpMmio || Pbmt.isUncache(s3_itlbPbmt)) && s3_exception.map(_.isNone).reduce(_ && _)
private val mmioCommit = VecInit(io.robCommits.map { commit => private val mmioCommit = VecInit(io.robCommits.map { commit =>
commit.valid && commit.bits.ftqIdx === s3_ftqReq.ftqIdx && commit.bits.ftqOffset === 0.U commit.valid && commit.bits.ftqIdx === s3_ftqReq.ftqIdx && commit.bits.ftqOffset === 0.U
}).asUInt.orR }).asUInt.orR
@ -682,9 +680,9 @@ class Ifu(implicit p: Parameters) extends IfuModule
is(MmioFsmState.WaitResp) { is(MmioFsmState.WaitResp) {
when(fromUncache.fire) { when(fromUncache.fire) {
val respIsRVC = isRVC(fromUncache.bits.data(1, 0)) val respIsRVC = isRVC(fromUncache.bits.data(1, 0))
val exception = ExceptionType.fromTilelink(fromUncache.bits.corrupt) val exception = ExceptionType(hasAf = fromUncache.bits.corrupt)
// when response is not RVC, and lower bits of pAddr is 6 => request crosses 8B boundary, need resend // when response is not RVC, and lower bits of pAddr is 6 => request crosses 8B boundary, need resend
val needResend = !respIsRVC && s3_pAddr(0)(2, 1) === 3.U && !ExceptionType.hasException(exception) val needResend = !respIsRVC && s3_pAddr(0)(2, 1) === 3.U && exception.isNone
mmioState := Mux(needResend, MmioFsmState.SendTlb, MmioFsmState.WaitCommit) mmioState := Mux(needResend, MmioFsmState.SendTlb, MmioFsmState.WaitCommit)
mmioException := exception mmioException := exception
mmioIsRvc := respIsRVC mmioIsRvc := respIsRVC
@ -702,16 +700,13 @@ class Ifu(implicit p: Parameters) extends IfuModule
when(io.itlb.resp.fire) { when(io.itlb.resp.fire) {
// we are using a blocked tlb, so resp.fire must have !resp.bits.miss // we are using a blocked tlb, so resp.fire must have !resp.bits.miss
assert(!io.itlb.resp.bits.miss, "blocked mode iTLB miss when resp.fire") assert(!io.itlb.resp.bits.miss, "blocked mode iTLB miss when resp.fire")
val tlbException = ExceptionType.fromTlbResp(io.itlb.resp.bits) val itlbException = ExceptionType.fromTlbResp(io.itlb.resp.bits)
// if itlb re-check respond pbmt mismatch with previous check, must be access fault // if itlb re-check respond pbmt mismatch with previous check, must be access fault
val pbmtMismatchException = Mux( val pbmtMismatchException = ExceptionType(hasAf = io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt)
io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt, // merge, itlbException has higher priority
ExceptionType.af, val exception = itlbException || pbmtMismatchException
ExceptionType.none
)
val exception = ExceptionType.merge(tlbException, pbmtMismatchException)
// if tlb has exception, abort checking pmp, just send instr & exception to iBuffer and wait for commit // if tlb has exception, abort checking pmp, just send instr & exception to iBuffer and wait for commit
mmioState := Mux(ExceptionType.hasException(exception), MmioFsmState.WaitCommit, MmioFsmState.SendPmp) mmioState := Mux(exception.hasException, MmioFsmState.WaitCommit, MmioFsmState.SendPmp)
// also save itlb response // also save itlb response
mmioException := exception mmioException := exception
mmioResendAddr := io.itlb.resp.bits.paddr(0) mmioResendAddr := io.itlb.resp.bits.paddr(0)
@ -721,16 +716,13 @@ class Ifu(implicit p: Parameters) extends IfuModule
} }
is(MmioFsmState.SendPmp) { is(MmioFsmState.SendPmp) {
val pmpException = ExceptionType.fromPMPResp(io.pmp.resp) val pmpException = ExceptionType.fromPmpResp(io.pmp.resp)
// if pmp re-check respond mismatch with previous check, must be access fault // if pmp re-check respond mismatch with previous check, must be access fault
val mmioMismatchException = Mux( val mmioMismatchException = ExceptionType(hasAf = io.pmp.resp.mmio =/= s3_pmpMmio)
io.pmp.resp.mmio =/= s3_pmpMmio, // merge, pmpException has higher priority
ExceptionType.af, val exception = pmpException || mmioMismatchException
ExceptionType.none
)
val exception = ExceptionType.merge(pmpException, mmioMismatchException)
// if pmp has exception, abort sending request, just send instr & exception to iBuffer and wait for commit // if pmp has exception, abort sending request, just send instr & exception to iBuffer and wait for commit
mmioState := Mux(ExceptionType.hasException(exception), MmioFsmState.WaitCommit, MmioFsmState.ResendReq) mmioState := Mux(exception.hasException, MmioFsmState.WaitCommit, MmioFsmState.ResendReq)
// also save pmp response // also save pmp response
mmioException := exception mmioException := exception
} }
@ -742,7 +734,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
is(MmioFsmState.WaitResendResp) { is(MmioFsmState.WaitResendResp) {
when(fromUncache.fire) { when(fromUncache.fire) {
mmioState := MmioFsmState.WaitCommit mmioState := MmioFsmState.WaitCommit
mmioException := ExceptionType.fromTilelink(fromUncache.bits.corrupt) mmioException := ExceptionType(hasAf = fromUncache.bits.corrupt)
mmioData(1) := fromUncache.bits.data(15, 0) mmioData(1) := fromUncache.bits.data(15, 0)
} }
} }
@ -860,8 +852,10 @@ class Ifu(implicit p: Parameters) extends IfuModule
a.bits := i.U a.bits := i.U
a.valid := checkerOutStage1.fixedTaken(i) && !s3_reqIsMmio a.valid := checkerOutStage1.fixedTaken(i) && !s3_reqIsMmio
} }
io.toIBuffer.bits.foldpc := s3_foldPc io.toIBuffer.bits.foldpc := s3_foldPc
io.toIBuffer.bits.exceptionType := ExceptionType.merge(s3_exceptionVec, s3_crossPageExceptionVec) io.toIBuffer.bits.exceptionType := VecInit((s3_exceptionVec zip s3_crossPageExceptionVec).map { case (e, ce) =>
e || ce // merge, cross page fix has lower priority
})
// backendException only needs to be set for the first instruction. // backendException only needs to be set for the first instruction.
// Other instructions in the same block may have pf or af set, // 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. // which is a side effect of the first instruction and actually not necessary.
@ -869,7 +863,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
case 0 => s3_isBackendException case 0 => s3_isBackendException
case _ => false.B case _ => false.B
} }
io.toIBuffer.bits.crossPageIPFFix := s3_crossPageExceptionVec.map(ExceptionType.hasException) io.toIBuffer.bits.crossPageIPFFix := s3_crossPageExceptionVec.map(_.hasException)
io.toIBuffer.bits.illegalInstr := s3_ill io.toIBuffer.bits.illegalInstr := s3_ill
io.toIBuffer.bits.triggered := s3_triggered io.toIBuffer.bits.triggered := s3_triggered
@ -899,8 +893,8 @@ class Ifu(implicit p: Parameters) extends IfuModule
// s3_gpAddr is valid iff gpf is detected // s3_gpAddr is valid iff gpf is detected
io.toBackend.gpaddrMem_wen := s3_toIBufferValid && Mux( io.toBackend.gpaddrMem_wen := s3_toIBufferValid && Mux(
s3_reqIsMmio, s3_reqIsMmio,
mmioException === ExceptionType.gpf, mmioException.isGpf,
s3_exception.map(_ === ExceptionType.gpf).reduce(_ || _) s3_exception.map(_.isGpf).reduce(_ || _)
) )
io.toBackend.gpaddrMem_waddr := s3_ftqReq.ftqIdx.value io.toBackend.gpaddrMem_waddr := s3_ftqReq.ftqIdx.value
io.toBackend.gpaddrMem_wdata.gpaddr := Mux(s3_reqIsMmio, mmioResendGpAddr.toUInt, s3_gpAddr.toUInt) io.toBackend.gpaddrMem_wdata.gpaddr := Mux(s3_reqIsMmio, mmioResendGpAddr.toUInt, s3_gpAddr.toUInt)
@ -951,7 +945,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
io.toIBuffer.bits.exceptionType(0) := mmioException io.toIBuffer.bits.exceptionType(0) := mmioException
// exception can happen in next page only when resend // exception can happen in next page only when resend
io.toIBuffer.bits.crossPageIPFFix(0) := mmioHasResend && ExceptionType.hasException(mmioException) io.toIBuffer.bits.crossPageIPFFix(0) := mmioHasResend && mmioException.hasException
io.toIBuffer.bits.illegalInstr(0) := mmioRvcExpander.io.ill io.toIBuffer.bits.illegalInstr(0) := mmioRvcExpander.io.ill
io.toIBuffer.bits.enqEnable := s3_mmioRange.asUInt io.toIBuffer.bits.enqEnable := s3_mmioRange.asUInt
@ -1053,12 +1047,12 @@ class Ifu(implicit p: Parameters) extends IfuModule
/* write back flush type */ /* write back flush type */
private val checkFaultType = wbCheckResultStage2.faultType private val checkFaultType = wbCheckResultStage2.faultType
private val checkJalFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalFault).reduce(_ || _) private val checkJalFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalFault).reduce(_ || _)
private val checkJalrFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalrFault).reduce(_ || _) private val checkJalrFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalrFault).reduce(_ || _)
private val checkRetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.retFault).reduce(_ || _) private val checkRetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.RetFault).reduce(_ || _)
private val checkTargetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.targetFault).reduce(_ || _) private val checkTargetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.TargetFault).reduce(_ || _)
private val checkNotCFIFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.notCfiFault).reduce(_ || _) private val checkNotCFIFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.NotCfiFault).reduce(_ || _)
private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.invalidTaken).reduce(_ || _) private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.InvalidTaken).reduce(_ || _)
XSPerfAccumulate("predecode_flush_jalFault", checkJalFault) XSPerfAccumulate("predecode_flush_jalFault", checkJalFault)
XSPerfAccumulate("predecode_flush_jalrFault", checkJalrFault) XSPerfAccumulate("predecode_flush_jalrFault", checkJalrFault)

View File

@ -139,14 +139,14 @@ class PredChecker(implicit p: Parameters) extends IfuModule {
io.resp.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) => io.resp.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) =>
faultType := MuxCase( faultType := MuxCase(
PreDecodeFaultType.noFault, PreDecodeFaultType.NoFault,
Seq( Seq(
jalFaultVecNext(i) -> PreDecodeFaultType.jalFault, jalFaultVecNext(i) -> PreDecodeFaultType.JalFault,
jalrFaultVecNext(i) -> PreDecodeFaultType.jalrFault, jalrFaultVecNext(i) -> PreDecodeFaultType.JalrFault,
retFaultVecNext(i) -> PreDecodeFaultType.retFault, retFaultVecNext(i) -> PreDecodeFaultType.RetFault,
targetFault(i) -> PreDecodeFaultType.targetFault, targetFault(i) -> PreDecodeFaultType.TargetFault,
notCFITakenNext(i) -> PreDecodeFaultType.notCfiFault, notCFITakenNext(i) -> PreDecodeFaultType.NotCfiFault,
invalidTakenNext(i) -> PreDecodeFaultType.invalidTaken invalidTakenNext(i) -> PreDecodeFaultType.InvalidTaken
) )
) )
} }

View File

@ -21,7 +21,7 @@ import freechips.rocketchip.tilelink.TLBundleA
import freechips.rocketchip.tilelink.TLBundleD import freechips.rocketchip.tilelink.TLBundleD
import freechips.rocketchip.tilelink.TLEdgeOut import freechips.rocketchip.tilelink.TLEdgeOut
import org.chipsalliance.cde.config.Parameters import org.chipsalliance.cde.config.Parameters
import utils.NamedUInt import utils.EnumUInt
// One miss entry deals with one mmio request // One miss entry deals with one mmio request
class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUncacheModule { class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUncacheModule {
@ -40,7 +40,7 @@ class InstrUncacheEntry(edge: TLEdgeOut)(implicit p: Parameters) extends InstrUn
val io: InstrUncacheEntryIO = IO(new InstrUncacheEntryIO(edge)) val io: InstrUncacheEntryIO = IO(new InstrUncacheEntryIO(edge))
private def nState: Int = 4 private def nState: Int = 4
private object State extends NamedUInt(log2Up(nState)) { private object State extends EnumUInt(nState) {
def Invalid: UInt = 0.U(width.W) def Invalid: UInt = 0.U(width.W)
def RefillReq: UInt = 1.U(width.W) def RefillReq: UInt = 1.U(width.W)
def RefillResp: UInt = 2.U(width.W) def RefillResp: UInt = 2.U(width.W)