From 5db7ae262bc91453e7a30cc43c3118a878f2815f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 19:30:07 -0700 Subject: [PATCH] tilelink2: first version of Narrower (only supports uncached IO) --- uncore/src/main/scala/tilelink2/Monitor.scala | 2 + .../src/main/scala/tilelink2/Narrower.scala | 117 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/Narrower.scala diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index b30a989e..71e2f933 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -46,6 +46,7 @@ object TLMonitor assert (is_aligned, "'A' channel PutPartial address not aligned to size") assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param") assert ((bundle.mask & ~mask) === UInt(0), "'A' channel PutPartial contains invalid mask") + assert (bundle.mask =/= UInt(0), "'A' channel PutPartial has a zero mask") } when (bundle.opcode === TLMessages.ArithmeticData) { @@ -111,6 +112,7 @@ object TLMonitor assert (is_aligned, "'B' channel PutPartial address not aligned to size") assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param") assert ((bundle.mask & ~mask) === UInt(0), "'B' channel PutPartial contains invalid mask") + assert (bundle.mask =/= UInt(0), "'B' channel PutPartial has a zero mask") } when (bundle.opcode === TLMessages.ArithmeticData) { diff --git a/uncore/src/main/scala/tilelink2/Narrower.scala b/uncore/src/main/scala/tilelink2/Narrower.scala new file mode 100644 index 00000000..83a5b6ce --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Narrower.scala @@ -0,0 +1,117 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +// innBeatBytes => the bus width after the adapter +class TLNarrower(innerBeatBytes: Int) extends LazyModule +{ + val node = TLAdapterNode( + clientFn = { case Seq(c) => c }, + managerFn = { case Seq(m) => m.copy(beatBytes = innerBeatBytes) }) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val edge = node.edgesOut(0) + val outerBeatBytes = edge.manager.beatBytes + require (outerBeatBytes < innerBeatBytes) + + val ratio = innerBeatBytes / outerBeatBytes + val bce = edge.manager.anySupportAcquire && edge.client.anySupportProbe + + def UIntToOH1(x: UInt, width: Int) = (UInt((1 << width) - 1) << x)(width*2-1, width) + def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None + + def split(in: HasTLData, fire: Bool): (Bool, UInt, UInt) = { + val dataSlices = Vec.tabulate (ratio) { i => in.data()((i+1)*outerBeatBytes*8-1, i*outerBeatBytes*8) } + val maskSlices = Vec.tabulate (ratio) { i => in.mask()((i+1)*outerBeatBytes -1, i*outerBeatBytes) } + val filter = Reg(UInt(width = ratio), init = SInt(-1, width = ratio).asUInt) + val mask = maskSlices.map(_.orR) + val hasData = in.hasData() + + // decoded_size = 1111 (for smallest), 0101, 0001 (for largest) + val sizeOH1 = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) + val decoded_size = Seq.tabulate(ratio) { i => trailingZeros(i).map(!sizeOH1(_)).getOrElse(Bool(true)) } + + val first = filter(ratio-1) + val new_filter = Mux(first, Cat(decoded_size.reverse), filter << 1) + val last = new_filter(ratio-1) || !hasData + when (fire) { + filter := new_filter + when (!hasData) { filter := SInt(-1, width = ratio).asUInt } + } + + val select = Cat(mask.reverse) & new_filter + // !!! if never data + (last, Mux1H(select, dataSlices), Mux1H(select, maskSlices)) + } + + def merge(in: HasTLData, fire: Bool): (Bool, UInt) = { + val count = RegInit(UInt(0, width = log2Ceil(ratio))) + val rdata = Reg(UInt(width = (ratio-1)*outerBeatBytes*8)) + val data = rdata << outerBeatBytes*8 | in.data() + val first = count === UInt(0) + val limit = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) + val last = count === limit || !in.hasData() + val cases = Vec.tabulate (log2Ceil(ratio)+1) { i => + val pow = 1 << i + Fill(1 << (ratio-i), data((pow+1)*outerBeatBytes*8-1, pow*outerBeatBytes*8)) + } + + when (fire) { + rdata := data + count := count + UInt(1) + when (last) { count := UInt(0) } + } + + // !!! if never data + (last, Mux1H(limit, cases)) + } + + val in = io.in(0) + val out = io.out(0) + + val (alast, adata, amask) = split(in.a.bits, out.a.fire()) + in.a.ready := out.a.ready && alast + out.a.valid := in.a.valid + out.a.bits := in.a.bits + out.a.bits.data := adata + out.a.bits.mask := amask + + val (dlast, ddata) = merge(out.d.bits, out.d.fire()) + out.d.ready := in.d.ready + in.d.valid := out.d.valid && dlast + in.d.bits := out.d.bits + in.d.bits.data := ddata + + if (bce) { + require (false) + // C has no wmask !!! +// val (clast, cdata, cmask) = split(in.c.bits, out.c.fire()) +// in.c.ready := out.c.ready && clast +// out.c.valid := in.c.valid +// out.c.bits := in.c.bits +// out.c.bits.data := cdata +// out.c.bits.mask := cmask + + in.e.ready := out.e.ready + out.e.valid := in.e.valid + out.e.bits := in.e.bits + } + } +} + +object TLNarrower +{ + // applied to the TL source node; connect (Narrower(x.node, 16) -> y.node) + def apply(x: TLBaseNode, innerBeatBytes: Int)(implicit lazyModule: LazyModule): TLBaseNode = { + val narrower = LazyModule(new TLNarrower(innerBeatBytes)) + lazyModule.connect(x -> narrower.node) + narrower.node + } +}