Streamline upstream flow with regards to CoalSourceGen

CoalescerSourceGen was prematurely reclaiming sourceIds in the presence
of coalResp backpressure, since it was not referring to coalResp.fire
and instead setting ready to always-true.  With this change
CoalSourceGen properly propagates both downstream and upstream
backpressure.
This commit is contained in:
Hansung Kim
2024-01-18 18:15:18 -08:00
parent 086b2a5398
commit b1a37d0dda

View File

@@ -797,6 +797,7 @@ class CoalescerSourceGen(
val outReq = Decoupled(coalReqT.cloneType) val outReq = Decoupled(coalReqT.cloneType)
// outResp is only needed for telling the downstream TL node that this // outResp is only needed for telling the downstream TL node that this
// sourcegen module is always ready to take in responses. // sourcegen module is always ready to take in responses.
val inResp = Decoupled(respT.cloneType)
// No need for inResp, since coalescerNode is directly replied by the // No need for inResp, since coalescerNode is directly replied by the
// outResp TileLink bundle. // outResp TileLink bundle.
val outResp = Flipped(Decoupled(respT.cloneType)) val outResp = Flipped(Decoupled(respT.cloneType))
@@ -812,12 +813,13 @@ class CoalescerSourceGen(
// passthrough logic // passthrough logic
io.outReq <> io.inReq io.outReq <> io.inReq
io.inResp <> io.outResp
// "man-in-the-middle" // "man-in-the-middle"
io.inReq.ready := io.outReq.ready && sourceGen.io.id.valid
// overwrite bits affected by sourcegen backpressure // overwrite bits affected by sourcegen backpressure
io.inReq.ready := io.outReq.ready && sourceGen.io.id.valid
io.outReq.valid := io.inReq.valid && sourceGen.io.id.valid io.outReq.valid := io.inReq.valid && sourceGen.io.id.valid
io.outReq.bits.source := sourceGen.io.id.bits io.outReq.bits.source := sourceGen.io.id.bits
io.outResp.ready := true.B // should be always ready to reclaim old ID
} }
class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig) class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
@@ -927,21 +929,20 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
// The request coming out of MultiCoalescer still needs to go through source // The request coming out of MultiCoalescer still needs to go through source
// ID generation. // ID generation.
// We pull the sourcegen part out of MultiCoalescer to a separate Module to // The source generator needs to be on both upstream and downstream flow, as
// reduce IO bloat in the coalescer and top-level clutter. // it needs to snoop on both reqs and resps to allocate/free the sourceIds.
// //
// The overall flow looks like: // The overall flow looks like:
// ┌────────────────┐ ┌─────────────────────┐ ┌────────────────────┐ //
// │ CoalShiftQueue ├─┤ Mono/MultiCoalescer ├─┤ CoalescerSourceGen ├── TileLink req // ┌────────────────┐ ┌─────────────────────┐ ┌────────────────────┐ ┌───────────────┐
// └────────────────┘ └─────────────────────┘ └────────────────────┘ // │ CoalShiftQueue ├─┤ Mono/MultiCoalescer ├─┤ CoalSourceGen(gen) ├─┤ InFlightTable ├── TileLink req
// ^ // └────────────────┘ └─────────────────────┘ └────────────────────┘ └───────────────┘
// ┌────────────┐ ┌─────────────┐ // ┌────────────┐ ┌─────────────┐ ┌────────────────────────┐ ┌───────────────┐
// │ RespQueues ├─┤ Uncoalescer ├──┴────── TileLink resp // │ RespQueues ├─┤ Uncoalescer ├─┤ CoalSourceGen(reclaim) ├─┤ InFlightTable ├── TileLink resp
// ────────────┘ └─────────────┘ // └────────────┘ └─────────────┘ └────────────────────────┘ └───────────────
// //
val coalSourceGen = Module(new CoalescerSourceGen(config, coalReqT, tlCoal.d.bits)) val coalSourceGen = Module(new CoalescerSourceGen(config, coalReqT, tlCoal.d.bits))
coalSourceGen.io.inReq <> coalescer.io.coalReq coalSourceGen.io.inReq <> coalescer.io.coalReq
coalSourceGen.io.outResp <> tlCoal.d
// InflightTable IO // InflightTable IO
// //
@@ -1071,8 +1072,10 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
// Uncoalescer IO // Uncoalescer IO
// //
// Connect coalesced response // Connect coalesced response
uncoalescer.io.coalResp.valid := tlCoal.d.valid uncoalescer.io.coalResp.valid := coalSourceGen.io.inResp.valid
uncoalescer.io.coalResp.bits.fromTLD(tlCoal.d.bits, tlCoal.d.fire) uncoalescer.io.coalResp.bits.fromTLD(coalSourceGen.io.inResp.bits, coalSourceGen.io.inResp.fire)
coalSourceGen.io.inResp.ready := uncoalescer.io.coalResp.ready
// Connect lookup result from InflightTable // Connect lookup result from InflightTable
uncoalescer.io.inflightLookup <> inflightTable.io.lookup uncoalescer.io.inflightLookup <> inflightTable.io.lookup
// InflightTable IO: Look up the table with incoming coalesced responses // InflightTable IO: Look up the table with incoming coalesced responses
@@ -1099,9 +1102,11 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
} }
} }
} }
// Uncoalescer backpressure: stall downstream when uncoalescer is not ready
// to accept new coalesced response // coalSourceGen is the last module before going to downstream
tlCoal.d.ready := uncoalescer.io.coalResp.ready // This handles backpressure to the downstream when uncoalescer is not ready,
// because uncoalescer is connected before coalSourceGen.
coalSourceGen.io.outResp <> tlCoal.d
// Debug // Debug
dontTouch(coalescer.io.coalReq) dontTouch(coalescer.io.coalReq)