From 023c6402e9c0d747f7c4545be1399813096e2c7d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:09:01 -0700 Subject: [PATCH 01/15] tilelink2: switch to DecoupledIO syntax --- src/main/scala/uncore/tilelink2/Arbiter.scala | 3 +- src/main/scala/uncore/tilelink2/Bundles.scala | 46 +++++++++---------- src/main/scala/uncore/tilelink2/Edges.scala | 3 +- src/main/scala/uncore/tilelink2/Monitor.scala | 10 ++-- .../scala/uncore/tilelink2/WidthWidget.scala | 7 ++- src/main/scala/uncore/tilelink2/Xbar.scala | 3 +- 6 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Arbiter.scala b/src/main/scala/uncore/tilelink2/Arbiter.scala index 8d4a0bb2..446e855f 100644 --- a/src/main/scala/uncore/tilelink2/Arbiter.scala +++ b/src/main/scala/uncore/tilelink2/Arbiter.scala @@ -3,7 +3,6 @@ package uncore.tilelink2 import Chisel._ -import chisel3.util.IrrevocableIO import diplomacy._ object TLArbiter @@ -14,7 +13,7 @@ object TLArbiter val lowestIndexFirst: Policy = (valids, idle) => valids.scanLeft(Bool(true))(_ && !_).init - def apply[T <: Data](policy: Policy)(sink: IrrevocableIO[T], sources: (UInt, IrrevocableIO[T])*) { + def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) { if (sources.isEmpty) { sink.valid := Bool(false) } else { diff --git a/src/main/scala/uncore/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala index b90c4a2c..d82d4691 100644 --- a/src/main/scala/uncore/tilelink2/Bundles.scala +++ b/src/main/scala/uncore/tilelink2/Bundles.scala @@ -3,7 +3,7 @@ package uncore.tilelink2 import Chisel._ -import chisel3.util.{Irrevocable, IrrevocableIO, ReadyValidIO} +import chisel3.util.{ReadyValidIO} import diplomacy._ import util.{AsyncQueueSource, AsyncQueueSink, GenericParameterizedBundle} @@ -165,11 +165,11 @@ final class TLBundleE(params: TLBundleParameters) class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) { - val a = Irrevocable(new TLBundleA(params)) - val b = Irrevocable(new TLBundleB(params)).flip - val c = Irrevocable(new TLBundleC(params)) - val d = Irrevocable(new TLBundleD(params)).flip - val e = Irrevocable(new TLBundleE(params)) + val a = Decoupled(new TLBundleA(params)) + val b = Decoupled(new TLBundleB(params)).flip + val c = Decoupled(new TLBundleC(params)) + val d = Decoupled(new TLBundleD(params)).flip + val e = Decoupled(new TLBundleE(params)) } object TLBundle @@ -177,20 +177,20 @@ object TLBundle def apply(params: TLBundleParameters) = new TLBundle(params) } -final class IrrevocableSnoop[+T <: Data](gen: T) extends Bundle +final class DecoupledSnoop[+T <: Data](gen: T) extends Bundle { val ready = Bool() val valid = Bool() val bits = gen.asOutput def fire(dummy: Int = 0) = ready && valid - override def cloneType: this.type = new IrrevocableSnoop(gen).asInstanceOf[this.type] + override def cloneType: this.type = new DecoupledSnoop(gen).asInstanceOf[this.type] } -object IrrevocableSnoop +object DecoupledSnoop { - def apply[T <: Data](i: IrrevocableIO[T]) = { - val out = Wire(new IrrevocableSnoop(i.bits)) + def apply[T <: Data](i: DecoupledIO[T]) = { + val out = Wire(new DecoupledSnoop(i.bits)) out.ready := i.ready out.valid := i.valid out.bits := i.bits @@ -200,22 +200,22 @@ object IrrevocableSnoop class TLBundleSnoop(params: TLBundleParameters) extends TLBundleBase(params) { - val a = new IrrevocableSnoop(new TLBundleA(params)) - val b = new IrrevocableSnoop(new TLBundleB(params)) - val c = new IrrevocableSnoop(new TLBundleC(params)) - val d = new IrrevocableSnoop(new TLBundleD(params)) - val e = new IrrevocableSnoop(new TLBundleE(params)) + val a = new DecoupledSnoop(new TLBundleA(params)) + val b = new DecoupledSnoop(new TLBundleB(params)) + val c = new DecoupledSnoop(new TLBundleC(params)) + val d = new DecoupledSnoop(new TLBundleD(params)) + val e = new DecoupledSnoop(new TLBundleE(params)) } object TLBundleSnoop { def apply(x: TLBundle) = { val out = Wire(new TLBundleSnoop(x.params)) - out.a <> IrrevocableSnoop(x.a) - out.b <> IrrevocableSnoop(x.b) - out.c <> IrrevocableSnoop(x.c) - out.d <> IrrevocableSnoop(x.d) - out.e <> IrrevocableSnoop(x.e) + out.a <> DecoupledSnoop(x.a) + out.b <> DecoupledSnoop(x.b) + out.c <> DecoupledSnoop(x.c) + out.d <> DecoupledSnoop(x.d) + out.e <> DecoupledSnoop(x.e) out } } @@ -234,14 +234,14 @@ final class AsyncBundle[T <: Data](val depth: Int, gen: T) extends Bundle object FromAsyncBundle { - def apply[T <: Data](x: AsyncBundle[T], sync: Int = 3): IrrevocableIO[T] = { + def apply[T <: Data](x: AsyncBundle[T], sync: Int = 3): DecoupledIO[T] = { val sink = Module(new AsyncQueueSink(x.mem(0), x.depth, sync)) x.ridx := sink.io.ridx sink.io.widx := x.widx sink.io.mem := x.mem sink.io.source_reset_n := x.source_reset_n x.sink_reset_n := !sink.reset - val out = Wire(Irrevocable(x.mem(0))) + val out = Wire(Decoupled(x.mem(0))) out.valid := sink.io.deq.valid out.bits := sink.io.deq.bits sink.io.deq.ready := out.ready diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index ee5a8bcb..0f83468f 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -4,7 +4,6 @@ package uncore.tilelink2 import Chisel._ import chisel3.internal.sourceinfo.SourceInfo -import chisel3.util.IrrevocableIO import diplomacy._ class TLEdge( @@ -232,7 +231,7 @@ class TLEdge( (first, last, beats1 & ~counter1) } - def firstlast(x: IrrevocableIO[TLChannel]): (Bool, Bool, UInt) = firstlast(x.bits, x.fire()) + def firstlast(x: DecoupledIO[TLChannel]): (Bool, Bool, UInt) = firstlast(x.bits, x.fire()) } class TLEdgeOut( diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index e6dbab2b..758a104b 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -281,7 +281,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source when (bundle.e.valid) { legalizeFormatE(bundle.e.bits, edge) } } - def legalizeMultibeatA(a: IrrevocableSnoop[TLBundleA], edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeMultibeatA(a: DecoupledSnoop[TLBundleA], edge: TLEdge)(implicit sourceInfo: SourceInfo) { val (a_first, _, _) = edge.firstlast(a.bits, a.fire()) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -304,7 +304,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source } } - def legalizeMultibeatB(b: IrrevocableSnoop[TLBundleB], edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeMultibeatB(b: DecoupledSnoop[TLBundleB], edge: TLEdge)(implicit sourceInfo: SourceInfo) { val (b_first, _, _) = edge.firstlast(b.bits, b.fire()) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -327,7 +327,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source } } - def legalizeMultibeatC(c: IrrevocableSnoop[TLBundleC], edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeMultibeatC(c: DecoupledSnoop[TLBundleC], edge: TLEdge)(implicit sourceInfo: SourceInfo) { val (c_first, _, _) = edge.firstlast(c.bits, c.fire()) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -353,7 +353,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source } } - def legalizeMultibeatD(d: IrrevocableSnoop[TLBundleD], edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeMultibeatD(d: DecoupledSnoop[TLBundleD], edge: TLEdge)(implicit sourceInfo: SourceInfo) { val (d_first, _, _) = edge.firstlast(d.bits, d.fire()) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -386,7 +386,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source legalizeMultibeatD(bundle.d, edge) } - def legalizeIrrevocable(irr: IrrevocableSnoop[TLChannel], edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeIrrevocable(irr: DecoupledSnoop[TLChannel], edge: TLEdge)(implicit sourceInfo: SourceInfo) { val last_v = RegNext(irr.valid, Bool(false)) val last_r = RegNext(irr.ready, Bool(false)) val last_b = RegNext(irr.bits) diff --git a/src/main/scala/uncore/tilelink2/WidthWidget.scala b/src/main/scala/uncore/tilelink2/WidthWidget.scala index f4699122..de646f6a 100644 --- a/src/main/scala/uncore/tilelink2/WidthWidget.scala +++ b/src/main/scala/uncore/tilelink2/WidthWidget.scala @@ -4,7 +4,6 @@ package uncore.tilelink2 import Chisel._ import chisel3.internal.sourceinfo.SourceInfo -import chisel3.util.{Irrevocable, IrrevocableIO} import diplomacy._ import scala.math.{min,max} @@ -22,7 +21,7 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule val out = node.bundleOut } - def merge[T <: TLDataChannel](edgeIn: TLEdge, in: IrrevocableIO[T], edgeOut: TLEdge, out: IrrevocableIO[T]) = { + def merge[T <: TLDataChannel](edgeIn: TLEdge, in: DecoupledIO[T], edgeOut: TLEdge, out: DecoupledIO[T]) = { val inBytes = edgeIn.manager.beatBytes val outBytes = edgeOut.manager.beatBytes val ratio = outBytes / inBytes @@ -86,7 +85,7 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule } } - def split[T <: TLDataChannel](edgeIn: TLEdge, in: IrrevocableIO[T], edgeOut: TLEdge, out: IrrevocableIO[T]) = { + def split[T <: TLDataChannel](edgeIn: TLEdge, in: DecoupledIO[T], edgeOut: TLEdge, out: DecoupledIO[T]) = { val inBytes = edgeIn.manager.beatBytes val outBytes = edgeOut.manager.beatBytes val ratio = inBytes / outBytes @@ -136,7 +135,7 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule // addr_lo gets truncated automagically } - def splice[T <: TLDataChannel](edgeIn: TLEdge, in: IrrevocableIO[T], edgeOut: TLEdge, out: IrrevocableIO[T]) = { + def splice[T <: TLDataChannel](edgeIn: TLEdge, in: DecoupledIO[T], edgeOut: TLEdge, out: DecoupledIO[T]) = { if (edgeIn.manager.beatBytes == edgeOut.manager.beatBytes) { // nothing to do; pass it through out <> in diff --git a/src/main/scala/uncore/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala index 6a6c8fa3..258c8b5f 100644 --- a/src/main/scala/uncore/tilelink2/Xbar.scala +++ b/src/main/scala/uncore/tilelink2/Xbar.scala @@ -3,7 +3,6 @@ package uncore.tilelink2 import Chisel._ -import chisel3.util.IrrevocableIO import diplomacy._ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends LazyModule @@ -141,7 +140,7 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends Lazy def filter[T](data: Seq[T], mask: Seq[Boolean]) = (data zip mask).filter(_._2).map(_._1) // Replicate an input port to each output port - def fanout[T <: TLChannel](input: IrrevocableIO[T], select: Seq[Bool]) = { + def fanout[T <: TLChannel](input: DecoupledIO[T], select: Seq[Bool]) = { val filtered = Wire(Vec(select.size, input)) for (i <- 0 until select.size) { filtered(i).bits := input.bits From e2e72ac9797a7a22aab4f5de8c8716f22e7d5341 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:58:29 -0700 Subject: [PATCH 02/15] tilelink2 Fragmenter: cope with Decoupled input --- .../scala/uncore/tilelink2/Fragmenter.scala | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 940342b9..3d91cc51 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -190,8 +190,11 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxLgPutPartials = maxPutPartials.map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) + // Make the request Irrevocable + val in_a = Queue(in.a, 1, flow=true) + // If this is infront of a single manager, these become constants - val find = manager.findFast(edgeIn.address(in.a.bits)) + val find = manager.findFast(edgeIn.address(in_a.bits)) val maxLgArithmetic = Mux1H(find, maxLgArithmetics) val maxLgLogical = Mux1H(find, maxLgLogicals) val maxLgGet = Mux1H(find, maxLgGets) @@ -200,7 +203,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxLgHint = Mux1H(find, maxLgHints) val limit = if (alwaysMin) lgMinSize else - MuxLookup(in.a.bits.opcode, lgMinSize, Array( + MuxLookup(in_a.bits.opcode, lgMinSize, Array( TLMessages.PutFullData -> maxLgPutFull, TLMessages.PutPartialData -> maxLgPutPartial, TLMessages.ArithmeticData -> maxLgArithmetic, @@ -208,11 +211,11 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten TLMessages.Get -> maxLgGet, TLMessages.Hint -> maxLgHint)) - val aOrig = in.a.bits.size + val aOrig = in_a.bits.size val aFrag = Mux(aOrig > limit, limit, aOrig) val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize)) val aFragOH1 = UIntToOH1(aFrag, log2Up(maxDownSize)) - val aHasData = node.edgesIn(0).hasData(in.a.bits) + val aHasData = node.edgesIn(0).hasData(in_a.bits) val aMask = Mux(aHasData, UInt(0), aFragOH1) val gennum = RegInit(UInt(0, width = counterBits)) @@ -224,11 +227,11 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten when (out.a.fire()) { gennum := new_gennum } val delay = !aHasData && aFragnum =/= UInt(0) - out.a.valid := in.a.valid - in.a.ready := out.a.ready && !delay - out.a.bits := in.a.bits - out.a.bits.addr_hi := in.a.bits.addr_hi | (~aFragnum << log2Ceil(minSize/beatBytes) & aOrigOH1 >> log2Ceil(beatBytes)) - out.a.bits.source := Cat(in.a.bits.source, aFragnum) + out.a.valid := in_a.valid + in_a.ready := out.a.ready && !delay + out.a.bits := in_a.bits + out.a.bits.addr_hi := in_a.bits.addr_hi | (~aFragnum << log2Ceil(minSize/beatBytes) & aOrigOH1 >> log2Ceil(beatBytes)) + out.a.bits.source := Cat(in_a.bits.source, aFragnum) out.a.bits.size := aFrag // Tie off unused channels From 405f66da3223c1d37418de86e4617f1ff03586fe Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:47:01 -0700 Subject: [PATCH 03/15] tilelink2 WidthWidget: cope with Decoupled inputs --- src/main/scala/uncore/tilelink2/WidthWidget.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/WidthWidget.scala b/src/main/scala/uncore/tilelink2/WidthWidget.scala index de646f6a..45530383 100644 --- a/src/main/scala/uncore/tilelink2/WidthWidget.scala +++ b/src/main/scala/uncore/tilelink2/WidthWidget.scala @@ -141,7 +141,7 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule out <> in } else if (edgeIn.manager.beatBytes > edgeOut.manager.beatBytes) { // split input to output - split(edgeIn, in, edgeOut, out) + split(edgeIn, Queue(in, 1, flow=true), edgeOut, out) } else { // merge input to output merge(edgeIn, in, edgeOut, out) From d8a1163131e9bd0e0f35a7bad9766c33cb9b6bbb Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:09:38 -0700 Subject: [PATCH 04/15] tilelink2 Monitor: don't enforce Irrevocable any more --- src/main/scala/uncore/tilelink2/Monitor.scala | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 758a104b..754a18a8 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -386,26 +386,6 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source legalizeMultibeatD(bundle.d, edge) } - def legalizeIrrevocable(irr: DecoupledSnoop[TLChannel], edge: TLEdge)(implicit sourceInfo: SourceInfo) { - val last_v = RegNext(irr.valid, Bool(false)) - val last_r = RegNext(irr.ready, Bool(false)) - val last_b = RegNext(irr.bits) - val bits_changed = irr.bits.asUInt === last_b.asUInt - - when (last_v && !last_r) { - assert(irr.valid, s"${irr.bits.channelName} had contents that were revoked by the supplier (valid lowered)" + extra) - assert(bits_changed, s"${irr.bits.channelName} had contents that were revoked by the supplier (contents changed)" + extra) - } - } - - def legalizeIrrevocable(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { - legalizeIrrevocable(bundle.a, edge) - legalizeIrrevocable(bundle.b, edge) - legalizeIrrevocable(bundle.c, edge) - legalizeIrrevocable(bundle.d, edge) - legalizeIrrevocable(bundle.e, edge) - } - def legalizeSourceUnique(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { val inflight = RegInit(UInt(0, width = edge.client.endSourceId)) @@ -438,7 +418,6 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source def legalize(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { legalizeFormat (bundle, edge) legalizeMultibeat (bundle, edge) - legalizeIrrevocable(bundle, edge) legalizeSourceUnique(bundle, edge) } From c4eadd3ab36a04a92287b33ce2658c3c81264b53 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:55:57 -0700 Subject: [PATCH 05/15] tilelink2 Monitor: enforce stricter transaction ordering --- src/main/scala/uncore/tilelink2/Monitor.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 754a18a8..f7887f0c 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -392,24 +392,20 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source val (_, a_last, _) = edge.firstlast(bundle.a.bits, bundle.a.fire()) val (_, d_last, _) = edge.firstlast(bundle.d.bits, bundle.d.fire()) - val bypass = bundle.a.bits.source === bundle.d.bits.source - val a_bypass = bypass && bundle.d.valid && d_last - val d_bypass = bypass && bundle.a.valid && a_last - if (edge.manager.minLatency > 0) { - assert(!bypass || !bundle.a.valid || !bundle.d.valid, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) + assert(bundle.a.bits.source =/= bundle.d.bits.source || !bundle.a.valid || !bundle.d.valid, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) } val a_set = Wire(init = UInt(0, width = edge.client.endSourceId)) when (bundle.a.fire()) { when (a_last) { a_set := UIntToOH(bundle.a.bits.source) } - assert(a_bypass || !inflight(bundle.a.bits.source), "'A' channel re-used a source ID" + extra) + assert(!inflight(bundle.a.bits.source), "'A' channel re-used a source ID" + extra) } val d_clr = Wire(init = UInt(0, width = edge.client.endSourceId)) when (bundle.d.fire() && bundle.d.bits.opcode =/= TLMessages.ReleaseAck) { when (d_last) { d_clr := UIntToOH(bundle.d.bits.source) } - assert(d_bypass || inflight(bundle.d.bits.source), "'D' channel acknowledged for nothing inflight" + extra) + assert((a_set | inflight)(bundle.d.bits.source), "'D' channel acknowledged for nothing inflight" + extra) } inflight := (inflight | a_set) & ~d_clr From 0e897b905f0d5dd91d7d17d08e61447262e10465 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:10:07 -0700 Subject: [PATCH 06/15] tilelink2 RegisterRouter: data path register is no longer required --- src/main/scala/uncore/tilelink2/RegisterRouter.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index 89c62021..e414eb92 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -41,10 +41,8 @@ class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = in.bits.mask := a.bits.mask in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size) - // Invoke the register map builder and make it Irrevocable - val out = Queue.irrevocable( - RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*), - entries = 1, flow = true) + // Invoke the register map builder + val out = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*) // No flow control needed in.valid := a.valid From 0aebf9e34180944c3519292969e87b979a4751d2 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:11:09 -0700 Subject: [PATCH 07/15] tilelink2 ToAXI4: no arbitration path register needed --- src/main/scala/uncore/tilelink2/ToAXI4.scala | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/ToAXI4.scala b/src/main/scala/uncore/tilelink2/ToAXI4.scala index 079f37dd..cf40cd19 100644 --- a/src/main/scala/uncore/tilelink2/ToAXI4.scala +++ b/src/main/scala/uncore/tilelink2/ToAXI4.scala @@ -221,12 +221,9 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule // Give R higher priority than B val r_wins = out.r.valid || r_holds_d - val in_d = Wire(in.d) - in.d <> Queue.irrevocable(in_d, entries=1, flow=combinational) - - out.r.ready := in_d.ready - out_b.ready := in_d.ready && !r_wins - in_d.valid := Mux(r_wins, out.r.valid, out_b.valid) + out.r.ready := in.d.ready + out_b.ready := in.d.ready && !r_wins + in.d.valid := Mux(r_wins, out.r.valid, out_b.valid) val r_error = out.r.bits.resp =/= AXI4Parameters.RESP_OKAY val b_error = out_b.bits.resp =/= AXI4Parameters.RESP_OKAY @@ -234,8 +231,8 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule val r_d = edgeIn.AccessAck(r_addr_lo, r_sink, r_source, r_size, UInt(0), r_error) val b_d = edgeIn.AccessAck(b_addr_lo, b_sink, b_source, b_size, b_error) - in_d.bits := Mux(r_wins, r_d, b_d) - in_d.bits.data := out.r.bits.data // avoid a costly Mux + in.d.bits := Mux(r_wins, r_d, b_d) + in.d.bits.data := out.r.bits.data // avoid a costly Mux // Tie off unused channels in.b.valid := Bool(false) From b6e9b0c5585994843b2f369b7cba2dbb7d4f9cf0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:35:16 -0700 Subject: [PATCH 08/15] tilelink2 Arbiter: allow preemption of first beat --- src/main/scala/uncore/tilelink2/Arbiter.scala | 16 ++++++---------- .../scala/uncore/tilelink2/AtomicAutomata.scala | 2 +- .../scala/uncore/tilelink2/HintHandler.scala | 4 ++-- src/main/scala/uncore/tilelink2/Xbar.scala | 10 +++++----- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Arbiter.scala b/src/main/scala/uncore/tilelink2/Arbiter.scala index 446e855f..a0891a0f 100644 --- a/src/main/scala/uncore/tilelink2/Arbiter.scala +++ b/src/main/scala/uncore/tilelink2/Arbiter.scala @@ -7,10 +7,10 @@ import diplomacy._ object TLArbiter { - // (valids, idle) => readys + // (valids, granted) => readys type Policy = (Seq[Bool], Bool) => Seq[Bool] - val lowestIndexFirst: Policy = (valids, idle) => + val lowestIndexFirst: Policy = (valids, granted) => valids.scanLeft(Bool(true))(_ && !_).init def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) { @@ -24,11 +24,12 @@ object TLArbiter // The number of beats which remain to be sent val beatsLeft = RegInit(UInt(0)) val idle = beatsLeft === UInt(0) + val latch = idle && sink.ready // winner (if any) claims sink // Who wants access to the sink? val valids = sourcesIn.map(_.valid) // Arbitrate amongst the requests - val readys = Vec(policy(valids, idle)) + val readys = Vec(policy(valids, latch)) // Which request wins arbitration? val winners = Vec((readys zip valids) map { case (r,v) => r&&v }) @@ -43,19 +44,13 @@ object TLArbiter // Track remaining beats val maskedBeats = (winners zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) } val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats - val todoBeats = Mux(idle, initBeats, beatsLeft) - beatsLeft := todoBeats - sink.fire() - assert (!sink.fire() || todoBeats =/= UInt(0)) // underflow is impoosible + beatsLeft := Mux(latch, initBeats, beatsLeft - sink.fire()) // The one-hot source granted access in the previous cycle val state = RegInit(Vec.fill(sources.size)(Bool(false))) val muxState = Mux(idle, winners, state) state := muxState - val ones = Vec.fill(sources.size)(Bool(true)) - val picked = Mux(idle, ones, state) - sink.valid := Mux1H(picked, valids) - if (sources.size > 1) { val allowed = Mux(idle, readys, state) (sourcesIn zip allowed) foreach { case (s, r) => @@ -65,6 +60,7 @@ object TLArbiter sourcesIn(0).ready := sink.ready } + sink.valid := Mux(idle, valids.reduce(_||_), Mux1H(state, valids)) sink.bits := Mux1H(muxState, sourcesIn.map(_.bits)) } } diff --git a/src/main/scala/uncore/tilelink2/AtomicAutomata.scala b/src/main/scala/uncore/tilelink2/AtomicAutomata.scala index 8bea60de..70bacae2 100644 --- a/src/main/scala/uncore/tilelink2/AtomicAutomata.scala +++ b/src/main/scala/uncore/tilelink2/AtomicAutomata.scala @@ -175,7 +175,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc source_c.bits := edgeOut.Put(a_cam_a.bits.source, edgeIn.address(a_cam_a.bits), a_cam_a.bits.size, amo_data)._2 // Finishing an AMO from the CAM has highest priority - TLArbiter(TLArbiter.lowestIndexFirst)(out.a, (UInt(1), source_c), (edgeOut.numBeats(in.a.bits), source_i)) + TLArbiter(TLArbiter.lowestIndexFirst)(out.a, (UInt(0), source_c), (edgeOut.numBeats1(in.a.bits), source_i)) // Capture the A state into the CAM when (source_i.fire() && !a_isSupported) { diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index 61161f9c..16d36a8e 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -46,7 +46,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f hint.bits := edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address)) out.a.bits := in.a.bits - TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats(out.d.bits), out.d), (UInt(1), hint)) + TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats1(out.d.bits), out.d), (UInt(0), hint)) } else { out.a.valid := in.a.valid in.a.ready := out.a.ready @@ -69,7 +69,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f hint.bits := edgeOut.HintAck(out.b.bits) in.b.bits := out.b.bits - TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats(in.c.bits), in.c), (UInt(1), hint)) + TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats1(in.c.bits), in.c), (UInt(0), hint)) } else if (bce) { in.b.valid := out.b.valid out.b.ready := in.b.ready diff --git a/src/main/scala/uncore/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala index 258c8b5f..058353a6 100644 --- a/src/main/scala/uncore/tilelink2/Xbar.scala +++ b/src/main/scala/uncore/tilelink2/Xbar.scala @@ -129,11 +129,11 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends Lazy val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => i.contains(o.d.bits.source) }) }) val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => o.contains(i.e.bits.sink) }) }) - val beatsAI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) }) - val beatsBO = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) }) - val beatsCI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.c.bits) }) - val beatsDO = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.d.bits) }) - val beatsEI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.e.bits) }) + val beatsAI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats1(i.a.bits) }) + val beatsBO = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats1(o.b.bits) }) + val beatsCI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats1(i.c.bits) }) + val beatsDO = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats1(o.d.bits) }) + val beatsEI = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats1(i.e.bits) }) // Which pairs support support transfers def transpose[T](x: Seq[Seq[T]]) = Seq.tabulate(x(0).size) { i => Seq.tabulate(x.size) { j => x(j)(i) } } From b42cfdc9dd7f63be23bffb126dade2c8319b243c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 18:37:24 -0700 Subject: [PATCH 09/15] tilelink2 Arbiter: there is only one winner --- src/main/scala/uncore/tilelink2/Arbiter.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Arbiter.scala b/src/main/scala/uncore/tilelink2/Arbiter.scala index a0891a0f..3ef0ca7e 100644 --- a/src/main/scala/uncore/tilelink2/Arbiter.scala +++ b/src/main/scala/uncore/tilelink2/Arbiter.scala @@ -31,24 +31,24 @@ object TLArbiter // Arbitrate amongst the requests val readys = Vec(policy(valids, latch)) // Which request wins arbitration? - val winners = Vec((readys zip valids) map { case (r,v) => r&&v }) + val winner = Vec((readys zip valids) map { case (r,v) => r&&v }) // Confirm the policy works properly require (readys.size == valids.size) - // Never two winners - val prefixOR = winners.scanLeft(Bool(false))(_||_).init - assert((prefixOR zip winners) map { case (p,w) => !p || !w } reduce {_ && _}) + // Never two winner + val prefixOR = winner.scanLeft(Bool(false))(_||_).init + assert((prefixOR zip winner) map { case (p,w) => !p || !w } reduce {_ && _}) // If there was any request, there is a winner - assert (!valids.reduce(_||_) || winners.reduce(_||_)) + assert (!valids.reduce(_||_) || winner.reduce(_||_)) // Track remaining beats - val maskedBeats = (winners zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) } + val maskedBeats = (winner zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) } val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats beatsLeft := Mux(latch, initBeats, beatsLeft - sink.fire()) // The one-hot source granted access in the previous cycle val state = RegInit(Vec.fill(sources.size)(Bool(false))) - val muxState = Mux(idle, winners, state) + val muxState = Mux(idle, winner, state) state := muxState if (sources.size > 1) { From 99c7003d11999af46cb2472293efbb92c1a16cb0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 20:11:05 -0700 Subject: [PATCH 10/15] tilelink2: allow preemption of Fragmenter and WidthWidget --- .../scala/uncore/tilelink2/Fragmenter.scala | 9 ++--- .../scala/uncore/tilelink2/Repeater.scala | 37 +++++++++++++++++++ .../scala/uncore/tilelink2/WidthWidget.scala | 10 +++-- 3 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/uncore/tilelink2/Repeater.scala diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 3d91cc51..e1083009 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -191,7 +191,8 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) // Make the request Irrevocable - val in_a = Queue(in.a, 1, flow=true) + val repeat = Wire(Bool()) + val in_a = Repeater(in.a, repeat) // If this is infront of a single manager, these become constants val find = manager.findFast(edgeIn.address(in_a.bits)) @@ -226,10 +227,8 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten when (out.a.fire()) { gennum := new_gennum } - val delay = !aHasData && aFragnum =/= UInt(0) - out.a.valid := in_a.valid - in_a.ready := out.a.ready && !delay - out.a.bits := in_a.bits + repeat := !aHasData && aFragnum =/= UInt(0) + out.a <> in_a out.a.bits.addr_hi := in_a.bits.addr_hi | (~aFragnum << log2Ceil(minSize/beatBytes) & aOrigOH1 >> log2Ceil(beatBytes)) out.a.bits.source := Cat(in_a.bits.source, aFragnum) out.a.bits.size := aFrag diff --git a/src/main/scala/uncore/tilelink2/Repeater.scala b/src/main/scala/uncore/tilelink2/Repeater.scala new file mode 100644 index 00000000..9835911e --- /dev/null +++ b/src/main/scala/uncore/tilelink2/Repeater.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +// A Repeater passes it's input to it's output, unless repeat is asserted. +// When repeat is asserted, the Repeater copies the input and repeats it next cycle. +class Repeater[T <: Data](gen: T) extends Module +{ + val io = new Bundle { + val repeat = Bool(INPUT) + val enq = Decoupled(gen).flip + val deq = Decoupled(gen) + } + + val full = RegInit(Bool(false)) + val saved = Reg(gen) + + // When !full, a repeater is pass-through + io.deq.valid := io.enq.valid || full + io.enq.ready := io.deq.ready && !full + io.deq.bits := Mux(full, saved, io.enq.bits) + + when (io.enq.fire() && io.repeat) { full := Bool(true); saved := io.enq.bits } + when (io.deq.fire() && !io.repeat) { full := Bool(false) } +} + +object Repeater +{ + def apply[T <: Data](enq: DecoupledIO[T], repeat: Bool): DecoupledIO[T] = { + val repeater = Module(new Repeater(enq.bits)) + repeater.io.repeat := repeat + repeater.io.enq := enq + repeater.io.deq + } +} diff --git a/src/main/scala/uncore/tilelink2/WidthWidget.scala b/src/main/scala/uncore/tilelink2/WidthWidget.scala index 45530383..32dc793b 100644 --- a/src/main/scala/uncore/tilelink2/WidthWidget.scala +++ b/src/main/scala/uncore/tilelink2/WidthWidget.scala @@ -120,9 +120,7 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule val dataOut = if (edgeIn.staticHasData(in.bits) == Some(false)) UInt(0) else Mux1H(select, dataSlices) val maskOut = Mux1H(select, maskSlices) - in.ready := out.ready && last - out.valid := in.valid - out.bits := in.bits + out <> in edgeOut.data(out.bits) := dataOut out.bits match { @@ -133,6 +131,9 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule } // addr_lo gets truncated automagically + + // Repeat the input if we're not last + !last } def splice[T <: TLDataChannel](edgeIn: TLEdge, in: DecoupledIO[T], edgeOut: TLEdge, out: DecoupledIO[T]) = { @@ -141,7 +142,8 @@ class TLWidthWidget(innerBeatBytes: Int) extends LazyModule out <> in } else if (edgeIn.manager.beatBytes > edgeOut.manager.beatBytes) { // split input to output - split(edgeIn, Queue(in, 1, flow=true), edgeOut, out) + val repeat = Wire(Bool()) + repeat := split(edgeIn, Repeater(in, repeat), edgeOut, out) } else { // merge input to output merge(edgeIn, in, edgeOut, out) From e5a14833586f3076e92b724b6bcaca0dddb4775e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 20:27:26 -0700 Subject: [PATCH 11/15] tilelink2 Fragmenter: eliminate most of the registers on A --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 16 ++++++++++++---- src/main/scala/uncore/tilelink2/Repeater.scala | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index e1083009..a98321b1 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -190,9 +190,10 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxLgPutPartials = maxPutPartials.map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) - // Make the request Irrevocable - val repeat = Wire(Bool()) - val in_a = Repeater(in.a, repeat) + // Make the request repeatable + val repeater = Module(new Repeater(in.a.bits)) + repeater.io.enq <> in.a + val in_a = repeater.io.deq // If this is infront of a single manager, these become constants val find = manager.findFast(edgeIn.address(in_a.bits)) @@ -227,12 +228,19 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten when (out.a.fire()) { gennum := new_gennum } - repeat := !aHasData && aFragnum =/= UInt(0) + repeater.io.repeat := !aHasData && aFragnum =/= UInt(0) out.a <> in_a out.a.bits.addr_hi := in_a.bits.addr_hi | (~aFragnum << log2Ceil(minSize/beatBytes) & aOrigOH1 >> log2Ceil(beatBytes)) out.a.bits.source := Cat(in_a.bits.source, aFragnum) out.a.bits.size := aFrag + // Optimize away some of the Repeater's registers + assert (!repeater.io.full || !aHasData) + out.a.bits.data := in.a.bits.data + val fullMask = UInt((BigInt(1) << beatBytes) - 1) + assert (!repeater.io.full || in_a.bits.mask === fullMask) + out.a.bits.mask := Mux(repeater.io.full, fullMask, in.a.bits.mask) + // Tie off unused channels in.b.valid := Bool(false) in.c.ready := Bool(true) diff --git a/src/main/scala/uncore/tilelink2/Repeater.scala b/src/main/scala/uncore/tilelink2/Repeater.scala index 9835911e..980c522e 100644 --- a/src/main/scala/uncore/tilelink2/Repeater.scala +++ b/src/main/scala/uncore/tilelink2/Repeater.scala @@ -10,6 +10,7 @@ class Repeater[T <: Data](gen: T) extends Module { val io = new Bundle { val repeat = Bool(INPUT) + val full = Bool(OUTPUT) val enq = Decoupled(gen).flip val deq = Decoupled(gen) } @@ -21,6 +22,7 @@ class Repeater[T <: Data](gen: T) extends Module io.deq.valid := io.enq.valid || full io.enq.ready := io.deq.ready && !full io.deq.bits := Mux(full, saved, io.enq.bits) + io.full := full when (io.enq.fire() && io.repeat) { full := Bool(true); saved := io.enq.bits } when (io.deq.fire() && !io.repeat) { full := Bool(false) } From 5d5b5a66f4d9600ffb3c5b3c4a1206722d591026 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 21:02:01 -0700 Subject: [PATCH 12/15] tilelink2 RAMModel: fix a write-bad-data bug --- src/main/scala/uncore/tilelink2/RAMModel.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala index 2ee1d607..bb560da7 100644 --- a/src/main/scala/uncore/tilelink2/RAMModel.scala +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -103,7 +103,7 @@ class TLRAMModel(log: String = "") extends LazyModule a_flight.size := edge.size(in.a.bits) a_flight.opcode := in.a.bits.opcode - flight(in.a.bits.source) := a_flight + when (in.a.fire()) { flight(in.a.bits.source) := a_flight } val bypass = if (edge.manager.minLatency > 0) Bool(false) else in.a.valid && in.a.bits.source === out.d.bits.source val d_flight = RegNext(Mux(bypass, a_flight, flight(out.d.bits.source))) From 200cf3dd13c0d78c43a7ec5e85f3b8fc301c24d9 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 21:02:31 -0700 Subject: [PATCH 13/15] tilelink2 Nodes: include some options to test for conformance --- src/main/scala/uncore/tilelink2/Nodes.scala | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/scala/uncore/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala index ffb10476..56a8ec66 100644 --- a/src/main/scala/uncore/tilelink2/Nodes.scala +++ b/src/main/scala/uncore/tilelink2/Nodes.scala @@ -21,6 +21,9 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL } var emitMonitors = true + var stressTestDecoupled = false + var combinationalCheck = false + def colour = "#000000" // black def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { val monitor = if (emitMonitors) { @@ -31,6 +34,40 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL (monitor, () => { bi <> bo monitor.foreach { _.module.io.in := TLBundleSnoop(bo) } + if (combinationalCheck) { + // It is forbidden for valid to depend on ready in TL2 + // If someone did that, then this will create a detectable combinational loop + bo.a.ready := bi.a.ready && bo.a.valid + bi.b.ready := bo.b.ready && bi.b.valid + bo.c.ready := bi.c.ready && bo.c.valid + bi.d.ready := bo.d.ready && bi.d.valid + bo.e.ready := bi.e.ready && bo.e.valid + } + if (stressTestDecoupled) { + // Randomly stall the transfers + val allow = LFSRNoiseMaker(5) + bi.a.valid := bo.a.valid && allow(0) + bo.a.ready := bi.a.ready && allow(0) + bo.b.valid := bi.b.valid && allow(1) + bi.b.ready := bo.b.ready && allow(1) + bi.c.valid := bo.c.valid && allow(2) + bo.c.ready := bi.c.ready && allow(2) + bo.d.valid := bi.d.valid && allow(3) + bi.d.ready := bo.d.ready && allow(3) + bi.e.valid := bo.e.valid && allow(4) + bo.e.ready := bi.e.ready && allow(4) + // Inject garbage whenever not valid + val bits_a = bo.a.bits.fromBits(LFSRNoiseMaker(bo.a.bits.asUInt.getWidth)) + val bits_b = bi.b.bits.fromBits(LFSRNoiseMaker(bi.b.bits.asUInt.getWidth)) + val bits_c = bo.c.bits.fromBits(LFSRNoiseMaker(bo.c.bits.asUInt.getWidth)) + val bits_d = bi.d.bits.fromBits(LFSRNoiseMaker(bi.d.bits.asUInt.getWidth)) + val bits_e = bo.e.bits.fromBits(LFSRNoiseMaker(bo.e.bits.asUInt.getWidth)) + when (!bi.a.valid) { bi.a.bits := bits_a } + when (!bo.b.valid) { bo.b.bits := bits_b } + when (!bi.c.valid) { bi.c.bits := bits_c } + when (!bo.d.valid) { bo.d.bits := bits_d } + when (!bi.e.valid) { bi.e.bits := bits_e } + } }) } From 54b73aef5784f971c69143528108ebfc5516e314 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Oct 2016 21:11:32 -0700 Subject: [PATCH 14/15] tilelink2: WidthWidget and Fragmenter no longer erase latency --- src/main/scala/uncore/tilelink2/Buffer.scala | 6 +++--- src/main/scala/uncore/tilelink2/Fragmenter.scala | 3 +-- src/main/scala/uncore/tilelink2/WidthWidget.scala | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index 659cf6dd..3ca2dec0 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -5,7 +5,7 @@ package uncore.tilelink2 import Chisel._ import chisel3.internal.sourceinfo.SourceInfo import diplomacy._ -import scala.math.max +import scala.math.{min,max} // pipe is only used if a queue has depth = 1 class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe: Boolean = true) extends LazyModule @@ -17,8 +17,8 @@ class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe: require (e >= 0) val node = TLAdapterNode( - clientFn = { seq => seq(0).copy(minLatency = seq(0).minLatency + max(1,b) + max(1,c)) }, - managerFn = { seq => seq(0).copy(minLatency = seq(0).minLatency + max(1,a) + max(1,d)) }) + clientFn = { seq => seq(0).copy(minLatency = seq(0).minLatency + min(1,b) + min(1,c)) }, + managerFn = { seq => seq(0).copy(minLatency = seq(0).minLatency + min(1,a) + min(1,d)) }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index a98321b1..10df7da8 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -39,10 +39,9 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten def mapClient(c: TLClientParameters) = c.copy( sourceId = IdRange(c.sourceId.start << fragmentBits, c.sourceId.end << fragmentBits)) - // Because the Fragmenter stalls inner A while serving outer, it can wipe away inner latency val node = TLAdapterNode( clientFn = { case Seq(c) => c.copy(clients = c.clients.map(mapClient)) }, - managerFn = { case Seq(m) => m.copy(managers = m.managers.map(mapManager), minLatency = 0) }) + managerFn = { case Seq(m) => m.copy(managers = m.managers.map(mapManager)) }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { diff --git a/src/main/scala/uncore/tilelink2/WidthWidget.scala b/src/main/scala/uncore/tilelink2/WidthWidget.scala index 32dc793b..bfbf9eb4 100644 --- a/src/main/scala/uncore/tilelink2/WidthWidget.scala +++ b/src/main/scala/uncore/tilelink2/WidthWidget.scala @@ -10,10 +10,9 @@ import scala.math.{min,max} // innBeatBytes => the new client-facing bus width class TLWidthWidget(innerBeatBytes: Int) extends LazyModule { - // Because we stall the request while sending beats, atomics can overlap => minLatency=0 val node = TLAdapterNode( - clientFn = { case Seq(c) => c.copy(minLatency = 0) }, - managerFn = { case Seq(m) => m.copy(minLatency = 0, beatBytes = innerBeatBytes) }) + clientFn = { case Seq(c) => c }, + managerFn = { case Seq(m) => m.copy(beatBytes = innerBeatBytes) }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { From 4e40f9bb597a2d5931fba33b6e32b0525c33f599 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 13 Oct 2016 10:29:55 -0700 Subject: [PATCH 15/15] tilelink2 Nodes: appease the PC police --- src/main/scala/regmapper/RegMapper.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/regmapper/RegMapper.scala b/src/main/scala/regmapper/RegMapper.scala index f456b899..57bf7f82 100644 --- a/src/main/scala/regmapper/RegMapper.scala +++ b/src/main/scala/regmapper/RegMapper.scala @@ -31,7 +31,7 @@ object RegMapper // Create a generic register-based device def apply(bytes: Int, concurrency: Int, undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = { val bytemap = mapping.toList - // Don't be an asshole... + // Negative addresses are bad bytemap.foreach { byte => require (byte._1 >= 0) } // Transform all fields into bit offsets Seq[(bit, field)]