From 3806bd8231b7023cb2468000d7499ed3d46476b1 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 16 May 2023 15:17:21 -0700 Subject: [PATCH 1/2] Support blockable credited interfaces (cherry picked from commit c8cf93510266935baeec640892752f756e9d5731) --- src/main/scala/util/Blockable.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/scala/util/Blockable.scala b/src/main/scala/util/Blockable.scala index 0c95ee9b459..3b96995dcf7 100644 --- a/src/main/scala/util/Blockable.scala +++ b/src/main/scala/util/Blockable.scala @@ -42,6 +42,20 @@ object Blockable { } } + implicit def BlockableCredited[T <: Data]: Blockable[CreditedIO[T]] = new Blockable[CreditedIO[T]] { + def blockWhile(enable_blocking: Bool, data: CreditedIO[T]): CreditedIO[T] = { + val res = Wire(chiselTypeOf(data)) + res.debit := data.debit + data.credit := res.credit + res.bits := data.bits + when (enable_blocking) { + res.debit := false.B + data.credit := false.B + } + res + } + } + implicit def BlockableVec[T <: Data : Blockable]: Blockable[Vec[T]] = new Blockable[Vec[T]] { def blockWhile(enable_blocking: Bool, data: Vec[T]): Vec[T] = { VecInit(data.map(x => implicitly[Blockable[T]].blockWhile(enable_blocking, x))) From d3b12237e3e216f6fac89def8cadae2e23fc7074 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Tue, 16 May 2023 15:20:43 -0700 Subject: [PATCH 2/2] Support dynamic credit count in senders for CreditedIO (cherry picked from commit 5a5c1278d405ff53b3c0d480c3df473e777547bc) --- src/main/scala/util/CreditedIO.scala | 40 ++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/scala/util/CreditedIO.scala b/src/main/scala/util/CreditedIO.scala index 5b9b77a0d96..2b61cefa1a6 100644 --- a/src/main/scala/util/CreditedIO.scala +++ b/src/main/scala/util/CreditedIO.scala @@ -45,35 +45,37 @@ final class CreditedIO[T <: Data](gen: T) extends Bundle /** Provide a DecoupledIO interface for sending CreditedIO[Data]. * Convert an IrrevocableIO input to DecoupledIO via Decoupled(). - * depth controls the maximum number of Data beats inflight. - * Sender powers on with credits=depth, so sender and receiver must agree on depth. + * maxDepth controls the maximum number of Data beats inflight. + * Sender powers on with credits=maxDepth, so sender and receiver must agree on maxDepth. * pipe=false increases the receiver=>sender trip time by one cycle. * pipe=true causes debit to depend on credit. */ - def toSender(depth: Int, pipe: Boolean = true): DecoupledIO[T] = { - require (depth >= 1) + def toSender(depth: UInt, maxDepth: Int, pipe: Boolean): DecoupledIO[T] = { + require (maxDepth >= 1) val res = Wire(DecoupledIO(genType)) - val counter = new CreditedIOCounter(depth, depth) + val counter = new CreditedIOCounter(maxDepth, depth, maxDepth) counter.update(this) res.ready := !counter.empty || (pipe.B && credit) debit := res.fire() bits := res.bits res } + def toSender(maxDepth: Int, pipe: Boolean = true): DecoupledIO[T] = + toSender(maxDepth.U, maxDepth, pipe) /** Provide an IrrevocableIO interface for receiving CreditedIO[Data]. * Conversion to DecoupledIO is done via application of Decoupled(). - * depth controls the Queue depth and thus maximum number of elements inflight. + * maxDepth controls the Queue depth and thus maximum number of elements inflight. * flow=false increases the sender=>receiver trip time by one cycle. * flow=true causes credit to depend on debit. */ - def toReceiver(depth: Int, flow: Boolean = true): IrrevocableIO[T] = { - require (depth >= 1) + def toReceiver(maxDepth: Int, flow: Boolean = true): IrrevocableIO[T] = { + require (maxDepth >= 1) val enq = Wire(DecoupledIO(genType)) enq.valid := debit enq.bits := bits assert (!enq.valid || enq.ready) - val res = Queue.irrevocable(enq, depth, pipe=true, flow=flow) + val res = Queue.irrevocable(enq, maxDepth, pipe=true, flow=flow) credit := res.fire() res } @@ -106,18 +108,21 @@ object CreditedIO { def apply[T <: Data](genType: T) = new CreditedIO(genType) - def fromSender[T <: Data](x: ReadyValidIO[T], depth: Int, pipe: Boolean = true): CreditedIO[T] = { + def fromSender[T <: Data](x: ReadyValidIO[T], depth: UInt, maxDepth: Int, pipe: Boolean): CreditedIO[T] = { val res = Wire(CreditedIO(chiselTypeOf(x.bits))) - val dec = res.toSender(depth, pipe) + val dec = res.toSender(depth, maxDepth, pipe) dec.valid := x.valid dec.bits := x.bits x.ready := dec.ready res } - def fromReceiver[T <: Data](x: ReadyValidIO[T], depth: Int, flow: Boolean = true): CreditedIO[T] = { + def fromSender[T <: Data](x: ReadyValidIO[T], maxDepth: Int, pipe: Boolean = true): CreditedIO[T] = + fromSender(x, maxDepth.U, maxDepth, pipe) + + def fromReceiver[T <: Data](x: ReadyValidIO[T], maxDepth: Int, flow: Boolean = true): CreditedIO[T] = { val res = Wire(CreditedIO(chiselTypeOf(x.bits))) - val irr = res.toReceiver(depth, flow) + val irr = res.toReceiver(maxDepth, flow) x.valid := irr.valid x.bits := irr.bits irr.ready := x.ready @@ -125,17 +130,18 @@ object CreditedIO } } -class CreditedIOCounter(val init: Int, val depth: Int) { +class CreditedIOCounter(val init: Int, val depth: UInt, val maxDepth: Int) { require (0 <= init) - require (init <= depth) + require (init <= maxDepth) + assert (depth <= maxDepth.U, "Depth exceeding maxDepth for CreditedIO") - private val v = RegInit(init.U(log2Ceil(depth+1).W)) + private val v = RegInit(init.U(log2Ceil(maxDepth+1).W)) private val nextV = WireInit(v) val value = v + 0.U val nextValue = nextV + 0.U - def full: Bool = v === depth.U + def full: Bool = v >= depth def empty: Bool = v === 0.U def update(credit: Bool, debit: Bool): Unit = {