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
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:
parent
3bfc5a3c90
commit
cbea99c932
|
|
@ -33,12 +33,12 @@ object PreDecodeInst {
|
|||
|
||||
val brTable = Array(
|
||||
// C_JAL -> List(BrType.jal),
|
||||
C_EBREAK -> List(BrType.notCFI), // c.ebreak should not be decoded as jalr, higher priority than c.jalr
|
||||
C_J -> List(BrType.jal),
|
||||
C_JALR -> List(BrType.jalr),
|
||||
C_BRANCH -> List(BrType.branch),
|
||||
JAL -> List(BrType.jal),
|
||||
JALR -> List(BrType.jalr),
|
||||
BRANCH -> List(BrType.branch)
|
||||
C_EBREAK -> List(BrType.NotCfi), // c.ebreak should not be decoded as jalr, higher priority than c.jalr
|
||||
C_J -> List(BrType.Jal),
|
||||
C_JALR -> List(BrType.Jalr),
|
||||
C_BRANCH -> List(BrType.Branch),
|
||||
JAL -> List(BrType.Jal),
|
||||
JALR -> List(BrType.Jalr),
|
||||
BRANCH -> List(BrType.Branch)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ object Itype extends NamedUInt(4) {
|
|||
def jumpTypeGen(brType: UInt, rd: OpRegType, rs: OpRegType): UInt = {
|
||||
|
||||
val isEqualRdRs = rd === rs
|
||||
val isJal = brType === BrType.jal
|
||||
val isJalr = brType === BrType.jalr
|
||||
val isBranch = brType === BrType.branch
|
||||
val isJal = brType === BrType.Jal
|
||||
val isJalr = brType === BrType.Jalr
|
||||
val isBranch = brType === BrType.Branch
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import ftq.FtqRedirectSramEntry
|
|||
import ftq.FtqRfComponents
|
||||
import org.chipsalliance.cde.config.Parameters
|
||||
import utility._
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
import xiangshan._
|
||||
import xiangshan.backend.GPAMemEntry
|
||||
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 {
|
||||
val req: FtqICacheInfo = new FtqICacheInfo
|
||||
val backendException: UInt = ExceptionType()
|
||||
val backendException: ExceptionType = new ExceptionType
|
||||
}
|
||||
|
||||
class FtqToFetchBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters {
|
||||
|
|
@ -152,138 +152,94 @@ class mmioCommitRead(implicit p: Parameters) extends XSBundle {
|
|||
val mmioLastCommit = Input(Bool())
|
||||
}
|
||||
|
||||
object ExceptionType extends NamedUInt(2) {
|
||||
def none: UInt = "b00".U(width.W)
|
||||
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
|
||||
class ExceptionType extends Bundle {
|
||||
val value: UInt = ExceptionType.Value()
|
||||
|
||||
def hasException(e: UInt): Bool = e =/= none
|
||||
def hasException(e: Vec[UInt]): Bool = e.map(_ =/= none).reduce(_ || _)
|
||||
def hasException(e: IndexedSeq[UInt]): Bool = hasException(VecInit(e))
|
||||
def isNone: Bool = value === ExceptionType.Value.None
|
||||
def isPf: Bool = value === ExceptionType.Value.Pf
|
||||
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(
|
||||
PopCount(VecInit(has_pf, has_gpf, has_af)) <= 1.U,
|
||||
"ExceptionType.fromOH receives input that is not one-hot: pf=%d, gpf=%d, af=%d",
|
||||
has_pf,
|
||||
has_gpf,
|
||||
has_af
|
||||
PopCount(VecInit(hasPf, hasGpf, hasAf)) <= 1.U,
|
||||
"ExceptionType receives input that is not one-hot: pf=%d, gpf=%d, af=%d",
|
||||
hasPf,
|
||||
hasGpf,
|
||||
hasAf
|
||||
)
|
||||
// input is at-most-one-hot encoded, so we don't worry about priority here.
|
||||
MuxCase(
|
||||
none,
|
||||
None,
|
||||
Seq(
|
||||
has_pf -> pf,
|
||||
has_gpf -> gpf,
|
||||
has_af -> af
|
||||
hasPf -> Pf,
|
||||
hasGpf -> Gpf,
|
||||
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
|
||||
def fromTlbResp(resp: TlbResp, useDup: Int = 0): UInt = {
|
||||
def fromTlbResp(resp: TlbResp, useDup: Int = 0): ExceptionType = {
|
||||
require(useDup >= 0 && useDup < resp.excp.length)
|
||||
// itlb is guaranteed to respond at most one exception
|
||||
fromOH(
|
||||
resp.excp(useDup).pf.instr,
|
||||
resp.excp(useDup).gpf.instr,
|
||||
resp.excp(useDup).af.instr
|
||||
apply(
|
||||
hasPf = resp.excp(useDup).pf.instr,
|
||||
hasGpf = resp.excp(useDup).gpf.instr,
|
||||
hasAf = resp.excp(useDup).af.instr
|
||||
)
|
||||
}
|
||||
|
||||
// raise af if pmp check failed
|
||||
def fromPMPResp(resp: PMPRespBundle): UInt =
|
||||
Mux(resp.instr, af, none)
|
||||
|
||||
// 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)): _*)))
|
||||
}
|
||||
def fromPmpResp(resp: PMPRespBundle): ExceptionType =
|
||||
apply(hasAf = resp.instr)
|
||||
}
|
||||
|
||||
object BrType extends NamedUInt(2) {
|
||||
def notCFI: UInt = "b00".U(width.W)
|
||||
def branch: UInt = "b01".U(width.W)
|
||||
def jal: UInt = "b10".U(width.W)
|
||||
def jalr: UInt = "b11".U(width.W)
|
||||
object BrType extends EnumUInt(4) {
|
||||
def NotCfi: UInt = 0.U(width.W)
|
||||
def Branch: UInt = 1.U(width.W)
|
||||
def Jal: UInt = 2.U(width.W)
|
||||
def Jalr: UInt = 3.U(width.W)
|
||||
}
|
||||
|
||||
class PreDecodeInfo extends Bundle { // 8 bit
|
||||
|
|
@ -293,10 +249,10 @@ class PreDecodeInfo extends Bundle { // 8 bit
|
|||
val isCall = Bool()
|
||||
val isRet = Bool()
|
||||
// val excType = UInt(3.W)
|
||||
def isBr = brType === BrType.branch
|
||||
def isJal = brType === BrType.jal
|
||||
def isJalr = brType === BrType.jalr
|
||||
def notCFI = brType === BrType.notCFI
|
||||
def isBr = brType === BrType.Branch
|
||||
def isJal = brType === BrType.Jal
|
||||
def isJalr = brType === BrType.Jalr
|
||||
def notCFI = brType === BrType.NotCfi
|
||||
}
|
||||
|
||||
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 ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
|
||||
val backendException = Vec(PredictWidth, Bool())
|
||||
val exceptionType = Vec(PredictWidth, ExceptionType())
|
||||
val exceptionType = Vec(PredictWidth, new ExceptionType)
|
||||
val crossPageIPFFix = Vec(PredictWidth, Bool())
|
||||
val illegalInstr = Vec(PredictWidth, Bool())
|
||||
val triggered = Vec(PredictWidth, TriggerAction())
|
||||
|
|
|
|||
|
|
@ -49,6 +49,41 @@ class IBufferIO(implicit p: Parameters) extends XSBundle {
|
|||
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 {
|
||||
val inst = UInt(32.W)
|
||||
val pc = PrunedAddr(VAddrBits)
|
||||
|
|
@ -109,48 +144,6 @@ class IBufEntry(implicit p: Parameters) extends XSBundle {
|
|||
cf.debug_seqNum := debug_seqNum
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -159,13 +159,13 @@ class Ftq(implicit p: Parameters) extends FtqModule
|
|||
// 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
|
||||
// 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))
|
||||
when(fromBackendRedirect.valid) {
|
||||
backendException := ExceptionType.fromOH(
|
||||
has_pf = fromBackendRedirect.bits.cfiUpdate.backendIPF,
|
||||
has_gpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF,
|
||||
has_af = fromBackendRedirect.bits.cfiUpdate.backendIAF
|
||||
backendException := ExceptionType(
|
||||
hasPf = fromBackendRedirect.bits.cfiUpdate.backendIPF,
|
||||
hasGpf = fromBackendRedirect.bits.cfiUpdate.backendIGPF,
|
||||
hasAf = fromBackendRedirect.bits.cfiUpdate.backendIAF
|
||||
)
|
||||
when(
|
||||
fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF ||
|
||||
|
|
@ -174,7 +174,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
|
|||
backendPcFaultPtr := ifuWbPtr_write
|
||||
}
|
||||
}.elsewhen(ifuWbPtr =/= backendPcFaultPtr) {
|
||||
backendException := ExceptionType.none
|
||||
backendException := ExceptionType.None
|
||||
}
|
||||
|
||||
// **********************************************************************
|
||||
|
|
@ -473,7 +473,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
|
|||
copy.ftqIdx := ifuPtr
|
||||
}
|
||||
io.toICache.fetchReq.bits.isBackendException :=
|
||||
ExceptionType.hasException(backendException) && backendPcFaultPtr === ifuPtr
|
||||
backendException.hasException && backendPcFaultPtr === ifuPtr
|
||||
|
||||
io.toICache.prefetchReq.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr
|
||||
io.toICache.prefetchReq.bits.req.fromFtqPcBundle(toPrefetchPcBundle)
|
||||
|
|
@ -481,7 +481,7 @@ class Ftq(implicit p: Parameters) extends FtqModule
|
|||
io.toICache.prefetchReq.bits.backendException := Mux(
|
||||
backendPcFaultPtr === pfPtr,
|
||||
backendException,
|
||||
ExceptionType.none
|
||||
ExceptionType.None
|
||||
)
|
||||
// io.toICache.fetchReq.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
|
||||
// io.toICache.fetchReq.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
|
||||
|
|
|
|||
|
|
@ -161,14 +161,14 @@ class ReplacerVictimBundle(implicit p: Parameters) extends ICacheBundle {
|
|||
/* ***** MainPipe ***** */
|
||||
// ICache(MainPipe) -> IFU
|
||||
class ICacheRespBundle(implicit p: Parameters) extends ICacheBundle {
|
||||
val doubleline: Bool = Bool()
|
||||
val vAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(VAddrBits))
|
||||
val data: UInt = UInt(blockBits.W)
|
||||
val pAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(PAddrBits))
|
||||
val exception: Vec[UInt] = Vec(PortNumber, ExceptionType())
|
||||
val pmpMmio: Vec[Bool] = Vec(PortNumber, Bool())
|
||||
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
|
||||
val isBackendException: Bool = Bool()
|
||||
val doubleline: Bool = Bool()
|
||||
val vAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(VAddrBits))
|
||||
val data: UInt = UInt(blockBits.W)
|
||||
val pAddr: Vec[PrunedAddr] = Vec(PortNumber, PrunedAddr(PAddrBits))
|
||||
val exception: Vec[ExceptionType] = Vec(PortNumber, new ExceptionType)
|
||||
val pmpMmio: Vec[Bool] = Vec(PortNumber, Bool())
|
||||
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
|
||||
val isBackendException: Bool = Bool()
|
||||
/* NOTE: GPAddrBits(=50bit) is not enough for gpAddr here, refer to PR#3795
|
||||
* Sv48*4 only allows 50bit gpAddr, when software violates this requirement
|
||||
* 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 ***** */
|
||||
class PrefetchReqBundle(implicit p: Parameters) extends ICacheBundle {
|
||||
val startAddr: PrunedAddr = PrunedAddr(VAddrBits)
|
||||
val nextlineStart: PrunedAddr = PrunedAddr(VAddrBits)
|
||||
val ftqIdx: FtqPtr = new FtqPtr
|
||||
val isSoftPrefetch: Bool = Bool()
|
||||
val backendException: UInt = ExceptionType()
|
||||
val startAddr: PrunedAddr = PrunedAddr(VAddrBits)
|
||||
val nextlineStart: PrunedAddr = PrunedAddr(VAddrBits)
|
||||
val ftqIdx: FtqPtr = new FtqPtr
|
||||
val isSoftPrefetch: Bool = Bool()
|
||||
val backendException: ExceptionType = new ExceptionType
|
||||
|
||||
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.
|
||||
*/
|
||||
class WayLookupEntry(implicit p: Parameters) extends ICacheBundle {
|
||||
val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
|
||||
val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
|
||||
val pTag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
|
||||
val itlbException: Vec[UInt] = Vec(PortNumber, ExceptionType())
|
||||
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
|
||||
val metaCodes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
|
||||
val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
|
||||
val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
|
||||
val pTag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
|
||||
val itlbException: Vec[ExceptionType] = Vec(PortNumber, new ExceptionType)
|
||||
val itlbPbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
|
||||
val metaCodes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
|
||||
}
|
||||
|
||||
class WayLookupGpfEntry(implicit p: Parameters) extends ICacheBundle {
|
||||
|
|
@ -233,14 +233,14 @@ class WayLookupBundle(implicit p: Parameters) extends ICacheBundle {
|
|||
val gpf = new WayLookupGpfEntry
|
||||
|
||||
// for compatibility
|
||||
def vSetIdx: Vec[UInt] = entry.vSetIdx
|
||||
def waymask: Vec[UInt] = entry.waymask
|
||||
def pTag: Vec[UInt] = entry.pTag
|
||||
def itlbException: Vec[UInt] = entry.itlbException
|
||||
def itlbPbmt: Vec[UInt] = entry.itlbPbmt
|
||||
def metaCodes: Vec[UInt] = entry.metaCodes
|
||||
def gpAddr: PrunedAddr = gpf.gpAddr
|
||||
def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE
|
||||
def vSetIdx: Vec[UInt] = entry.vSetIdx
|
||||
def waymask: Vec[UInt] = entry.waymask
|
||||
def pTag: Vec[UInt] = entry.pTag
|
||||
def itlbException: Vec[ExceptionType] = entry.itlbException
|
||||
def itlbPbmt: Vec[UInt] = entry.itlbPbmt
|
||||
def metaCodes: Vec[UInt] = entry.metaCodes
|
||||
def gpAddr: PrunedAddr = gpf.gpAddr
|
||||
def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE
|
||||
}
|
||||
|
||||
/* ***** Miss ***** */
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import freechips.rocketchip.regmapper.RegReadFn
|
|||
import freechips.rocketchip.regmapper.RegWriteFn
|
||||
import freechips.rocketchip.tilelink.TLRegisterNode
|
||||
import org.chipsalliance.cde.config.Parameters
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
import xiangshan.frontend.PrunedAddrInit
|
||||
|
||||
// currently for ECC control only
|
||||
|
|
@ -61,7 +61,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
|
|||
|
||||
// eccCtrl.ierror: inject error code
|
||||
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 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
|
||||
|
|
@ -78,7 +78,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
|
|||
}
|
||||
// eccCtrl.istatus: inject status
|
||||
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 Working: UInt = 1.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
|
||||
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 DataArray: UInt = 2.U(width.W)
|
||||
@unused
|
||||
|
|
@ -151,7 +151,7 @@ class ICacheCtrlUnit(params: ICacheCtrlUnitParameters)(implicit p: Parameters) e
|
|||
|
||||
// inject FSM
|
||||
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()`
|
||||
// but we want UpperCamelCase for constants for better readability, so we dont use Enum() here
|
||||
def Idle: UInt = 0.U(width.W)
|
||||
|
|
|
|||
|
|
@ -224,14 +224,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
|
|||
p.bits.size := 3.U
|
||||
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))
|
||||
|
||||
// merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next
|
||||
private val s1_exceptionOut = ExceptionType.merge(
|
||||
s1_itlbException,
|
||||
s1_pmpException
|
||||
)
|
||||
private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p })
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
|
|
@ -418,7 +415,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
|
|||
private val s2_shouldFetch = VecInit((0 until PortNumber).map { i =>
|
||||
(!s2_hits(i) || s2_corruptRefetch(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(_ && _)
|
||||
})
|
||||
|
||||
|
|
@ -446,14 +443,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
|
|||
private val s2_fetchFinish = !s2_shouldFetch.reduce(_ || _)
|
||||
|
||||
// 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
|
||||
|
||||
// merge s2 exceptions, itlb has the highest priority, then l2
|
||||
private val s2_exceptionOut = ExceptionType.merge(
|
||||
s2_exception, // includes itlb/pmp exception
|
||||
s2_l2Exception
|
||||
)
|
||||
// merge s2 exceptions, itlb/pmp has the highest priority, then l2
|
||||
private val s2_exceptionOut = VecInit((s2_exception zip s2_l2Exception).map { case (in, l2) => in || l2 })
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
|
|
@ -468,7 +462,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
|
|||
toIfu.bits.pAddr := s2_pAddr
|
||||
(0 until PortNumber).foreach { i =>
|
||||
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.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.miss0Hit1 := !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.miss0Except1 := !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) && s2_exception(1).hasException && s2_doubleline
|
||||
io.perf.bankHit(0) := s2_hits(0)
|
||||
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))
|
||||
|
||||
/** <PERF> fetch bubble generated by icache miss */
|
||||
|
|
@ -553,7 +547,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
|
|||
*/
|
||||
if (env.EnableDifftest) {
|
||||
val discards = (0 until PortNumber).map { i =>
|
||||
ExceptionType.hasException(toIfu.bits.exception(i)) ||
|
||||
toIfu.bits.exception(i).hasException ||
|
||||
toIfu.bits.pmpMmio(i) ||
|
||||
Pbmt.isUncache(toIfu.bits.itlbPbmt(i))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@ import utility.DataHoldBypass
|
|||
import utility.PriorityMuxDefault
|
||||
import utility.ValidHold
|
||||
import utility.XSPerfAccumulate
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
import xiangshan.cache.mmu.Pbmt
|
||||
import xiangshan.cache.mmu.TlbCmd
|
||||
import xiangshan.cache.mmu.TlbRequestIO
|
||||
import xiangshan.cache.mmu.ValidHoldBypass // FIXME: should move this to utility?
|
||||
import xiangshan.frontend.ExceptionType
|
||||
import xiangshan.frontend.PrunedAddr
|
||||
import xiangshan.frontend.PrunedAddrInit
|
||||
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 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 ItlbResend: UInt = 1.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))
|
||||
})
|
||||
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 =>
|
||||
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
|
||||
// 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
|
||||
private val s1_itlbException = ExceptionType.merge(
|
||||
s1_backendException,
|
||||
s1_itlbExceptionRaw
|
||||
)
|
||||
private val s1_itlbException = VecInit((s1_backendException zip s1_itlbExceptionRaw).map { case (b, i) => b || i })
|
||||
// debug
|
||||
dontTouch(s1_itlbExceptionRaw)
|
||||
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 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(
|
||||
s1_itlbExceptionIsGpf zip (0 until PortNumber).map(i => s1_gpAddrRaw(i) - (i << blockOffBits).U),
|
||||
0.U.asTypeOf(s1_gpAddrRaw(0))
|
||||
|
|
@ -326,7 +322,7 @@ class ICachePrefetchPipe(implicit p: Parameters) extends ICacheModule
|
|||
toWayLookup.bits.itlbException(i) := Mux(
|
||||
excpValid,
|
||||
s1_itlbException(i), // includes backend exception
|
||||
ExceptionType.none
|
||||
ExceptionType.None
|
||||
)
|
||||
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.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))
|
||||
|
||||
// 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
|
||||
private val s1_exceptionOut = ExceptionType.merge(
|
||||
s1_itlbException, // includes backend exception
|
||||
s1_pmpException
|
||||
)
|
||||
// here, itlb exception includes backend exception
|
||||
private val s1_exceptionOut = VecInit((s1_itlbException zip s1_pmpException).map { case (i, p) => i || p })
|
||||
|
||||
// merge pmp mmio and itlb 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 =>
|
||||
!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(_ && _)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class ICacheWayLookup(implicit p: Parameters) extends ICacheModule with ICacheMi
|
|||
io.write.ready := !full && !gpfStall
|
||||
when(io.write.fire) {
|
||||
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
|
||||
// note this will override the read (L156)
|
||||
gpfEntry.valid := !(canBypass && io.read.fire)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package xiangshan.frontend.ifu
|
|||
import chisel3._
|
||||
import chisel3.util._
|
||||
import org.chipsalliance.cde.config.Parameters
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
import xiangshan.frontend.PrunedAddr
|
||||
|
||||
/* ***
|
||||
|
|
@ -32,14 +32,14 @@ import xiangshan.frontend.PrunedAddr
|
|||
* *** */
|
||||
|
||||
/* ***** PreDecode ***** */
|
||||
object PreDecodeFaultType extends NamedUInt(3) {
|
||||
def noFault: UInt = "b000".U(width.W)
|
||||
def jalFault: UInt = "b001".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 targetFault: UInt = "b011".U(width.W)
|
||||
def notCfiFault: UInt = "b100".U(width.W) // not CFI taken or invalid instruction taken
|
||||
def invalidTaken: UInt = "b101".U(width.W)
|
||||
def jalrFault: UInt = "b110".U(width.W)
|
||||
object PreDecodeFaultType extends EnumUInt(7) {
|
||||
def NoFault: UInt = 0.U(width.W)
|
||||
def JalFault: UInt = 1.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 = 3.U(width.W)
|
||||
def NotCfiFault: UInt = 4.U(width.W) // not CFI taken or invalid instruction taken
|
||||
def InvalidTaken: UInt = 5.U(width.W)
|
||||
def JalrFault: UInt = 6.U(width.W)
|
||||
}
|
||||
|
||||
/* ***** Ifu last half ***** */
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ trait PreDecodeHelper extends HasXSParameter {
|
|||
def isLink(reg: UInt): Bool = reg === 1.U || reg === 5.U
|
||||
|
||||
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) = {
|
||||
val brType = getBrType(inst)
|
||||
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 isCall = (brType === BrType.jal && !isRVC(inst) || brType === BrType.jalr) && isLink(rd) // Only for RV64
|
||||
val isRet = brType === BrType.jalr && isLink(rs) && !isCall
|
||||
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 isRet = brType === BrType.Jalr && isLink(rs) && !isCall
|
||||
(brType, isCall, isRet)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import utility.XSDebug
|
|||
import utility.XSError
|
||||
import utility.XSPerfAccumulate
|
||||
import utility.XSPerfHistogram
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
import xiangshan.FrontendTdataDistributeIO
|
||||
import xiangshan.RedirectLevel
|
||||
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
|
||||
private val s2_mmioMismatchException = VecInit(Seq(
|
||||
ExceptionType.none, // mark the exception only on the second line
|
||||
Mux(
|
||||
// not double-line, skip check
|
||||
!fromICache.bits.doubleline || (
|
||||
ExceptionType.None, // mark the exception only on the second line
|
||||
ExceptionType(hasAf =
|
||||
// if not double-line, skip check
|
||||
fromICache.bits.doubleline && (
|
||||
// is double-line, ask for consistent pmp_mmio and itlb_pbmt value
|
||||
fromICache.bits.pmpMmio(0) === fromICache.bits.pmpMmio(1) &&
|
||||
fromICache.bits.itlbPbmt(0) === fromICache.bits.itlbPbmt(1)
|
||||
),
|
||||
ExceptionType.none,
|
||||
ExceptionType.af
|
||||
fromICache.bits.pmpMmio(0) =/= fromICache.bits.pmpMmio(1) ||
|
||||
fromICache.bits.itlbPbmt(0) =/= fromICache.bits.itlbPbmt(1)
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
// 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
|
||||
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_exceptionVec = VecInit((0 until PredictWidth).map(i =>
|
||||
MuxCase(
|
||||
ExceptionType.none,
|
||||
ExceptionType.None,
|
||||
Seq(
|
||||
!isNextLine(s2_pc(i), s2_ftqReq.startAddr) -> s2_exception(0),
|
||||
(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 =>
|
||||
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),
|
||||
ExceptionType.none
|
||||
ExceptionType.None
|
||||
)
|
||||
})
|
||||
XSPerfAccumulate("fetch_bubble_icache_not_resp", s2_valid && !icacheRespAllValid)
|
||||
|
|
@ -563,7 +561,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
|
||||
/* *** mmio *** */
|
||||
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 WaitLastCommit: UInt = 1.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 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 mmioHasResend = RegInit(false.B)
|
||||
private val mmioResendAddr = RegInit(PrunedAddrInit(0.U(PAddrBits.W)))
|
||||
|
|
@ -591,7 +589,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
private def mmioReset(): Unit = {
|
||||
mmioState := MmioFsmState.Idle
|
||||
mmioData.foreach(_ := 0.U)
|
||||
mmioException := ExceptionType.none
|
||||
mmioException := ExceptionType.None
|
||||
mmioIsRvc := false.B
|
||||
mmioHasResend := false.B
|
||||
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
|
||||
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 =>
|
||||
commit.valid && commit.bits.ftqIdx === s3_ftqReq.ftqIdx && commit.bits.ftqOffset === 0.U
|
||||
}).asUInt.orR
|
||||
|
|
@ -682,9 +680,9 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
is(MmioFsmState.WaitResp) {
|
||||
when(fromUncache.fire) {
|
||||
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
|
||||
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)
|
||||
mmioException := exception
|
||||
mmioIsRvc := respIsRVC
|
||||
|
|
@ -702,16 +700,13 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
when(io.itlb.resp.fire) {
|
||||
// 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")
|
||||
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
|
||||
val pbmtMismatchException = Mux(
|
||||
io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt,
|
||||
ExceptionType.af,
|
||||
ExceptionType.none
|
||||
)
|
||||
val exception = ExceptionType.merge(tlbException, pbmtMismatchException)
|
||||
val pbmtMismatchException = ExceptionType(hasAf = io.itlb.resp.bits.pbmt(0) =/= s3_itlbPbmt)
|
||||
// merge, itlbException has higher priority
|
||||
val exception = itlbException || pbmtMismatchException
|
||||
// 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
|
||||
mmioException := exception
|
||||
mmioResendAddr := io.itlb.resp.bits.paddr(0)
|
||||
|
|
@ -721,16 +716,13 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
}
|
||||
|
||||
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
|
||||
val mmioMismatchException = Mux(
|
||||
io.pmp.resp.mmio =/= s3_pmpMmio,
|
||||
ExceptionType.af,
|
||||
ExceptionType.none
|
||||
)
|
||||
val exception = ExceptionType.merge(pmpException, mmioMismatchException)
|
||||
val mmioMismatchException = ExceptionType(hasAf = io.pmp.resp.mmio =/= s3_pmpMmio)
|
||||
// merge, pmpException has higher priority
|
||||
val exception = pmpException || mmioMismatchException
|
||||
// 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
|
||||
mmioException := exception
|
||||
}
|
||||
|
|
@ -742,7 +734,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
is(MmioFsmState.WaitResendResp) {
|
||||
when(fromUncache.fire) {
|
||||
mmioState := MmioFsmState.WaitCommit
|
||||
mmioException := ExceptionType.fromTilelink(fromUncache.bits.corrupt)
|
||||
mmioException := ExceptionType(hasAf = fromUncache.bits.corrupt)
|
||||
mmioData(1) := fromUncache.bits.data(15, 0)
|
||||
}
|
||||
}
|
||||
|
|
@ -860,8 +852,10 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
a.bits := i.U
|
||||
a.valid := checkerOutStage1.fixedTaken(i) && !s3_reqIsMmio
|
||||
}
|
||||
io.toIBuffer.bits.foldpc := s3_foldPc
|
||||
io.toIBuffer.bits.exceptionType := ExceptionType.merge(s3_exceptionVec, s3_crossPageExceptionVec)
|
||||
io.toIBuffer.bits.foldpc := s3_foldPc
|
||||
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.
|
||||
// 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.
|
||||
|
|
@ -869,7 +863,7 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
case 0 => s3_isBackendException
|
||||
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.triggered := s3_triggered
|
||||
|
||||
|
|
@ -899,8 +893,8 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
// s3_gpAddr is valid iff gpf is detected
|
||||
io.toBackend.gpaddrMem_wen := s3_toIBufferValid && Mux(
|
||||
s3_reqIsMmio,
|
||||
mmioException === ExceptionType.gpf,
|
||||
s3_exception.map(_ === ExceptionType.gpf).reduce(_ || _)
|
||||
mmioException.isGpf,
|
||||
s3_exception.map(_.isGpf).reduce(_ || _)
|
||||
)
|
||||
io.toBackend.gpaddrMem_waddr := s3_ftqReq.ftqIdx.value
|
||||
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
|
||||
// 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.enqEnable := s3_mmioRange.asUInt
|
||||
|
|
@ -1053,12 +1047,12 @@ class Ifu(implicit p: Parameters) extends IfuModule
|
|||
|
||||
/* write back flush type */
|
||||
private val checkFaultType = wbCheckResultStage2.faultType
|
||||
private val checkJalFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalFault).reduce(_ || _)
|
||||
private val checkJalrFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.jalrFault).reduce(_ || _)
|
||||
private val checkRetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.retFault).reduce(_ || _)
|
||||
private val checkTargetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.targetFault).reduce(_ || _)
|
||||
private val checkNotCFIFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.notCfiFault).reduce(_ || _)
|
||||
private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.invalidTaken).reduce(_ || _)
|
||||
private val checkJalFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalFault).reduce(_ || _)
|
||||
private val checkJalrFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.JalrFault).reduce(_ || _)
|
||||
private val checkRetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.RetFault).reduce(_ || _)
|
||||
private val checkTargetFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.TargetFault).reduce(_ || _)
|
||||
private val checkNotCFIFault = wbValid && checkFaultType.map(_ === PreDecodeFaultType.NotCfiFault).reduce(_ || _)
|
||||
private val checkInvalidTaken = wbValid && checkFaultType.map(_ === PreDecodeFaultType.InvalidTaken).reduce(_ || _)
|
||||
|
||||
XSPerfAccumulate("predecode_flush_jalFault", checkJalFault)
|
||||
XSPerfAccumulate("predecode_flush_jalrFault", checkJalrFault)
|
||||
|
|
|
|||
|
|
@ -139,14 +139,14 @@ class PredChecker(implicit p: Parameters) extends IfuModule {
|
|||
|
||||
io.resp.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) =>
|
||||
faultType := MuxCase(
|
||||
PreDecodeFaultType.noFault,
|
||||
PreDecodeFaultType.NoFault,
|
||||
Seq(
|
||||
jalFaultVecNext(i) -> PreDecodeFaultType.jalFault,
|
||||
jalrFaultVecNext(i) -> PreDecodeFaultType.jalrFault,
|
||||
retFaultVecNext(i) -> PreDecodeFaultType.retFault,
|
||||
targetFault(i) -> PreDecodeFaultType.targetFault,
|
||||
notCFITakenNext(i) -> PreDecodeFaultType.notCfiFault,
|
||||
invalidTakenNext(i) -> PreDecodeFaultType.invalidTaken
|
||||
jalFaultVecNext(i) -> PreDecodeFaultType.JalFault,
|
||||
jalrFaultVecNext(i) -> PreDecodeFaultType.JalrFault,
|
||||
retFaultVecNext(i) -> PreDecodeFaultType.RetFault,
|
||||
targetFault(i) -> PreDecodeFaultType.TargetFault,
|
||||
notCFITakenNext(i) -> PreDecodeFaultType.NotCfiFault,
|
||||
invalidTakenNext(i) -> PreDecodeFaultType.InvalidTaken
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import freechips.rocketchip.tilelink.TLBundleA
|
|||
import freechips.rocketchip.tilelink.TLBundleD
|
||||
import freechips.rocketchip.tilelink.TLEdgeOut
|
||||
import org.chipsalliance.cde.config.Parameters
|
||||
import utils.NamedUInt
|
||||
import utils.EnumUInt
|
||||
|
||||
// One miss entry deals with one mmio request
|
||||
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))
|
||||
|
||||
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 RefillReq: UInt = 1.U(width.W)
|
||||
def RefillResp: UInt = 2.U(width.W)
|
||||
|
|
|
|||
Loading…
Reference in New Issue