scalafmt
This commit is contained in:
@@ -14,13 +14,18 @@ import freechips.rocketchip.tilelink._
|
|||||||
|
|
||||||
// Note: numNewSrcId is not a part of CoreParam, because the SIMT core should be agnostic to how inflight coalesced request can be genertated
|
// Note: numNewSrcId is not a part of CoreParam, because the SIMT core should be agnostic to how inflight coalesced request can be genertated
|
||||||
case class SIMTCoreParams(nLanes: Int = 4, nSrcIds: Int = 8)
|
case class SIMTCoreParams(nLanes: Int = 4, nSrcIds: Int = 8)
|
||||||
case class MemtraceCoreParams(tracefilename: String = "undefined", traceHasSource: Boolean = false)
|
case class MemtraceCoreParams(
|
||||||
|
tracefilename: String = "undefined",
|
||||||
|
traceHasSource: Boolean = false
|
||||||
|
)
|
||||||
case class CoalXbarParam()
|
case class CoalXbarParam()
|
||||||
|
|
||||||
case object SIMTCoreKey extends Field[Option[SIMTCoreParams]](None /*default*/)
|
case object SIMTCoreKey extends Field[Option[SIMTCoreParams]](None /*default*/ )
|
||||||
case object MemtraceCoreKey extends Field[Option[MemtraceCoreParams]](None /*default*/)
|
case object MemtraceCoreKey
|
||||||
case object CoalescerKey extends Field[Option[CoalescerConfig]](None /*default*/)
|
extends Field[Option[MemtraceCoreParams]](None /*default*/ )
|
||||||
case object CoalXbarKey extends Field[Option[CoalXbarParam]](None /*default*/)
|
case object CoalescerKey
|
||||||
|
extends Field[Option[CoalescerConfig]](None /*default*/ )
|
||||||
|
case object CoalXbarKey extends Field[Option[CoalXbarParam]](None /*default*/ )
|
||||||
|
|
||||||
trait InFlightTableSizeEnum extends ChiselEnum {
|
trait InFlightTableSizeEnum extends ChiselEnum {
|
||||||
val INVALID: Type
|
val INVALID: Type
|
||||||
@@ -81,19 +86,25 @@ case class CoalescerConfig(
|
|||||||
) {
|
) {
|
||||||
// maximum coalesced size
|
// maximum coalesced size
|
||||||
def maxCoalLogSize: Int = {
|
def maxCoalLogSize: Int = {
|
||||||
require(coalLogSizes.max <= dataBusWidth,
|
require(
|
||||||
"multi-beat coalesced reads/writes are currently not supported")
|
coalLogSizes.max <= dataBusWidth,
|
||||||
|
"multi-beat coalesced reads/writes are currently not supported"
|
||||||
|
)
|
||||||
if (coalLogSizes.max < dataBusWidth) {
|
if (coalLogSizes.max < dataBusWidth) {
|
||||||
println("======== Warning: coalescer's max coalescing size is set to " +
|
println(
|
||||||
s"${coalLogSizes.max}, which is narrower than data bus width " +
|
"======== Warning: coalescer's max coalescing size is set to " +
|
||||||
s"${dataBusWidth}. This might indicate misconfiguration.")
|
s"${coalLogSizes.max}, which is narrower than data bus width " +
|
||||||
|
s"${dataBusWidth}. This might indicate misconfiguration."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
coalLogSizes.max
|
coalLogSizes.max
|
||||||
}
|
}
|
||||||
def wordSizeWidth: Int = {
|
def wordSizeWidth: Int = {
|
||||||
val w = log2Ceil(wordSizeInBytes)
|
val w = log2Ceil(wordSizeInBytes)
|
||||||
require(wordSizeInBytes == 1 << w,
|
require(
|
||||||
s"wordSizeInBytes (${wordSizeInBytes}) is not power of two")
|
wordSizeInBytes == 1 << w,
|
||||||
|
s"wordSizeInBytes (${wordSizeInBytes}) is not power of two"
|
||||||
|
)
|
||||||
w
|
w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,9 +178,16 @@ class CoalescingUnit(config: CoalescerConfig)(implicit p: Parameters) extends La
|
|||||||
// Protocol-agnostic bundles that represent a request and a response to the
|
// Protocol-agnostic bundles that represent a request and a response to the
|
||||||
// coalescer.
|
// coalescer.
|
||||||
|
|
||||||
class Request(sourceWidth: Int, sizeWidth: Int, addressWidth: Int, dataWidth: Int)
|
class Request(
|
||||||
extends Bundle {
|
sourceWidth: Int,
|
||||||
require(dataWidth % 8 == 0, s"dataWidth (${dataWidth} bits) is not multiple of 8")
|
sizeWidth: Int,
|
||||||
|
addressWidth: Int,
|
||||||
|
dataWidth: Int
|
||||||
|
) extends Bundle {
|
||||||
|
require(
|
||||||
|
dataWidth % 8 == 0,
|
||||||
|
s"dataWidth (${dataWidth} bits) is not multiple of 8"
|
||||||
|
)
|
||||||
val op = Bool() // 0=READ 1=WRITE
|
val op = Bool() // 0=READ 1=WRITE
|
||||||
val address = UInt(addressWidth.W)
|
val address = UInt(addressWidth.W)
|
||||||
val size = UInt(sizeWidth.W)
|
val size = UInt(sizeWidth.W)
|
||||||
@@ -213,7 +231,10 @@ case class CoalescedRequest(config: CoalescerConfig)
|
|||||||
|
|
||||||
class Response(sourceWidth: Int, sizeWidth: Int, dataWidth: Int)
|
class Response(sourceWidth: Int, sizeWidth: Int, dataWidth: Int)
|
||||||
extends Bundle {
|
extends Bundle {
|
||||||
require(dataWidth % 8 == 0, s"dataWidth (${dataWidth} bits) is not multiple of 8")
|
require(
|
||||||
|
dataWidth % 8 == 0,
|
||||||
|
s"dataWidth (${dataWidth} bits) is not multiple of 8"
|
||||||
|
)
|
||||||
val op = UInt(1.W) // 0=READ 1=WRITE
|
val op = UInt(1.W) // 0=READ 1=WRITE
|
||||||
val size = UInt(sizeWidth.W)
|
val size = UInt(sizeWidth.W)
|
||||||
val source = UInt(sourceWidth.W)
|
val source = UInt(sourceWidth.W)
|
||||||
@@ -262,13 +283,13 @@ case class CoalescedResponse(config: CoalescerConfig)
|
|||||||
// If `ignoreInUse`, just keep giving out new IDs without any collision checking.
|
// If `ignoreInUse`, just keep giving out new IDs without any collision checking.
|
||||||
// This might result in TL violation.
|
// This might result in TL violation.
|
||||||
class SourceGenerator[T <: Data](
|
class SourceGenerator[T <: Data](
|
||||||
sourceWidth: Int,
|
sourceWidth: Int,
|
||||||
metadata: Option[T] = None,
|
metadata: Option[T] = None,
|
||||||
ignoreInUse: Boolean = false
|
ignoreInUse: Boolean = false
|
||||||
) extends Module {
|
) extends Module {
|
||||||
def getMetadataType = metadata match {
|
def getMetadataType = metadata match {
|
||||||
case Some(gen) => gen.cloneType
|
case Some(gen) => gen.cloneType
|
||||||
case None => UInt(0.W)
|
case None => UInt(0.W)
|
||||||
}
|
}
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val gen = Input(Bool())
|
val gen = Input(Bool())
|
||||||
@@ -327,7 +348,7 @@ class SourceGenerator[T <: Data](
|
|||||||
}
|
}
|
||||||
|
|
||||||
when(io.gen && io.id.valid) {
|
when(io.gen && io.id.valid) {
|
||||||
when (!io.reclaim.valid) {
|
when(!io.reclaim.valid) {
|
||||||
assert(outstanding < (1 << sourceWidth).U)
|
assert(outstanding < (1 << sourceWidth).U)
|
||||||
outstanding := outstanding + 1.U
|
outstanding := outstanding + 1.U
|
||||||
}
|
}
|
||||||
@@ -627,7 +648,7 @@ class MonoCoalescer(
|
|||||||
class MultiCoalescer(
|
class MultiCoalescer(
|
||||||
config: CoalescerConfig,
|
config: CoalescerConfig,
|
||||||
queueT: CoalShiftQueue[NonCoalescedRequest],
|
queueT: CoalShiftQueue[NonCoalescedRequest],
|
||||||
coalReqT: CoalescedRequest,
|
coalReqT: CoalescedRequest
|
||||||
) extends Module {
|
) extends Module {
|
||||||
val invalidateT = Valid(Vec(config.numLanes, UInt(config.reqQueueDepth.W)))
|
val invalidateT = Valid(Vec(config.numLanes, UInt(config.reqQueueDepth.W)))
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
@@ -864,7 +885,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
reqQueues.io.coalescable := coalescer.io.coalescable
|
reqQueues.io.coalescable := coalescer.io.coalescable
|
||||||
reqQueues.io.invalidate := coalescer.io.invalidate
|
reqQueues.io.invalidate := coalescer.io.invalidate
|
||||||
|
|
||||||
val inflightTable = Module(new InFlightTable(config, nonCoalReqT, coalReqT, coalRespT))
|
val inflightTable = Module(
|
||||||
|
new InFlightTable(config, nonCoalReqT, coalReqT, coalRespT)
|
||||||
|
)
|
||||||
val uncoalescer = Module(new Uncoalescer(config, inflightTable.entryT))
|
val uncoalescer = Module(new Uncoalescer(config, inflightTable.entryT))
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -903,27 +926,27 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
assert(legal, "unhandled illegal TL req gen")
|
assert(legal, "unhandled illegal TL req gen")
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
// when (tlIn.a.valid) {
|
// when (tlIn.a.valid) {
|
||||||
// TLPrintf(s"tlIn(${lane}).a",
|
// TLPrintf(s"tlIn(${lane}).a",
|
||||||
// tlIn.a.bits.address,
|
// tlIn.a.bits.address,
|
||||||
// tlIn.a.bits.size,
|
// tlIn.a.bits.size,
|
||||||
// tlIn.a.bits.mask,
|
// tlIn.a.bits.mask,
|
||||||
// TLUtils.AOpcodeIsStore(tlIn.a.bits.opcode),
|
// TLUtils.AOpcodeIsStore(tlIn.a.bits.opcode),
|
||||||
// tlIn.a.bits.data,
|
// tlIn.a.bits.data,
|
||||||
// 0.U
|
// 0.U
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
// when (tlOut.a.valid) {
|
// when (tlOut.a.valid) {
|
||||||
// TLPrintf(s"tlOut(${lane}).a",
|
// TLPrintf(s"tlOut(${lane}).a",
|
||||||
// tlOut.a.bits.address,
|
// tlOut.a.bits.address,
|
||||||
// tlOut.a.bits.size,
|
// tlOut.a.bits.size,
|
||||||
// tlOut.a.bits.mask,
|
// tlOut.a.bits.mask,
|
||||||
// TLUtils.AOpcodeIsStore(tlOut.a.bits.opcode),
|
// TLUtils.AOpcodeIsStore(tlOut.a.bits.opcode),
|
||||||
// tlOut.a.bits.data,
|
// tlOut.a.bits.data,
|
||||||
// 0.U
|
// 0.U
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
val (tlCoal, edgeCoal) = outer.coalescerNode.out.head
|
val (tlCoal, edgeCoal) = outer.coalescerNode.out.head
|
||||||
@@ -942,7 +965,9 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
// │ RespQueues ├─┤ Uncoalescer ├─┤ CoalSourceGen(reclaim) ├─┤ InFlightTable ├── 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
|
||||||
|
|
||||||
// InflightTable IO
|
// InflightTable IO
|
||||||
@@ -1043,8 +1068,10 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
// MultiPortQueue, and eventually serialized.
|
// MultiPortQueue, and eventually serialized.
|
||||||
respQueue.io.enq(respQueueNoncoalPort).valid := tlOut.d.valid
|
respQueue.io.enq(respQueueNoncoalPort).valid := tlOut.d.valid
|
||||||
respQueue.io.enq(respQueueNoncoalPort).bits := resp
|
respQueue.io.enq(respQueueNoncoalPort).bits := resp
|
||||||
assert(respQueue.io.deq.length == 1,
|
assert(
|
||||||
"respQueue should have only one dequeue port to the upstream")
|
respQueue.io.deq.length == 1,
|
||||||
|
"respQueue should have only one dequeue port to the upstream"
|
||||||
|
)
|
||||||
respQueue.io.deq.head.ready := tlIn.d.ready
|
respQueue.io.deq.head.ready := tlIn.d.ready
|
||||||
|
|
||||||
tlIn.d.valid := respQueue.io.deq.head.valid
|
tlIn.d.valid := respQueue.io.deq.head.valid
|
||||||
@@ -1074,7 +1101,8 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
//
|
//
|
||||||
// Connect coalesced response
|
// Connect coalesced response
|
||||||
uncoalescer.io.coalResp.valid := coalSourceGen.io.inResp.valid
|
uncoalescer.io.coalResp.valid := coalSourceGen.io.inResp.valid
|
||||||
uncoalescer.io.coalResp.bits.fromTLD(coalSourceGen.io.inResp.bits, coalSourceGen.io.inResp.fire)
|
uncoalescer.io.coalResp.bits
|
||||||
|
.fromTLD(coalSourceGen.io.inResp.bits, coalSourceGen.io.inResp.fire)
|
||||||
coalSourceGen.io.inResp.ready := uncoalescer.io.coalResp.ready
|
coalSourceGen.io.inResp.ready := uncoalescer.io.coalResp.ready
|
||||||
|
|
||||||
// Connect lookup result from InflightTable
|
// Connect lookup result from InflightTable
|
||||||
@@ -1086,24 +1114,27 @@ class CoalescingUnitImp(outer: CoalescingUnit, config: CoalescerConfig)
|
|||||||
inflightTable.io.lookupSourceId.bits := coalSourceGen.io.inResp.bits.source
|
inflightTable.io.lookupSourceId.bits := coalSourceGen.io.inResp.bits.source
|
||||||
|
|
||||||
// Connect uncoalescer results back into response queue
|
// Connect uncoalescer results back into response queue
|
||||||
(respQueues zip uncoalescer.io.respQueueIO).zipWithIndex.foreach
|
(respQueues zip uncoalescer.io.respQueueIO).zipWithIndex.foreach {
|
||||||
{ case ((q, sameLaneUncoalResps), lane) =>
|
case ((q, sameLaneUncoalResps), lane) =>
|
||||||
// reqQueueDepth here is the maximum number of same-lane, different-time
|
// reqQueueDepth here is the maximum number of same-lane, different-time
|
||||||
// requests that can go into a single coalesced response. We need to have
|
// requests that can go into a single coalesced response. We need to have
|
||||||
// that many enq ports to not backpressure the uncoalescer.
|
// that many enq ports to not backpressure the uncoalescer.
|
||||||
require(q.io.enq.length == config.reqQueueDepth + respQueueUncoalPortOffset,
|
require(
|
||||||
s"wrong number of enq ports for MultiPort response queue")
|
q.io.enq.length == config.reqQueueDepth + respQueueUncoalPortOffset,
|
||||||
// slice the ports reserved for uncoalesced response
|
s"wrong number of enq ports for MultiPort response queue"
|
||||||
val sameLaneEnqPorts = q.io.enq.slice(respQueueUncoalPortOffset, q.io.enq.length)
|
)
|
||||||
(sameLaneEnqPorts zip sameLaneUncoalResps).foreach {
|
// slice the ports reserved for uncoalesced response
|
||||||
case (enqPort, uncoalResp) => {
|
val sameLaneEnqPorts =
|
||||||
enqPort <> uncoalResp
|
q.io.enq.slice(respQueueUncoalPortOffset, q.io.enq.length)
|
||||||
// assert(
|
(sameLaneEnqPorts zip sameLaneUncoalResps).foreach {
|
||||||
// enqPort.ready,
|
case (enqPort, uncoalResp) => {
|
||||||
// cf"respQueue: enq port for uncoalesced response is blocked on lane $lane"
|
enqPort <> uncoalResp
|
||||||
// )
|
// assert(
|
||||||
|
// enqPort.ready,
|
||||||
|
// cf"respQueue: enq port for uncoalesced response is blocked on lane $lane"
|
||||||
|
// )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// coalSourceGen is the last module before going to downstream
|
// coalSourceGen is the last module before going to downstream
|
||||||
@@ -1127,7 +1158,8 @@ class Uncoalescer(
|
|||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val inflightLookup = Flipped(Decoupled(inflightEntryT))
|
val inflightLookup = Flipped(Decoupled(inflightEntryT))
|
||||||
val coalResp = Flipped(Decoupled(new CoalescedResponse(config)))
|
val coalResp = Flipped(Decoupled(new CoalescedResponse(config)))
|
||||||
val respQueueIO = Vec(config.numLanes,
|
val respQueueIO = Vec(
|
||||||
|
config.numLanes,
|
||||||
// reqQueueDepth because if we're doing time-coalescing, that's the
|
// reqQueueDepth because if we're doing time-coalescing, that's the
|
||||||
// maximum number of same-lane, different-time requests that can go into
|
// maximum number of same-lane, different-time requests that can go into
|
||||||
// a single coalesced request.
|
// a single coalesced request.
|
||||||
@@ -1137,7 +1169,12 @@ class Uncoalescer(
|
|||||||
|
|
||||||
// Un-coalescing logic
|
// Un-coalescing logic
|
||||||
//
|
//
|
||||||
def getCoalescedDataChunk(data: UInt, dataWidth: Int, offset: UInt, logSize: UInt): UInt = {
|
def getCoalescedDataChunk(
|
||||||
|
data: UInt,
|
||||||
|
dataWidth: Int,
|
||||||
|
offset: UInt,
|
||||||
|
logSize: UInt
|
||||||
|
): UInt = {
|
||||||
assert(logSize === 2.U, "currently only supporting 4-byte accesses. TODO")
|
assert(logSize === 2.U, "currently only supporting 4-byte accesses. TODO")
|
||||||
|
|
||||||
// sizeInBits should be simulation-only construct
|
// sizeInBits should be simulation-only construct
|
||||||
@@ -1167,46 +1204,52 @@ class Uncoalescer(
|
|||||||
// ready. This is necessary because uncoalescing logic is a combinational
|
// ready. This is necessary because uncoalescing logic is a combinational
|
||||||
// logic that produces all the split responses at the same cycle, so it needs
|
// logic that produces all the split responses at the same cycle, so it needs
|
||||||
// to be guaranteed that all of them has somewhere to go.
|
// to be guaranteed that all of them has somewhere to go.
|
||||||
val allRespQueueEnqReady = io.respQueueIO.map(_.map(_.ready).reduce(_ && _)).reduce(_ && _)
|
val allRespQueueEnqReady =
|
||||||
|
io.respQueueIO.map(_.map(_.ready).reduce(_ && _)).reduce(_ && _)
|
||||||
tablePipeRegDeq.ready := allRespQueueEnqReady
|
tablePipeRegDeq.ready := allRespQueueEnqReady
|
||||||
coalRespPipeRegDeq.ready := allRespQueueEnqReady
|
coalRespPipeRegDeq.ready := allRespQueueEnqReady
|
||||||
|
|
||||||
assert(io.coalResp.fire === io.inflightLookup.fire,
|
assert(
|
||||||
"enqueue timing for uncoalescer pipeline registers out-of-sync!")
|
io.coalResp.fire === io.inflightLookup.fire,
|
||||||
assert(tablePipeRegDeq.fire === coalRespPipeRegDeq.fire,
|
"enqueue timing for uncoalescer pipeline registers out-of-sync!"
|
||||||
"dequeue timing for uncoalescer pipeline registers out-of-sync!")
|
)
|
||||||
|
assert(
|
||||||
|
tablePipeRegDeq.fire === coalRespPipeRegDeq.fire,
|
||||||
|
"dequeue timing for uncoalescer pipeline registers out-of-sync!"
|
||||||
|
)
|
||||||
|
|
||||||
// Un-coalesce responses back to individual lanes. Connect uncoalesced
|
// Un-coalesce responses back to individual lanes. Connect uncoalesced
|
||||||
// results back into each lane's response queue.
|
// results back into each lane's response queue.
|
||||||
val tableRow = tablePipeRegDeq
|
val tableRow = tablePipeRegDeq
|
||||||
(io.respQueueIO zip tableRow.bits.lanes).zipWithIndex.foreach { case ((enqIOs, lane), laneNum) =>
|
(io.respQueueIO zip tableRow.bits.lanes).zipWithIndex.foreach {
|
||||||
lane.reqs.zipWithIndex.foreach { case (req, depth) =>
|
case ((enqIOs, lane), laneNum) =>
|
||||||
val enqIO = enqIOs(depth)
|
lane.reqs.zipWithIndex.foreach { case (req, depth) =>
|
||||||
enqIO.valid := false.B
|
val enqIO = enqIOs(depth)
|
||||||
enqIO.bits := DontCare
|
enqIO.valid := false.B
|
||||||
// debug
|
enqIO.bits := DontCare
|
||||||
// when (resp.valid) {
|
// debug
|
||||||
// printf(s"${i}-th uncoalesced response came back from lane ${laneNum}\n")
|
// when (resp.valid) {
|
||||||
// }
|
// printf(s"${i}-th uncoalesced response came back from lane ${laneNum}\n")
|
||||||
// dontTouch(q.io.enq(respQueueCoalPortOffset))
|
// }
|
||||||
|
// dontTouch(q.io.enq(respQueueCoalPortOffset))
|
||||||
|
|
||||||
when(tableRow.valid && req.valid) {
|
when(tableRow.valid && req.valid) {
|
||||||
enqIO.valid := tableRow.fire && req.valid
|
enqIO.valid := tableRow.fire && req.valid
|
||||||
enqIO.bits.op := req.op
|
enqIO.bits.op := req.op
|
||||||
enqIO.bits.source := req.source
|
enqIO.bits.source := req.source
|
||||||
val logSize = tableRow.bits.sizeEnumT.enumToLogSize(req.sizeEnum)
|
val logSize = tableRow.bits.sizeEnumT.enumToLogSize(req.sizeEnum)
|
||||||
enqIO.bits.size := logSize
|
enqIO.bits.size := logSize
|
||||||
enqIO.bits.data :=
|
enqIO.bits.data :=
|
||||||
getCoalescedDataChunk(
|
getCoalescedDataChunk(
|
||||||
coalRespPipeRegDeq.bits.data,
|
coalRespPipeRegDeq.bits.data,
|
||||||
coalRespPipeRegDeq.bits.data.getWidth,
|
coalRespPipeRegDeq.bits.data.getWidth,
|
||||||
req.offset,
|
req.offset,
|
||||||
logSize
|
logSize
|
||||||
)
|
)
|
||||||
// is this necessary?
|
// is this necessary?
|
||||||
enqIO.bits.error := DontCare
|
enqIO.bits.error := DontCare
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,9 +1262,10 @@ class InFlightTable(
|
|||||||
config: CoalescerConfig,
|
config: CoalescerConfig,
|
||||||
nonCoalReqT: NonCoalescedRequest,
|
nonCoalReqT: NonCoalescedRequest,
|
||||||
coalReqT: CoalescedRequest,
|
coalReqT: CoalescedRequest,
|
||||||
coalRespT: CoalescedResponse,
|
coalRespT: CoalescedResponse
|
||||||
) extends Module {
|
) extends Module {
|
||||||
val offsetBits = config.maxCoalLogSize - config.wordSizeWidth // assumes word offset
|
val offsetBits =
|
||||||
|
config.maxCoalLogSize - config.wordSizeWidth // assumes word offset
|
||||||
val entryT = new InFlightTableEntry(
|
val entryT = new InFlightTableEntry(
|
||||||
config.numLanes,
|
config.numLanes,
|
||||||
config.reqQueueDepth,
|
config.reqQueueDepth,
|
||||||
@@ -1243,11 +1287,13 @@ class InFlightTable(
|
|||||||
val inCoalReq = Flipped(Decoupled(coalReqT))
|
val inCoalReq = Flipped(Decoupled(coalReqT))
|
||||||
// invalidate signal coming out of coalescer. Needed to generate new entry
|
// invalidate signal coming out of coalescer. Needed to generate new entry
|
||||||
// for the table.
|
// for the table.
|
||||||
val invalidate = Input(Valid(Vec(config.numLanes, UInt(config.reqQueueDepth.W))))
|
val invalidate =
|
||||||
|
Input(Valid(Vec(config.numLanes, UInt(config.reqQueueDepth.W))))
|
||||||
// coalescing window, connected to the contents of the request queues.
|
// coalescing window, connected to the contents of the request queues.
|
||||||
// Need this to generate new entry for the table.
|
// Need this to generate new entry for the table.
|
||||||
// TODO: duplicate type construction
|
// TODO: duplicate type construction
|
||||||
val windowElts = Input(Vec(config.numLanes, Vec(config.reqQueueDepth, nonCoalReqT)))
|
val windowElts =
|
||||||
|
Input(Vec(config.numLanes, Vec(config.reqQueueDepth, nonCoalReqT)))
|
||||||
// InflightTable simply passes through the inCoalReq to outCoalReq, only snooping
|
// InflightTable simply passes through the inCoalReq to outCoalReq, only snooping
|
||||||
// on its data to record what's necessary.
|
// on its data to record what's necessary.
|
||||||
val outCoalReq = Decoupled(coalReqT)
|
val outCoalReq = Decoupled(coalReqT)
|
||||||
@@ -1319,7 +1365,7 @@ class InFlightTable(
|
|||||||
reqEntry.source := req.source
|
reqEntry.source := req.source
|
||||||
reqEntry.offset := ((req.address % (1 << config.maxCoalLogSize).U) >> config.wordSizeWidth)
|
reqEntry.offset := ((req.address % (1 << config.maxCoalLogSize).U) >> config.wordSizeWidth)
|
||||||
reqEntry.sizeEnum := config.sizeEnum.logSizeToEnum(req.size)
|
reqEntry.sizeEnum := config.sizeEnum.logSizeToEnum(req.size)
|
||||||
// TODO: load/store op
|
// TODO: load/store op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dontTouch(newEntry)
|
dontTouch(newEntry)
|
||||||
@@ -1347,23 +1393,27 @@ class InFlightTable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lookup logic
|
// Lookup logic
|
||||||
io.lookupResult.valid := io.lookupSourceId.valid && table(io.lookupSourceId.bits).valid
|
io.lookupResult.valid := io.lookupSourceId.valid && table(
|
||||||
|
io.lookupSourceId.bits
|
||||||
|
).valid
|
||||||
io.lookupResult.bits := table(io.lookupSourceId.bits).bits
|
io.lookupResult.bits := table(io.lookupSourceId.bits).bits
|
||||||
// every lookup to the table should succeed as the request should have
|
// every lookup to the table should succeed as the request should have
|
||||||
// gotten recorded earlier than the response
|
// gotten recorded earlier than the response
|
||||||
when(io.lookupSourceId.valid) {
|
when(io.lookupSourceId.valid) {
|
||||||
assert(table(io.lookupSourceId.bits).valid === true.B,
|
assert(
|
||||||
"table lookup with a valid sourceId failed")
|
table(io.lookupSourceId.bits).valid === true.B,
|
||||||
|
"table lookup with a valid sourceId failed"
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
!(enqFire && io.lookupResult.fire &&
|
||||||
|
(enqSource === io.lookupSourceId.bits)),
|
||||||
|
"inflight table: enqueueing and looking up the same srcId at the same cycle is not handled"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// Dequeue as soon as lookup succeeds
|
// Dequeue as soon as lookup succeeds
|
||||||
when(io.lookupResult.fire) {
|
when(io.lookupResult.fire) {
|
||||||
table(io.lookupSourceId.bits).valid := false.B
|
table(io.lookupSourceId.bits).valid := false.B
|
||||||
}
|
}
|
||||||
assert(
|
|
||||||
!((enqFire === true.B) && (io.lookupResult.fire === true.B) &&
|
|
||||||
(enqSource === io.lookupSourceId.bits)),
|
|
||||||
"inflight table: enqueueing and looking up the same srcId at the same cycle is not handled"
|
|
||||||
)
|
|
||||||
|
|
||||||
dontTouch(io.lookupResult)
|
dontTouch(io.lookupResult)
|
||||||
}
|
}
|
||||||
@@ -1399,12 +1449,15 @@ object TLUtils {
|
|||||||
when(checkOpcode) {
|
when(checkOpcode) {
|
||||||
assert(
|
assert(
|
||||||
opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData ||
|
opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData ||
|
||||||
opcode === TLMessages.Get,
|
opcode === TLMessages.Get,
|
||||||
"unhandled TL A opcode found"
|
"unhandled TL A opcode found"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Mux(opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData,
|
Mux(
|
||||||
true.B, false.B)
|
opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData,
|
||||||
|
true.B,
|
||||||
|
false.B
|
||||||
|
)
|
||||||
}
|
}
|
||||||
def DOpcodeIsStore(opcode: UInt, checkOpcode: Bool): Bool = {
|
def DOpcodeIsStore(opcode: UInt, checkOpcode: Bool): Bool = {
|
||||||
when(checkOpcode) {
|
when(checkOpcode) {
|
||||||
@@ -1531,92 +1584,95 @@ class MemTraceDriverImp(
|
|||||||
Cat(8.U(4.W), addr(27, 0))
|
Cat(8.U(4.W), addr(27, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
val sourceGens = Seq.fill(config.numLanes)(Module(
|
val sourceGens = Seq.fill(config.numLanes)(
|
||||||
new SourceGenerator(
|
Module(
|
||||||
log2Ceil(config.numOldSrcIds),
|
new SourceGenerator(
|
||||||
ignoreInUse = false
|
log2Ceil(config.numOldSrcIds),
|
||||||
|
ignoreInUse = false
|
||||||
|
)
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
|
||||||
// Advance source ID for all lanes in synchrony
|
// Advance source ID for all lanes in synchrony
|
||||||
val syncedSourceGenValid = sourceGens.map(_.io.id.valid).reduce(_ && _)
|
val syncedSourceGenValid = sourceGens.map(_.io.id.valid).reduce(_ && _)
|
||||||
|
|
||||||
// Take requests off of the queue and generate TL requests
|
// Take requests off of the queue and generate TL requests
|
||||||
(outer.laneNodes zip reqQueues).zipWithIndex.foreach { case ((node, reqQ), lane) =>
|
(outer.laneNodes zip reqQueues).zipWithIndex.foreach {
|
||||||
val (tlOut, edge) = node.out(0)
|
case ((node, reqQ), lane) =>
|
||||||
|
val (tlOut, edge) = node.out(0)
|
||||||
|
|
||||||
val req = reqQ.io.deq.bits
|
val req = reqQ.io.deq.bits
|
||||||
// backpressure from downstream propagates into the queue
|
// backpressure from downstream propagates into the queue
|
||||||
reqQ.io.deq.ready := tlOut.a.ready && syncedSourceGenValid
|
reqQ.io.deq.ready := tlOut.a.ready && syncedSourceGenValid
|
||||||
|
|
||||||
// Core only makes accesses of granularity larger than a word, so we want
|
// Core only makes accesses of granularity larger than a word, so we want
|
||||||
// the trace driver to act so as well.
|
// the trace driver to act so as well.
|
||||||
// That means if req.size is smaller than word size, we need to pad data
|
// That means if req.size is smaller than word size, we need to pad data
|
||||||
// with zeros to generate a word-size request, and set mask accordingly.
|
// with zeros to generate a word-size request, and set mask accordingly.
|
||||||
val offsetInWord = req.address % config.wordSizeInBytes.U
|
val offsetInWord = req.address % config.wordSizeInBytes.U
|
||||||
val subword = req.size < log2Ceil(config.wordSizeInBytes).U
|
val subword = req.size < log2Ceil(config.wordSizeInBytes).U
|
||||||
|
|
||||||
// `mask` is currently unused
|
// `mask` is currently unused
|
||||||
// val mask = Wire(UInt(config.wordSizeInBytes.W))
|
// val mask = Wire(UInt(config.wordSizeInBytes.W))
|
||||||
val wordData = Wire(UInt((config.wordSizeInBytes * 8 * 2).W))
|
val wordData = Wire(UInt((config.wordSizeInBytes * 8 * 2).W))
|
||||||
val sizeInBytes = Wire(UInt((sizeW + 1).W))
|
val sizeInBytes = Wire(UInt((sizeW + 1).W))
|
||||||
sizeInBytes := (1.U) << req.size
|
sizeInBytes := (1.U) << req.size
|
||||||
// mask := Mux(subword, (~((~0.U(64.W)) << sizeInBytes)) << offsetInWord, ~0.U)
|
// mask := Mux(subword, (~((~0.U(64.W)) << sizeInBytes)) << offsetInWord, ~0.U)
|
||||||
wordData := Mux(subword, req.data << (offsetInWord * 8.U), req.data)
|
wordData := Mux(subword, req.data << (offsetInWord * 8.U), req.data)
|
||||||
val wordAlignedAddress =
|
val wordAlignedAddress =
|
||||||
req.address & ~((1 << log2Ceil(config.wordSizeInBytes)) - 1).U(addrW.W)
|
req.address & ~((1 << log2Ceil(config.wordSizeInBytes)) - 1).U(addrW.W)
|
||||||
val wordAlignedSize = Mux(subword, 2.U, req.size)
|
val wordAlignedSize = Mux(subword, 2.U, req.size)
|
||||||
|
|
||||||
val sourceGen = sourceGens(lane)
|
val sourceGen = sourceGens(lane)
|
||||||
sourceGen.io.gen := tlOut.a.fire
|
sourceGen.io.gen := tlOut.a.fire
|
||||||
// assert(sourceGen.io.id.valid)
|
// assert(sourceGen.io.id.valid)
|
||||||
sourceGen.io.reclaim.valid := tlOut.d.fire
|
sourceGen.io.reclaim.valid := tlOut.d.fire
|
||||||
sourceGen.io.reclaim.bits := tlOut.d.bits.source
|
sourceGen.io.reclaim.bits := tlOut.d.bits.source
|
||||||
sourceGen.io.meta := DontCare
|
sourceGen.io.meta := DontCare
|
||||||
|
|
||||||
val (plegal, pbits) = edge.Put(
|
val (plegal, pbits) = edge.Put(
|
||||||
fromSource = sourceGen.io.id.bits,
|
fromSource = sourceGen.io.id.bits,
|
||||||
toAddress = hashToValidPhyAddr(wordAlignedAddress),
|
toAddress = hashToValidPhyAddr(wordAlignedAddress),
|
||||||
lgSize = wordAlignedSize, // trace line already holds log2(size)
|
lgSize = wordAlignedSize, // trace line already holds log2(size)
|
||||||
// data should be aligned to beatBytes
|
// data should be aligned to beatBytes
|
||||||
data =
|
data =
|
||||||
(wordData << (8.U * (wordAlignedAddress % edge.manager.beatBytes.U))).asUInt
|
(wordData << (8.U * (wordAlignedAddress % edge.manager.beatBytes.U))).asUInt
|
||||||
)
|
|
||||||
val (glegal, gbits) = edge.Get(
|
|
||||||
fromSource = sourceGen.io.id.bits,
|
|
||||||
toAddress = hashToValidPhyAddr(wordAlignedAddress),
|
|
||||||
lgSize = wordAlignedSize
|
|
||||||
)
|
|
||||||
val legal = Mux(req.is_store, plegal, glegal)
|
|
||||||
val bits = Mux(req.is_store, pbits, gbits)
|
|
||||||
|
|
||||||
tlOut.a.valid := reqQ.io.deq.valid && syncedSourceGenValid
|
|
||||||
when(tlOut.a.fire) {
|
|
||||||
assert(legal, "illegal TL req gen")
|
|
||||||
}
|
|
||||||
tlOut.a.bits := bits
|
|
||||||
tlOut.b.ready := true.B
|
|
||||||
tlOut.c.valid := false.B
|
|
||||||
tlOut.d.ready := true.B
|
|
||||||
tlOut.e.valid := false.B
|
|
||||||
|
|
||||||
// debug
|
|
||||||
dontTouch(reqQ.io.enq)
|
|
||||||
dontTouch(reqQ.io.deq)
|
|
||||||
when(tlOut.a.valid) {
|
|
||||||
TLPrintf(
|
|
||||||
"MemTraceDriver",
|
|
||||||
tlOut.a.bits.source,
|
|
||||||
tlOut.a.bits.address,
|
|
||||||
tlOut.a.bits.size,
|
|
||||||
tlOut.a.bits.mask,
|
|
||||||
req.is_store,
|
|
||||||
tlOut.a.bits.data,
|
|
||||||
req.data
|
|
||||||
)
|
)
|
||||||
}
|
val (glegal, gbits) = edge.Get(
|
||||||
dontTouch(tlOut.a)
|
fromSource = sourceGen.io.id.bits,
|
||||||
dontTouch(tlOut.d)
|
toAddress = hashToValidPhyAddr(wordAlignedAddress),
|
||||||
|
lgSize = wordAlignedSize
|
||||||
|
)
|
||||||
|
val legal = Mux(req.is_store, plegal, glegal)
|
||||||
|
val bits = Mux(req.is_store, pbits, gbits)
|
||||||
|
|
||||||
|
tlOut.a.valid := reqQ.io.deq.valid && syncedSourceGenValid
|
||||||
|
when(tlOut.a.fire) {
|
||||||
|
assert(legal, "illegal TL req gen")
|
||||||
|
}
|
||||||
|
tlOut.a.bits := bits
|
||||||
|
tlOut.b.ready := true.B
|
||||||
|
tlOut.c.valid := false.B
|
||||||
|
tlOut.d.ready := true.B
|
||||||
|
tlOut.e.valid := false.B
|
||||||
|
|
||||||
|
// debug
|
||||||
|
dontTouch(reqQ.io.enq)
|
||||||
|
dontTouch(reqQ.io.deq)
|
||||||
|
when(tlOut.a.valid) {
|
||||||
|
TLPrintf(
|
||||||
|
"MemTraceDriver",
|
||||||
|
tlOut.a.bits.source,
|
||||||
|
tlOut.a.bits.address,
|
||||||
|
tlOut.a.bits.size,
|
||||||
|
tlOut.a.bits.mask,
|
||||||
|
req.is_store,
|
||||||
|
tlOut.a.bits.data,
|
||||||
|
req.data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
dontTouch(tlOut.a)
|
||||||
|
dontTouch(tlOut.d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give some slack time after trace EOF to get some outstanding responses
|
// Give some slack time after trace EOF to get some outstanding responses
|
||||||
@@ -1627,8 +1683,8 @@ class MemTraceDriverImp(
|
|||||||
}
|
}
|
||||||
io.finished := traceFinished
|
io.finished := traceFinished
|
||||||
|
|
||||||
//currently the .cc file ouptuts finished=true while it still need to issue one more request
|
// currently the .cc file ouptuts finished=true while it still need to issue one more request
|
||||||
val noValidReqs = sim.io.trace_read.valid === 0.U
|
val noValidReqs = sim.io.trace_read.valid === 0.U
|
||||||
val allReqReclaimed = !(sourceGens.map(_.io.inflight).reduce(_ || _))
|
val allReqReclaimed = !(sourceGens.map(_.io.inflight).reduce(_ || _))
|
||||||
|
|
||||||
when(traceFinished && allReqReclaimed && noValidReqs) {
|
when(traceFinished && allReqReclaimed && noValidReqs) {
|
||||||
@@ -1821,7 +1877,10 @@ class MemTraceLogger(
|
|||||||
// and transaction happened.
|
// and transaction happened.
|
||||||
resp.valid := tlOut.d.fire
|
resp.valid := tlOut.d.fire
|
||||||
resp.size := tlOut.d.bits.size
|
resp.size := tlOut.d.bits.size
|
||||||
resp.is_store := TLUtils.DOpcodeIsStore(tlOut.d.bits.opcode, tlOut.d.fire)
|
resp.is_store := TLUtils.DOpcodeIsStore(
|
||||||
|
tlOut.d.bits.opcode,
|
||||||
|
tlOut.d.fire
|
||||||
|
)
|
||||||
resp.source := tlOut.d.bits.source
|
resp.source := tlOut.d.bits.source
|
||||||
// NOTE: TL D channel doesn't carry address nor mask, so there's no easy
|
// NOTE: TL D channel doesn't carry address nor mask, so there's no easy
|
||||||
// way to figure out which bytes the master actually use. Since we
|
// way to figure out which bytes the master actually use. Since we
|
||||||
@@ -1911,7 +1970,7 @@ class MemTraceLogger(
|
|||||||
// depending on this, e.g. response trace will not contain an address column.
|
// depending on this, e.g. response trace will not contain an address column.
|
||||||
class SimMemTraceLogger(
|
class SimMemTraceLogger(
|
||||||
isResponse: Boolean,
|
isResponse: Boolean,
|
||||||
filenameBase: String, // usually the same as `filename` of SimMemTrace
|
filenameBase: String, // usually the same as `filename` of SimMemTrace
|
||||||
filenameSuffix: String, // can be ".req", ".resp", .etc
|
filenameSuffix: String, // can be ".req", ".resp", .etc
|
||||||
numLanes: Int
|
numLanes: Int
|
||||||
) extends BlackBox(
|
) extends BlackBox(
|
||||||
|
|||||||
Reference in New Issue
Block a user