axi4: make maxFlight a per-master parameter
This commit is contained in:
parent
e1a072a644
commit
d27e1928dd
@ -13,11 +13,26 @@ class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule
|
|||||||
require (idBits >= 0)
|
require (idBits >= 0)
|
||||||
|
|
||||||
val node = AXI4AdapterNode(
|
val node = AXI4AdapterNode(
|
||||||
masterFn = { mp => mp.copy(
|
masterFn = { mp =>
|
||||||
userBits = mp.userBits + max(0, log2Ceil(mp.endId) - idBits),
|
// Create one new "master" per ID
|
||||||
masters = Seq(AXI4MasterParameters(
|
val masters = Array.tabulate(1 << idBits) { i => AXI4MasterParameters(
|
||||||
id = IdRange(0, min(mp.endId, 1 << idBits)),
|
id = IdRange(i, i+1),
|
||||||
aligned = mp.masters.map(_.aligned).reduce(_ && _))))
|
aligned = true,
|
||||||
|
maxFlight = Some(0))
|
||||||
|
}
|
||||||
|
// Squash the information from original masters into new ID masters
|
||||||
|
mp.masters.foreach { m =>
|
||||||
|
for (i <- m.id.start until m.id.end) {
|
||||||
|
val j = i % (1 << idBits)
|
||||||
|
val old = masters(j)
|
||||||
|
masters(j) = old.copy(
|
||||||
|
aligned = old.aligned && m.aligned,
|
||||||
|
maxFlight = old.maxFlight.flatMap { o => m.maxFlight.map { n => o+n } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp.copy(
|
||||||
|
userBits = mp.userBits + max(0, log2Ceil(mp.endId) - idBits),
|
||||||
|
masters = masters)
|
||||||
},
|
},
|
||||||
slaveFn = { sp => sp.copy(
|
slaveFn = { sp => sp.copy(
|
||||||
slaves = sp.slaves.map(s => s.copy(
|
slaves = sp.slaves.map(s => s.copy(
|
||||||
|
@ -62,21 +62,21 @@ case class AXI4SlavePortParameters(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class AXI4MasterParameters(
|
case class AXI4MasterParameters(
|
||||||
id: IdRange = IdRange(0, 1),
|
id: IdRange = IdRange(0, 1),
|
||||||
aligned: Boolean = false,
|
aligned: Boolean = false,
|
||||||
nodePath: Seq[BaseNode] = Seq())
|
maxFlight: Option[Int] = None, // None = infinite, else is a per-ID cap
|
||||||
|
nodePath: Seq[BaseNode] = Seq())
|
||||||
{
|
{
|
||||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||||
|
maxFlight.foreach { m => require (m >= 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AXI4MasterPortParameters(
|
case class AXI4MasterPortParameters(
|
||||||
masters: Seq[AXI4MasterParameters],
|
masters: Seq[AXI4MasterParameters],
|
||||||
userBits: Int = 0,
|
userBits: Int = 0)
|
||||||
maxFlight: Int = 0) // at most X transactions per ID (0 = unlimited)
|
|
||||||
{
|
{
|
||||||
val endId = masters.map(_.id.end).max
|
val endId = masters.map(_.id.end).max
|
||||||
require (userBits >= 0)
|
require (userBits >= 0)
|
||||||
require (maxFlight >= 0)
|
|
||||||
|
|
||||||
// Require disjoint ranges for ids
|
// Require disjoint ranges for ids
|
||||||
masters.combinations(2).foreach { case Seq(x,y) => require (!x.id.overlaps(y.id), s"$x and $y overlap") }
|
masters.combinations(2).foreach { case Seq(x,y) => require (!x.id.overlaps(y.id), s"$x and $y overlap") }
|
||||||
|
@ -9,8 +9,9 @@ import diplomacy._
|
|||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
|
|
||||||
case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
||||||
dFn = { case AXI4MasterPortParameters(masters, userBits, maxFlight) =>
|
dFn = { case AXI4MasterPortParameters(masters, userBits) =>
|
||||||
require (maxFlight > 0, "AXI4 must include a maximum transactions per ID to convert to TL")
|
masters.foreach { m => require (m.maxFlight.isDefined, "AXI4 must include a transaction maximum per ID to convert to TL") }
|
||||||
|
val maxFlight = masters.map(_.maxFlight.get).max
|
||||||
TLClientPortParameters(
|
TLClientPortParameters(
|
||||||
clients = masters.flatMap { m =>
|
clients = masters.flatMap { m =>
|
||||||
for (id <- m.id.start until m.id.end)
|
for (id <- m.id.start until m.id.end)
|
||||||
@ -50,7 +51,7 @@ class AXI4ToTL()(implicit p: Parameters) extends LazyModule
|
|||||||
val numIds = edgeIn.master.endId
|
val numIds = edgeIn.master.endId
|
||||||
val beatBytes = edgeOut.manager.beatBytes
|
val beatBytes = edgeOut.manager.beatBytes
|
||||||
val countBits = AXI4Parameters.lenBits + (1 << AXI4Parameters.sizeBits) - 1
|
val countBits = AXI4Parameters.lenBits + (1 << AXI4Parameters.sizeBits) - 1
|
||||||
val maxFlight = edgeIn.master.maxFlight
|
val maxFlight = edgeIn.master.masters.map(_.maxFlight.get).max
|
||||||
val addedBits = log2Ceil(maxFlight) + 1
|
val addedBits = log2Ceil(maxFlight) + 1
|
||||||
|
|
||||||
require (edgeIn.master.userBits == 0, "AXI4 user bits cannot be transported by TL")
|
require (edgeIn.master.userBits == 0, "AXI4 user bits cannot be transported by TL")
|
||||||
|
@ -10,12 +10,15 @@ import uncore.tilelink2.UIntToOH1
|
|||||||
|
|
||||||
class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) extends LazyModule
|
class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
// !!! make maxFlightPerId a cap and maxFlight a per AXI4 Master parameter
|
|
||||||
val maxFlightPerId = capMaxFlight.getOrElse(8)
|
|
||||||
require (maxFlightPerId >= 1)
|
|
||||||
|
|
||||||
val node = AXI4AdapterNode(
|
val node = AXI4AdapterNode(
|
||||||
masterFn = { mp => mp.copy(maxFlight = maxFlightPerId, userBits = 0) },
|
masterFn = { mp => mp.copy(
|
||||||
|
userBits = 0,
|
||||||
|
masters = mp.masters.map { m => m.copy(
|
||||||
|
maxFlight = (m.maxFlight, capMaxFlight) match {
|
||||||
|
case (Some(x), Some(y)) => Some(x min y)
|
||||||
|
case (Some(x), None) => Some(x)
|
||||||
|
case (None, Some(y)) => Some(y)
|
||||||
|
case (None, None) => None })})},
|
||||||
slaveFn = { sp => sp })
|
slaveFn = { sp => sp })
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
@ -29,18 +32,31 @@ class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) e
|
|||||||
val need_bypass = edgeOut.slave.minLatency < 1
|
val need_bypass = edgeOut.slave.minLatency < 1
|
||||||
require (bits > 0) // useless UserYanker!
|
require (bits > 0) // useless UserYanker!
|
||||||
|
|
||||||
val rqueues = Seq.fill(edgeIn.master.endId) { Module(new Queue(UInt(width = bits), maxFlightPerId, flow=need_bypass)) }
|
edgeOut.master.masters.foreach { m =>
|
||||||
val wqueues = Seq.fill(edgeIn.master.endId) { Module(new Queue(UInt(width = bits), maxFlightPerId, flow=need_bypass)) }
|
require (m.maxFlight.isDefined, "UserYanker needs a flight cap on each ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
def queue(id: Int) = {
|
||||||
|
val depth = edgeOut.master.masters.find(_.id.contains(id)).flatMap(_.maxFlight).getOrElse(0)
|
||||||
|
if (depth == 0) {
|
||||||
|
Wire(new QueueIO(UInt(width = bits), 1)) // unused ID => undefined value
|
||||||
|
} else {
|
||||||
|
Module(new Queue(UInt(width = bits), depth, flow=need_bypass)).io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val rqueues = Seq.tabulate(edgeIn.master.endId) { i => queue(i) }
|
||||||
|
val wqueues = Seq.tabulate(edgeIn.master.endId) { i => queue(i) }
|
||||||
|
|
||||||
val arid = in.ar.bits.id
|
val arid = in.ar.bits.id
|
||||||
val ar_ready = Vec(rqueues.map(_.io.enq.ready))(arid)
|
val ar_ready = Vec(rqueues.map(_.enq.ready))(arid)
|
||||||
in .ar.ready := out.ar.ready && ar_ready
|
in .ar.ready := out.ar.ready && ar_ready
|
||||||
out.ar.valid := in .ar.valid && ar_ready
|
out.ar.valid := in .ar.valid && ar_ready
|
||||||
out.ar.bits := in .ar.bits
|
out.ar.bits := in .ar.bits
|
||||||
|
|
||||||
val rid = out.r.bits.id
|
val rid = out.r.bits.id
|
||||||
val r_valid = Vec(rqueues.map(_.io.deq.valid))(rid)
|
val r_valid = Vec(rqueues.map(_.deq.valid))(rid)
|
||||||
val r_bits = Vec(rqueues.map(_.io.deq.bits))(rid)
|
val r_bits = Vec(rqueues.map(_.deq.bits))(rid)
|
||||||
assert (!out.r.valid || r_valid) // Q must be ready faster than the response
|
assert (!out.r.valid || r_valid) // Q must be ready faster than the response
|
||||||
in.r <> out.r
|
in.r <> out.r
|
||||||
in.r.bits.user.get := r_bits
|
in.r.bits.user.get := r_bits
|
||||||
@ -48,20 +64,20 @@ class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) e
|
|||||||
val arsel = UIntToOH(arid, edgeIn.master.endId).toBools
|
val arsel = UIntToOH(arid, edgeIn.master.endId).toBools
|
||||||
val rsel = UIntToOH(rid, edgeIn.master.endId).toBools
|
val rsel = UIntToOH(rid, edgeIn.master.endId).toBools
|
||||||
(rqueues zip (arsel zip rsel)) foreach { case (q, (ar, r)) =>
|
(rqueues zip (arsel zip rsel)) foreach { case (q, (ar, r)) =>
|
||||||
q.io.deq.ready := out.r .valid && in .r .ready && r && out.r.bits.last
|
q.deq.ready := out.r .valid && in .r .ready && r && out.r.bits.last
|
||||||
q.io.enq.valid := in .ar.valid && out.ar.ready && ar
|
q.enq.valid := in .ar.valid && out.ar.ready && ar
|
||||||
q.io.enq.bits := in.ar.bits.user.get
|
q.enq.bits := in.ar.bits.user.get
|
||||||
}
|
}
|
||||||
|
|
||||||
val awid = in.aw.bits.id
|
val awid = in.aw.bits.id
|
||||||
val aw_ready = Vec(wqueues.map(_.io.enq.ready))(awid)
|
val aw_ready = Vec(wqueues.map(_.enq.ready))(awid)
|
||||||
in .aw.ready := out.aw.ready && aw_ready
|
in .aw.ready := out.aw.ready && aw_ready
|
||||||
out.aw.valid := in .aw.valid && aw_ready
|
out.aw.valid := in .aw.valid && aw_ready
|
||||||
out.aw.bits := in .aw.bits
|
out.aw.bits := in .aw.bits
|
||||||
|
|
||||||
val bid = out.b.bits.id
|
val bid = out.b.bits.id
|
||||||
val b_valid = Vec(wqueues.map(_.io.deq.valid))(bid)
|
val b_valid = Vec(wqueues.map(_.deq.valid))(bid)
|
||||||
val b_bits = Vec(wqueues.map(_.io.deq.bits))(bid)
|
val b_bits = Vec(wqueues.map(_.deq.bits))(bid)
|
||||||
assert (!out.b.valid || b_valid) // Q must be ready faster than the response
|
assert (!out.b.valid || b_valid) // Q must be ready faster than the response
|
||||||
in.b <> out.b
|
in.b <> out.b
|
||||||
in.b.bits.user.get := b_bits
|
in.b.bits.user.get := b_bits
|
||||||
@ -69,9 +85,9 @@ class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) e
|
|||||||
val awsel = UIntToOH(awid, edgeIn.master.endId).toBools
|
val awsel = UIntToOH(awid, edgeIn.master.endId).toBools
|
||||||
val bsel = UIntToOH(bid, edgeIn.master.endId).toBools
|
val bsel = UIntToOH(bid, edgeIn.master.endId).toBools
|
||||||
(wqueues zip (awsel zip bsel)) foreach { case (q, (aw, b)) =>
|
(wqueues zip (awsel zip bsel)) foreach { case (q, (aw, b)) =>
|
||||||
q.io.deq.ready := out.b .valid && in .b .ready && b
|
q.deq.ready := out.b .valid && in .b .ready && b
|
||||||
q.io.enq.valid := in .aw.valid && out.aw.ready && aw
|
q.enq.valid := in .aw.valid && out.aw.ready && aw
|
||||||
q.io.enq.bits := in.aw.bits.user.get
|
q.enq.bits := in.aw.bits.user.get
|
||||||
}
|
}
|
||||||
|
|
||||||
out.w <> in.w
|
out.w <> in.w
|
||||||
|
@ -16,9 +16,10 @@ case class TLToAXI4Node(beatBytes: Int) extends MixedAdapterNode(TLImp, AXI4Imp)
|
|||||||
val idStart = idSize.scanLeft(0)(_+_).init
|
val idStart = idSize.scanLeft(0)(_+_).init
|
||||||
val masters = ((idStart zip idSize) zip p.clients) map { case ((start, size), c) =>
|
val masters = ((idStart zip idSize) zip p.clients) map { case ((start, size), c) =>
|
||||||
AXI4MasterParameters(
|
AXI4MasterParameters(
|
||||||
id = IdRange(start, start+size),
|
id = IdRange(start, start+size),
|
||||||
aligned = true,
|
aligned = true,
|
||||||
nodePath = c.nodePath)
|
maxFlight = Some(if (c.requestFifo) c.sourceId.size else 1),
|
||||||
|
nodePath = c.nodePath)
|
||||||
}
|
}
|
||||||
AXI4MasterPortParameters(
|
AXI4MasterPortParameters(
|
||||||
masters = masters,
|
masters = masters,
|
||||||
|
Loading…
Reference in New Issue
Block a user