Fix backpressure for coalReq not being respected

... due to coalReq.ready being set at the wrong place;
needs to be set at the output of CoalSourceGen, instead of
MultiCoalescer or Uncoalescer.
This commit is contained in:
Hansung Kim
2023-05-15 22:22:52 -07:00
parent 7b5ea31cdf
commit 869c6c9f9c

View File

@@ -560,7 +560,7 @@ class MonoCoalescer(
class MultiCoalescer(
config: CoalescerConfig,
queueT: CoalShiftQueue[NonCoalescedRequest],
coalReqT: Request,
coalReqT: CoalescedRequest,
) extends Module {
val invalidateT = Valid(Vec(config.numLanes, UInt(config.queueDepth.W)))
val io = IO(new Bundle {
@@ -801,7 +801,8 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
enq.valid := tlIn.a.valid
enq.bits := req
// Respect arbiter and uncoalescer backpressure
deq.ready := tlOut.a.ready && uncoalescer.io.coalReq.ready
// deq.ready := tlOut.a.ready && uncoalescer.io.coalReq.ready
deq.ready := tlOut.a.ready
// Stall upstream core or memtrace driver when shiftqueue is not ready
tlIn.a.ready := enq.ready
tlOut.a.valid := deq.valid
@@ -849,6 +850,8 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
val coalSourceGen = Module(new CoalescerSourceGen(config, coalReqT, tlCoal.d.bits))
coalSourceGen.io.inReq <> coalescer.io.coalReq
coalSourceGen.io.inResp <> tlCoal.d
// downstream backpressure on the coalesced edge
coalSourceGen.io.outReq.ready := tlCoal.a.ready
// This is the final coalesced request.
val coalReq = coalSourceGen.io.outReq
dontTouch(coalReq)
@@ -856,7 +859,6 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
tlCoal.a.valid := coalReq.valid
tlCoal.a.bits := coalReq.bits.toTLA(edgeCoal)
coalescer.io.coalReq.ready := tlCoal.a.ready
tlCoal.b.ready := true.B
tlCoal.c.valid := false.B
// tlCoal.d.ready should be connected to uncoalescer's ready, done below.
@@ -964,7 +966,8 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
// Uncoalescer input
//
// connect coalesced request to be recorded in the uncoalescer table
uncoalescer.io.coalReq <> coalReq
uncoalescer.io.coalReq.valid := coalReq.valid
uncoalescer.io.coalReq.bits := coalReq.bits
uncoalescer.io.invalidate := coalescer.io.invalidate
uncoalescer.io.windowElts := reqQueues.io.elts
// coalesced response to be used to look up the uncoalescer table
@@ -1005,7 +1008,8 @@ class Uncoalescer(
val inflightTable = Module(new InflightCoalReqTable(config))
val io = IO(new Bundle {
// generated coalesced request, connected to the output of the coalescer.
val coalReq = Flipped(DecoupledIO(coalReqT.cloneType))
// val coalReq = Flipped(DecoupledIO(coalReqT.cloneType))
val coalReq = Input(Valid(coalReqT.cloneType))
// invalidate signal coming out of coalescer.
val invalidate = Input(Valid(Vec(config.numLanes, UInt(config.queueDepth.W))))
// coalescing window, connected to the contents of the request queues.
@@ -1021,10 +1025,16 @@ class Uncoalescer(
)
})
// If inflight table is full, we cannot accept new requests to record them.
// This might happen when we sent out many requests and exhausted all source
// IDs, but they haven't come back yet.
io.coalReq.ready := inflightTable.io.enq.ready
// Inflight table being full is equivalent to source ID being exhausted.
// Therefore, it should never be possible for inflight table to be full and
// coalescer to be firing a valid request at the same time.
// TODO: inflight table is really a more sophisticated sourcegen. Let it
// also take care of sourcegen instead of having a separte pass
// (CoalescerSourceGen).
when(!inflightTable.io.enq.ready) {
assert(!io.coalReq.valid,
"tried to fire a coalesced request when uncoalescer is not ready")
}
// Construct a new entry for the inflight table using generated coalesced request
def generateInflightTableEntry: InflightCoalReqTableEntry = {