fix(StoreQueue): not do nc store when having exception (#4661)
EMU Test / Changes Detection (push) Waiting to run
Details
EMU Test / Generate Verilog (push) Blocked by required conditions
Details
EMU Test / EMU - Basics (push) Blocked by required conditions
Details
EMU Test / EMU - CHI (push) Blocked by required conditions
Details
EMU Test / Docker Build (push) Blocked by required conditions
Details
EMU Test / EMU - Performance (push) Blocked by required conditions
Details
EMU Test / EMU - MC (push) Blocked by required conditions
Details
EMU Test / SIMV - Basics (push) Blocked by required conditions
Details
EMU Test / Upload Artifacts (push) Blocked by required conditions
Details
EMU Test / Check Submodules (push) Blocked by required conditions
Details
EMU Test / Check Format (push) Blocked by required conditions
Details
Release Jobs / build-xsdev-image (push) Waiting to run
Details
EMU Test / Changes Detection (push) Waiting to run
Details
EMU Test / Generate Verilog (push) Blocked by required conditions
Details
EMU Test / EMU - Basics (push) Blocked by required conditions
Details
EMU Test / EMU - CHI (push) Blocked by required conditions
Details
EMU Test / Docker Build (push) Blocked by required conditions
Details
EMU Test / EMU - Performance (push) Blocked by required conditions
Details
EMU Test / EMU - MC (push) Blocked by required conditions
Details
EMU Test / SIMV - Basics (push) Blocked by required conditions
Details
EMU Test / Upload Artifacts (push) Blocked by required conditions
Details
EMU Test / Check Submodules (push) Blocked by required conditions
Details
EMU Test / Check Format (push) Blocked by required conditions
Details
Release Jobs / build-xsdev-image (push) Waiting to run
Details
### Bug Description The NC store does not handle exceptions properly. When an exception occurs during its execution, the store queue (SQ) continues to process it as if it were a normal nc store—this includes committing it and sending it to the uncache—resulting in an invalid memory access. ### Bug Analysis In the current SQ design, for regular stores, both `rdataPtr` and `deqPtr` advance based on handshakes with `dataBuffer` and `SBuffer`, respectively. Thus, even if an exception occurs, the store is marked as `committed = true` and passed into both buffers. If an exception is detected at the `SBuffer`, the actual write is skipped. For NC stores, the `committed` logic is reused from regular stores. However, there is no dedicated handling for exceptional cases in the later pipeline stages—such as preventing handshake with the `UBuffer`, or allowing the handshake but skipping the write. This fix adopts the former approach: **NC stores will not perform a handshake with the `UBuffer` when an exception is detected**, in order to preserve a clean and consistent `UBuffer` interface. ### Solution * NC stores continue to be marked as `committed = true`. * Only when `!completed(rptr0) && allvalid(rptr0) && !hasException(rptr0)` is satisfied, the NC store is allowed to enter the `UBuffer`. * If the instruction causes an exception, the backend will flush it and all subsequent instructions. * When the flushed instruction reaches the NC store entry in the store queue, `completed` is set to `true`. * For `deqPtr`, since `deqPtr` advances based on the `completed` signal, no additional changes are needed. * For `rdataPtr`, behavior remains unchanged for regular stores, but for NC stores, advancement is now triggered by `completed` instead of `ncReadNextTrigger`.
This commit is contained in:
parent
f96455c94b
commit
3c8fe1e213
|
@ -285,6 +285,7 @@ class StoreQueue(implicit p: Parameters) extends XSModule
|
||||||
val enqPtr = enqPtrExt(0).value
|
val enqPtr = enqPtrExt(0).value
|
||||||
val deqPtr = deqPtrExt(0).value
|
val deqPtr = deqPtrExt(0).value
|
||||||
val cmtPtr = cmtPtrExt(0).value
|
val cmtPtr = cmtPtrExt(0).value
|
||||||
|
val rdPtr = rdataPtrExt(0).value
|
||||||
|
|
||||||
val validCount = distanceBetween(enqPtrExt(0), deqPtrExt(0))
|
val validCount = distanceBetween(enqPtrExt(0), deqPtrExt(0))
|
||||||
val allowEnqueue = validCount <= (StoreQueueSize - LSQStEnqWidth).U
|
val allowEnqueue = validCount <= (StoreQueueSize - LSQStEnqWidth).U
|
||||||
|
@ -314,10 +315,23 @@ class StoreQueue(implicit p: Parameters) extends XSModule
|
||||||
assert(EnsbufferWidth <= 2)
|
assert(EnsbufferWidth <= 2)
|
||||||
// rdataPtrExtNext and rdataPtrExtNext+1 entry will be read from dataModule
|
// rdataPtrExtNext and rdataPtrExtNext+1 entry will be read from dataModule
|
||||||
val rdataPtrExtNext = Wire(Vec(EnsbufferWidth, new SqPtr))
|
val rdataPtrExtNext = Wire(Vec(EnsbufferWidth, new SqPtr))
|
||||||
rdataPtrExtNext := rdataPtrExt.map(i => i +
|
val sqReadCnt = WireInit(0.U(log2Ceil(EnsbufferWidth + 1).W))
|
||||||
PopCount(dataBuffer.io.enq.map(x=> x.fire && x.bits.sqNeedDeq)) +
|
val readyReadGoVec = WireInit(VecInit((0 until EnsbufferWidth).map(i =>
|
||||||
PopCount(ncReadNextTrigger || io.mmioStout.fire || io.vecmmioStout.fire)
|
if(i == 0) {
|
||||||
)
|
dataBuffer.io.enq(i).fire && dataBuffer.io.enq(i).bits.sqNeedDeq ||
|
||||||
|
allocated(rdataPtrExt(i).value) && completed(rdataPtrExt(i).value) && nc(rdataPtrExt(i).value) ||
|
||||||
|
io.mmioStout.fire || io.vecmmioStout.fire
|
||||||
|
} else {
|
||||||
|
dataBuffer.io.enq(i).fire && dataBuffer.io.enq(i).bits.sqNeedDeq ||
|
||||||
|
allocated(rdataPtrExt(i).value) && completed(rdataPtrExt(i).value) && nc(rdataPtrExt(i).value)
|
||||||
|
}
|
||||||
|
)))
|
||||||
|
for (i <- 0 until EnsbufferWidth) {
|
||||||
|
when(readyReadGoVec.take(i + 1).reduce(_ && _)) {
|
||||||
|
sqReadCnt := (i + 1).U // increase one by one
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdataPtrExtNext := rdataPtrExt.map(_ + sqReadCnt)
|
||||||
|
|
||||||
// deqPtrExtNext traces which inst is about to leave store queue
|
// deqPtrExtNext traces which inst is about to leave store queue
|
||||||
val deqPtrExtNext = Wire(Vec(EnsbufferWidth, new SqPtr))
|
val deqPtrExtNext = Wire(Vec(EnsbufferWidth, new SqPtr))
|
||||||
|
@ -876,7 +890,10 @@ class StoreQueue(implicit p: Parameters) extends XSModule
|
||||||
val rptr0 = rdataPtrExt(0).value
|
val rptr0 = rdataPtrExt(0).value
|
||||||
switch(ncState){
|
switch(ncState){
|
||||||
is(nc_idle) {
|
is(nc_idle) {
|
||||||
when(nc(rptr0) && allocated(rptr0) && committed(rptr0) && !mmio(rptr0) && !isVec(rptr0)) {
|
when(
|
||||||
|
nc(rptr0) && allocated(rptr0) && !completed(rptr0) && committed(rptr0) &&
|
||||||
|
allvalid(rptr0) && !isVec(rptr0) && !hasException(rptr0) && !mmio(rptr0)
|
||||||
|
) {
|
||||||
ncState := nc_req
|
ncState := nc_req
|
||||||
ncWaitRespPtrReg := rptr0
|
ncWaitRespPtrReg := rptr0
|
||||||
}
|
}
|
||||||
|
@ -1078,26 +1095,33 @@ class StoreQueue(implicit p: Parameters) extends XSModule
|
||||||
// TODO: Deal with vector store mmio
|
// TODO: Deal with vector store mmio
|
||||||
for (i <- 0 until CommitWidth) {
|
for (i <- 0 until CommitWidth) {
|
||||||
// don't mark misalign store as committed
|
// don't mark misalign store as committed
|
||||||
|
val ptr = cmtPtrExt(i).value
|
||||||
|
val isCommit = WireInit(false.B)
|
||||||
when (
|
when (
|
||||||
allocated(cmtPtrExt(i).value) &&
|
allocated(ptr) &&
|
||||||
isNotAfter(uop(cmtPtrExt(i).value).robIdx, GatedRegNext(io.rob.pendingPtr)) &&
|
isNotAfter(uop(ptr).robIdx, GatedRegNext(io.rob.pendingPtr)) &&
|
||||||
!needCancel(cmtPtrExt(i).value) &&
|
!needCancel(ptr) &&
|
||||||
(!waitStoreS2(cmtPtrExt(i).value) || isVec(cmtPtrExt(i).value))) {
|
(!waitStoreS2(ptr) || isVec(ptr))) {
|
||||||
if (i == 0){
|
if (i == 0){
|
||||||
// TODO: fixme for vector mmio
|
// TODO: fixme for vector mmio
|
||||||
when ((mmioState === s_idle) || (mmioState === s_wait && scommit > 0.U)){
|
when ((mmioState === s_idle) || (mmioState === s_wait && scommit > 0.U)){
|
||||||
when ((isVec(cmtPtrExt(i).value) && vecMbCommit(cmtPtrExt(i).value)) || !isVec(cmtPtrExt(i).value)) {
|
when ((isVec(ptr) && vecMbCommit(ptr)) || !isVec(ptr)) {
|
||||||
committed(cmtPtrExt(0).value) := true.B
|
isCommit := true.B
|
||||||
|
committed(ptr) := true.B
|
||||||
commitVec(0) := true.B
|
commitVec(0) := true.B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when ((isVec(cmtPtrExt(i).value) && vecMbCommit(cmtPtrExt(i).value)) || !isVec(cmtPtrExt(i).value)) {
|
when ((isVec(ptr) && vecMbCommit(ptr)) || !isVec(ptr)) {
|
||||||
committed(cmtPtrExt(i).value) := commitVec(i - 1) || committed(cmtPtrExt(i).value)
|
isCommit := commitVec(i - 1) || committed(ptr)
|
||||||
|
committed(ptr) := commitVec(i - 1) || committed(ptr)
|
||||||
commitVec(i) := commitVec(i - 1)
|
commitVec(i) := commitVec(i - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
when(isCommit && nc(ptr) && hasException(ptr)) {
|
||||||
|
completed(ptr) := true.B
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commitCount := PopCount(commitVec)
|
commitCount := PopCount(commitVec)
|
||||||
|
|
Loading…
Reference in New Issue