Skip to content

Commit

Permalink
fix(ICache): block waylookup if there is a pending gpf (OpenXiangShan…
Browse files Browse the repository at this point in the history
…#3719)

In the existing design, ICache assumes that once a gpf occurs, it works
on the wrong path until a flush (redirect) arrives, so it can discard
redundant gpf/gpaddr data to reduce power/area.

As shown below, the 2nd(orange) and 3rd(blue) gpaddr write to wayLookup
is discarded.

![241011-wave-old](https://github.com/user-attachments/assets/878a0894-9d97-437d-aaa3-486d380da74f)

This assumption is mostly true, except:
1. Consider a 34B fetch block in which the first 32B have no exceptions
and consist entirely of RVC instructions, and the last 2B cross a page
boundary and a gpf occurs.
2. The IFU sends at most 16 instructions to the ibuffer, and therefore
discards the last 2B. This way, none of the instructions received by the
backend have exceptions and no flush (redirect) is generated.
3. The next fetch block again has a gpf, which ICache (wayLookup)
considers redundant and discards the gpaddr data.
4. When the instruction with gpf is sent to the backend, the backend
does not get the correct gpaddr and caused an error.

Fix: block writes when there is gpf/gpaddr data in wayLookup that is not
read by mainPipe (i.e. is pending).

As shown below, the 1st(yellow) gpaddr write is bypassed to read port,
the 2nd is stored in gpf entry, and the 3rd is stalled until the 2nd is
read. So all 3 gpaddr data are sent to backend(gpaMem).

![241011-wave-new](https://github.com/user-attachments/assets/d856a08c-4a89-49f0-90da-81d140aee3b1)
  • Loading branch information
ngc7331 authored Oct 12, 2024
1 parent 753370f commit b7a4433
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions src/main/scala/xiangshan/frontend/icache/WayLookup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {

private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry)))
private val gpfPtr = RegInit(WayLookupPtr(false.B, 0.U))
private val gpf_hit = gpfPtr === readPtr && gpf_entry.valid

when(io.flush) {
// we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf
Expand Down Expand Up @@ -143,25 +144,38 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
* read
******************************************************************************
*/
// if the entry is empty, but there is a valid write, we can bypass it to read port (maybe timing critical)
private val can_bypass = empty && io.write.valid
io.read.valid := !empty || io.write.valid
when (empty && io.write.valid) { // bypass
when (can_bypass) {
io.read.bits := io.write.bits
}.otherwise {
}.otherwise { // can't bypass
io.read.bits.entry := entries(readPtr.value)
io.read.bits.gpf := Mux(readPtr === gpfPtr && gpf_entry.valid, gpf_entry.bits, 0.U.asTypeOf(new WayLookupGPFEntry))
when(gpf_hit) { // ptr match && entry valid
io.read.bits.gpf := gpf_entry.bits
// also clear gpf_entry.valid when it's read, note this will be override by write (L175)
when (io.read.fire) {
gpf_entry.valid := false.B
}
}.otherwise { // gpf not hit
io.read.bits.gpf := 0.U.asTypeOf(new WayLookupGPFEntry)
}
}

/**
******************************************************************************
* write
******************************************************************************
*/
io.write.ready := !full
// if there is a valid gpf to be read, we should stall the write
private val gpf_stall = gpf_entry.valid && !(io.read.fire && gpf_hit)
io.write.ready := !full && !gpf_stall
when(io.write.fire) {
entries(writePtr.value) := io.write.bits.entry
// save gpf iff no gpf is already saved
when(!gpf_entry.valid && io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_||_)) {
gpf_entry.valid := true.B
when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_||_)) {
// if gpf_entry is bypassed, we don't need to save it
// note this will override the read (L156)
gpf_entry.valid := !(can_bypass && io.read.fire)
gpf_entry.bits := io.write.bits.gpf
gpfPtr := writePtr
}
Expand Down

0 comments on commit b7a4433

Please sign in to comment.