From 6fc3ec3d63f01a173a36d45c0e5ef9ddc8812d9e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 13 Mar 2017 16:03:21 -0700 Subject: [PATCH 1/7] tileink2: add a TestRAM; a zero-delay RAM useful for testing TLRAM always answers after 1 cycle. We need a RAM that answers in 0. --- src/main/scala/uncore/tilelink2/TestRAM.scala | 83 +++++++++++++++++++ src/main/scala/unittest/Configs.scala | 1 + 2 files changed, 84 insertions(+) create mode 100644 src/main/scala/uncore/tilelink2/TestRAM.scala diff --git a/src/main/scala/uncore/tilelink2/TestRAM.scala b/src/main/scala/uncore/tilelink2/TestRAM.scala new file mode 100644 index 00000000..74dd2f75 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/TestRAM.scala @@ -0,0 +1,83 @@ +// See LICENSE.SiFive for license details. + +package uncore.tilelink2 + +import Chisel._ +import config._ +import diplomacy._ +import util._ + +// Do not use this for synthesis! Only for simulation. +class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule +{ + val device = new MemoryDevice + + val node = TLManagerNode(Seq(TLManagerPortParameters( + Seq(TLManagerParameters( + address = List(address), + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = executable, + supportsGet = TransferSizes(1, beatBytes), + supportsPutPartial = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + fifoId = Some(0))), // requests are handled in order + beatBytes = beatBytes))) + + // We require the address range to include an entire beat (for the write mask) + require ((address.mask & (beatBytes-1)) == beatBytes-1) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + } + + def bigBits(x: BigInt, tail: List[Boolean] = List.empty[Boolean]): List[Boolean] = + if (x == 0) tail.reverse else bigBits(x >> 1, ((x & 1) == 1) :: tail) + val mask = bigBits(address.mask >> log2Ceil(beatBytes)) + + val in = io.in(0) + val edge = node.edgesIn(0) + + val addrBits = (mask zip edge.addr_hi(in.a.bits).toBools).filter(_._1).map(_._2) + val memAddress = Cat(addrBits.reverse) + val mem = Mem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8))) + + // "Flow control" + in.a.ready := in.d.ready + in.d.valid := in.a.valid + + val hasData = edge.hasData(in.a.bits) + val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) } + + in.d.bits := edge.AccessAck(in.a.bits, UInt(0)) + in.d.bits.data := Cat(mem(memAddress).reverse) + in.d.bits.opcode := Mux(hasData, TLMessages.AccessAck, TLMessages.AccessAckData) + when (in.a.fire() && hasData) { mem.write(memAddress, wdata, in.a.bits.mask.toBools) } + + // Tie off unused channels + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + } +} + +/** Synthesizeable unit testing */ +import unittest._ + +class TLRAMZeroDelay(ramBeatBytes: Int)(implicit p: Parameters) extends LazyModule { + val fuzz = LazyModule(new TLFuzzer(5000)) + val model = LazyModule(new TLRAMModel) + val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes)) + + model.node := fuzz.node + ram.node := TLDelayer(0.25)(model.node) + + lazy val module = new LazyModuleImp(this) with HasUnitTestIO { + io.finished := fuzz.module.io.finished + } +} + +class TLRAMZeroDelayTest(ramBeatBytes: Int)(implicit p: Parameters) extends UnitTest(timeout = 500000) { + io.finished := Module(LazyModule(new TLRAMZeroDelay(ramBeatBytes)).module).io.finished +} diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index 95a22002..a927eeda 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -28,6 +28,7 @@ class WithTLSimpleUnitTests extends Config((site, here, up) => { Module(new uncore.tilelink2.TLRAMSimpleTest(1)), Module(new uncore.tilelink2.TLRAMSimpleTest(4)), Module(new uncore.tilelink2.TLRAMSimpleTest(16)), + Module(new uncore.tilelink2.TLRAMZeroDelayTest(4)), Module(new uncore.tilelink2.TLRR0Test), Module(new uncore.tilelink2.TLRR1Test), Module(new uncore.tilelink2.TLRAMRationalCrossingTest), From 3c5c877409a45155f41a08898911771e6176a86c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 13 Mar 2017 19:55:27 -0700 Subject: [PATCH 2/7] tilelink2: make TLBuffer API more flexible --- src/main/scala/uncore/tilelink2/Buffer.scala | 74 ++++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index 8a864ec3..b7a51c4d 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -8,33 +8,60 @@ import config._ import diplomacy._ 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)(implicit p: Parameters) extends LazyModule +case class TLBufferParams(depth: Int, flow: Boolean, pipe: Boolean) { - require (a >= 0) - require (b >= 0) - require (c >= 0) - require (d >= 0) - require (e >= 0) + require (depth >= 0) + def isDefined = depth > 0 + def latency = if (isDefined && !flow) 1 else 0 +} + +object TLBufferParams +{ + implicit def apply(depth: Int): TLBufferParams = TLBufferParams(depth, false, false) + + val default = TLBufferParams(2) + val none = TLBufferParams(0) + val flow = TLBufferParams(1, true, false) + val pipe = TLBufferParams(1, false, true) +} + +class TLBuffer( + a: TLBufferParams, + b: TLBufferParams, + c: TLBufferParams, + d: TLBufferParams, + e: TLBufferParams)(implicit p: Parameters) extends LazyModule +{ + def this(ace: TLBufferParams, bd: TLBufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace) + def this(abcde: TLBufferParams)(implicit p: Parameters) = this(abcde, abcde) + def this()(implicit p: Parameters) = this(TLBufferParams.default) val node = TLAdapterNode( - clientFn = { p => p.copy(minLatency = p.minLatency + min(1,b) + min(1,c)) }, - managerFn = { p => p.copy(minLatency = p.minLatency + min(1,a) + min(1,d)) }) + clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) }, + managerFn = { p => p.copy(minLatency = p.minLatency + a.latency + d.latency) }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut } - + + def buffer[T <: Data](config: TLBufferParams, data: DecoupledIO[T]): DecoupledIO[T] = { + if (config.isDefined) { + Queue(data, config.depth, pipe=config.pipe, flow=config.flow) + } else { + data + } + } + ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => - if (a>0) { out.a <> Queue(in .a, a, pipe && a<2) } else { out.a <> in.a } - if (d>0) { in .d <> Queue(out.d, d, pipe && d<2) } else { in.d <> out.d } + out.a <> buffer(a, in .a) + in .d <> buffer(d, out.d) if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) { - if (b>0) { in .b <> Queue(out.b, b, pipe && b<2) } else { in.b <> out.b } - if (c>0) { out.c <> Queue(in .c, c, pipe && c<2) } else { out.c <> in.c } - if (e>0) { out.e <> Queue(in .e, e, pipe && e<2) } else { out.e <> in.e } + in .b <> buffer(b, out.b) + out.c <> buffer(c, in .c) + out.e <> buffer(e, in .e) } else { in.b.valid := Bool(false) in.c.ready := Bool(true) @@ -50,13 +77,16 @@ class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe: object TLBuffer { // applied to the TL source node; y.node := TLBuffer(x.node) - def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(2)(x) - def apply(entries: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, true)(x) - def apply(entries: Int, pipe: Boolean) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, entries, pipe)(x) - def apply(ace: Int, bd: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, true)(x) - def apply(ace: Int, bd: Int, pipe: Boolean)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace, pipe)(x) - def apply(a: Int, b: Int, c: Int, d: Int, e: Int, pipe: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { - val buffer = LazyModule(new TLBuffer(a, b, c, d, e, pipe)) + def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(TLBufferParams.default)(x) + def apply(abcde: TLBufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x) + def apply(ace: TLBufferParams, bd: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x) + def apply( + a: TLBufferParams, + b: TLBufferParams, + c: TLBufferParams, + d: TLBufferParams, + e: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + val buffer = LazyModule(new TLBuffer(a, b, c, d, e)) buffer.node := x buffer.node } From d98fd942f165d2a0293dd6ed5e5117650bbf2e1e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 14 Mar 2017 17:37:41 -0700 Subject: [PATCH 3/7] tilelink2: optimize the supportsX check circuits --- .../scala/uncore/tilelink2/Parameters.scala | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 0a8ffd17..01d2b620 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -118,37 +118,40 @@ case class TLManagerPortParameters( // Does this Port manage this ID/address? def containsSafe(address: UInt) = findSafe(address).reduce(_ || _) - private def safe_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { - val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) - if (allSame) containsSafe(address) && member(managers(0)).containsLg(lgSize) else { - Mux1H(findSafe(address), managers.map(member(_).containsLg(lgSize))) - } - } - private def fast_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { - val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) - if (allSame) member(managers(0)).containsLg(lgSize) else { - Mux1H(findFast(address), managers.map(member(_).containsLg(lgSize))) - } + private def supportHelper( + safe: Boolean, + member: TLManagerParameters => TransferSizes, + address: UInt, + lgSize: UInt, + range: Option[TransferSizes]): Bool = { + def trim(x: TransferSizes) = range.map(_.intersect(x)).getOrElse(x) + val supportCases = managers.groupBy(m => trim(member(m))).mapValues(_.flatMap(_.address)) + val mask = if (safe) ~BigInt(0) else AddressDecoder(supportCases.values.toList) + val simplified = supportCases.mapValues(seq => AddressSet.unify(seq.map(_.widen(~mask)).distinct)) + simplified.map { case (s, a) => + (Bool(Some(s) == range) || s.containsLg(lgSize)) && + a.map(_.contains(address)).reduce(_||_) + }.foldLeft(Bool(false))(_||_) } // Check for support of a given operation at a specific address - val supportsAcquireTSafe = safe_helper(_.supportsAcquireT) _ - val supportsAcquireBSafe = safe_helper(_.supportsAcquireB) _ - val supportsArithmeticSafe = safe_helper(_.supportsArithmetic) _ - val supportsLogicalSafe = safe_helper(_.supportsLogical) _ - val supportsGetSafe = safe_helper(_.supportsGet) _ - val supportsPutFullSafe = safe_helper(_.supportsPutFull) _ - val supportsPutPartialSafe = safe_helper(_.supportsPutPartial) _ - val supportsHintSafe = safe_helper(_.supportsHint) _ + def supportsAcquireTSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireT, address, lgSize, range) + def supportsAcquireBSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireB, address, lgSize, range) + def supportsArithmeticSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsArithmetic, address, lgSize, range) + def supportsLogicalSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsLogical, address, lgSize, range) + def supportsGetSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsGet, address, lgSize, range) + def supportsPutFullSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutFull, address, lgSize, range) + def supportsPutPartialSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutPartial, address, lgSize, range) + def supportsHintSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsHint, address, lgSize, range) - val supportsAcquireTFast = fast_helper(_.supportsAcquireT) _ - val supportsAcquireBFast = fast_helper(_.supportsAcquireB) _ - val supportsArithmeticFast = fast_helper(_.supportsArithmetic) _ - val supportsLogicalFast = fast_helper(_.supportsLogical) _ - val supportsGetFast = fast_helper(_.supportsGet) _ - val supportsPutFullFast = fast_helper(_.supportsPutFull) _ - val supportsPutPartialFast = fast_helper(_.supportsPutPartial) _ - val supportsHintFast = fast_helper(_.supportsHint) _ + def supportsAcquireTFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireT, address, lgSize, range) + def supportsAcquireBFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireB, address, lgSize, range) + def supportsArithmeticFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsArithmetic, address, lgSize, range) + def supportsLogicalFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsLogical, address, lgSize, range) + def supportsGetFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsGet, address, lgSize, range) + def supportsPutFullFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutFull, address, lgSize, range) + def supportsPutPartialFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutPartial, address, lgSize, range) + def supportsHintFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsHint, address, lgSize, range) } case class TLClientParameters( From 5885bf29b5c77dc6583612e582edc934f81e3a21 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 13 Mar 2017 16:09:42 -0700 Subject: [PATCH 4/7] axi4: improve test harness --- src/main/scala/uncore/axi4/Test.scala | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/scala/uncore/axi4/Test.scala b/src/main/scala/uncore/axi4/Test.scala index fb46cf9c..924fdeae 100644 --- a/src/main/scala/uncore/axi4/Test.scala +++ b/src/main/scala/uncore/axi4/Test.scala @@ -25,7 +25,7 @@ class AXI4LiteFuzzRAM()(implicit p: Parameters) extends LazyModule val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) model.node := fuzz.node - xbar.node := TLDelayer(0.1)(model.node) + xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node))) ram.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, true )(xbar.node)) gpio.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, false)(xbar.node)) @@ -48,7 +48,7 @@ class AXI4FullFuzzRAM()(implicit p: Parameters) extends LazyModule val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) model.node := fuzz.node - xbar.node := TLDelayer(0.1)(model.node) + xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node))) ram.node := AXI4Fragmenter(lite=false, maxInFlight = 2)(TLToAXI4(4,false)(xbar.node)) gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node)) @@ -69,7 +69,12 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule val model = LazyModule(new TLRAMModel("AXI4FuzzMaster")) model.node := fuzz.node - node := TLToAXI4(4)(TLDelayer(0.1)(model.node)) + node := + TLToAXI4(4)( + TLDelayer(0.1)( + TLBuffer(TLBufferParams.flow)( + TLDelayer(0.1)( + model.node)))) lazy val module = new LazyModuleImp(this) { val io = new Bundle { @@ -84,9 +89,16 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule { val node = AXI4InputNode() - val ram = LazyModule(new TLRAM(AddressSet(0x0, 0xfff))) + val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0xfff))) - ram.node := TLFragmenter(4, 16)(AXI4ToTL()(AXI4Fragmenter()(node))) + ram.node := + TLFragmenter(4, 16)( + TLDelayer(0.1)( + TLBuffer(TLBufferParams.flow)( + TLDelayer(0.1)( + AXI4ToTL()( + AXI4Fragmenter()( + node)))))) lazy val module = new LazyModuleImp(this) { val io = new Bundle { From 7f71df09255c1ba046875e3c0586d14c521e1b88 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 14 Mar 2017 10:28:52 -0700 Subject: [PATCH 5/7] apb: better test coverage --- src/main/scala/uncore/apb/Test.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/apb/Test.scala b/src/main/scala/uncore/apb/Test.scala index e59c5820..c6d6f56e 100644 --- a/src/main/scala/uncore/apb/Test.scala +++ b/src/main/scala/uncore/apb/Test.scala @@ -25,9 +25,14 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule val gpio = LazyModule(new RRTest0(0x100)) model.node := fuzz.node - xbar.node := TLToAPB()(TLDelayer(0.1)(model.node)) ram.node := xbar.node gpio.node := xbar.node + xbar.node := + TLToAPB()( + TLDelayer(0.2)( + TLBuffer(TLBufferParams.flow)( + TLDelayer(0.2)( + model.node)))) lazy val module = new LazyModuleImp(this) with HasUnitTestIO { io.finished := fuzz.module.io.finished From 0c5fd760892fc1bff5d6c7be18a05dcd3f701a2b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 13 Mar 2017 15:06:51 -0700 Subject: [PATCH 6/7] ahb: implement a ToTL bridge --- src/main/scala/uncore/ahb/Parameters.scala | 4 - src/main/scala/uncore/ahb/ToTL.scala | 139 +++++++++++++++++++++ 2 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/uncore/ahb/ToTL.scala diff --git a/src/main/scala/uncore/ahb/Parameters.scala b/src/main/scala/uncore/ahb/Parameters.scala index f8b0b85a..88b5c794 100644 --- a/src/main/scala/uncore/ahb/Parameters.scala +++ b/src/main/scala/uncore/ahb/Parameters.scala @@ -43,10 +43,6 @@ case class AHBSlavePortParameters( // Check that the link can be implemented in AHB require (maxTransfer <= beatBytes * AHBParameters.maxTransfer) - lazy val routingMask = AddressDecoder(slaves.map(_.address)) - def findSafe(address: UInt) = Vec(slaves.map(_.address.map(_.contains(address)).reduce(_ || _))) - def findFast(address: UInt) = Vec(slaves.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _))) - // Require disjoint ranges for addresses slaves.combinations(2).foreach { case Seq(x,y) => x.address.foreach { a => y.address.foreach { b => diff --git a/src/main/scala/uncore/ahb/ToTL.scala b/src/main/scala/uncore/ahb/ToTL.scala new file mode 100644 index 00000000..7d721f84 --- /dev/null +++ b/src/main/scala/uncore/ahb/ToTL.scala @@ -0,0 +1,139 @@ +// See LICENSE.SiFive for license details. + +package uncore.ahb + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import config._ +import diplomacy._ +import uncore.tilelink2._ + +case class AHBToTLNode() extends MixedAdapterNode(AHBImp, TLImp)( + dFn = { case AHBMasterPortParameters(masters) => + TLClientPortParameters(clients = masters.map { m => + TLClientParameters(nodePath = m.nodePath) + }) + }, + uFn = { mp => AHBSlavePortParameters( + slaves = mp.managers.map { m => + def adjust(x: TransferSizes) = { + if (x.contains(mp.beatBytes)) { + TransferSizes(x.min, m.minAlignment.min(mp.beatBytes * AHBParameters.maxTransfer).toInt) + } else { // larger than beatBytes requires beatBytes if misaligned + x.intersect(TransferSizes(1, mp.beatBytes)) + } + } + + AHBSlaveParameters( + address = m.address, + resources = m.resources, + regionType = m.regionType, + executable = m.executable, + nodePath = m.nodePath, + supportsWrite = adjust(m.supportsPutFull), + supportsRead = adjust(m.supportsGet))}, + beatBytes = mp.beatBytes) + }) + +class AHBToTL()(implicit p: Parameters) extends LazyModule +{ + val node = AHBToTLNode() + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => + val beatBytes = edgeOut.manager.beatBytes + + val d_send = RegInit(Bool(false)) + val d_recv = RegInit(Bool(false)) + val d_error = RegInit(Bool(false)) + val d_pause = RegInit(Bool(false)) + val d_write = RegInit(Bool(false)) + val d_addr = Reg(in.haddr) + val d_size = Reg(in.hsize) + + when (out.d.valid) { d_recv := Bool(false); d_error := d_error || out.d.bits.error } + when (out.a.ready) { d_send := Bool(false) } + + val a_count = RegInit(UInt(0, width = 4)) + val a_first = a_count === UInt(0) + val d_last = a_first + + val burst_sizes = Seq(1, 1, 4, 4, 8, 8, 16, 16) + val a_burst_size = Vec(burst_sizes.map(beats => UInt(log2Ceil(beats * beatBytes))))(in.hburst) + val a_burst_mask = Vec(burst_sizes.map(beats => UInt(beats * beatBytes - 1)))(in.hburst) + + val a_burst_ok = + in.htrans === AHBParameters.TRANS_NONSEQ && // only start burst on first AHB beat + in.hsize === UInt(log2Ceil(beatBytes)) && // not a narrow burst + (in.haddr & a_burst_mask) === UInt(0) && // address aligned to burst size + in.hburst =/= AHBParameters.BURST_INCR && // we know the burst length a priori + Mux(in.hwrite, // target device supports the burst + edgeOut.manager.supportsPutFullSafe(in.haddr, a_burst_size), + edgeOut.manager.supportsGetSafe (in.haddr, a_burst_size)) + + val beat = TransferSizes(1, beatBytes) + val a_legal = // Is the single-beat access allowed? + Mux(in.hwrite, + edgeOut.manager.supportsPutFullSafe(in.haddr, in.hsize, Some(beat)), + edgeOut.manager.supportsGetSafe (in.haddr, in.hsize, Some(beat))) + + val a_access = in.htrans === AHBParameters.TRANS_NONSEQ || in.htrans === AHBParameters.TRANS_SEQ + val a_accept = in.hready && in.hsel && a_access + + when (a_accept) { + a_count := a_count - UInt(1) + d_error := d_error || !a_legal + when ( in.hwrite) { d_send := Bool(true) } + when (!in.hwrite) { d_recv := Bool(true) } + when (a_first) { + a_count := Mux(a_burst_ok, a_burst_mask >> log2Ceil(beatBytes), UInt(0)) + d_send := a_legal + d_recv := a_legal + d_error := !a_legal + d_pause := Bool(false) + d_write := in.hwrite + d_addr := in.haddr + d_size := Mux(a_burst_ok, a_burst_size, in.hsize) + } + } + + out.a.valid := d_send + out.a.bits.opcode := Mux(d_write, TLMessages.PutFullData, TLMessages.Get) + out.a.bits.param := UInt(0) + out.a.bits.size := d_size + out.a.bits.source := UInt(0) + out.a.bits.address := d_addr + out.a.bits.data := in.hwdata + out.a.bits.mask := maskGen(d_addr, d_size, beatBytes) + + // Save the error for the last beat (so the master can't cancel the burst) + // When we report an error, we need to be hreadyout LOW for one cycle + val inject_error = d_last && (d_error || (out.d.valid && out.d.bits.error)) + when (inject_error) { d_pause := Bool(true) } + + out.d.ready := d_recv // backpressure AccessAckData arriving faster than AHB beats + in.hrdata := out.d.bits.data + in.hresp := inject_error + in.hreadyout := (!inject_error || d_pause) && Mux(d_write, (!d_send || out.a.ready) && (!d_last || !d_recv || out.d.valid), out.d.valid || !d_recv) + + // Unused channels + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) + } + } +} + +object AHBToTL +{ + def apply()(x: AHBOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + val tl = LazyModule(new AHBToTL) + tl.node := x + tl.node + } +} From c95c2ca9c83397e335c321c353ced2f9c300e584 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 13 Mar 2017 16:24:57 -0700 Subject: [PATCH 7/7] AHB: include bridge unit tests --- src/main/scala/uncore/ahb/Test.scala | 65 ++++++++++++++++++++++++++- src/main/scala/unittest/Configs.scala | 1 + 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/main/scala/uncore/ahb/Test.scala b/src/main/scala/uncore/ahb/Test.scala index a139b4bb..6bcf94f7 100644 --- a/src/main/scala/uncore/ahb/Test.scala +++ b/src/main/scala/uncore/ahb/Test.scala @@ -16,10 +16,10 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter new AHBRegBundle((), _) with RRTest1Bundle)( new AHBRegModule((), _, _) with RRTest1Module) -class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule +class AHBFuzzNative()(implicit p: Parameters) extends LazyModule { val fuzz = LazyModule(new TLFuzzer(5000)) - val model = LazyModule(new TLRAMModel("AHBFuzzMaster")) + val model = LazyModule(new TLRAMModel("AHBFuzzNative")) var xbar = LazyModule(new AHBFanout) val ram = LazyModule(new AHBRAM(AddressSet(0x0, 0xff))) val gpio = LazyModule(new RRTest0(0x100)) @@ -34,6 +34,67 @@ class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule } } +class AHBNativeTest()(implicit p: Parameters) extends UnitTest(500000) { + val dut = Module(LazyModule(new AHBFuzzNative).module) + io.finished := dut.io.finished +} + +class AHBFuzzMaster()(implicit p: Parameters) extends LazyModule +{ + val node = AHBOutputNode() + val fuzz = LazyModule(new TLFuzzer(5000)) + val model = LazyModule(new TLRAMModel("AHBFuzzMaster")) + + model.node := fuzz.node + node := + TLToAHB()( + TLDelayer(0.2)( + TLBuffer(TLBufferParams.flow)( + TLDelayer(0.2)( + model.node)))) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val out = node.bundleOut + val finished = Bool(OUTPUT) + } + + io.finished := fuzz.module.io.finished + } +} + +class AHBFuzzSlave()(implicit p: Parameters) extends LazyModule +{ + val node = AHBInputNode() + val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0xfff))) + + ram.node := + TLFragmenter(4, 16)( + TLDelayer(0.2)( + TLBuffer(TLBufferParams.flow)( + TLDelayer(0.2)( + AHBToTL()( + node))))) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + } + } +} + +class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule +{ + val master = LazyModule(new AHBFuzzMaster) + val slave = LazyModule(new AHBFuzzSlave) + + slave.node := master.node + + lazy val module = new LazyModuleImp(this) with HasUnitTestIO { + io.finished := master.module.io.finished + } +} + class AHBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) { val dut = Module(LazyModule(new AHBFuzzBridge).module) io.finished := dut.io.finished diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index a927eeda..5d6803d6 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -13,6 +13,7 @@ class WithUncoreUnitTests extends Config((site, here, up) => { Seq( Module(new uncore.tilelink2.TLFuzzRAMTest), Module(new uncore.ahb.AHBBridgeTest), + Module(new uncore.ahb.AHBNativeTest), Module(new uncore.apb.APBBridgeTest), Module(new uncore.axi4.AXI4LiteFuzzRAMTest), Module(new uncore.axi4.AXI4FullFuzzRAMTest),