add metadata field in SourceGenerator table
This enables using SourceGenerator as a sourceId converter/restorer.
This commit is contained in:
@@ -254,41 +254,59 @@ case class CoalescedResponse(config: CoalescerConfig)
|
|||||||
dataWidth = (8 * (1 << config.maxCoalLogSize))
|
dataWidth = (8 * (1 << config.maxCoalLogSize))
|
||||||
)
|
)
|
||||||
|
|
||||||
// If `ignoreInUse`, just keep giving out new IDs without checking if it is in
|
// `metadata` is an extra field in the sourceId table that can be used for
|
||||||
// use.
|
// storing e.g. the UUID originally attached to a request. This is useful for
|
||||||
class SourceGenerator(sourceWidth: Int, ignoreInUse: Boolean = true)
|
// using this module as a source ID converter / compressor. If `None`, this
|
||||||
|
// field is not instantiated.
|
||||||
|
// TODO: implement lookup logic.
|
||||||
|
//
|
||||||
|
// If `ignoreInUse`, just keep giving out new IDs without any collision checking.
|
||||||
|
// This might result in TL violation.
|
||||||
|
class SourceGenerator[T <: Data](
|
||||||
|
sourceWidth: Int,
|
||||||
|
metadata: Option[T] = None,
|
||||||
|
ignoreInUse: Boolean = true
|
||||||
|
)
|
||||||
extends Module {
|
extends Module {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val gen = Input(Bool())
|
val gen = Input(Bool())
|
||||||
val reclaim = Input(Valid(UInt(sourceWidth.W)))
|
val reclaim = Input(Valid(UInt(sourceWidth.W)))
|
||||||
val id = Output(Valid(UInt(sourceWidth.W)))
|
val id = Output(Valid(UInt(sourceWidth.W)))
|
||||||
|
// for debugging; indicates whether there is at least one inflight request
|
||||||
|
// that hasn't been reclaimed yet
|
||||||
val inflight = Output(Bool())
|
val inflight = Output(Bool())
|
||||||
})
|
})
|
||||||
val head = RegInit(UInt(sourceWidth.W), 0.U)
|
val head = RegInit(UInt(sourceWidth.W), 0.U)
|
||||||
head := Mux(io.gen, head + 1.U, head)
|
head := Mux(io.gen, head + 1.U, head)
|
||||||
|
|
||||||
// for debugging
|
|
||||||
// also for indicating if there is at least one inflight request that hasn't been reclaimed
|
|
||||||
val outstanding = RegInit(UInt((sourceWidth + 1).W), 0.U)
|
val outstanding = RegInit(UInt((sourceWidth + 1).W), 0.U)
|
||||||
io.inflight := (outstanding > 0.U) || io.gen
|
io.inflight := (outstanding > 0.U) || io.gen
|
||||||
|
|
||||||
val numSourceId = 1 << sourceWidth
|
val numSourceId = 1 << sourceWidth
|
||||||
// true: in use, false: available
|
val row = new Bundle {
|
||||||
val occupancyTable = Mem(numSourceId, Valid(UInt(sourceWidth.W)))
|
val meta = metadata match {
|
||||||
when(reset.asBool) {
|
case Some(gen) => gen.cloneType
|
||||||
(0 until numSourceId).foreach { occupancyTable(_).valid := false.B }
|
case None => UInt(0.W)
|
||||||
|
}
|
||||||
|
val id = Valid(UInt(sourceWidth.W))
|
||||||
}
|
}
|
||||||
val frees = (0 until numSourceId).map(!occupancyTable(_).valid)
|
// valid: in use, invalid: available
|
||||||
|
// val occupancyTable = Mem(numSourceId, Valid(UInt(sourceWidth.W)))
|
||||||
|
val occupancyTable = Mem(numSourceId, row)
|
||||||
|
when(reset.asBool) {
|
||||||
|
(0 until numSourceId).foreach { occupancyTable(_).id.valid := false.B }
|
||||||
|
}
|
||||||
|
val frees = (0 until numSourceId).map(!occupancyTable(_).id.valid)
|
||||||
val lowestFree = PriorityEncoder(frees)
|
val lowestFree = PriorityEncoder(frees)
|
||||||
val lowestFreeRow = occupancyTable(lowestFree)
|
val lowestFreeRow = occupancyTable(lowestFree)
|
||||||
|
|
||||||
io.id.valid := (if (ignoreInUse) true.B else !lowestFreeRow.valid)
|
io.id.valid := (if (ignoreInUse) true.B else !lowestFreeRow.id.valid)
|
||||||
io.id.bits := lowestFree
|
io.id.bits := lowestFree
|
||||||
when(io.gen && io.id.valid /* fire */ ) {
|
when(io.gen && io.id.valid /* fire */ ) {
|
||||||
occupancyTable(io.id.bits).valid := true.B // mark in use
|
occupancyTable(io.id.bits).id.valid := true.B // mark in use
|
||||||
}
|
}
|
||||||
when(io.reclaim.valid) {
|
when(io.reclaim.valid) {
|
||||||
occupancyTable(io.reclaim.bits).valid := false.B // mark freed
|
occupancyTable(io.reclaim.bits).id.valid := false.B // mark freed
|
||||||
}
|
}
|
||||||
|
|
||||||
when(io.gen && io.id.valid) {
|
when(io.gen && io.id.valid) {
|
||||||
@@ -738,6 +756,9 @@ class MultiCoalescer(
|
|||||||
if (!config.enable) disable
|
if (!config.enable) disable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This module mostly handles the correct ready/valid handshake depending on
|
||||||
|
// sourceId availability. Actual generation logic is done by the
|
||||||
|
// SourceGenerator module.
|
||||||
class CoalescerSourceGen(
|
class CoalescerSourceGen(
|
||||||
config: CoalescerConfig,
|
config: CoalescerConfig,
|
||||||
coalReqT: CoalescedRequest,
|
coalReqT: CoalescedRequest,
|
||||||
@@ -758,6 +779,7 @@ class CoalescerSourceGen(
|
|||||||
// TODO: make sourceGen.io.reclaim Decoupled?
|
// TODO: make sourceGen.io.reclaim Decoupled?
|
||||||
|
|
||||||
io.outReq <> io.inReq
|
io.outReq <> io.inReq
|
||||||
|
// "man-in-the-middle"
|
||||||
io.inReq.ready := io.outReq.ready && sourceGen.io.id.valid
|
io.inReq.ready := io.outReq.ready && sourceGen.io.id.valid
|
||||||
// overwrite bits affected by sourcegen backpressure
|
// overwrite bits affected by sourcegen backpressure
|
||||||
io.outReq.valid := io.inReq.valid && sourceGen.io.id.valid
|
io.outReq.valid := io.inReq.valid && sourceGen.io.id.valid
|
||||||
|
|||||||
Reference in New Issue
Block a user