Use rocket-chip MultiPortQueue to serialize responses
NOT tested yet
This commit is contained in:
@@ -7,7 +7,7 @@ import chisel3.util._
|
|||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
// import freechips.rocketchip.devices.tilelink.TLTestRAM
|
// import freechips.rocketchip.devices.tilelink.TLTestRAM
|
||||||
import freechips.rocketchip.util.ShiftQueue
|
import freechips.rocketchip.util.{ShiftQueue, MultiPortQueue}
|
||||||
import freechips.rocketchip.unittest._
|
import freechips.rocketchip.unittest._
|
||||||
|
|
||||||
class CoalescingUnit(numLanes: Int = 1)(implicit p: Parameters)
|
class CoalescingUnit(numLanes: Int = 1)(implicit p: Parameters)
|
||||||
@@ -64,15 +64,32 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int)
|
|||||||
}
|
}
|
||||||
val respQueueEntryT = new RespQueueEntry(sourceWidth)
|
val respQueueEntryT = new RespQueueEntry(sourceWidth)
|
||||||
val respQueues = Seq.tabulate(numLanes) { _ =>
|
val respQueues = Seq.tabulate(numLanes) { _ =>
|
||||||
|
// Module(
|
||||||
|
// new ShiftQueue(respQueueEntryT, 8 /* FIXME depth hardcoded */ )
|
||||||
|
// )
|
||||||
Module(
|
Module(
|
||||||
new ShiftQueue(respQueueEntryT, 8 /* FIXME hardcoded */ )
|
new MultiPortQueue(
|
||||||
|
respQueueEntryT,
|
||||||
|
// enq_lanes = 1 + M, where 1 is the response for the original per-lane
|
||||||
|
// requests that didn't get coalesced, and M is the number of coalescer
|
||||||
|
// nodes.
|
||||||
|
2,
|
||||||
|
// deq_lanes = 1 because we're serializing all responses to 1 port that
|
||||||
|
// goes back to the core.
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
4 /* FIXME depth hardcoded */
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Port 0: from original responses
|
||||||
|
// Port 1~M: from M coalescer nodes
|
||||||
|
val respQueueCoalPortOffset = 1
|
||||||
|
|
||||||
// Per-lane request and response queues
|
// Per-lane request and response queues
|
||||||
//
|
//
|
||||||
// Override IdentityNode implementation so that we wire node output to the
|
// Override IdentityNode implementation so that we can instantiate
|
||||||
// queue output, instead of directly passing through node input.
|
// queues between input and output edges to buffer requests and responses.
|
||||||
// See IdentityNode definition in `diplomacy/Nodes.scala`.
|
// See IdentityNode definition in `diplomacy/Nodes.scala`.
|
||||||
(outer.node.in zip outer.node.out).zipWithIndex.foreach {
|
(outer.node.in zip outer.node.out).zipWithIndex.foreach {
|
||||||
case (((_, edgeIn), _), 0) =>
|
case (((_, edgeIn), _), 0) =>
|
||||||
@@ -118,13 +135,15 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int)
|
|||||||
resp.source := tlOut.d.bits.source
|
resp.source := tlOut.d.bits.source
|
||||||
resp.data := tlOut.d.bits.data
|
resp.data := tlOut.d.bits.data
|
||||||
|
|
||||||
respQueue.io.enq.valid := tlOut.d.valid
|
// Originally non-coalesced responses. Coalesced (but split) responses
|
||||||
respQueue.io.enq.bits := resp
|
// will also be enqueued into the same queue.
|
||||||
|
respQueue.io.enq(0).valid := tlOut.d.valid
|
||||||
|
respQueue.io.enq(0).bits := resp
|
||||||
// TODO: deq.ready should respect upstream ready
|
// TODO: deq.ready should respect upstream ready
|
||||||
respQueue.io.deq.ready := true.B
|
respQueue.io.deq(0).ready := true.B
|
||||||
|
|
||||||
tlIn.d.valid := respQueue.io.deq.valid
|
tlIn.d.valid := respQueue.io.deq(0).valid
|
||||||
val respHead = respQueue.io.deq.bits
|
val respHead = respQueue.io.deq(0).bits
|
||||||
val respBits = edgeIn.AccessAck(
|
val respBits = edgeIn.AccessAck(
|
||||||
toSource = respHead.source,
|
toSource = respHead.source,
|
||||||
lgSize = 0.U,
|
lgSize = 0.U,
|
||||||
@@ -213,22 +232,26 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int)
|
|||||||
val coalRespData = Wire(UInt(tlCoal.params.dataBits.W))
|
val coalRespData = Wire(UInt(tlCoal.params.dataBits.W))
|
||||||
coalRespData := tlCoal.d.bits.data
|
coalRespData := tlCoal.d.bits.data
|
||||||
|
|
||||||
when(inflightTable.io.lookup.valid) {
|
val found = inflightTable.io.lookup.bits
|
||||||
val found = inflightTable.io.lookup.bits
|
found.lanes.zipWithIndex.foreach { case (l, i) =>
|
||||||
found.lanes.zipWithIndex.foreach { case (l, i) =>
|
val respQueue = respQueues(i)
|
||||||
val respQueue = respQueues(i)
|
respQueue.io.enq(respQueueCoalPortOffset).valid := false.B
|
||||||
respQueue.io.enq.valid := l.valid
|
respQueue.io.enq(respQueueCoalPortOffset).bits := DontCare
|
||||||
respQueue.io.enq.bits.source := 0.U // FIXME: only looking at 0th entry
|
|
||||||
|
when(inflightTable.io.lookup.valid) {
|
||||||
|
respQueue.io.enq(respQueueCoalPortOffset).valid := l.valid
|
||||||
|
// FIXME: only looking at 0th entry
|
||||||
|
respQueue.io.enq(respQueueCoalPortOffset).bits.source := 0.U
|
||||||
// FIXME: disregard size enum for now
|
// FIXME: disregard size enum for now
|
||||||
val sizeMask = (1.U << 4) - 1.U
|
val sizeMask = (1.U << 4) - 1.U
|
||||||
val dataWidth = tlCoal.params.dataBits
|
val dataWidth = tlCoal.params.dataBits
|
||||||
// FIXME: handle multi-head input to the queue
|
respQueue.io.enq(respQueueCoalPortOffset).bits.data :=
|
||||||
respQueue.io.enq.bits.data := (coalRespData >> (dataWidth - 4)) & sizeMask
|
(coalRespData >> (dataWidth - 4)) & sizeMask
|
||||||
|
}
|
||||||
|
|
||||||
when(l.valid) {
|
when(l.valid) {
|
||||||
when(l.reqs(0).valid) {
|
when(l.reqs(0).valid) {
|
||||||
printf(s"lane ${i} req 0 is valid!\n")
|
printf(s"lane ${i} req 0 is valid!\n")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +280,7 @@ class CoalescingUnitImp(outer: CoalescingUnit, numLanes: Int)
|
|||||||
dontTouch(tlCoal.d)
|
dontTouch(tlCoal.d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InflightCoalReqTable is a reservation station-like structure that records
|
// InflightCoalReqTable is a table structure that records
|
||||||
// for each unanswered coalesced request which lane the request originated
|
// for each unanswered coalesced request which lane the request originated
|
||||||
// from, what their original TileLink sourceId were, etc. We use this info to
|
// from, what their original TileLink sourceId were, etc. We use this info to
|
||||||
// split the coalesced response back to individual per-lane responses with the
|
// split the coalesced response back to individual per-lane responses with the
|
||||||
@@ -267,8 +290,8 @@ class InflightCoalReqTable(
|
|||||||
val sourceWidth: Int,
|
val sourceWidth: Int,
|
||||||
val entries: Int
|
val entries: Int
|
||||||
) extends Module {
|
) extends Module {
|
||||||
val offsetBits = 4 // FIXME
|
val offsetBits = 4 // FIXME hardcoded
|
||||||
val sizeBits = 2 // FIXME
|
val sizeBits = 2 // FIXME hardcoded
|
||||||
val entryT =
|
val entryT =
|
||||||
new InflightCoalReqTableEntry(numLanes, sourceWidth, offsetBits, sizeBits)
|
new InflightCoalReqTableEntry(numLanes, sourceWidth, offsetBits, sizeBits)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user