fix(exception): Add guest page fault logic of misalign and vlsu (#3537)
In our previous design, we did not consider the handling of gpf of unaligned & vector load and stores. This commit adds a fix to correctly return the guest paddr when gpf happens in the above instructions.
This commit is contained in:
parent
8b2f7abc34
commit
a53daa0fd6
|
|
@ -1636,6 +1636,10 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
|
|||
loadMisalignBuffer.io.overwriteExpBuf.vaddr,
|
||||
storeMisalignBuffer.io.overwriteExpBuf.vaddr
|
||||
)
|
||||
val misalignBufExceptionGpaddr = Mux(loadMisalignBuffer.io.overwriteExpBuf.valid,
|
||||
loadMisalignBuffer.io.overwriteExpBuf.gpaddr,
|
||||
storeMisalignBuffer.io.overwriteExpBuf.gpaddr
|
||||
)
|
||||
|
||||
val vSegmentException = RegInit(false.B)
|
||||
when (DelayN(redirect.valid, 10) && vSegmentException) {
|
||||
|
|
@ -1648,6 +1652,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
|
|||
val vSegmentExceptionVl = RegEnable(vSegmentUnit.io.exceptionInfo.bits.vl, vSegmentUnit.io.exceptionInfo.valid)
|
||||
val vSegmentExceptionAddress = RegEnable(vSegmentUnit.io.exceptionInfo.bits.vaddr, vSegmentUnit.io.exceptionInfo.valid)
|
||||
val atomicsExceptionGPAddress = RegEnable(atomicsUnit.io.exceptionAddr.bits.gpaddr, atomicsUnit.io.exceptionAddr.valid)
|
||||
val vSegmentExceptionGPAddress = RegEnable(vSegmentUnit.io.exceptionInfo.bits.gpaddr, vSegmentUnit.io.exceptionInfo.valid)
|
||||
io.mem_to_ooo.lsqio.vaddr := RegNext(Mux(
|
||||
atomicsException,
|
||||
atomicsExceptionAddress,
|
||||
|
|
@ -1671,8 +1676,17 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
|
|||
)
|
||||
|
||||
XSError(atomicsException && atomicsUnit.io.in.valid, "new instruction before exception triggers\n")
|
||||
io.mem_to_ooo.lsqio.gpaddr := RegNext(Mux(atomicsException, atomicsExceptionGPAddress, lsq.io.exceptionAddr.gpaddr))
|
||||
|
||||
io.mem_to_ooo.lsqio.gpaddr := RegNext(Mux(
|
||||
atomicsException,
|
||||
atomicsExceptionGPAddress,
|
||||
Mux(misalignBufExceptionOverwrite,
|
||||
misalignBufExceptionGpaddr,
|
||||
Mux(vSegmentException,
|
||||
vSegmentExceptionGPAddress,
|
||||
lsq.io.exceptionAddr.gpaddr
|
||||
)
|
||||
)
|
||||
))
|
||||
io.mem_to_ooo.topToBackendBypass match { case x =>
|
||||
x.hartId := io.hartId
|
||||
x.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class LoadMisalignBuffer(implicit p: Parameters) extends XSModule
|
|||
val overwriteExpBuf = Output(new XSBundle {
|
||||
val valid = Bool()
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
})
|
||||
val flushLdExpBuff = Output(Bool())
|
||||
})
|
||||
|
|
@ -564,10 +565,12 @@ class LoadMisalignBuffer(implicit p: Parameters) extends XSModule
|
|||
// NOTE: spectial case (unaligned load cross page, page fault happens in next page)
|
||||
// if exception happens in the higher page address part, overwrite the loadExceptionBuffer vaddr
|
||||
val overwriteExpBuf = GatedValidRegNext(req_valid && cross16BytesBoundary && globalException && (curPtr === 1.U))
|
||||
val overwriteAddr = GatedRegNext(splitLoadResp(curPtr).vaddr)
|
||||
val overwriteVaddr = GatedRegNext(splitLoadResp(curPtr).vaddr)
|
||||
val overwriteGpaddr = GatedRegNext(splitLoadResp(curPtr).gpaddr)
|
||||
|
||||
io.overwriteExpBuf.valid := overwriteExpBuf
|
||||
io.overwriteExpBuf.vaddr := overwriteAddr
|
||||
io.overwriteExpBuf.vaddr := overwriteVaddr
|
||||
io.overwriteExpBuf.gpaddr := overwriteGpaddr
|
||||
|
||||
// when no exception or mmio, flush loadExceptionBuffer at s_wb
|
||||
val flushLdExpBuff = GatedValidRegNext(req_valid && (bufferState === s_wb) && !(globalMMIO || globalException))
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ class LoadQueue(implicit p: Parameters) extends XSModule
|
|||
exceptionBuffer.io.req(LoadPipelineWidth + i).valid := io.vecFeedback(i).valid && io.vecFeedback(i).bits.feedback(VecFeedbacks.FLUSH) // have exception
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits := DontCare
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits.vaddr := io.vecFeedback(i).bits.vaddr
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits.gpaddr := io.vecFeedback(i).bits.gpaddr
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits.uop.uopIdx := io.vecFeedback(i).bits.uopidx
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits.uop.robIdx := io.vecFeedback(i).bits.robidx
|
||||
exceptionBuffer.io.req(LoadPipelineWidth + i).bits.uop.vpu.vstart := io.vecFeedback(i).bits.vstart
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ class StoreMisalignBuffer(implicit p: Parameters) extends XSModule
|
|||
val overwriteExpBuf = Output(new XSBundle {
|
||||
val valid = Bool()
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
})
|
||||
val sqControl = new StoreMaBufToSqControlIO
|
||||
})
|
||||
|
|
@ -591,9 +592,11 @@ class StoreMisalignBuffer(implicit p: Parameters) extends XSModule
|
|||
// if exception happens in the higher page address part, overwrite the storeExceptionBuffer vaddr
|
||||
val overwriteExpBuf = GatedValidRegNext(req_valid && cross16BytesBoundary && globalException && (curPtr === 1.U))
|
||||
val overwriteAddr = GatedRegNext(splitStoreResp(curPtr).vaddr)
|
||||
val overwriteGpaddr = GatedRegNext(splitStoreResp(curPtr).gpaddr)
|
||||
|
||||
io.overwriteExpBuf.valid := overwriteExpBuf
|
||||
io.overwriteExpBuf.vaddr := overwriteAddr
|
||||
io.overwriteExpBuf.gpaddr := overwriteGpaddr
|
||||
|
||||
XSPerfAccumulate("alloc", RegNext(!req_valid) && req_valid)
|
||||
XSPerfAccumulate("flush", flush)
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ class StoreQueue(implicit p: Parameters) extends XSModule
|
|||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).valid := io.vecFeedback(i).valid && io.vecFeedback(i).bits.feedback(VecFeedbacks.FLUSH) // have exception
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits := DontCare
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits.vaddr := io.vecFeedback(i).bits.vaddr
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits.gpaddr := io.vecFeedback(i).bits.gpaddr
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits.uop.uopIdx := io.vecFeedback(i).bits.uopidx
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits.uop.robIdx := io.vecFeedback(i).bits.robidx
|
||||
exceptionBuffer.io.storeAddrIn(StorePipelineWidth * 2 + i).bits.uop.vpu.vstart := io.vecFeedback(i).bits.vstart
|
||||
|
|
|
|||
|
|
@ -1554,6 +1554,7 @@ class LoadUnit(implicit p: Parameters) extends XSModule
|
|||
io.vecldout.bits.flushState := DontCare
|
||||
io.vecldout.bits.exceptionVec := ExceptionNO.selectByFu(s3_out.bits.uop.exceptionVec, VlduCfg)
|
||||
io.vecldout.bits.vaddr := s3_in.vaddr
|
||||
io.vecldout.bits.gpaddr := s3_in.gpaddr
|
||||
io.vecldout.bits.mmio := DontCare
|
||||
|
||||
io.vecldout.valid := s3_out.valid && !s3_out.bits.uop.robIdx.needFlush(io.redirect) && s3_vecout.isvec ||
|
||||
|
|
|
|||
|
|
@ -485,6 +485,7 @@ class StoreUnit(implicit p: Parameters) extends XSModule
|
|||
sx_in(i).mbIndex := s3_in.mbIndex
|
||||
sx_in(i).mask := s3_in.mask
|
||||
sx_in(i).vaddr := s3_in.vaddr
|
||||
sx_in(i).gpaddr := s3_in.gpaddr
|
||||
sx_ready(i) := !s3_valid(i) || sx_in(i).output.uop.robIdx.needFlush(io.redirect) || (if (TotalDelayCycles == 0) io.stout.ready else sx_ready(i+1))
|
||||
} else {
|
||||
val cur_kill = sx_in(i).output.uop.robIdx.needFlush(io.redirect)
|
||||
|
|
@ -522,6 +523,7 @@ class StoreUnit(implicit p: Parameters) extends XSModule
|
|||
io.vecstout.bits.alignedType := sx_last_in.alignedType
|
||||
io.vecstout.bits.mask := sx_last_in.mask
|
||||
io.vecstout.bits.vaddr := sx_last_in.vaddr
|
||||
io.vecstout.bits.gpaddr := sx_last_in.gpaddr
|
||||
// io.vecstout.bits.reg_offset.map(_ := DontCare)
|
||||
// io.vecstout.bits.elemIdx.map(_ := sx_last_in.elemIdx)
|
||||
// io.vecstout.bits.elemIdxInsideVd.map(_ := DontCare)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class MBufferBundle(implicit p: Parameters) extends VLSUBundle{
|
|||
val vstart = UInt(elemIdxBits.W)
|
||||
val vl = UInt(elemIdxBits.W)
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
val fof = Bool()
|
||||
val vlmax = UInt(elemIdxBits.W)
|
||||
|
||||
|
|
@ -102,6 +103,7 @@ abstract class BaseVMergeBuffer(isVStore: Boolean=false)(implicit p: Parameters)
|
|||
sink.feedback(VecFeedbacks.LAST) := true.B
|
||||
sink.vstart := source.vstart // TODO: if lsq need vl for fof?
|
||||
sink.vaddr := source.vaddr
|
||||
sink.gpaddr := source.gpaddr
|
||||
sink.vl := source.vl
|
||||
sink.exceptionVec := ExceptionNO.selectByFu(source.exceptionVec, fuCfg)
|
||||
sink
|
||||
|
|
@ -241,6 +243,7 @@ abstract class BaseVMergeBuffer(isVStore: Boolean=false)(implicit p: Parameters)
|
|||
entries(wbMbIndex(i)).vstart := selElemInfield
|
||||
entries(wbMbIndex(i)).exceptionVec := ExceptionNO.selectByFu(selExceptionVec, fuCfg)
|
||||
entries(wbMbIndex(i)).vaddr := vaddr
|
||||
entries(wbMbIndex(i)).gpaddr := selPort(0).gpaddr
|
||||
}.otherwise{
|
||||
entries(wbMbIndex(i)).vl := selElemInfield
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,9 @@ class VSegmentBundle(implicit p: Parameters) extends VLSUBundle
|
|||
// for exception
|
||||
val vstart = UInt(elemIdxBits.W)
|
||||
val exceptionVaddr = UInt(VAddrBits.W)
|
||||
val exceptionGpaddr = UInt(GPAddrBits.W)
|
||||
val exception_va = Bool()
|
||||
val exception_gpa = Bool()
|
||||
val exception_pa = Bool()
|
||||
val exceptionVstart = UInt(elemIdxBits.W)
|
||||
val exceptionVl = UInt(elemIdxBits.W)
|
||||
|
|
@ -172,6 +174,7 @@ class VSegmentUnit (implicit p: Parameters) extends VLSUModule
|
|||
val splitPtrNext = WireInit(0.U.asTypeOf(new VSegUPtr))
|
||||
|
||||
val exception_va = WireInit(false.B)
|
||||
val exception_gpa = WireInit(false.B)
|
||||
val exception_pa = WireInit(false.B)
|
||||
|
||||
val maxSegIdx = instMicroOp.vl - 1.U
|
||||
|
|
@ -251,7 +254,7 @@ class VSegmentUnit (implicit p: Parameters) extends VLSUModule
|
|||
|
||||
}.elsewhen(state === s_pm){
|
||||
/* if is vStore, send data to sbuffer, so don't need query dcache */
|
||||
stateNext := Mux(exception_pa || exception_va,
|
||||
stateNext := Mux(exception_pa || exception_va || exception_gpa,
|
||||
s_finish,
|
||||
Mux(FuType.isVLoad(instMicroOp.uop.fuType), s_cache_req, s_send_data))
|
||||
|
||||
|
|
@ -381,10 +384,13 @@ class VSegmentUnit (implicit p: Parameters) extends VLSUModule
|
|||
when(io.dtlb.resp.fire && state === s_wait_tlb_resp){
|
||||
exceptionVec(storePageFault) := io.dtlb.resp.bits.excp(0).pf.st && canTriggerException
|
||||
exceptionVec(loadPageFault) := io.dtlb.resp.bits.excp(0).pf.ld && canTriggerException
|
||||
exceptionVec(storeGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.st && canTriggerException
|
||||
exceptionVec(loadGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.ld && canTriggerException
|
||||
exceptionVec(storeAccessFault) := io.dtlb.resp.bits.excp(0).af.st && canTriggerException
|
||||
exceptionVec(loadAccessFault) := io.dtlb.resp.bits.excp(0).af.ld && canTriggerException
|
||||
when(!io.dtlb.resp.bits.miss){
|
||||
instMicroOp.paddr := io.dtlb.resp.bits.paddr(0)
|
||||
instMicroOp.exceptionGpaddr := io.dtlb.resp.bits.gpaddr(0)
|
||||
}
|
||||
}
|
||||
// pmp
|
||||
|
|
@ -403,15 +409,17 @@ class VSegmentUnit (implicit p: Parameters) extends VLSUModule
|
|||
|
||||
exception_va := exceptionVec(storePageFault) || exceptionVec(loadPageFault) ||
|
||||
exceptionVec(storeAccessFault) || exceptionVec(loadAccessFault) || (missAligned && canTriggerException)
|
||||
exception_gpa := exceptionVec(storeGuestPageFault) || exceptionVec(loadGuestPageFault)
|
||||
exception_pa := (pmp.st || pmp.ld || pmp.mmio) && canTriggerException
|
||||
|
||||
instMicroOp.exception_pa := exception_pa
|
||||
instMicroOp.exception_va := exception_va
|
||||
instMicroOp.exception_gpa := exception_gpa
|
||||
// update storeAccessFault bit. Currently, we don't support vector MMIO
|
||||
exceptionVec(loadAccessFault) := (exceptionVec(loadAccessFault) || pmp.ld || pmp.mmio) && canTriggerException
|
||||
exceptionVec(storeAccessFault) := (exceptionVec(storeAccessFault) || pmp.st || pmp.mmio) && canTriggerException
|
||||
|
||||
when(exception_va || exception_pa) {
|
||||
when(exception_va || exception_gpa || exception_pa) {
|
||||
when(canTriggerException) {
|
||||
instMicroOp.exceptionVaddr := vaddr
|
||||
instMicroOp.exceptionVl := segmentIdx // for exception
|
||||
|
|
@ -653,6 +661,7 @@ class VSegmentUnit (implicit p: Parameters) extends VLSUModule
|
|||
io.exceptionInfo.bits.uopidx := uopq(deqPtr.value).uop.vpu.vuopIdx
|
||||
io.exceptionInfo.bits.vstart := instMicroOp.exceptionVstart
|
||||
io.exceptionInfo.bits.vaddr := instMicroOp.exceptionVaddr
|
||||
io.exceptionInfo.bits.gpaddr := instMicroOp.exceptionGpaddr
|
||||
io.exceptionInfo.bits.vl := instMicroOp.exceptionVl
|
||||
io.exceptionInfo.valid := (state === s_finish) && instMicroOp.uop.exceptionVec.asUInt.orR && !isEmpty(enqPtr, deqPtr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ class VecPipelineFeedbackIO(isVStore: Boolean=false) (implicit p: Parameters) ex
|
|||
//val atomic = Bool()
|
||||
val exceptionVec = ExceptionVec()
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
//val vec = new OnlyVecExuOutput
|
||||
// feedback
|
||||
val vecFeedback = Bool()
|
||||
|
|
@ -191,6 +192,7 @@ class FeedbackToLsqIO(implicit p: Parameters) extends VLSUBundle{
|
|||
val robidx = new RobPtr
|
||||
val uopidx = UopIdx()
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
val feedback = Vec(VecFeedbacks.allFeedbacks, Bool())
|
||||
// for exception
|
||||
val vstart = UInt(elemIdxBits.W)
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ class VecMemExuOutput(isVector: Boolean = false)(implicit p: Parameters) extends
|
|||
val mbIndex = UInt(vsmBindexBits.W)
|
||||
val mask = UInt(VLENB.W)
|
||||
val vaddr = UInt(VAddrBits.W)
|
||||
val gpaddr = UInt(GPAddrBits.W)
|
||||
}
|
||||
|
||||
object MulNum {
|
||||
|
|
|
|||
Loading…
Reference in New Issue