From d27e1928dd86fd0244390885b936c470d29207f0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 25 Apr 2017 18:49:33 -0700 Subject: [PATCH] axi4: make maxFlight a per-master parameter --- src/main/scala/uncore/axi4/IdIndexer.scala | 25 +++++++-- src/main/scala/uncore/axi4/Parameters.scala | 12 ++--- src/main/scala/uncore/axi4/ToTL.scala | 7 +-- src/main/scala/uncore/axi4/UserYanker.scala | 54 +++++++++++++------- src/main/scala/uncore/tilelink2/ToAXI4.scala | 7 +-- 5 files changed, 69 insertions(+), 36 deletions(-) diff --git a/src/main/scala/uncore/axi4/IdIndexer.scala b/src/main/scala/uncore/axi4/IdIndexer.scala index fa3916b1..b7283417 100644 --- a/src/main/scala/uncore/axi4/IdIndexer.scala +++ b/src/main/scala/uncore/axi4/IdIndexer.scala @@ -13,11 +13,26 @@ class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule require (idBits >= 0) val node = AXI4AdapterNode( - masterFn = { mp => 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(_ && _)))) + 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 = masters) }, slaveFn = { sp => sp.copy( slaves = sp.slaves.map(s => s.copy( diff --git a/src/main/scala/uncore/axi4/Parameters.scala b/src/main/scala/uncore/axi4/Parameters.scala index a3a8f472..9ef05c77 100644 --- a/src/main/scala/uncore/axi4/Parameters.scala +++ b/src/main/scala/uncore/axi4/Parameters.scala @@ -62,21 +62,21 @@ case class AXI4SlavePortParameters( } case class AXI4MasterParameters( - id: IdRange = IdRange(0, 1), - aligned: Boolean = false, - nodePath: Seq[BaseNode] = Seq()) + 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") } diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala index 8e2dd849..d1edd5b6 100644 --- a/src/main/scala/uncore/axi4/ToTL.scala +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -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") diff --git a/src/main/scala/uncore/axi4/UserYanker.scala b/src/main/scala/uncore/axi4/UserYanker.scala index 521b04a2..72bd7bdc 100644 --- a/src/main/scala/uncore/axi4/UserYanker.scala +++ b/src/main/scala/uncore/axi4/UserYanker.scala @@ -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 diff --git a/src/main/scala/uncore/tilelink2/ToAXI4.scala b/src/main/scala/uncore/tilelink2/ToAXI4.scala index 0229bc0f..5d26a547 100644 --- a/src/main/scala/uncore/tilelink2/ToAXI4.scala +++ b/src/main/scala/uncore/tilelink2/ToAXI4.scala @@ -16,9 +16,10 @@ case class TLToAXI4Node(beatBytes: Int) extends MixedAdapterNode(TLImp, AXI4Imp) val idStart = idSize.scanLeft(0)(_+_).init val masters = ((idStart zip idSize) zip p.clients) map { case ((start, size), c) => AXI4MasterParameters( - id = IdRange(start, start+size), - aligned = true, - nodePath = c.nodePath) + id = IdRange(start, start+size), + aligned = true, + maxFlight = Some(if (c.requestFifo) c.sourceId.size else 1), + nodePath = c.nodePath) } AXI4MasterPortParameters( masters = masters,