1
0

axi4: make maxFlight a per-master parameter

This commit is contained in:
Wesley W. Terpstra 2017-04-25 18:49:33 -07:00
parent e1a072a644
commit d27e1928dd
5 changed files with 69 additions and 36 deletions

View File

@ -13,11 +13,26 @@ class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule
require (idBits >= 0)
val node = AXI4AdapterNode(
masterFn = { mp => mp.copy(
masterFn = { mp =>
// Create one new "master" per ID
val masters = Array.tabulate(1 << idBits) { i => AXI4MasterParameters(
id = IdRange(i, i+1),
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 = Seq(AXI4MasterParameters(
id = IdRange(0, min(mp.endId, 1 << idBits)),
aligned = mp.masters.map(_.aligned).reduce(_ && _))))
masters = masters)
},
slaveFn = { sp => sp.copy(
slaves = sp.slaves.map(s => s.copy(

View File

@ -64,19 +64,19 @@ case class AXI4SlavePortParameters(
case class AXI4MasterParameters(
id: IdRange = IdRange(0, 1),
aligned: Boolean = false,
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")
maxFlight.foreach { m => require (m >= 0) }
}
case class AXI4MasterPortParameters(
masters: Seq[AXI4MasterParameters],
userBits: Int = 0,
maxFlight: Int = 0) // at most X transactions per ID (0 = unlimited)
userBits: Int = 0)
{
val endId = masters.map(_.id.end).max
require (userBits >= 0)
require (maxFlight >= 0)
// Require disjoint ranges for ids
masters.combinations(2).foreach { case Seq(x,y) => require (!x.id.overlaps(y.id), s"$x and $y overlap") }

View File

@ -9,8 +9,9 @@ import diplomacy._
import uncore.tilelink2._
case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
dFn = { case AXI4MasterPortParameters(masters, userBits, maxFlight) =>
require (maxFlight > 0, "AXI4 must include a maximum transactions per ID to convert to TL")
dFn = { case AXI4MasterPortParameters(masters, userBits) =>
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(
clients = masters.flatMap { m =>
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 beatBytes = edgeOut.manager.beatBytes
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
require (edgeIn.master.userBits == 0, "AXI4 user bits cannot be transported by TL")

View File

@ -10,12 +10,15 @@ import uncore.tilelink2.UIntToOH1
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(
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 })
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
require (bits > 0) // useless UserYanker!
val rqueues = Seq.fill(edgeIn.master.endId) { Module(new Queue(UInt(width = bits), maxFlightPerId, flow=need_bypass)) }
val wqueues = Seq.fill(edgeIn.master.endId) { Module(new Queue(UInt(width = bits), maxFlightPerId, flow=need_bypass)) }
edgeOut.master.masters.foreach { m =>
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 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
out.ar.valid := in .ar.valid && ar_ready
out.ar.bits := in .ar.bits
val rid = out.r.bits.id
val r_valid = Vec(rqueues.map(_.io.deq.valid))(rid)
val r_bits = Vec(rqueues.map(_.io.deq.bits))(rid)
val r_valid = Vec(rqueues.map(_.deq.valid))(rid)
val r_bits = Vec(rqueues.map(_.deq.bits))(rid)
assert (!out.r.valid || r_valid) // Q must be ready faster than the response
in.r <> out.r
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 rsel = UIntToOH(rid, edgeIn.master.endId).toBools
(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.io.enq.valid := in .ar.valid && out.ar.ready && ar
q.io.enq.bits := in.ar.bits.user.get
q.deq.ready := out.r .valid && in .r .ready && r && out.r.bits.last
q.enq.valid := in .ar.valid && out.ar.ready && ar
q.enq.bits := in.ar.bits.user.get
}
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
out.aw.valid := in .aw.valid && aw_ready
out.aw.bits := in .aw.bits
val bid = out.b.bits.id
val b_valid = Vec(wqueues.map(_.io.deq.valid))(bid)
val b_bits = Vec(wqueues.map(_.io.deq.bits))(bid)
val b_valid = Vec(wqueues.map(_.deq.valid))(bid)
val b_bits = Vec(wqueues.map(_.deq.bits))(bid)
assert (!out.b.valid || b_valid) // Q must be ready faster than the response
in.b <> out.b
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 bsel = UIntToOH(bid, edgeIn.master.endId).toBools
(wqueues zip (awsel zip bsel)) foreach { case (q, (aw, b)) =>
q.io.deq.ready := out.b .valid && in .b .ready && b
q.io.enq.valid := in .aw.valid && out.aw.ready && aw
q.io.enq.bits := in.aw.bits.user.get
q.deq.ready := out.b .valid && in .b .ready && b
q.enq.valid := in .aw.valid && out.aw.ready && aw
q.enq.bits := in.aw.bits.user.get
}
out.w <> in.w

View File

@ -18,6 +18,7 @@ case class TLToAXI4Node(beatBytes: Int) extends MixedAdapterNode(TLImp, AXI4Imp)
AXI4MasterParameters(
id = IdRange(start, start+size),
aligned = true,
maxFlight = Some(if (c.requestFifo) c.sourceId.size else 1),
nodePath = c.nodePath)
}
AXI4MasterPortParameters(