Experiment with coalescing across all lanes

This commit is contained in:
Hansung Kim
2023-04-02 12:23:28 -07:00
parent d62732fb89
commit c0d502960f

View File

@@ -11,7 +11,6 @@ import freechips.rocketchip.util.MultiPortQueue
import freechips.rocketchip.unittest._
class CoalescingUnit(numLanes: Int = 1)(implicit p: Parameters) extends LazyModule {
// Identity node that captures the incoming TL requests and passes them
// through the other end, dropping coalesced requests. This node is what
// will be visible to upstream and downstream nodes.
@@ -136,7 +135,8 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
// Invalidate coalesced requests
// FIXME: hardcoded lanes
val invalidate = coalReqValid && (lane == 0 || lane == 2).B
// val invalidate = coalReqValid && (lane == 0 || lane == 2).B
val invalidate = coalReqValid
tlOut.a.valid := reqQueue.io.deq.valid && !invalidate
val reqHead = reqQueue.io.deq.bits
@@ -158,6 +158,7 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
val resp = Wire(respQueueEntryT)
resp.source := tlOut.d.bits.source
resp.data := tlOut.d.bits.data
// TODO: read/write bit?
// Queue up responses that didn't get coalesced originally ("noncoalesced" responses).
// Coalesced (but uncoalesced back) responses will also be enqueued into the same queue.
@@ -206,11 +207,14 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
// TODO: bogus address
coalReqAddress := (0xabcd.U + coalSourceId) << 4
// FIXME: coalesce lane 0 and lane 2's queue head whenever they're valid
coalReqValid := reqQueues(0).io.deq.valid && reqQueues(2).io.deq.valid
coalReqValid := reqQueues(0).io.deq.valid && reqQueues(1).io.deq.valid &&
reqQueues(2).io.deq.valid && reqQueues(3).io.deq.valid
when(coalReqValid) {
// invalidate original requests due to coalescing
reqQueues(0).io.invalidate := 0x1.U
reqQueues(1).io.invalidate := 0x1.U
reqQueues(2).io.invalidate := 0x1.U
reqQueues(3).io.invalidate := 0x1.U
}
val (legal, bits) = edgeCoal.Get(
@@ -246,7 +250,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
}
}
newEntry.lanes(0).reqs(0).valid := true.B
newEntry.lanes(1).reqs(0).valid := true.B
newEntry.lanes(2).reqs(0).valid := true.B
newEntry.lanes(3).reqs(0).valid := true.B
dontTouch(newEntry)
// Uncoalescer module sncoalesces responses back to each lane
@@ -267,9 +273,11 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int) extends LazyModule
uncoalescer.io.coalRespSrcId := tlCoal.d.bits.source
uncoalescer.io.coalRespData := tlCoal.d.bits.data
// Queue up uncoalesced responses into each lane's response queue
// Queue up synthesized uncoalesced responses into each lane's response queue
(respQueues zip uncoalescer.io.uncoalResps).foreach { case (q, lanes) =>
lanes.zipWithIndex.foreach { case (resp, i) =>
// TODO: rather than crashing, deassert tlOut.d.ready to stall downtream
// cache. This should ideally not happen though.
assert(
q.io.enq(respQueueCoalPortOffset + i).ready,
s"respQueue: enq port for 0-th coalesced response is blocked"
@@ -474,11 +482,10 @@ class InflightCoalReqTableEntry(
val lanes = Vec(numLanes, new PerLane)
}
// Mostly copied from freechips.rocketchip.util.ShiftQueue, except that every
// queue entry and its valid signal are exposed as output IO.
// A shift-register queue implementation that supports invalidating entries
// and exposing queue contents as output IO. (TODO: support deadline)
// Initially copied from freechips.rocketchip.util.ShiftQueue.
// If `pipe` is true, support enqueueing to a full queue when also dequeueing.
//
// TODO: support deadline
class CoalShiftQueue[T <: Data](
gen: T,
val entries: Int,
@@ -506,11 +513,12 @@ class CoalShiftQueue[T <: Data](
private val used = RegInit(UInt(entries.W), 0.U)
private val elts = Reg(Vec(entries, gen))
// Indexing is tail-to-head: i=0 equals tail, i=entries-1 equals topmost reg
def pad(mask: Int => Bool) = { i: Int =>
if (i == -1) true.B else if (i == entries) false.B else mask(i)
}
def paddedUsed = pad({ i: Int => used(i) })
def validAfterInv(i: Int) = Mux(io.invalidate(i), false.B, valid(i))
def validAfterInv(i: Int) = valid(i) && !io.invalidate(i)
val shift = io.deq.ready || (used =/= 0.U) && !validAfterInv(0)
for (i <- 0 until entries) {
@@ -526,7 +534,6 @@ class CoalShiftQueue[T <: Data](
valid(i) := Mux(
shift,
(io.enq.fire && !paddedUsed(i + 1) && used(i)) || pad(validAfterInv)(i + 1),
// TODO: handle enqueueing to invalidated tail?
(io.enq.fire && paddedUsed(i - 1) && !used(i)) || validAfterInv(i)
)
}