Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(VLSU): fix vector exception writeback to 'MergeBuffer' logic #4137

Merged
merged 1 commit into from
Jan 7, 2025

Conversation

Anzooooo
Copy link
Member

@Anzooooo Anzooooo commented Jan 6, 2025

Fixed the bug of abnormal signal loss when writing back.

Previously, we expected to compare only the ports of the writebacks that triggered the exception and pick the oldest. See the annotation below:

// for exception, select exception, when multi port writeback exception, we need select oldest one
def selectOldest[T <: VecPipelineFeedbackIO](valid: Seq[Bool], bits: Seq[T], sel: Seq[UInt]): (Seq[Bool], Seq[T], Seq[UInt]) = {
assert(valid.length == bits.length)
assert(valid.length == sel.length)
if (valid.length == 0 || valid.length == 1) {
(valid, bits, sel)
} else if (valid.length == 2) {
val res = Seq.fill(2)(Wire(ValidIO(chiselTypeOf(bits(0)))))
for (i <- res.indices) {
res(i).valid := valid(i)
res(i).bits := bits(i)
}
val oldest = Mux(valid(0) && valid(1),
Mux(sel(0) < sel(1),
res(0), res(1)),
Mux(valid(0) && !valid(1), res(0), res(1)))
val oldidx = Mux(valid(0) && valid(1),
Mux(sel(0) < sel(1),
sel(0), sel(1)),
Mux(valid(0) && !valid(1), sel(0), sel(1)))
(Seq(oldest.valid), Seq(oldest.bits), Seq(oldidx))
} else {
val left = selectOldest(valid.take(valid.length / 2), bits.take(bits.length / 2), sel.take(sel.length / 2))
val right = selectOldest(valid.takeRight(valid.length - (valid.length / 2)), bits.takeRight(bits.length - (bits.length / 2)), sel.takeRight(sel.length - (sel.length / 2)))
selectOldest(left._1 ++ right._1, left._2 ++ right._2, left._3 ++ right._3)
}
}
val pipeValid = io.fromPipeline.map(_.valid)
val pipeBits = io.fromPipeline.map(_.bits)
val wbElemIdx = pipeBits.map(_.elemIdx)
val wbMbIndex = pipeBits.map(_.mBIndex)
val wbElemIdxInField = wbElemIdx.zip(wbMbIndex).map(x => x._1 & (entries(x._2).vlmax - 1.U))
val portHasExcp = pipeBits.zip(mergePortMatrix).map{case (port, v) =>
(0 until pipeWidth).map{case i =>
val pipeHasExcep = ExceptionNO.selectByFu(port.exceptionVec, fuCfg).asUInt.orR
(v(i) && ((pipeHasExcep && io.fromPipeline(i).bits.mask.orR) || TriggerAction.isDmode(port.trigger))) // this port have exception or merged port have exception
}.reduce(_ || _)
}
for((pipewb, i) <- io.fromPipeline.zipWithIndex){
val entry = entries(wbMbIndex(i))
val entryVeew = entry.uop.vpu.veew
val entryIsUS = LSUOpType.isAllUS(entry.uop.fuOpType)
val entryHasException = ExceptionNO.selectByFu(entry.exceptionVec, fuCfg).asUInt.orR
val entryExcp = entryHasException && entry.mask.orR
val entryVaddr = entry.vaddr
val entryVstart = entry.vstart
val entryElemIdx = entry.elemIdx
val sel = selectOldest(mergePortMatrix(i), pipeBits, wbElemIdxInField)
val selPort = sel._2
val selElemInfield = selPort(0).elemIdx & (entries(wbMbIndex(i)).vlmax - 1.U)
val selExceptionVec = selPort(0).exceptionVec
val selVaddr = selPort(0).vaddr
val selElemIdx = selPort(0).elemIdx
val isUSFirstUop = !selPort(0).elemIdx.orR
// Only the first unaligned uop of unit-stride needs to be offset.
// When unaligned, the lowest bit of mask is 0.
// example: 16'b1111_1111_1111_0000
val firstUnmask = genVFirstUnmask(selPort(0).mask).asUInt
val vaddrOffset = Mux(entryIsUS, firstUnmask, 0.U)
val vaddr = selVaddr + vaddrOffset
val vstart = Mux(entryIsUS, selPort(0).vstart, selElemInfield)
// select oldest port to raise exception
when((((entryElemIdx >= selElemIdx) && entryExcp && portHasExcp(i)) || (!entryExcp && portHasExcp(i))) && pipewb.valid && !mergedByPrevPortVec(i)) {
entry.uop.trigger := selPort(0).trigger
entry.elemIdx := selElemIdx
when(!entry.fof || vstart === 0.U){
// For fof loads, if element 0 raises an exception, vl is not modified, and the trap is taken.
entry.vstart := vstart
entry.exceptionVec := ExceptionNO.selectByFu(selExceptionVec, fuCfg)
entry.vaddr := vaddr
entry.vaNeedExt := selPort(0).vaNeedExt
entry.gpaddr := selPort(0).gpaddr
entry.isForVSnonLeafPTE := selPort(0).isForVSnonLeafPTE
}.otherwise{
entry.uop.vpu.vta := VType.tu
entry.vl := Mux(entry.vl < vstart, entry.vl, vstart)
}
}
}

But amazingly, I just realised that the implementation doesn't match the annotation.
The current implementation can be problematic in that if the write-back port that did not have an exception is older, the port that triggered the exception is not elected.

Use s3_exception to try to optimise timing.

Fixed the bug of abnormal signal loss when writing back.

Use s3_exception to try to optimise timing
@XiangShanRobot
Copy link

[Generated by IPC robot]
commit: c7ec60a

commit astar copy_and_run coremark gcc gromacs lbm linux mcf microbench milc namd povray wrf xalancbmk
c7ec60a 1.814 0.442 2.640 1.231 2.152 2.141 2.361 0.933 1.406 1.985 3.107 2.558 2.267 3.308

master branch:

commit astar copy_and_run coremark gcc gromacs lbm linux mcf microbench milc namd povray wrf xalancbmk
4d393af 1.231 2.152 2.141 0.933 1.985 3.107 3.308
7cc7723 2.639 1.407
398aeef 1.814 0.442 2.639 1.231 2.152 2.141 2.361 0.933 1.403 1.985 3.107 2.558 2.267 3.308
d94fbff 1.814 0.442 2.639 1.231 2.152 2.141 2.361 0.933 1.403 1.985 3.107 2.558 2.267 3.308
3642c22 1.814 0.442 2.639 1.231 2.152 2.141 2.361 0.933 1.403 1.985 3.107 2.558 2.267 3.308

@Anzooooo Anzooooo marked this pull request as ready for review January 6, 2025 14:39
@Tang-Haojin Tang-Haojin merged commit da51a7a into master Jan 7, 2025
9 checks passed
@Tang-Haojin Tang-Haojin deleted the wzz-vec-excp branch January 7, 2025 01:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants