From 7328b55abdc2f3c07cb48290de1ee9db8568b4da Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 19 Aug 2016 11:08:35 -0700 Subject: [PATCH 01/87] tilelink2: first cut at parameterization --- uncore/src/main/scala/tilelink2/Bases.scala | 41 ++++ uncore/src/main/scala/tilelink2/Bundles.scala | 77 +++++++ uncore/src/main/scala/tilelink2/Nodes.scala | 121 +++++++++++ .../src/main/scala/tilelink2/Operations.scala | 51 +++++ .../src/main/scala/tilelink2/Parameters.scala | 205 ++++++++++++++++++ 5 files changed, 495 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/Bases.scala create mode 100644 uncore/src/main/scala/tilelink2/Bundles.scala create mode 100644 uncore/src/main/scala/tilelink2/Nodes.scala create mode 100644 uncore/src/main/scala/tilelink2/Operations.scala create mode 100644 uncore/src/main/scala/tilelink2/Parameters.scala diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala new file mode 100644 index 00000000..64e30679 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -0,0 +1,41 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import scala.collection.mutable.ListBuffer +import chisel3.internal.sourceinfo.SourceInfo + +abstract class TLFactory +{ + private val bindings = ListBuffer[(TLBaseNode, Int, TLBaseNode, Int, SourceInfo)]() + + def tl(manager: TLBaseNode, client: TLBaseNode)(implicit sourceInfo: SourceInfo) = { + val (i, j) = manager.edge(client) + bindings += ((manager, i, client, j, sourceInfo)) + } + + def module: TLModule + + protected[tilelink2] def instantiate() = { + // Find all TLFactory members of self + for (m <- getClass.getMethods) { + if (m.getParameterTypes.isEmpty && + !java.lang.reflect.Modifier.isStatic(m.getModifiers) && + !(m.getName contains '$') && + classOf[TLFactory].isAssignableFrom(m.getReturnType)) { + // ... and force their lazy module members to exist + m.invoke(this).asInstanceOf[TLFactory].module + } + } + bindings.foreach { case (x, i, y, j, s) => + x.bundleIn(i).<>(y.bundleOut(j))(s) + } + } +} + +abstract class TLModule(factory: TLFactory) extends Module +{ + override def desiredName = factory.getClass.getName.split('.').last + factory.instantiate() +} diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala new file mode 100644 index 00000000..6225ae06 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -0,0 +1,77 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle +{ + override def cloneType = { + try { + this.getClass.getConstructors.head.newInstance(params).asInstanceOf[this.type] + } catch { + case e: java.lang.IllegalArgumentException => + throwException("Unable to use TLBundleBase.cloneType on " + + this.getClass + ", probably because " + this.getClass + + "() takes more than one argument. Consider overriding " + + "cloneType() on " + this.getClass, e) + } + } +} + +class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) +{ + val opcode = UInt(width = 3) + val param = UInt(width = 3) // amo_opcode || perms(req) + val size = UInt(width = params.sizeBits) + val source = UInt(width = params.sourceBits) // from + val address = UInt(width = params.addressBits) // to + val wmask = UInt(width = params.dataBits/8) + val data = UInt(width = params.dataBits) +} + +class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) +{ + val opcode = UInt(width = 3) + val param = UInt(width = 3) // amo_opcode || perms(req) + val size = UInt(width = params.sizeBits) + val source = UInt(width = params.sourceBits) // to + val address = UInt(width = params.addressBits) // from + val wmask = UInt(width = params.dataBits/8) + val data = UInt(width = params.dataBits) +} + +class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) +{ + val opcode = UInt(width = 3) + val param = UInt(width = 3) // perms(from=>to) + val size = UInt(width = params.sizeBits) + val address = UInt(width = params.addressBits) // to + val data = UInt(width = params.dataBits) + val error = Bool() +} + +class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) +{ + val opcode = UInt(width = 3) + val param = UInt(width = 3) // perms(to) + val size = UInt(width = params.sizeBits) + val source = UInt(width = params.sourceBits) // to + val sink = UInt(width = params.sinkBits) // from + val data = UInt(width = params.dataBits) + val error = Bool() +} + +class TLBundleE(params: TLBundleParameters) extends TLBundleBase(params) +{ + val sink = UInt(width = params.sourceBits) // to +} + +class TLBundle(params: TLBundleParameters) extends TLBundleBase(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)) +} diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala new file mode 100644 index 00000000..1e4f0d4e --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -0,0 +1,121 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import scala.collection.mutable.ListBuffer + +class TLBaseNode( + private val clientFn: Option[Seq[TLClientPortParameters] => TLClientPortParameters], + private val managerFn: Option[Seq[TLManagerPortParameters] => TLManagerPortParameters], + private val numClientPorts: Range.Inclusive, + private val numManagerPorts: Range.Inclusive) +{ + // At least 0 ports must be supported + require (!numClientPorts.isEmpty) + require (!numManagerPorts.isEmpty) + require (numClientPorts.start >= 0) + require (numManagerPorts.start >= 0) + + val noClients = numClientPorts.size == 1 && numClientPorts.contains(0) + val noManagers = numManagerPorts.size == 1 && numManagerPorts.contains(0) + + require (noClients || clientFn.isDefined) + require (noManagers || managerFn.isDefined) + + private val accClientPorts = ListBuffer[TLBaseNode]() + private val accManagerPorts = ListBuffer[TLBaseNode]() + private var clientRealized = false + private var managerRealized = false + + protected[tilelink2] def edge(x: TLBaseNode) = { + require (!noManagers) + require (!managerRealized) + require (!x.noClients) + require (!x.clientRealized) + val i = accManagerPorts.size + val j = x.accClientPorts.size + accManagerPorts += x + x.accClientPorts += this + (i, j) + } + + private lazy val clientPorts = { clientRealized = true; require (numClientPorts.contains(accClientPorts.size)); accClientPorts.result() } + private lazy val managerPorts = { managerRealized = true; require (numManagerPorts.contains(accManagerPorts.size)); accManagerPorts.result() } + private lazy val clientParams : Option[TLClientPortParameters] = clientFn.map(_(managerPorts.map(_.clientParams.get))) + private lazy val managerParams : Option[TLManagerPortParameters] = managerFn.map(_(clientPorts.map(_.managerParams.get))) + + lazy val edgesOut = clientPorts.map { n => new TLEdgeOut(clientParams.get, n.managerParams.get) } + lazy val edgesIn = managerPorts.map { n => new TLEdgeIn (n.clientParams.get, managerParams.get) } + + lazy val bundleOut = Vec(edgesOut.size, new TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) + lazy val bundleIn = Vec(edgesIn .size, new TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip +} + +class TLClientNode( + params: TLClientParameters, + numPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + clientFn = Some {case Seq() => TLClientPortParameters(Seq(params))}, + managerFn = None, + numClientPorts = numPorts, + numManagerPorts = 0 to 0) +{ + require(numPorts.end >= 1) +} + +object TLClientNode +{ + def apply( + params: TLClientParameters, + numPorts: Range.Inclusive = 1 to 1) = new TLClientNode(params, numPorts) +} + +class TLManagerNode( + beatBytes: Int, + params: TLManagerParameters, + numPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + clientFn = None, + managerFn = Some {case Seq() => TLManagerPortParameters(Seq(params), beatBytes)}, + numClientPorts = 0 to 0, + numManagerPorts = numPorts) +{ + require(numPorts.end >= 1) +} + +object TLManagerNode +{ + def apply( + beatBytes: Int, + params: TLManagerParameters, + numPorts: Range.Inclusive = 1 to 1) = new TLManagerNode(beatBytes, params, numPorts) +} + +class TLAdapterNode( + clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, + managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, + numClientPorts: Range.Inclusive = 1 to 1, + numManagerPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + clientFn = Some(clientFn), + managerFn = Some(managerFn), + numClientPorts = numClientPorts, + numManagerPorts = numManagerPorts) + +object TLAdapterNode +{ + def apply( + clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, + managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, + numClientPorts: Range.Inclusive = 1 to 1, + numManagerPorts: Range.Inclusive = 1 to 1) = new TLAdapterNode(clientFn, managerFn, numClientPorts, numManagerPorts) +} + +class TLIDNode extends TLBaseNode( + clientFn = Some({case Seq(x) => x}), + managerFn = Some({case Seq(x) => x}), + numClientPorts = 1 to 1, + numManagerPorts = 1 to 1) + +object TLIDNode +{ + def apply() = new TLIDNode() +} diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala new file mode 100644 index 00000000..33f5e6c6 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -0,0 +1,51 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +class TLEdgeOut( + client: TLClientPortParameters, + manager: TLManagerPortParameters) + extends TLEdgeParameters(client, manager) +{ + // Transfers + def Acquire(x: Int) = () // A + def Release(x: Int) = () // C + def ReleaseData(x: Int) = () // C + def ProbeAck(x: Int) = () // C + def ProbeDataAck(x: Int) = () // C + def GrantAck(x: Int) = () // E + + // Accessors + def Get(x: Int) = () // A + def Put(x: Int) = () // A + def Atomic(x: Int) = () // A + def AccessAck(x: Int) = () // C + def AccessDataAck(x: Int) = () // C + + def Hint(x: Int) = () // A + def HintAck(x: Int) = () // C +} + +class TLEdgeIn( + client: TLClientPortParameters, + manager: TLManagerPortParameters) + extends TLEdgeParameters(client, manager) +{ + // Transfers + def Probe(x: Int) = () // B + def Grant(x: Int) = () // D + def GrantData(x: Int) = () // D + def ReleaseAck(x: Int) = () // D + + // Accessors + def Get(x: Int) = () // B + def Put(x: Int) = () // B + def Atomic(x: Int) = () // B + def AccessAck(x: Int) = () // D + def AccessDataAck(x: Int) = () // D + + def Hint(x: Int) = () // B + def HintAck(x: Int) = () // D +} diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala new file mode 100644 index 00000000..e894d8d9 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -0,0 +1,205 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import scala.math.max + +/** Options for memory regions */ +object RegionType { + sealed trait T + case object CACHED extends T + case object TRACKED extends T + case object UNCACHED extends T + case object UNCACHEABLE extends T + val cases = Seq(CACHED, TRACKED, UNCACHED, UNCACHEABLE) +} + +// A non-empty half-open range; [start, end) +case class IdRange(start: Int, end: Int) +{ + require (start >= 0) + require (end >= 0) + require (start < end) // not empty + + // This is a strict partial ordering + def <(x: IdRange) = end <= x.start + def >(x: IdRange) = x < this + + def overlaps(x: IdRange) = start < x.end && x.start < end + def contains(x: IdRange) = start <= x.start && x.end <= end + // contains => overlaps (because empty is forbidden) + + def contains(x: Int) = start <= x && x < end + def contains(x: UInt) = UInt(start) <= x && x < UInt(end) // !!! special-case = + + def shift(x: Int) = IdRange(start+x, end+x) +} + +// An potentially empty inclusive range of 2-powers [min, max] +case class TransferSizes(min: Int, max: Int) +{ + def this(x: Int) = this(x, x) + + require (min <= max) + require (min != 0 || max == 0) + require (max == 0 || isPow2(max)) + require (min == 0 || isPow2(min)) + + def none = min == 0 + def contains(x: Int) = isPow2(x) && min <= x && x <= max + def containsLg(x: Int) = contains(1 << x) + def containsLg(x: UInt) = if (none) Bool(false) else { UInt(log2Ceil(min)) <= x && x <= UInt(log2Ceil(max)) } // !!! special-case = + + def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max) + + def intersect(x: TransferSizes) = + if (x.max < min || min < x.max) TransferSizes.none + else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max)) +} + +object TransferSizes { + def apply(x: Int) = new TransferSizes(x) + val none = new TransferSizes(0) +} + +// AddressSets specify the mask of bits consumed by the manager +// The base address used by the crossbar for routing +case class AddressSet(mask: BigInt, base: Option[BigInt] = None) +{ + // Forbid empty sets + require (base == None || (base.get & mask) == 0) + + def contains(x: BigInt) = ((x ^ base.get) & ~mask) == 0 + def contains(x: UInt) = ((x ^ UInt(base.get)) & UInt(~mask)) === UInt(0) + + // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) + // if base = None, it will be auto-assigned and thus not overlap anything + def overlaps(x: AddressSet) = (base, x.base) match { + case (Some(tbase), Some(xbase)) => (~(mask | x.mask) & (tbase ^ xbase)) == 0 + case _ => false + } + + // contains iff bitwise: x.mask => mask && contains(x.base) + def contains(x: AddressSet) = ((x.mask | (base.get ^ x.base.get)) & ~mask) == 0 + // 1 less than the number of bytes to which the manager should be aligned + def alignment1 = ((mask + 1) & ~mask) - 1 + def max = base.get | mask +} + +case class TLManagerParameters( + address: Seq[AddressSet], + sinkId: IdRange = IdRange(0, 1), + regionType: RegionType.T = RegionType.UNCACHEABLE, + // Supports both Acquire+Release of these sizes + supportsAcquire: TransferSizes = TransferSizes.none, + supportsAtomic: TransferSizes = TransferSizes.none, + supportsGet: TransferSizes = TransferSizes.none, + supportsPutFull: TransferSizes = TransferSizes.none, + supportsPutPartial: TransferSizes = TransferSizes.none, + supportsHints: Boolean = false, + // If fifoId=Some, all messages sent to the same fifoId are delivered in FIFO order + fifoId: Option[Int] = None) +{ + address.combinations(2).foreach({ case Seq(x,y) => + require (!x.overlaps(y)) + }) + address.foreach({ case a => + require (supportsAcquire.none || a.alignment1 >= supportsAcquire.max-1) + }) + + val maxTransfer = List( + supportsAcquire.max, + supportsAtomic.max, + supportsGet.max, + supportsPutFull.max, + supportsPutPartial.max).max +} + +case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes: Int) +{ + require (isPow2(beatBytes)) + + // Require disjoint ranges for Ids and addresses + managers.combinations(2).foreach({ case Seq(x,y) => + require (!x.sinkId.overlaps(y.sinkId)) + x.address.foreach({ a => y.address.foreach({ b => + require (!a.overlaps(b)) + })}) + }) + + def endSinkId = managers.map(_.sinkId.end).max + def maxAddress = managers.map(_.address.map(_.max).max).max + def maxGet = managers.map(_.supportsGet.max).max + def maxTransfer = managers.map(_.maxTransfer).max + + // These return Option[TLSinkParameters] for your convenience + def findById(x: Int) = managers.find(_.sinkId.contains(x)) + def findByAddress(x: BigInt) = managers.find(_.address.exists(_.contains(x))) + + //def buildCacheInfo(): UInt => Chilse(RegionType) // UInt = address, not sink_id + //def buildAtomicInfo(): UInt => Bool +} + +case class TLClientParameters( + sourceId: IdRange = IdRange(0,1), + // Supports both Probe+Grant of these sizes + supportsProbe: TransferSizes = TransferSizes.none, + supportsAtomics: TransferSizes = TransferSizes.none, + supportsGet: TransferSizes = TransferSizes.none, + supportsPutFull: TransferSizes = TransferSizes.none, + supportsPutPartial: TransferSizes = TransferSizes.none, + supportsHints: Boolean = false) +{ + val maxTransfer = List( + supportsProbe.max, + supportsAtomics.max, + supportsGet.max, + supportsPutFull.max, + supportsPutPartial.max).max +} + +case class TLClientPortParameters(clients: Seq[TLClientParameters]) { + def endSourceId = clients.map(_.sourceId.end).max + def maxTransfer = clients.map(_.maxTransfer).max +// def nSources: Int = sourceView.map(_.sourceIds.count).sum +// def nCaches: Int = sourceView.map(s => if(s.supportsProbe) 1 else 0).sum + //def makeSourceToCache() = ... + //def makeCacheToStartSource() = ... +} + +case class TLBundleParameters( + addressBits: Int, + dataBits: Int, + sourceBits: Int, + sinkBits: Int, + sizeBits: Int) +{ + // Chisel has issues with 0-width wires + require (addressBits >= 1) + require (dataBits >= 1) + require (sourceBits >= 1) + require (sinkBits >= 1) + require (sizeBits >= 1) + require (isPow2(dataBits)) + + def union(x: TLBundleParameters) = + TLBundleParameters( + max(addressBits, x.addressBits), + max(dataBits, x.dataBits), + max(sourceBits, x.sourceBits), + max(sinkBits, x.sinkBits), + max(sizeBits, x.sizeBits)) +} + +case class TLEdgeParameters( + client: TLClientPortParameters, + manager: TLManagerPortParameters) +{ + val bundle = TLBundleParameters( + addressBits = log2Up(manager.maxAddress + 1) - log2Up(manager.beatBytes), + dataBits = manager.beatBytes * 8, + sourceBits = log2Up(client.endSourceId), + sinkBits = log2Up(manager.endSinkId), + sizeBits = log2Up(log2Up(max(client.maxTransfer, manager.maxTransfer))+1)) +} From 9a460322da7d3036105a342282294aa7cd7a19ae Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 19 Aug 2016 13:47:18 -0700 Subject: [PATCH 02/87] tilelink2: add synthesizable test methods for Parameters --- .../src/main/scala/tilelink2/Parameters.scala | 95 ++++++++++++++++--- 1 file changed, 80 insertions(+), 15 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index e894d8d9..34760410 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -61,6 +61,8 @@ case class TransferSizes(min: Int, max: Int) object TransferSizes { def apply(x: Int) = new TransferSizes(x) val none = new TransferSizes(0) + + implicit def asBool(x: TransferSizes) = !x.none } // AddressSets specify the mask of bits consumed by the manager @@ -91,13 +93,13 @@ case class TLManagerParameters( address: Seq[AddressSet], sinkId: IdRange = IdRange(0, 1), regionType: RegionType.T = RegionType.UNCACHEABLE, - // Supports both Acquire+Release of these sizes + // Supports both Acquire+Release+Finish of these sizes supportsAcquire: TransferSizes = TransferSizes.none, supportsAtomic: TransferSizes = TransferSizes.none, supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, - supportsHints: Boolean = false, + supportsHint: Boolean = false, // If fifoId=Some, all messages sent to the same fifoId are delivered in FIFO order fifoId: Option[Int] = None) { @@ -108,6 +110,7 @@ case class TLManagerParameters( require (supportsAcquire.none || a.alignment1 >= supportsAcquire.max-1) }) + // Largest support transfer of all types val maxTransfer = List( supportsAcquire.max, supportsAtomic.max, @@ -128,44 +131,106 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes })}) }) + // Bounds on required sizes def endSinkId = managers.map(_.sinkId.end).max def maxAddress = managers.map(_.address.map(_.max).max).max - def maxGet = managers.map(_.supportsGet.max).max def maxTransfer = managers.map(_.maxTransfer).max + + // Operation sizes supported by all outward Managers + val allSupportAcquire = managers.map(_.supportsAcquire) .reduce(_ intersect _) + val allSupportAtomic = managers.map(_.supportsAtomic) .reduce(_ intersect _) + val allSupportGet = managers.map(_.supportsGet) .reduce(_ intersect _) + val allSupportPutFull = managers.map(_.supportsPutFull) .reduce(_ intersect _) + val allSupportPutPartial = managers.map(_.supportsPutPartial).reduce(_ intersect _) + val allSupportHint = managers.map(_.supportsHint) .reduce(_ && _) - // These return Option[TLSinkParameters] for your convenience - def findById(x: Int) = managers.find(_.sinkId.contains(x)) - def findByAddress(x: BigInt) = managers.find(_.address.exists(_.contains(x))) + // These return Option[TLManagerParameters] for your convenience + def find(address: BigInt) = managers.find(_.address.exists(_.contains(address))) + def findById(id: Int) = managers.find(_.sinkId.contains(id)) - //def buildCacheInfo(): UInt => Chilse(RegionType) // UInt = address, not sink_id - //def buildAtomicInfo(): UInt => Bool + // Synthesizable lookup methods + def find(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _))) + def findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id))) + + // Does this Port manage this ID/address? + def contains(address: UInt) = find(address).reduce(_ || _) + def containsById(id: UInt) = findById(id).reduce(_ || _) + + private def safety_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { + (find(address) zip managers.map(member(_).containsLg(lgSize))) + .map { case (m, s) => m && s } reduce (_ || _) + } + + // Check for support of a given operation at a specific address + val supportsAcquire = safety_helper(_.supportsAcquire) _ + val supportsAtomic = safety_helper(_.supportsAtomic) _ + val supportsGet = safety_helper(_.supportsGet) _ + val supportsPutFull = safety_helper(_.supportsPutFull) _ + val supportsPutPartial = safety_helper(_.supportsPutPartial) _ + def supportsHint(address: UInt) = { + (find(address) zip managers.map(_.supportsHint)) + .map { case (m, b) => m && Bool(b) } reduce (_ || _) + } } case class TLClientParameters( sourceId: IdRange = IdRange(0,1), // Supports both Probe+Grant of these sizes supportsProbe: TransferSizes = TransferSizes.none, - supportsAtomics: TransferSizes = TransferSizes.none, + supportsAtomic: TransferSizes = TransferSizes.none, supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, - supportsHints: Boolean = false) + supportsHint: Boolean = false) { val maxTransfer = List( supportsProbe.max, - supportsAtomics.max, + supportsAtomic.max, supportsGet.max, supportsPutFull.max, supportsPutPartial.max).max } case class TLClientPortParameters(clients: Seq[TLClientParameters]) { + // Require disjoint ranges for Ids + clients.combinations(2).foreach({ case Seq(x,y) => + require (!x.sourceId.overlaps(y.sourceId)) + }) + + // Bounds on required sizes def endSourceId = clients.map(_.sourceId.end).max def maxTransfer = clients.map(_.maxTransfer).max -// def nSources: Int = sourceView.map(_.sourceIds.count).sum -// def nCaches: Int = sourceView.map(s => if(s.supportsProbe) 1 else 0).sum - //def makeSourceToCache() = ... - //def makeCacheToStartSource() = ... + + // Operation sizes supported by all inward Clients + val allSupportProbe = clients.map(_.supportsProbe) .reduce(_ intersect _) + val allSupportAtomic = clients.map(_.supportsAtomic) .reduce(_ intersect _) + val allSupportGet = clients.map(_.supportsGet) .reduce(_ intersect _) + val allSupportPutFull = clients.map(_.supportsPutFull) .reduce(_ intersect _) + val allSupportPutPartial = clients.map(_.supportsPutPartial).reduce(_ intersect _) + val allSupportHint = clients.map(_.supportsHint) .reduce(_ && _) + + // These return Option[TLClientParameters] for your convenience + def find(id: Int) = clients.find(_.sourceId.contains(id)) + + // Synthesizable lookup methods + def find(id: UInt) = Vec(clients.map(_.sourceId.contains(id))) + def contains(id: UInt) = find(id).reduce(_ || _) + + private def safety_helper(member: TLClientParameters => TransferSizes)(address: UInt, lgSize: UInt) = { + (find(address) zip clients.map(member(_).containsLg(lgSize))) + .map { case (m, s) => m && s } reduce (_ || _) + } + + // Check for support of a given operation at a specific id + val supportsProbe = safety_helper(_.supportsProbe) _ + val supportsAtomic = safety_helper(_.supportsAtomic) _ + val supportsGet = safety_helper(_.supportsGet) _ + val supportsPutFull = safety_helper(_.supportsPutFull) _ + val supportsPutPartial = safety_helper(_.supportsPutPartial) _ + def supportsHint(address: UInt) = { + (find(address) zip clients.map(_.supportsHint)) + .map { case (m, b) => m && Bool(b) } reduce (_ || _) + } } case class TLBundleParameters( From 8592cbf0e3989c0a9b7340fdcfcf610b80fabfda Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 19 Aug 2016 15:25:51 -0700 Subject: [PATCH 03/87] tilelink2: Message and Permisison types from Henry --- uncore/src/main/scala/tilelink2/Bundles.scala | 59 +++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 6225ae06..b77313f9 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -19,10 +19,60 @@ abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle } } +object TLMessages +{ + // A B C D E + val Get = UInt(0) // . . + val PutFullData = UInt(1) // . . + val PutPartialData = UInt(2) // . . + val AtomicData = UInt(3) // . . + val Hint = UInt(4) // . . + val AccessAck = UInt(0) // . . + val AccessAckData = UInt(1) // . . + val Acquire = UInt(5) // . + val Probe = UInt(5) // . + val ProbeAck = UInt(2) // . + val ProbeAckData = UInt(3) // . + val Release = UInt(4) // . + val ReleaseData = UInt(5) // . +//val PutThroughData = UInt(6) // . // future extension + val ReleaseAck = UInt(2) // . + val Grant = UInt(3) // . + val GrantData = UInt(4) // . + val GrantAck = UInt(0) // . +} + +object TLPermissions +{ + // Cap types (Grant = new permissions, Probe = permisions <= target) + val toT = UInt(0) + val toB = UInt(1) + val toN = UInt(2) + + // Grow types (Acquire = permissions >= target) + val NtoB = UInt(0) + val NtoT = UInt(1) + val BtoT = UInt(2) + + // Shrink types (ProbeAck, Release) + val TtoB = UInt(0) + val TtoN = UInt(1) + val BtoN = UInt(2) + + // Report types (ProbeAck) + val TtoT = UInt(3) + val BtoB = UInt(4) + val NtoN = UInt(5) +} + +object TLAtomics +{ +} + class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 3) // amo_opcode || perms(req) + val param = UInt(width = 4) // amo_opcode || perms || hint val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to @@ -33,7 +83,7 @@ class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 3) // amo_opcode || perms(req) + val param = UInt(width = 4) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val address = UInt(width = params.addressBits) // from @@ -44,8 +94,9 @@ class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 3) // perms(from=>to) + val param = UInt(width = 3) val size = UInt(width = params.sizeBits) + val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to val data = UInt(width = params.dataBits) val error = Bool() @@ -54,7 +105,7 @@ class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 3) // perms(to) + val param = UInt(width = 2) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from From 5b10c1a328cd139d0f5ba5611f4d9272b2ce3738 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 19 Aug 2016 18:39:21 -0700 Subject: [PATCH 04/87] tilelink2: arithmetic and logical atomics must be distinct (priv spec 3.5.3) --- uncore/src/main/scala/tilelink2/Bundles.scala | 13 +++++----- .../src/main/scala/tilelink2/Parameters.scala | 24 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index b77313f9..a28a3e7f 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -25,12 +25,13 @@ object TLMessages val Get = UInt(0) // . . val PutFullData = UInt(1) // . . val PutPartialData = UInt(2) // . . - val AtomicData = UInt(3) // . . - val Hint = UInt(4) // . . + val ArithmeticData = UInt(3) // . . + val LogicalData = UInt(4) // . . + val Hint = UInt(5) // . . val AccessAck = UInt(0) // . . val AccessAckData = UInt(1) // . . - val Acquire = UInt(5) // . - val Probe = UInt(5) // . + val Acquire = UInt(6) // . + val Probe = UInt(6) // . val ProbeAck = UInt(2) // . val ProbeAckData = UInt(3) // . val Release = UInt(4) // . @@ -72,7 +73,7 @@ object TLAtomics class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 4) // amo_opcode || perms || hint + val param = UInt(width = 3) // amo_opcode || perms || hint val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to @@ -83,7 +84,7 @@ class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) { val opcode = UInt(width = 3) - val param = UInt(width = 4) + val param = UInt(width = 3) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val address = UInt(width = params.addressBits) // from diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 34760410..5503b7fe 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -95,7 +95,8 @@ case class TLManagerParameters( regionType: RegionType.T = RegionType.UNCACHEABLE, // Supports both Acquire+Release+Finish of these sizes supportsAcquire: TransferSizes = TransferSizes.none, - supportsAtomic: TransferSizes = TransferSizes.none, + supportsArithmetic: TransferSizes = TransferSizes.none, + supportsLogical: TransferSizes = TransferSizes.none, supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, @@ -113,7 +114,8 @@ case class TLManagerParameters( // Largest support transfer of all types val maxTransfer = List( supportsAcquire.max, - supportsAtomic.max, + supportsArithmetic.max, + supportsLogical.max, supportsGet.max, supportsPutFull.max, supportsPutPartial.max).max @@ -138,7 +140,8 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes // Operation sizes supported by all outward Managers val allSupportAcquire = managers.map(_.supportsAcquire) .reduce(_ intersect _) - val allSupportAtomic = managers.map(_.supportsAtomic) .reduce(_ intersect _) + val allSupportArithmetic = managers.map(_.supportsArithmetic).reduce(_ intersect _) + val allSupportLogical = managers.map(_.supportsLogical) .reduce(_ intersect _) val allSupportGet = managers.map(_.supportsGet) .reduce(_ intersect _) val allSupportPutFull = managers.map(_.supportsPutFull) .reduce(_ intersect _) val allSupportPutPartial = managers.map(_.supportsPutPartial).reduce(_ intersect _) @@ -163,7 +166,8 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes // Check for support of a given operation at a specific address val supportsAcquire = safety_helper(_.supportsAcquire) _ - val supportsAtomic = safety_helper(_.supportsAtomic) _ + val supportsArithmetic = safety_helper(_.supportsArithmetic) _ + val supportsLogical = safety_helper(_.supportsLogical) _ val supportsGet = safety_helper(_.supportsGet) _ val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ @@ -177,7 +181,8 @@ case class TLClientParameters( sourceId: IdRange = IdRange(0,1), // Supports both Probe+Grant of these sizes supportsProbe: TransferSizes = TransferSizes.none, - supportsAtomic: TransferSizes = TransferSizes.none, + supportsArithmetic: TransferSizes = TransferSizes.none, + supportsLogical: TransferSizes = TransferSizes.none, supportsGet: TransferSizes = TransferSizes.none, supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, @@ -185,7 +190,8 @@ case class TLClientParameters( { val maxTransfer = List( supportsProbe.max, - supportsAtomic.max, + supportsArithmetic.max, + supportsLogical.max, supportsGet.max, supportsPutFull.max, supportsPutPartial.max).max @@ -203,7 +209,8 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { // Operation sizes supported by all inward Clients val allSupportProbe = clients.map(_.supportsProbe) .reduce(_ intersect _) - val allSupportAtomic = clients.map(_.supportsAtomic) .reduce(_ intersect _) + val allSupportArithmetic = clients.map(_.supportsArithmetic).reduce(_ intersect _) + val allSupportLogical = clients.map(_.supportsLogical) .reduce(_ intersect _) val allSupportGet = clients.map(_.supportsGet) .reduce(_ intersect _) val allSupportPutFull = clients.map(_.supportsPutFull) .reduce(_ intersect _) val allSupportPutPartial = clients.map(_.supportsPutPartial).reduce(_ intersect _) @@ -223,7 +230,8 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { // Check for support of a given operation at a specific id val supportsProbe = safety_helper(_.supportsProbe) _ - val supportsAtomic = safety_helper(_.supportsAtomic) _ + val supportsArithmetic = safety_helper(_.supportsArithmetic) _ + val supportsLogical = safety_helper(_.supportsLogical) _ val supportsGet = safety_helper(_.supportsGet) _ val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ From 45e152e97e61915eee40c233801a425d1a005d17 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 19 Aug 2016 20:28:58 -0700 Subject: [PATCH 05/87] tilelink2: include Operation constructors --- .../src/main/scala/tilelink2/Operations.scala | 351 ++++++++++++++++-- .../src/main/scala/tilelink2/Parameters.scala | 13 +- 2 files changed, 335 insertions(+), 29 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 33f5e6c6..8f1fd4ea 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -10,22 +10,181 @@ class TLEdgeOut( extends TLEdgeParameters(client, manager) { // Transfers - def Acquire(x: Int) = () // A - def Release(x: Int) = () // C - def ReleaseData(x: Int) = () // C - def ProbeAck(x: Int) = () // C - def ProbeDataAck(x: Int) = () // C - def GrantAck(x: Int) = () // E + def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { + // !!! Monitor: lgSize >= beatBytes + // !!! Monitor: check address alignment + // !!! Monitor: check param values + val legal = manager.supportsAcquire(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.Acquire + a.param := growPermissions + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := SInt(-1).asUInt + a.data := UInt(0) + (legal, a) + } - // Accessors - def Get(x: Int) = () // A - def Put(x: Int) = () // A - def Atomic(x: Int) = () // A - def AccessAck(x: Int) = () // C - def AccessDataAck(x: Int) = () // C - - def Hint(x: Int) = () // A - def HintAck(x: Int) = () // C + def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = { + val legal = manager.supportsAcquire(toAddress, lgSize) + val c = new TLBundleC(bundle) + c.opcode := TLMessages.Release + c.param := shrinkPermissions + c.size := lgSize + c.source := fromSource + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := UInt(0) + c.error := Bool(false) + (legal, c) + } + + def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = { + val legal = manager.supportsAcquire(toAddress, lgSize) + val c = new TLBundleC(bundle) + c.opcode := TLMessages.ReleaseData + c.param := shrinkPermissions + c.size := lgSize + c.source := fromSource + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := data + c.error := Bool(false) + (legal, c) + } + + def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt) = { + val c = new TLBundleC(bundle) + c.opcode := TLMessages.ProbeAck + c.param := reportPermissions + c.size := lgSize + c.source := UInt(0) + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := UInt(0) + c.error := Bool(false) + c + } + + def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt, data: UInt) = { + val c = new TLBundleC(bundle) + c.opcode := TLMessages.ProbeAckData + c.param := reportPermissions + c.size := lgSize + c.source := UInt(0) + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := data + c.error := Bool(false) + c + } + + def GrantAck(toSink: UInt) = { + val e = new TLBundleE(bundle) + e.sink := toSink + e + } + + // Accesses + def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { + val legal = manager.supportsGet(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.Get + a.param := UInt(0) + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := fullMask(toAddress, lgSize) + a.data := UInt(0) + (legal, a) + } + + def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = { + val legal = manager.supportsPutFull(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.PutFullData + a.param := UInt(0) + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := fullMask(toAddress, lgSize) + a.data := data + (legal, a) + } + + def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + // !!! Monitor: check that wmask is contained in lgSize + val legal = manager.supportsPutPartial(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.PutPartialData + a.param := UInt(0) + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := wmask + a.data := data + (legal, a) + } + + def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + val legal = manager.supportsArithmetic(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.ArithmeticData + a.param := atomic + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := fullMask(toAddress, lgSize) + a.data := data + (legal, a) + } + + def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + val legal = manager.supportsLogical(toAddress, lgSize) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.LogicalData + a.param := atomic + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := fullMask(toAddress, lgSize) + a.data := data + (legal, a) + } + + def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { + val legal = manager.supportsHint(toAddress) + val a = new TLBundleA(bundle) + a.opcode := TLMessages.Hint + a.param := param + a.size := lgSize + a.source := fromSource + a.address := toAddress >> log2Up(manager.beatBytes) + a.wmask := fullMask(toAddress, lgSize) + a.data := UInt(0) + (legal, a) + } + + def AccessAck(toAddress: UInt, lgSize: UInt, error: Bool = Bool(false)) = { + val c = new TLBundleC(bundle) + c.opcode := TLMessages.AccessAck + c.param := UInt(0) + c.size := lgSize + c.source := UInt(0) + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := UInt(0) + c.error := error + c + } + + def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt) = { + val c = new TLBundleC(bundle) + c.opcode := TLMessages.AccessAckData + c.param := UInt(0) + c.size := lgSize + c.source := UInt(0) + c.address := toAddress >> log2Up(manager.beatBytes) + c.data := data + c.error := Bool(false) + c + } } class TLEdgeIn( @@ -34,18 +193,156 @@ class TLEdgeIn( extends TLEdgeParameters(client, manager) { // Transfers - def Probe(x: Int) = () // B - def Grant(x: Int) = () // D - def GrantData(x: Int) = () // D - def ReleaseAck(x: Int) = () // D + def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { + val legal = client.supportsProbe(fromAddress, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.Probe + b.param := capPermissions + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := UInt(0) + (legal, b) + } - // Accessors - def Get(x: Int) = () // B - def Put(x: Int) = () // B - def Atomic(x: Int) = () // B - def AccessAck(x: Int) = () // D - def AccessDataAck(x: Int) = () // D + def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.Grant + d.param := capPermissions + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.data := UInt(0) + d.error := Bool(false) + d + } - def Hint(x: Int) = () // B - def HintAck(x: Int) = () // D + def GrantData(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.GrantData + d.param := capPermissions + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.data := data + d.error := Bool(false) + d + } + + def ReleaseAck(toSource: UInt, lgSize: UInt) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.ReleaseAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := UInt(0) + d.data := UInt(0) + d.error := Bool(false) + d + } + + // Accesses + def Get(fromAddress: UInt, toSource: UInt, lgSize: UInt) = { + val legal = client.supportsGet(toSource, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.Get + b.param := UInt(0) + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := UInt(0) + (legal, b) + } + + def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt) = { + val legal = client.supportsPutFull(toSource, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.PutFullData + b.param := UInt(0) + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := data + (legal, b) + } + + def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + val legal = client.supportsPutPartial(toSource, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.PutPartialData + b.param := UInt(0) + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := wmask + b.data := data + (legal, b) + } + + def Arithmetic(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + val legal = client.supportsArithmetic(toSource, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.ArithmeticData + b.param := atomic + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := data + (legal, b) + } + + def Logical(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + val legal = client.supportsLogical(toSource, lgSize) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.LogicalData + b.param := atomic + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := data + (legal, b) + } + + def Hint(fromAddress: UInt, toSource: UInt, lgSize: UInt, param: UInt) = { + val legal = client.supportsHint(toSource) + val b = new TLBundleB(bundle) + b.opcode := TLMessages.Hint + b.param := param + b.size := lgSize + b.source := toSource + b.address := fromAddress >> log2Up(manager.beatBytes) + b.wmask := fullMask(fromAddress, lgSize) + b.data := UInt(0) + (legal, b) + } + + + def AccessAck(toSource: UInt, lgSize: UInt, error: Bool = Bool(false)) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.AccessAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := UInt(0) + d.data := UInt(0) + d.error := error + d + } + + def AccessAck(toSource: UInt, lgSize: UInt, data: UInt) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.AccessAckData + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := UInt(0) + d.data := data + d.error := Bool(false) + d + } } diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 5503b7fe..11afeee9 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -36,7 +36,7 @@ case class IdRange(start: Int, end: Int) def shift(x: Int) = IdRange(start+x, end+x) } -// An potentially empty inclusive range of 2-powers [min, max] +// An potentially empty inclusive range of 2-powers [min, max] (in bytes) case class TransferSizes(min: Int, max: Int) { def this(x: Int) = this(x, x) @@ -269,10 +269,19 @@ case class TLEdgeParameters( client: TLClientPortParameters, manager: TLManagerPortParameters) { + val maxTransfer = max(client.maxTransfer, manager.maxTransfer) + val maxLgSize = log2Up(maxTransfer) + val bundle = TLBundleParameters( addressBits = log2Up(manager.maxAddress + 1) - log2Up(manager.beatBytes), dataBits = manager.beatBytes * 8, sourceBits = log2Up(client.endSourceId), sinkBits = log2Up(manager.endSinkId), - sizeBits = log2Up(log2Up(max(client.maxTransfer, manager.maxTransfer))+1)) + sizeBits = log2Up(maxLgSize+1)) + + def addressMask(lgSize: UInt) = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } .toBits.asUInt + def isAligned(address: UInt, lgSize: UInt) = (address & addressMask(lgSize)) === UInt(0) + +// !!! wrong: + def fullMask(address: UInt, lgSize: UInt) = UInt(0) } From 8cff45f2542641189752e79a0fa6eac33da8b8ee Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 13:18:01 -0700 Subject: [PATCH 06/87] tilelink2: use byte-aligned addressing This makes it possible to fully validate user input in a monitor. We will override the lower bits with constant 0s in the TL connect. --- .../src/main/scala/tilelink2/Operations.scala | 45 +++++++++---------- .../src/main/scala/tilelink2/Parameters.scala | 33 +++++++++++--- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 8f1fd4ea..4a7aada5 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -11,16 +11,13 @@ class TLEdgeOut( { // Transfers def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { - // !!! Monitor: lgSize >= beatBytes - // !!! Monitor: check address alignment - // !!! Monitor: check param values val legal = manager.supportsAcquire(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.Acquire a.param := growPermissions a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := SInt(-1).asUInt a.data := UInt(0) (legal, a) @@ -33,7 +30,7 @@ class TLEdgeOut( c.param := shrinkPermissions c.size := lgSize c.source := fromSource - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := UInt(0) c.error := Bool(false) (legal, c) @@ -46,7 +43,7 @@ class TLEdgeOut( c.param := shrinkPermissions c.size := lgSize c.source := fromSource - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := data c.error := Bool(false) (legal, c) @@ -58,7 +55,7 @@ class TLEdgeOut( c.param := reportPermissions c.size := lgSize c.source := UInt(0) - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := UInt(0) c.error := Bool(false) c @@ -70,7 +67,7 @@ class TLEdgeOut( c.param := reportPermissions c.size := lgSize c.source := UInt(0) - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := data c.error := Bool(false) c @@ -90,7 +87,7 @@ class TLEdgeOut( a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := fullMask(toAddress, lgSize) a.data := UInt(0) (legal, a) @@ -103,21 +100,20 @@ class TLEdgeOut( a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := fullMask(toAddress, lgSize) a.data := data (legal, a) } def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { - // !!! Monitor: check that wmask is contained in lgSize val legal = manager.supportsPutPartial(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.PutPartialData a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := wmask a.data := data (legal, a) @@ -130,7 +126,7 @@ class TLEdgeOut( a.param := atomic a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := fullMask(toAddress, lgSize) a.data := data (legal, a) @@ -143,7 +139,7 @@ class TLEdgeOut( a.param := atomic a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := fullMask(toAddress, lgSize) a.data := data (legal, a) @@ -156,7 +152,7 @@ class TLEdgeOut( a.param := param a.size := lgSize a.source := fromSource - a.address := toAddress >> log2Up(manager.beatBytes) + a.address := toAddress a.wmask := fullMask(toAddress, lgSize) a.data := UInt(0) (legal, a) @@ -168,7 +164,7 @@ class TLEdgeOut( c.param := UInt(0) c.size := lgSize c.source := UInt(0) - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := UInt(0) c.error := error c @@ -180,7 +176,7 @@ class TLEdgeOut( c.param := UInt(0) c.size := lgSize c.source := UInt(0) - c.address := toAddress >> log2Up(manager.beatBytes) + c.address := toAddress c.data := data c.error := Bool(false) c @@ -200,7 +196,7 @@ class TLEdgeIn( b.param := capPermissions b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := UInt(0) (legal, b) @@ -250,7 +246,7 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := UInt(0) (legal, b) @@ -263,7 +259,7 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := data (legal, b) @@ -276,7 +272,7 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := wmask b.data := data (legal, b) @@ -289,7 +285,7 @@ class TLEdgeIn( b.param := atomic b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := data (legal, b) @@ -302,7 +298,7 @@ class TLEdgeIn( b.param := atomic b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := data (legal, b) @@ -315,13 +311,12 @@ class TLEdgeIn( b.param := param b.size := lgSize b.source := toSource - b.address := fromAddress >> log2Up(manager.beatBytes) + b.address := fromAddress b.wmask := fullMask(fromAddress, lgSize) b.data := UInt(0) (legal, b) } - def AccessAck(toSource: UInt, lgSize: UInt, error: Bool = Bool(false)) = { val d = new TLBundleD(bundle) d.opcode := TLMessages.AccessAck diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 11afeee9..e59a66bc 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -272,16 +272,39 @@ case class TLEdgeParameters( val maxTransfer = max(client.maxTransfer, manager.maxTransfer) val maxLgSize = log2Up(maxTransfer) + // Sanity check the link... + require (maxTransfer >= manager.beatBytes) + val bundle = TLBundleParameters( - addressBits = log2Up(manager.maxAddress + 1) - log2Up(manager.beatBytes), + addressBits = log2Up(manager.maxAddress + 1), dataBits = manager.beatBytes * 8, sourceBits = log2Up(client.endSourceId), sinkBits = log2Up(manager.endSinkId), sizeBits = log2Up(maxLgSize+1)) - def addressMask(lgSize: UInt) = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } .toBits.asUInt - def isAligned(address: UInt, lgSize: UInt) = (address & addressMask(lgSize)) === UInt(0) + def isAligned(address: UInt, lgSize: UInt) = + if (maxLgSize == 0) Bool(true) else { + val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } + address & mask.toBits.asUInt === UInt(0) + } -// !!! wrong: - def fullMask(address: UInt, lgSize: UInt) = UInt(0) + // This gets used everywhere, so make the smallest circuit possible ... + def fullMask(address: UInt, lgSize: UInt) = { + val lgBytes = log2Ceil(manager.beatBytes) + def helper(i: Int): Seq[(Bool, Bool)] = { + if (i == 0) { + Seq((lgSize >= UInt(lgBytes), Bool(true))) + } else { + val sub = helper(i-1) + val size = lgSize === UInt(lgBytes - i) + Seq.tabulate (1 << i) { j => + val (sub_acc, sub_eq) = sub(j/2) + val eq = sub_eq && address(lgBytes - i) === Bool(j % 2 == 1) + val acc = sub_acc || (size && eq) + (acc, eq) + } + } + } + Vec(helper(lgBytes).map(_._1)).toBits.asUInt + } } From 6599bcb77bfd1dc30f281bc524baf5fe917b2830 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 13:28:52 -0700 Subject: [PATCH 07/87] tilelink2: statically check Operations are remotely plausible --- .../src/main/scala/tilelink2/Operations.scala | 16 ++++++++++++++++ .../src/main/scala/tilelink2/Parameters.scala | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 4a7aada5..6291e03d 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -11,6 +11,7 @@ class TLEdgeOut( { // Transfers def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { + require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.Acquire @@ -24,6 +25,7 @@ class TLEdgeOut( } def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = { + require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) val c = new TLBundleC(bundle) c.opcode := TLMessages.Release @@ -37,6 +39,7 @@ class TLEdgeOut( } def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = { + require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) val c = new TLBundleC(bundle) c.opcode := TLMessages.ReleaseData @@ -81,6 +84,7 @@ class TLEdgeOut( // Accesses def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { + require (manager.anySupportGet) val legal = manager.supportsGet(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.Get @@ -94,6 +98,7 @@ class TLEdgeOut( } def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = { + require (manager.anySupportPutFull) val legal = manager.supportsPutFull(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.PutFullData @@ -107,6 +112,7 @@ class TLEdgeOut( } def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + require (manager.anySupportPutPartial) val legal = manager.supportsPutPartial(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.PutPartialData @@ -120,6 +126,7 @@ class TLEdgeOut( } def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + require (manager.anySupportArithmetic) val legal = manager.supportsArithmetic(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.ArithmeticData @@ -133,6 +140,7 @@ class TLEdgeOut( } def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + require (manager.anySupportLogical) val legal = manager.supportsLogical(toAddress, lgSize) val a = new TLBundleA(bundle) a.opcode := TLMessages.LogicalData @@ -146,6 +154,7 @@ class TLEdgeOut( } def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { + require (manager.anySupportHint) val legal = manager.supportsHint(toAddress) val a = new TLBundleA(bundle) a.opcode := TLMessages.Hint @@ -190,6 +199,7 @@ class TLEdgeIn( { // Transfers def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { + require (client.anySupportProbe) val legal = client.supportsProbe(fromAddress, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.Probe @@ -240,6 +250,7 @@ class TLEdgeIn( // Accesses def Get(fromAddress: UInt, toSource: UInt, lgSize: UInt) = { + require (client.anySupportGet) val legal = client.supportsGet(toSource, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.Get @@ -253,6 +264,7 @@ class TLEdgeIn( } def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt) = { + require (client.anySupportPutFull) val legal = client.supportsPutFull(toSource, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.PutFullData @@ -266,6 +278,7 @@ class TLEdgeIn( } def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + require (client.anySupportPutPartial) val legal = client.supportsPutPartial(toSource, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.PutPartialData @@ -279,6 +292,7 @@ class TLEdgeIn( } def Arithmetic(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + require (client.anySupportArithmetic) val legal = client.supportsArithmetic(toSource, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.ArithmeticData @@ -292,6 +306,7 @@ class TLEdgeIn( } def Logical(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { + require (client.anySupportLogical) val legal = client.supportsLogical(toSource, lgSize) val b = new TLBundleB(bundle) b.opcode := TLMessages.LogicalData @@ -305,6 +320,7 @@ class TLEdgeIn( } def Hint(fromAddress: UInt, toSource: UInt, lgSize: UInt, param: UInt) = { + require (client.anySupportHint) val legal = client.supportsHint(toSource) val b = new TLBundleB(bundle) b.opcode := TLMessages.Hint diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index e59a66bc..f481b9ea 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -147,6 +147,15 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes val allSupportPutPartial = managers.map(_.supportsPutPartial).reduce(_ intersect _) val allSupportHint = managers.map(_.supportsHint) .reduce(_ && _) + // Operation supported by at least one outward Managers + val anySupportAcquire = managers.map(!_.supportsAcquire.none) .reduce(_ || _) + val anySupportArithmetic = managers.map(!_.supportsArithmetic.none).reduce(_ || _) + val anySupportLogical = managers.map(!_.supportsLogical.none) .reduce(_ || _) + val anySupportGet = managers.map(!_.supportsGet.none) .reduce(_ || _) + val anySupportPutFull = managers.map(!_.supportsPutFull.none) .reduce(_ || _) + val anySupportPutPartial = managers.map(!_.supportsPutPartial.none).reduce(_ || _) + val anySupportHint = managers.map( _.supportsHint) .reduce(_ || _) + // These return Option[TLManagerParameters] for your convenience def find(address: BigInt) = managers.find(_.address.exists(_.contains(address))) def findById(id: Int) = managers.find(_.sinkId.contains(id)) @@ -216,6 +225,15 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val allSupportPutPartial = clients.map(_.supportsPutPartial).reduce(_ intersect _) val allSupportHint = clients.map(_.supportsHint) .reduce(_ && _) + // Operation is supported by at least one client + val anySupportProbe = clients.map(!_.supportsProbe.none) .reduce(_ || _) + val anySupportArithmetic = clients.map(!_.supportsArithmetic.none).reduce(_ || _) + val anySupportLogical = clients.map(!_.supportsLogical.none) .reduce(_ || _) + val anySupportGet = clients.map(!_.supportsGet.none) .reduce(_ || _) + val anySupportPutFull = clients.map(!_.supportsPutFull.none) .reduce(_ || _) + val anySupportPutPartial = clients.map(!_.supportsPutPartial.none).reduce(_ || _) + val anySupportHint = clients.map( _.supportsHint) .reduce(_ || _) + // These return Option[TLClientParameters] for your convenience def find(id: Int) = clients.find(_.sourceId.contains(id)) From 492a38aedcdf179b743456a02321c359673549db Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 15:36:39 -0700 Subject: [PATCH 08/87] tilelink2: only accesses can have errors (release must make forward progress) --- uncore/src/main/scala/tilelink2/Bundles.scala | 33 +++++++++++----- .../src/main/scala/tilelink2/Operations.scala | 39 ++++++++++++------- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index a28a3e7f..503a685b 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -30,17 +30,23 @@ object TLMessages val Hint = UInt(5) // . . val AccessAck = UInt(0) // . . val AccessAckData = UInt(1) // . . + val AccessAckError = UInt(2) // . . val Acquire = UInt(6) // . val Probe = UInt(6) // . - val ProbeAck = UInt(2) // . - val ProbeAckData = UInt(3) // . - val Release = UInt(4) // . - val ReleaseData = UInt(5) // . -//val PutThroughData = UInt(6) // . // future extension - val ReleaseAck = UInt(2) // . - val Grant = UInt(3) // . - val GrantData = UInt(4) // . + val ProbeAck = UInt(3) // . + val ProbeAckData = UInt(4) // . + val Release = UInt(5) // . + val ReleaseData = UInt(6) // . +//val PutThroughData = UInt(7) // . // future extension + val ReleaseAck = UInt(3) // . + val Grant = UInt(4) // . + val GrantData = UInt(5) // . val GrantAck = UInt(0) // . + + def isA(x: UInt) = x <= Acquire + def isB(x: UInt) = x <= Probe + def isC(x: UInt) = x <= ReleaseData + def isD(x: UInt) = x <= GrantData } object TLPermissions @@ -49,25 +55,34 @@ object TLPermissions val toT = UInt(0) val toB = UInt(1) val toN = UInt(2) + def isCap(x: UInt) = x <= toN // Grow types (Acquire = permissions >= target) val NtoB = UInt(0) val NtoT = UInt(1) val BtoT = UInt(2) + def isGrow(x: UInt) = x <= BtoT // Shrink types (ProbeAck, Release) val TtoB = UInt(0) val TtoN = UInt(1) val BtoN = UInt(2) + def isShrink(x: UInt) = x <= BtoN // Report types (ProbeAck) val TtoT = UInt(3) val BtoB = UInt(4) val NtoN = UInt(5) + def isReport(x: UInt) = x <= NtoN } object TLAtomics { + // Arithmetic types + def isArithmetic(x: UInt) = Bool(true) + + // Logical types + def isLogical(x: UInt) = Bool(true) } class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) @@ -100,7 +115,6 @@ class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to val data = UInt(width = params.dataBits) - val error = Bool() } class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) @@ -111,7 +125,6 @@ class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from val data = UInt(width = params.dataBits) - val error = Bool() } class TLBundleE(params: TLBundleParameters) extends TLBundleBase(params) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 6291e03d..476421a1 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -34,7 +34,6 @@ class TLEdgeOut( c.source := fromSource c.address := toAddress c.data := UInt(0) - c.error := Bool(false) (legal, c) } @@ -48,7 +47,6 @@ class TLEdgeOut( c.source := fromSource c.address := toAddress c.data := data - c.error := Bool(false) (legal, c) } @@ -60,7 +58,6 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := UInt(0) - c.error := Bool(false) c } @@ -72,7 +69,6 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := data - c.error := Bool(false) c } @@ -167,7 +163,7 @@ class TLEdgeOut( (legal, a) } - def AccessAck(toAddress: UInt, lgSize: UInt, error: Bool = Bool(false)) = { + def AccessAck(toAddress: UInt, lgSize: UInt) = { val c = new TLBundleC(bundle) c.opcode := TLMessages.AccessAck c.param := UInt(0) @@ -175,7 +171,17 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := UInt(0) - c.error := error + c + } + + def AccessAckError(toAddress: UInt, lgSize: UInt) = { + val c = new TLBundleC(bundle) + c.opcode := TLMessages.AccessAckError + c.param := UInt(0) + c.size := lgSize + c.source := UInt(0) + c.address := toAddress + c.data := UInt(0) c } @@ -187,7 +193,6 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := data - c.error := Bool(false) c } } @@ -207,7 +212,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.wmask := SInt(-1).asUInt b.data := UInt(0) (legal, b) } @@ -220,7 +225,6 @@ class TLEdgeIn( d.source := toSource d.sink := fromSink d.data := UInt(0) - d.error := Bool(false) d } @@ -232,7 +236,6 @@ class TLEdgeIn( d.source := toSource d.sink := fromSink d.data := data - d.error := Bool(false) d } @@ -244,7 +247,6 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := UInt(0) - d.error := Bool(false) d } @@ -333,7 +335,7 @@ class TLEdgeIn( (legal, b) } - def AccessAck(toSource: UInt, lgSize: UInt, error: Bool = Bool(false)) = { + def AccessAck(toSource: UInt, lgSize: UInt) = { val d = new TLBundleD(bundle) d.opcode := TLMessages.AccessAck d.param := UInt(0) @@ -341,7 +343,17 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := UInt(0) - d.error := error + d + } + + def AccessAckError(toSource: UInt, lgSize: UInt) = { + val d = new TLBundleD(bundle) + d.opcode := TLMessages.AccessAckError + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := UInt(0) + d.data := UInt(0) d } @@ -353,7 +365,6 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := data - d.error := Bool(false) d } } From d7e839280f42f811aae0d79de447799dc0fdc463 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 15:37:30 -0700 Subject: [PATCH 09/87] tilelink2: include legal message monitor --- uncore/src/main/scala/tilelink2/Bases.scala | 1 + uncore/src/main/scala/tilelink2/Monitor.scala | 244 ++++++++++++++++++ .../src/main/scala/tilelink2/Parameters.scala | 12 +- 3 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 uncore/src/main/scala/tilelink2/Monitor.scala diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index 64e30679..3f1f59c3 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -29,6 +29,7 @@ abstract class TLFactory } } bindings.foreach { case (x, i, y, j, s) => + TLMonitor.legalize(y.bundleOut(j), y.edgesOut(j), x.bundleIn(i), x.edgesIn(i), s) x.bundleIn(i).<>(y.bundleOut(j))(s) } } diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala new file mode 100644 index 00000000..f91a3063 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -0,0 +1,244 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo + +object TLMonitor +{ + def legalizeA(bundle: TLBundleA, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode")(sourceInfo) + + when (bundle.opcode === TLMessages.Acquire) { + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel Acquire carries invalid source ID")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Acquire address not aligned to size")(sourceInfo) + assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param")(sourceInfo) + assert (bundle.wmask === SInt(-1).asUInt, "'A' channel Acquire contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Get) { + assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel Get carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Get address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'A' channel Get carries invalid param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Get contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.PutFullData) { + assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel PutFull carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel PutFull address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel PutFull contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.PutPartialData) { + assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel PutPartial carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel PutPartial address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param")(sourceInfo) + assert ((bundle.wmask & ~edge.fullMask(bundle.address, bundle.size)) === UInt(0), "'A' channel PutPartial contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.ArithmeticData) { + assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel Arithmetic carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Arithmetic address not aligned to size")(sourceInfo) + assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Arithmetic contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.LogicalData) { + assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel Logical carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Logical address not aligned to size")(sourceInfo) + assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Logical contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Hint) { + assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'A' channel Hint carries invalid source ID")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Hint address not aligned to size")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Hint contains invalid wmask")(sourceInfo) + } + } + + def legalizeB(bundle: TLBundleB, edge: TLEdgeIn, sourceInfo: SourceInfo) = { + assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode")(sourceInfo) + + when (bundle.opcode === TLMessages.Probe) { + assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel Probe carries unmanaged address")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Probe address not aligned to size")(sourceInfo) + assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param")(sourceInfo) + assert (bundle.wmask === SInt(-1).asUInt, "'B' channel Probe contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Get) { + assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel Get carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Get address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'B' channel Get carries invalid param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Get contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.PutFullData) { + assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel PutFull carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel PutFull address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel PutFull contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.PutPartialData) { + assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel PutPartial carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel PutPartial address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param")(sourceInfo) + assert ((bundle.wmask & ~edge.fullMask(bundle.address, bundle.size)) === UInt(0), "'B' channel PutPartial contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.ArithmeticData) { + assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel Arithmetic carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Arithmetic address not aligned to size")(sourceInfo) + assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Arithmetic contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.LogicalData) { + assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel Logical carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Logical address not aligned to size")(sourceInfo) + assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Logical contains invalid wmask")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Hint) { + assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client")(sourceInfo) + assert (edge.manager.contains(bundle.address), "'B' channel Hint carries unmanaged address")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Hint address not aligned to size")(sourceInfo) + assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Hint contains invalid wmask")(sourceInfo) + } + } + + def legalizeC(bundle: TLBundleC, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode")(sourceInfo) + + when (bundle.opcode === TLMessages.ProbeAck) { + assert (edge.manager.contains(bundle.address), "'C' channel ProbeAck carries unmanaged address")(sourceInfo) + // source is ignored + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ProbeAck address not aligned to size")(sourceInfo) + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.ProbeAckData) { + assert (edge.manager.contains(bundle.address), "'C' channel ProbeAckData carries unmanaged address")(sourceInfo) + // source is ignored + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ProbeAckData address not aligned to size")(sourceInfo) + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Release) { + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'C' channel Release carries invalid source ID")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel Release address not aligned to size")(sourceInfo) + assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.ReleaseData) { + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager")(sourceInfo) + assert (edge.client.contains(bundle.source), "'C' channel ReleaseData carries invalid source ID")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat")(sourceInfo) + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ReleaseData address not aligned to size")(sourceInfo) + assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAck) { + assert (edge.manager.contains(bundle.address), "'C' channel AccessAck carries unmanaged address")(sourceInfo) + // source is ignored + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAck address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAckError) { + assert (edge.manager.contains(bundle.address), "'C' channel AccessAckError carries unmanaged address")(sourceInfo) + // source is ignored + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAckError address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'C' channel AccessAckError carries invalid param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAckData) { + assert (edge.manager.contains(bundle.address), "'C' channel AccessAckData carries unmanaged address")(sourceInfo) + // source is ignored + assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAckData address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param")(sourceInfo) + } + } + + def legalizeD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { + assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode")(sourceInfo) + + when (bundle.opcode === TLMessages.ReleaseAck) { + assert (edge.client.contains(bundle.source), "'D' channel ReleaseAck carries invalid source ID")(sourceInfo) + // sink is ignored + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat")(sourceInfo) + assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.Grant) { + assert (edge.client.contains(bundle.source), "'D' channel Grant carries invalid source ID")(sourceInfo) + assert (edge.manager.contains(bundle.sink), "'D' channel Grant carries invalid sink ID")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat")(sourceInfo) + assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.GrantData) { + assert (edge.client.contains(bundle.source), "'D' channel GrantData carries invalid source ID")(sourceInfo) + assert (edge.manager.contains(bundle.sink), "'D' channel GrantData carries invalid sink ID")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat")(sourceInfo) + assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAck) { + assert (edge.client.contains(bundle.source), "'D' channel AccessAck carries invalid source ID")(sourceInfo) + // sink is ignored + // size is ignored + assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAckError) { + assert (edge.client.contains(bundle.source), "'D' channel AccessAckError carries invalid source ID")(sourceInfo) + // sink is ignored + // size is ignored + assert (bundle.param === UInt(0), "'D' channel AccessAckError carries invalid param")(sourceInfo) + } + + when (bundle.opcode === TLMessages.AccessAckData) { + assert (edge.client.contains(bundle.source), "'D' channel AccessAckData carries invalid source ID")(sourceInfo) + // sink is ignored + // size is ignored + assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param")(sourceInfo) + } + } + + def legalizeE(bundle: TLBundleE, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID")(sourceInfo) + } + + def legalize(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { + when (bundleOut.a.valid) { legalizeA(bundleOut.a.bits, edgeOut, sourceInfo) } + when (bundleIn .b.valid) { legalizeB(bundleIn .b.bits, edgeIn, sourceInfo) } + when (bundleOut.c.valid) { legalizeC(bundleOut.c.bits, edgeOut, sourceInfo) } + when (bundleIn .d.valid) { legalizeD(bundleIn .d.bits, edgeIn, sourceInfo) } + when (bundleOut.e.valid) { legalizeE(bundleOut.e.bits, edgeOut, sourceInfo) } + } +} diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index f481b9ea..5658a116 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -73,7 +73,7 @@ case class AddressSet(mask: BigInt, base: Option[BigInt] = None) require (base == None || (base.get & mask) == 0) def contains(x: BigInt) = ((x ^ base.get) & ~mask) == 0 - def contains(x: UInt) = ((x ^ UInt(base.get)) & UInt(~mask)) === UInt(0) + def contains(x: UInt) = ((x ^ UInt(base.get)) & ~UInt(mask)) === UInt(0) // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) // if base = None, it will be auto-assigned and thus not overlap anything @@ -241,8 +241,8 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { def find(id: UInt) = Vec(clients.map(_.sourceId.contains(id))) def contains(id: UInt) = find(id).reduce(_ || _) - private def safety_helper(member: TLClientParameters => TransferSizes)(address: UInt, lgSize: UInt) = { - (find(address) zip clients.map(member(_).containsLg(lgSize))) + private def safety_helper(member: TLClientParameters => TransferSizes)(id: UInt, lgSize: UInt) = { + (find(id) zip clients.map(member(_).containsLg(lgSize))) .map { case (m, s) => m && s } reduce (_ || _) } @@ -253,8 +253,8 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val supportsGet = safety_helper(_.supportsGet) _ val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ - def supportsHint(address: UInt) = { - (find(address) zip clients.map(_.supportsHint)) + def supportsHint(id: UInt) = { + (find(id) zip clients.map(_.supportsHint)) .map { case (m, b) => m && Bool(b) } reduce (_ || _) } } @@ -303,7 +303,7 @@ case class TLEdgeParameters( def isAligned(address: UInt, lgSize: UInt) = if (maxLgSize == 0) Bool(true) else { val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } - address & mask.toBits.asUInt === UInt(0) + (address & mask.toBits.asUInt) === UInt(0) } // This gets used everywhere, so make the smallest circuit possible ... From af295959797230cc9d636e12d89e7cde317215d9 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 16:03:26 -0700 Subject: [PATCH 10/87] tilelink2: eliminate common subexpressions in Monitor to reduce firrtl output --- uncore/src/main/scala/tilelink2/Monitor.scala | 141 ++++++++++-------- 1 file changed, 79 insertions(+), 62 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index f91a3063..bd8863bf 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -9,177 +9,191 @@ object TLMonitor { def legalizeA(bundle: TLBundleA, edge: TLEdgeOut, sourceInfo: SourceInfo) = { assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode")(sourceInfo) + + // Reuse these subexpressions to save some firrtl lines + val source_ok = edge.client.contains(bundle.source) + val is_aligned = edge.isAligned(bundle.address, bundle.size) + val wmask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Acquire) { assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel Acquire carries invalid source ID")(sourceInfo) + assert (source_ok, "'A' channel Acquire carries invalid source ID")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Acquire address not aligned to size")(sourceInfo) + assert (is_aligned, "'A' channel Acquire address not aligned to size")(sourceInfo) assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param")(sourceInfo) assert (bundle.wmask === SInt(-1).asUInt, "'A' channel Acquire contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.Get) { assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel Get carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Get address not aligned to size")(sourceInfo) + assert (source_ok, "'A' channel Get carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel Get address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel Get carries invalid param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Get contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel Get contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.PutFullData) { assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel PutFull carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel PutFull address not aligned to size")(sourceInfo) + assert (source_ok, "'A' channel PutFull carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel PutFull address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel PutFull contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel PutFull contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.PutPartialData) { assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel PutPartial carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel PutPartial address not aligned to size")(sourceInfo) + assert (source_ok, "'A' channel PutPartial carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel PutPartial address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.wmask & ~edge.fullMask(bundle.address, bundle.size)) === UInt(0), "'A' channel PutPartial contains invalid wmask")(sourceInfo) + assert ((bundle.wmask & ~wmask) === UInt(0), "'A' channel PutPartial contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.ArithmeticData) { assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel Arithmetic carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Arithmetic address not aligned to size")(sourceInfo) + assert (source_ok, "'A' channel Arithmetic carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel Arithmetic address not aligned to size")(sourceInfo) assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Arithmetic contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel Arithmetic contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.LogicalData) { assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel Logical carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Logical address not aligned to size")(sourceInfo) + assert (source_ok, "'A' channel Logical carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel Logical address not aligned to size")(sourceInfo) assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Logical contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel Logical contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.Hint) { assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'A' channel Hint carries invalid source ID")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'A' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Hint contains invalid wmask")(sourceInfo) + assert (source_ok, "'A' channel Hint carries invalid source ID")(sourceInfo) + assert (is_aligned, "'A' channel Hint address not aligned to size")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel Hint contains invalid wmask")(sourceInfo) } } def legalizeB(bundle: TLBundleB, edge: TLEdgeIn, sourceInfo: SourceInfo) = { assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode")(sourceInfo) + // Reuse these subexpressions to save some firrtl lines + val address_ok = edge.manager.contains(bundle.source) + val is_aligned = edge.isAligned(bundle.address, bundle.size) + val wmask = edge.fullMask(bundle.address, bundle.size) + when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel Probe carries unmanaged address")(sourceInfo) + assert (address_ok, "'B' channel Probe carries unmanaged address")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Probe address not aligned to size")(sourceInfo) + assert (is_aligned, "'B' channel Probe address not aligned to size")(sourceInfo) assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param")(sourceInfo) assert (bundle.wmask === SInt(-1).asUInt, "'B' channel Probe contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.Get) { assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel Get carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Get address not aligned to size")(sourceInfo) + assert (address_ok, "'B' channel Get carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel Get address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel Get carries invalid param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'A' channel Get contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'A' channel Get contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.PutFullData) { assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel PutFull carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel PutFull address not aligned to size")(sourceInfo) + assert (address_ok, "'B' channel PutFull carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel PutFull address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel PutFull contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'B' channel PutFull contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.PutPartialData) { assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel PutPartial carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel PutPartial address not aligned to size")(sourceInfo) + assert (address_ok, "'B' channel PutPartial carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel PutPartial address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.wmask & ~edge.fullMask(bundle.address, bundle.size)) === UInt(0), "'B' channel PutPartial contains invalid wmask")(sourceInfo) + assert ((bundle.wmask & ~wmask) === UInt(0), "'B' channel PutPartial contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.ArithmeticData) { assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel Arithmetic carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Arithmetic address not aligned to size")(sourceInfo) + assert (address_ok, "'B' channel Arithmetic carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel Arithmetic address not aligned to size")(sourceInfo) assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Arithmetic contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'B' channel Arithmetic contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.LogicalData) { assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel Logical carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Logical address not aligned to size")(sourceInfo) + assert (address_ok, "'B' channel Logical carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel Logical address not aligned to size")(sourceInfo) assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Logical contains invalid wmask")(sourceInfo) + assert (bundle.wmask === wmask, "'B' channel Logical contains invalid wmask")(sourceInfo) } when (bundle.opcode === TLMessages.Hint) { assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client")(sourceInfo) - assert (edge.manager.contains(bundle.address), "'B' channel Hint carries unmanaged address")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'B' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.wmask === edge.fullMask(bundle.address, bundle.size), "'B' channel Hint contains invalid wmask")(sourceInfo) + assert (address_ok, "'B' channel Hint carries unmanaged address")(sourceInfo) + assert (is_aligned, "'B' channel Hint address not aligned to size")(sourceInfo) + assert (bundle.wmask === wmask, "'B' channel Hint contains invalid wmask")(sourceInfo) } } def legalizeC(bundle: TLBundleC, edge: TLEdgeOut, sourceInfo: SourceInfo) = { assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode")(sourceInfo) + val source_ok = edge.client.contains(bundle.source) + val is_aligned = edge.isAligned(bundle.address, bundle.size) + val address_ok = edge.manager.contains(bundle.source) + when (bundle.opcode === TLMessages.ProbeAck) { - assert (edge.manager.contains(bundle.address), "'C' channel ProbeAck carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel ProbeAck carries unmanaged address")(sourceInfo) // source is ignored assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ProbeAck address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel ProbeAck address not aligned to size")(sourceInfo) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param")(sourceInfo) } when (bundle.opcode === TLMessages.ProbeAckData) { - assert (edge.manager.contains(bundle.address), "'C' channel ProbeAckData carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel ProbeAckData carries unmanaged address")(sourceInfo) // source is ignored assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ProbeAckData address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel ProbeAckData address not aligned to size")(sourceInfo) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param")(sourceInfo) } when (bundle.opcode === TLMessages.Release) { assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'C' channel Release carries invalid source ID")(sourceInfo) + assert (source_ok, "'C' channel Release carries invalid source ID")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel Release address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel Release address not aligned to size")(sourceInfo) assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param")(sourceInfo) } when (bundle.opcode === TLMessages.ReleaseData) { assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager")(sourceInfo) - assert (edge.client.contains(bundle.source), "'C' channel ReleaseData carries invalid source ID")(sourceInfo) + assert (source_ok, "'C' channel ReleaseData carries invalid source ID")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat")(sourceInfo) - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel ReleaseData address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel ReleaseData address not aligned to size")(sourceInfo) assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAck) { - assert (edge.manager.contains(bundle.address), "'C' channel AccessAck carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel AccessAck carries unmanaged address")(sourceInfo) // source is ignored - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAck address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel AccessAck address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAckError) { - assert (edge.manager.contains(bundle.address), "'C' channel AccessAckError carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel AccessAckError carries unmanaged address")(sourceInfo) // source is ignored - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAckError address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel AccessAckError address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'C' channel AccessAckError carries invalid param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAckData) { - assert (edge.manager.contains(bundle.address), "'C' channel AccessAckData carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel AccessAckData carries unmanaged address")(sourceInfo) // source is ignored - assert (edge.isAligned(bundle.address, bundle.size), "'C' channel AccessAckData address not aligned to size")(sourceInfo) + assert (is_aligned, "'C' channel AccessAckData address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param")(sourceInfo) } } @@ -187,43 +201,46 @@ object TLMonitor def legalizeD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode")(sourceInfo) + val source_ok = edge.client.contains(bundle.source) + val sink_ok = edge.manager.containsById(bundle.sink) + when (bundle.opcode === TLMessages.ReleaseAck) { - assert (edge.client.contains(bundle.source), "'D' channel ReleaseAck carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel ReleaseAck carries invalid source ID")(sourceInfo) // sink is ignored assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat")(sourceInfo) assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param")(sourceInfo) } when (bundle.opcode === TLMessages.Grant) { - assert (edge.client.contains(bundle.source), "'D' channel Grant carries invalid source ID")(sourceInfo) - assert (edge.manager.contains(bundle.sink), "'D' channel Grant carries invalid sink ID")(sourceInfo) + assert (source_ok, "'D' channel Grant carries invalid source ID")(sourceInfo) + assert (sink_ok, "'D' channel Grant carries invalid sink ID")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat")(sourceInfo) assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param")(sourceInfo) } when (bundle.opcode === TLMessages.GrantData) { - assert (edge.client.contains(bundle.source), "'D' channel GrantData carries invalid source ID")(sourceInfo) - assert (edge.manager.contains(bundle.sink), "'D' channel GrantData carries invalid sink ID")(sourceInfo) + assert (source_ok, "'D' channel GrantData carries invalid source ID")(sourceInfo) + assert (sink_ok, "'D' channel GrantData carries invalid sink ID")(sourceInfo) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat")(sourceInfo) assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAck) { - assert (edge.client.contains(bundle.source), "'D' channel AccessAck carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel AccessAck carries invalid source ID")(sourceInfo) // sink is ignored // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAckError) { - assert (edge.client.contains(bundle.source), "'D' channel AccessAckError carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel AccessAckError carries invalid source ID")(sourceInfo) // sink is ignored // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAckError carries invalid param")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAckData) { - assert (edge.client.contains(bundle.source), "'D' channel AccessAckData carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel AccessAckData carries invalid source ID")(sourceInfo) // sink is ignored // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param")(sourceInfo) From 9c62f5d9c1f1532fb70bd61b5b4f446a28bfcc76 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 22 Aug 2016 16:43:00 -0700 Subject: [PATCH 11/87] tilelink2: shave off a few more firrtl monitor lines --- uncore/src/main/scala/tilelink2/Parameters.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 5658a116..addc2991 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -315,9 +315,11 @@ case class TLEdgeParameters( } else { val sub = helper(i-1) val size = lgSize === UInt(lgBytes - i) + val bit = address(lgBytes - i) + val nbit = !bit Seq.tabulate (1 << i) { j => val (sub_acc, sub_eq) = sub(j/2) - val eq = sub_eq && address(lgBytes - i) === Bool(j % 2 == 1) + val eq = sub_eq && (if (j % 2 == 1) bit else nbit) val acc = sub_acc || (size && eq) (acc, eq) } From 1cd85ff0507f06743f12019447105611dbaad566 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 23 Aug 2016 16:23:35 -0700 Subject: [PATCH 12/87] tilelink2: add some bundle introspection to scaffold the xbar --- uncore/src/main/scala/tilelink2/Bundles.scala | 112 +++++++++++++++--- .../src/main/scala/tilelink2/Operations.scala | 47 +++++++- .../src/main/scala/tilelink2/Parameters.scala | 39 ++---- 3 files changed, 147 insertions(+), 51 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 503a685b..9cc724e1 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -19,28 +19,32 @@ abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle } } +// common combos in lazy policy: +// Put + Acquire +// Release + AccessAck + object TLMessages { // A B C D E - val Get = UInt(0) // . . - val PutFullData = UInt(1) // . . - val PutPartialData = UInt(2) // . . - val ArithmeticData = UInt(3) // . . - val LogicalData = UInt(4) // . . + val PutFullData = UInt(0) // . . + val PutPartialData = UInt(1) // . . + val ArithmeticData = UInt(2) // . . + val LogicalData = UInt(3) // . . + val Get = UInt(4) // . . val Hint = UInt(5) // . . val AccessAck = UInt(0) // . . val AccessAckData = UInt(1) // . . - val AccessAckError = UInt(2) // . . + val AccessAckError = UInt(6) // . . val Acquire = UInt(6) // . val Probe = UInt(6) // . - val ProbeAck = UInt(3) // . - val ProbeAckData = UInt(4) // . - val Release = UInt(5) // . - val ReleaseData = UInt(6) // . -//val PutThroughData = UInt(7) // . // future extension - val ReleaseAck = UInt(3) // . - val Grant = UInt(4) // . - val GrantData = UInt(5) // . + val ProbeAck = UInt(2) // . + val ProbeAckData = UInt(3) // . + val Release = UInt(4) // . + val ReleaseData = UInt(5) // . +//val PutThroughData = UInt(7) // . // future extension ? + val Grant = UInt(2) // . + val GrantData = UInt(3) // . + val ReleaseAck = UInt(4) // . val GrantAck = UInt(0) // . def isA(x: UInt) = x <= Acquire @@ -85,7 +89,28 @@ object TLAtomics def isLogical(x: UInt) = Bool(true) } -class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) +trait HasTLOpcode +{ + // The data field in this message has value + def hasData(x: Int=0): Bool + // This message requires a response + def hasFollowUp(x: Int=0): Bool + // The size field of the opcode + def size(x: Int=0): UInt +} + +trait HasTLData extends HasTLOpcode +{ + def data(x: Int=0): UInt + def wmask(x: Int=0): UInt +} + +// !!! trait HasTLSource|Sink|Address +// !!! trait param: from and to perms + +class TLBundleA(params: TLBundleParameters) + extends TLBundleBase(params) + with HasTLData { val opcode = UInt(width = 3) val param = UInt(width = 3) // amo_opcode || perms || hint @@ -94,9 +119,21 @@ class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) val address = UInt(width = params.addressBits) // to val wmask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) + + def hasData(x: Int=0) = !opcode(2) +// opcode === TLMessages.PutFullData || +// opcode === TLMessages.PutPartialData || +// opcode === TLMessages.ArithmeticData || +// opcode === TLMessages.LogicalData + def hasFollowUp(x: Int=0) = Bool(true) + def size(x: Int=0) = size + def data(x: Int=0) = data + def wmask(x: Int=0) = wmask } -class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) +class TLBundleB(params: TLBundleParameters) + extends TLBundleBase(params) + with HasTLData { val opcode = UInt(width = 3) val param = UInt(width = 3) @@ -105,9 +142,17 @@ class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) val address = UInt(width = params.addressBits) // from val wmask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) + + def hasData(x: Int=0) = !opcode(2) + def hasFollowUp(x: Int=0) = Bool(true) + def size(x: Int=0) = size + def data(x: Int=0) = data + def wmask(x: Int=0) = wmask } -class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) +class TLBundleC(params: TLBundleParameters) + extends TLBundleBase(params) + with HasTLData { val opcode = UInt(width = 3) val param = UInt(width = 3) @@ -115,9 +160,22 @@ class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to val data = UInt(width = params.dataBits) + + def hasData(x: Int=0) = opcode(0) +// opcode === TLMessages.AccessAckData || +// opcode === TLMessages.ProbeAckData || +// opcode === TLMessages.ReleaseData + def hasFollowUp(x: Int=0) = opcode(2) && !opcode(1) +// opcode === TLMessages.Release || +// opcode === TLMessages.ReleaseData + def size(x: Int=0) = size + def data(x: Int=0) = data + def wmask(x: Int=0) = SInt(-1, width = params.dataBits/8).asUInt } -class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) +class TLBundleD(params: TLBundleParameters) + extends TLBundleBase(params) + with HasTLData { val opcode = UInt(width = 3) val param = UInt(width = 2) @@ -125,11 +183,27 @@ class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from val data = UInt(width = params.dataBits) + + def hasData(x: Int=0) = opcode(0) +// opcode === TLMessages.AccessAckData || +// opcode === TLMessages.GrantData + def hasFollowUp(x: Int=0) = !opcode(2) && opcode(1) +// opcode === TLMessages.Grant || +// opcode === TLMessages.GrantData + def size(x: Int=0) = size + def data(x: Int=0) = data + def wmask(x: Int=0) = SInt(-1, width = params.dataBits/8).asUInt } -class TLBundleE(params: TLBundleParameters) extends TLBundleBase(params) +class TLBundleE(params: TLBundleParameters) + extends TLBundleBase(params) + with HasTLOpcode { val sink = UInt(width = params.sourceBits) // to + + def hasData(x: Int=0) = Bool(false) + def hasFollowUp(x: Int=0) = Bool(false) + def size(x: Int=0) = UInt(log2Up(params.dataBits/8)) } class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 476421a1..af956178 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -4,10 +4,53 @@ package uncore.tilelink2 import Chisel._ -class TLEdgeOut( +class TLEdge( client: TLClientPortParameters, manager: TLManagerPortParameters) extends TLEdgeParameters(client, manager) +{ + def isAligned(address: UInt, lgSize: UInt) = + if (maxLgSize == 0) Bool(true) else { + val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } + (address & mask.toBits.asUInt) === UInt(0) + } + + // This gets used everywhere, so make the smallest circuit possible ... + def fullMask(address: UInt, lgSize: UInt) = { + val lgBytes = log2Ceil(manager.beatBytes) + def helper(i: Int): Seq[(Bool, Bool)] = { + if (i == 0) { + Seq((lgSize >= UInt(lgBytes), Bool(true))) + } else { + val sub = helper(i-1) + val size = lgSize === UInt(lgBytes - i) + val bit = address(lgBytes - i) + val nbit = !bit + Seq.tabulate (1 << i) { j => + val (sub_acc, sub_eq) = sub(j/2) + val eq = sub_eq && (if (j % 2 == 1) bit else nbit) + val acc = sub_acc || (size && eq) + (acc, eq) + } + } + } + Vec(helper(lgBytes).map(_._1)).toBits.asUInt + } + + def numBeats(bundle: HasTLOpcode) = { + val hasData = bundle.hasData() + val size = bundle.size() + val cutoff = log2Ceil(manager.beatBytes) + val small = size <= UInt(cutoff) + val decode = Vec.tabulate (1+maxLgSize-cutoff) { i => UInt(i + cutoff) === size } + Mux(!hasData || small, UInt(1), decode) + } +} + +class TLEdgeOut( + client: TLClientPortParameters, + manager: TLManagerPortParameters) + extends TLEdge(client, manager) { // Transfers def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { @@ -200,7 +243,7 @@ class TLEdgeOut( class TLEdgeIn( client: TLClientPortParameters, manager: TLManagerPortParameters) - extends TLEdgeParameters(client, manager) + extends TLEdge(client, manager) { // Transfers def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index addc2991..cef5190a 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -31,7 +31,11 @@ case class IdRange(start: Int, end: Int) // contains => overlaps (because empty is forbidden) def contains(x: Int) = start <= x && x < end - def contains(x: UInt) = UInt(start) <= x && x < UInt(end) // !!! special-case = + def contains(x: UInt) = + if (start+1 == end) { UInt(start) === x } + else if (((end-1) & ~start) == end-start-1) + { ((UInt(start) ^ x) & ~UInt(end-start-1)) === UInt(0) } + else { UInt(start) <= x && x < UInt(end) } def shift(x: Int) = IdRange(start+x, end+x) } @@ -49,7 +53,10 @@ case class TransferSizes(min: Int, max: Int) def none = min == 0 def contains(x: Int) = isPow2(x) && min <= x && x <= max def containsLg(x: Int) = contains(1 << x) - def containsLg(x: UInt) = if (none) Bool(false) else { UInt(log2Ceil(min)) <= x && x <= UInt(log2Ceil(max)) } // !!! special-case = + def containsLg(x: UInt) = + if (none) Bool(false) + else if (min == max) { UInt(log2Ceil(min)) === x } + else { UInt(log2Ceil(min)) <= x && x <= UInt(log2Ceil(max)) } def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max) @@ -299,32 +306,4 @@ case class TLEdgeParameters( sourceBits = log2Up(client.endSourceId), sinkBits = log2Up(manager.endSinkId), sizeBits = log2Up(maxLgSize+1)) - - def isAligned(address: UInt, lgSize: UInt) = - if (maxLgSize == 0) Bool(true) else { - val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } - (address & mask.toBits.asUInt) === UInt(0) - } - - // This gets used everywhere, so make the smallest circuit possible ... - def fullMask(address: UInt, lgSize: UInt) = { - val lgBytes = log2Ceil(manager.beatBytes) - def helper(i: Int): Seq[(Bool, Bool)] = { - if (i == 0) { - Seq((lgSize >= UInt(lgBytes), Bool(true))) - } else { - val sub = helper(i-1) - val size = lgSize === UInt(lgBytes - i) - val bit = address(lgBytes - i) - val nbit = !bit - Seq.tabulate (1 << i) { j => - val (sub_acc, sub_eq) = sub(j/2) - val eq = sub_eq && (if (j % 2 == 1) bit else nbit) - val acc = sub_acc || (size && eq) - (acc, eq) - } - } - } - Vec(helper(lgBytes).map(_._1)).toBits.asUInt - } } From 34f65938b6c3f1ce30c81ef0d3378d9595838efc Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 24 Aug 2016 13:50:11 -0700 Subject: [PATCH 13/87] tilelink2: add a TLBundle constructor --- uncore/src/main/scala/tilelink2/Bundles.scala | 5 +++++ uncore/src/main/scala/tilelink2/Nodes.scala | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 9cc724e1..fb29bc1d 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -214,3 +214,8 @@ class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) val d = Decoupled(new TLBundleD(params)).flip val e = Decoupled(new TLBundleE(params)) } + +object TLBundle +{ + def apply(params: TLBundleParameters) = new TLBundle(params) +} diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index 1e4f0d4e..a15b01c3 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -48,8 +48,8 @@ class TLBaseNode( lazy val edgesOut = clientPorts.map { n => new TLEdgeOut(clientParams.get, n.managerParams.get) } lazy val edgesIn = managerPorts.map { n => new TLEdgeIn (n.clientParams.get, managerParams.get) } - lazy val bundleOut = Vec(edgesOut.size, new TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) - lazy val bundleIn = Vec(edgesIn .size, new TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip + lazy val bundleOut = Vec(edgesOut.size, TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) + lazy val bundleIn = Vec(edgesIn .size, TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip } class TLClientNode( From e50630999828c295f112fbba930ef5e10aa8ba00 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 24 Aug 2016 13:50:32 -0700 Subject: [PATCH 14/87] tilelink2: prototype crossbar implementation --- .../src/main/scala/tilelink2/Operations.scala | 2 +- .../src/main/scala/tilelink2/Parameters.scala | 2 +- uncore/src/main/scala/tilelink2/Xbar.scala | 211 ++++++++++++++++++ 3 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 uncore/src/main/scala/tilelink2/Xbar.scala diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index af956178..9ed177be 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -43,7 +43,7 @@ class TLEdge( val cutoff = log2Ceil(manager.beatBytes) val small = size <= UInt(cutoff) val decode = Vec.tabulate (1+maxLgSize-cutoff) { i => UInt(i + cutoff) === size } - Mux(!hasData || small, UInt(1), decode) + Mux(!hasData || small, UInt(1), decode.toBits.asUInt) } } diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index cef5190a..98dfcf16 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -19,7 +19,6 @@ object RegionType { case class IdRange(start: Int, end: Int) { require (start >= 0) - require (end >= 0) require (start < end) // not empty // This is a strict partial ordering @@ -38,6 +37,7 @@ case class IdRange(start: Int, end: Int) else { UInt(start) <= x && x < UInt(end) } def shift(x: Int) = IdRange(start+x, end+x) + def size = end - start } // An potentially empty inclusive range of 2-powers [min, max] (in bytes) diff --git a/uncore/src/main/scala/tilelink2/Xbar.scala b/uncore/src/main/scala/tilelink2/Xbar.scala new file mode 100644 index 00000000..20325196 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Xbar.scala @@ -0,0 +1,211 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +object TLXbar +{ + def lowestIndex(requests: Vec[Bool], execute: Bool) = { + // lowest-index first is stateless; ignore execute + val ors = Vec(requests.scanLeft(Bool(false))(_ || _).init) // prefix-OR + Vec((ors zip requests) map { case (o, r) => !o && r }) + } +} + +class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extends TLFactory +{ + def mapInputIds (ports: Seq[TLClientPortParameters ]) = assignRanges(ports.map(_.endSourceId)) + def mapOutputIds(ports: Seq[TLManagerPortParameters]) = assignRanges(ports.map(_.endSinkId)) + + def assignRanges(sizes: Seq[Int]) = { + val pow2Sizes = sizes.map(1 << log2Ceil(_)) + val tuples = pow2Sizes.zipWithIndex.sortBy(_._1) // record old index, then sort by increasing size + val starts = tuples.scanRight(0)(_._1 + _).tail // suffix-sum of the sizes = the start positions + val ranges = (tuples zip starts) map { case ((sz, i), st) => (IdRange(st, st+sz), i) } + ranges.sortBy(_._2).map(_._1) // Restore orignal order + } + + def relabeler() = { + var idFactory = 0 + () => { + val fifoMap = scala.collection.mutable.HashMap.empty[Int, Int] + (x: Int) => { + if (fifoMap.contains(x)) fifoMap(x) else { + val out = idFactory + idFactory = idFactory + 1 + fifoMap += (x -> out) + out + } + } + } + } + + val node = TLAdapterNode( + numClientPorts = 1 to 32, + numManagerPorts = 1 to 32, + clientFn = { seq => + val clients = (mapInputIds(seq) zip seq) flatMap { case (range, port) => + port.clients map { client => client.copy( + sourceId = client.sourceId.shift(range.start) + )} + } + TLClientPortParameters(clients) + }, + managerFn = { seq => + val fifoIdFactory = relabeler() + val managers = (mapOutputIds(seq) zip seq) flatMap { case (range, port) => + require (port.beatBytes == seq(0).beatBytes) + val fifoIdMapper = fifoIdFactory() + port.managers map { manager => manager.copy( + sinkId = manager.sinkId.shift(range.start), + fifoId = manager.fifoId.map(fifoIdMapper(_)) + )} + } + TLManagerPortParameters(managers, seq(0).beatBytes) + }) + + lazy val module = Module(new TLModule(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + // Grab the port ID mapping + val inputIdRanges = mapInputIds(node.edgesIn.map(_.client)) + val outputIdRanges = mapOutputIds(node.edgesOut.map(_.manager)) + + // We need an intermediate size of bundle with the widest possible identifiers + val wide_bundle = io.in(0).params.union(io.out(0).params) + + // Handle size = 1 gracefully (Chisel3 empty range is broken) + def trim(id: UInt, size: Int) = if (size <= 1) UInt(0) else id(log2Ceil(size)-1, 0) + def transpose(x: Seq[Seq[Bool]]) = Vec.tabulate(x(0).size) { i => Vec.tabulate(x.size) { j => x(j)(i) } } + + // Transform input bundle sources (sinks use global namespace on both sides) + val in = Wire(Vec(io.in.size, TLBundle(wide_bundle))) + for (i <- 0 until in.size) { + val r = inputIdRanges(i) + in(i) <> io.in(i) + // prefix sources + in(i).a.bits.source := io.in(i).a.bits.source | UInt(r.start) + in(i).c.bits.source := io.in(i).c.bits.source | UInt(r.start) + // defix sources + io.in(i).b.bits.source := trim(in(i).b.bits.source, r.size) + io.in(i).d.bits.source := trim(in(i).d.bits.source, r.size) + } + + // Transform output bundle sinks (sources use global namespace on both sides) + val out = Wire(Vec(io.out.size, TLBundle(wide_bundle))) + for (i <- 0 until out.size) { + val r = outputIdRanges(i) + io.out(i) <> out(i) + // prefix sinks + out(i).d.bits.sink := io.out(i).d.bits.sink | UInt(r.start) + // defix sinks + io.out(i).e.bits.sink := trim(out(i).e.bits.sink, r.size) + } + + // The crossbar cross-connection state; defined later + val grantedAIO = Wire(Vec(in .size, Vec(out.size, Bool()))) + val grantedBOI = Wire(Vec(out.size, Vec( in.size, Bool()))) + val grantedCIO = Wire(Vec(in .size, Vec(out.size, Bool()))) + val grantedDOI = Wire(Vec(out.size, Vec(in .size, Bool()))) + val grantedEIO = Wire(Vec(in .size, Vec(out.size, Bool()))) + + val grantedAOI = transpose(grantedAIO) + val grantedBIO = transpose(grantedBOI) + val grantedCOI = transpose(grantedCIO) + val grantedDIO = transpose(grantedDOI) + val grantedEOI = transpose(grantedEIO) + + // Mux1H passes a single-source through unmasked. That's bad for control. + def Mux1C(sel: Seq[Bool], ctl: Seq[Bool]) = (sel zip ctl).map{ case (a,b) => a && b }.reduce(_ || _) + + // Mux clients to managers + for (o <- 0 until out.size) { + out(o).a.valid := Mux1C(grantedAOI(o), in.map(_.a.valid)) + out(o).a.bits := Mux1H(grantedAOI(o), in.map(_.a.bits)) + out(o).b.ready := Mux1C(grantedBOI(o), in.map(_.b.ready)) + out(o).c.valid := Mux1C(grantedCOI(o), in.map(_.c.valid)) + out(o).c.bits := Mux1H(grantedCOI(o), in.map(_.c.bits)) + out(o).d.ready := Mux1C(grantedDOI(o), in.map(_.d.ready)) + out(o).e.valid := Mux1C(grantedEOI(o), in.map(_.e.valid)) + out(o).e.bits := Mux1H(grantedEOI(o), in.map(_.e.bits)) + } + + // Mux managers to clients + for (i <- 0 until in.size) { + in(i).a.ready := Mux1C(grantedAIO(i), out.map(_.a.ready)) + in(i).b.valid := Mux1C(grantedBIO(i), out.map(_.b.valid)) + in(i).b.bits := Mux1H(grantedBIO(i), out.map(_.b.bits)) + in(i).c.ready := Mux1C(grantedCIO(i), out.map(_.c.ready)) + in(i).d.valid := Mux1C(grantedDIO(i), out.map(_.d.valid)) + in(i).d.bits := Mux1H(grantedDIO(i), out.map(_.d.bits)) + in(i).e.ready := Mux1C(grantedEIO(i), out.map(_.e.ready)) + } + + val requestAIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.a.valid && o.manager.contains(i.a.bits.address) }) }) + val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i .contains(o.b.bits.source) }) }) + val requestCIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.c.valid && o.manager.contains(i.c.bits.address) }) }) + val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.b.bits.source) }) }) + val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o .contains(i.e.bits.sink) }) }) + + val beatsA = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) }) + val beatsB = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) }) + val beatsC = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.c.bits) }) + val beatsD = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.d.bits) }) + val beatsE = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.e.bits) }) + + // Which pairs support support transfers + val maskIO = Vec.tabulate(in.size) { i => Vec.tabulate(out.size) { o => + Bool(node.edgesIn(i).client.anySupportProbe && node.edgesOut(o).manager.anySupportAcquire) + } } + val maskOI = transpose(maskIO) + + // Mask out BCE channel connections (to be optimized away) for transfer-incapable pairings + def mask(a: Seq[Seq[Bool]], b: Seq[Seq[Bool]]) = + Vec((a zip b) map { case (x, y) => Vec((x zip y) map { case (a, b) => a && b }) }) + + grantedAIO := arbitrate( requestAIO, beatsA, out.map(_.a.fire())) + grantedBOI := mask(arbitrate(mask(requestBOI, maskOI), beatsB, in .map(_.b.fire())), maskOI) + grantedCIO := mask(arbitrate(mask(requestCIO, maskIO), beatsC, out.map(_.c.fire())), maskIO) + grantedDOI := arbitrate( requestDOI, beatsD, in .map(_.d.fire())) + grantedEIO := mask(arbitrate(mask(requestEIO, maskIO), beatsE, out.map(_.e.fire())), maskIO) + + def arbitrate(request: Seq[Seq[Bool]], beats: Seq[UInt], progress: Seq[Bool]) = { + request foreach { row => require (row.size == progress.size) } // consistent # of resources + request foreach { resources => // only one resource is requested + val prefixOR = resources.scanLeft(Bool(false))(_ || _).init + assert (!(prefixOR zip resources).map{case (a, b) => a && b}.reduce(_ || _)) + } + transpose((transpose(request) zip progress).map { case (r,p) => arbitrate1(r, beats, p) }) + } + + def arbitrate1(requests: Vec[Bool], beats: Seq[UInt], progress: Bool) = { + require (requests.size == beats.size) // consistent # of requesters + + val beatsLeft = RegInit(UInt(0)) + val idle = beatsLeft === UInt(0) + + // Apply policy to select which requester wins + val winners = Vec(policy(requests, idle)) + + // Supposing we take the winner as input, how many beats must be sent? + val initBeats = Mux1H(winners, beats) + // What is the counter state before progress? + val todoBeats = Mux(idle, initBeats, beatsLeft) + // Apply progress and register the result + beatsLeft := todoBeats - progress.asUInt + assert (!progress || todoBeats =/= UInt(0)) // underflow should be impossible + + // The previous arbitration state of the resource + val state = RegInit(Vec.fill(requests.size)(Bool(false))) + // Only take a new value while idle + val muxState = Mux(idle, winners, state) + state := muxState + + muxState + } + }) +} From e24ba617547da8f2e3a007d8b483739d14b62930 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 24 Aug 2016 16:07:45 -0700 Subject: [PATCH 15/87] tilelink2: distinguish two levels of uncacheability --- uncore/src/main/scala/tilelink2/Parameters.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 98dfcf16..f14a0d4e 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -11,8 +11,9 @@ object RegionType { case object CACHED extends T case object TRACKED extends T case object UNCACHED extends T - case object UNCACHEABLE extends T - val cases = Seq(CACHED, TRACKED, UNCACHED, UNCACHEABLE) + case object PUT_EFFECTS extends T + case object GET_EFFECTS extends T // GET_EFFECTS => PUT_EFFECTS + val cases = Seq(CACHED, TRACKED, UNCACHED, PUT_EFFECTS, GET_EFFECTS) } // A non-empty half-open range; [start, end) @@ -99,7 +100,7 @@ case class AddressSet(mask: BigInt, base: Option[BigInt] = None) case class TLManagerParameters( address: Seq[AddressSet], sinkId: IdRange = IdRange(0, 1), - regionType: RegionType.T = RegionType.UNCACHEABLE, + regionType: RegionType.T = RegionType.GET_EFFECTS, // Supports both Acquire+Release+Finish of these sizes supportsAcquire: TransferSizes = TransferSizes.none, supportsArithmetic: TransferSizes = TransferSizes.none, From 4b99bd3be1f61974555fa2d51234ca73459a647c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 14:13:09 -0700 Subject: [PATCH 16/87] tilelink2: mask out unnecessary address bits --- uncore/src/main/scala/tilelink2/Bases.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index 3f1f59c3..c9333886 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -31,6 +31,10 @@ abstract class TLFactory bindings.foreach { case (x, i, y, j, s) => TLMonitor.legalize(y.bundleOut(j), y.edgesOut(j), x.bundleIn(i), x.edgesIn(i), s) x.bundleIn(i).<>(y.bundleOut(j))(s) + val mask = ~UInt(x.edgesIn(i).manager.beatBytes - 1) + x.bundleIn (i).a.bits.address.:=(mask & y.bundleOut(j).a.bits.address)(s) + y.bundleOut(j).b.bits.address.:=(mask & x.bundleIn (i).b.bits.address)(s) + x.bundleIn (i).c.bits.address.:=(mask & y.bundleOut(j).c.bits.address)(s) } } } From 3a441d853f7edd31949deb087dba4a84cfb46b31 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 14:13:54 -0700 Subject: [PATCH 17/87] tilelink2: clarify that fifoId only applies to accesses (not hints) --- uncore/src/main/scala/tilelink2/Parameters.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index f14a0d4e..a6b07da9 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -77,7 +77,7 @@ object TransferSizes { // The base address used by the crossbar for routing case class AddressSet(mask: BigInt, base: Option[BigInt] = None) { - // Forbid empty sets + // Forbid misaligned base address (and empty sets) require (base == None || (base.get & mask) == 0) def contains(x: BigInt) = ((x ^ base.get) & ~mask) == 0 @@ -95,6 +95,9 @@ case class AddressSet(mask: BigInt, base: Option[BigInt] = None) // 1 less than the number of bytes to which the manager should be aligned def alignment1 = ((mask + 1) & ~mask) - 1 def max = base.get | mask + + // A strided slave has serves discontiguous ranges + def strided = alignment1 != mask } case class TLManagerParameters( @@ -109,7 +112,7 @@ case class TLManagerParameters( supportsPutFull: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none, supportsHint: Boolean = false, - // If fifoId=Some, all messages sent to the same fifoId are delivered in FIFO order + // If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order fifoId: Option[Int] = None) { address.combinations(2).foreach({ case Seq(x,y) => From a87c2d13e223350ceb6928e637e4f97d0ddb9e5a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 14:15:37 -0700 Subject: [PATCH 18/87] tilelink2: include an abstract definition for register mapped devices --- .../src/main/scala/tilelink2/RegField.scala | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/RegField.scala diff --git a/uncore/src/main/scala/tilelink2/RegField.scala b/uncore/src/main/scala/tilelink2/RegField.scala new file mode 100644 index 00000000..b8e638e3 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/RegField.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn) +object RegField +{ + type ReadFn = Bool => (Bool, UInt) + type WriteFn = (Bool, UInt) => Bool + type Map = (Int, Seq[RegField]) + + def apply(n: Int) : RegField = apply(n, noR, noW) + def apply(n: Int, rw: UInt) : RegField = apply(n, regR(rw), regW(rw)) + def apply(n: Int, r: UInt, w: UInt) : RegField = apply(n, regR(r), regW(w)) + def apply(n: Int, r: UInt, w: WriteFn) : RegField = apply(n, regR(r), w) + def apply(n: Int, r: ReadFn, w: UInt) : RegField = apply(n, r, regW(w)) + def R(n: Int, r: ReadFn) : RegField = apply(n, r, noW) + def R(n: Int, r: UInt) : RegField = R(n, regR(r)) + def W(n: Int, w: WriteFn) : RegField = apply(n, noR, w) + def W(n: Int, w: UInt) : RegField = W(n, regW(w)) + + private val noR = (en: Bool) => (Bool(true), UInt(0)) + private val noW = (en: Bool, in: UInt) => Bool(true) + private def regR(reg: UInt) = (en: Bool) => (Bool(true), reg) + private def regW(reg: UInt) = (en: Bool, in: UInt) => + { + when (en) { reg := in } + Bool(true) + } +} + +trait HasRegMap +{ + def regmap(mapping: RegField.Map*): Unit +} From 0ff33a31a42f4d99aca67828a10f63d623d541b2 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 14:16:17 -0700 Subject: [PATCH 19/87] tilelink2: add a stub SRAM manager --- uncore/src/main/scala/tilelink2/SRAM.scala | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/SRAM.scala diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala new file mode 100644 index 00000000..0b3ff2f5 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -0,0 +1,24 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLFactory +{ + val node = TLManagerNode(beatBytes, TLManagerParameters( + address = List(address), + regionType = RegionType.UNCACHED, + supportsGet = TransferSizes(1, beatBytes), + supportsPutPartial = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + fifoId = Some(0))) // requests are handled in order + + lazy val module = Module(new TLModule(this) { + val io = new Bundle { + val in = node.bundleIn + } + + // do stuff + }) +} From 4649c42f50532fdfc9a8dd64a60c2289c361dc7f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 15:03:39 -0700 Subject: [PATCH 20/87] tilelink2: use a new type in the signature of null-parameter Bundle methods --- uncore/src/main/scala/tilelink2/Bundles.scala | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index fb29bc1d..08a936a8 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -89,20 +89,26 @@ object TLAtomics def isLogical(x: UInt) = Bool(true) } +class Bogus +object Bogus +{ + def apply() = new Bogus +} + trait HasTLOpcode { // The data field in this message has value - def hasData(x: Int=0): Bool + def hasData(x: Bogus = Bogus()): Bool // This message requires a response - def hasFollowUp(x: Int=0): Bool + def hasFollowUp(x: Bogus = Bogus()): Bool // The size field of the opcode - def size(x: Int=0): UInt + def size(x: Bogus = Bogus()): UInt } trait HasTLData extends HasTLOpcode { - def data(x: Int=0): UInt - def wmask(x: Int=0): UInt + def data(x: Bogus = Bogus()): UInt + def wmask(x: Bogus = Bogus()): UInt } // !!! trait HasTLSource|Sink|Address @@ -120,15 +126,15 @@ class TLBundleA(params: TLBundleParameters) val wmask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) - def hasData(x: Int=0) = !opcode(2) + def hasData(x: Bogus = Bogus()) = !opcode(2) // opcode === TLMessages.PutFullData || // opcode === TLMessages.PutPartialData || // opcode === TLMessages.ArithmeticData || // opcode === TLMessages.LogicalData - def hasFollowUp(x: Int=0) = Bool(true) - def size(x: Int=0) = size - def data(x: Int=0) = data - def wmask(x: Int=0) = wmask + def hasFollowUp(x: Bogus = Bogus()) = Bool(true) + def size(x: Bogus = Bogus()) = size + def data(x: Bogus = Bogus()) = data + def wmask(x: Bogus = Bogus()) = wmask } class TLBundleB(params: TLBundleParameters) @@ -143,11 +149,11 @@ class TLBundleB(params: TLBundleParameters) val wmask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) - def hasData(x: Int=0) = !opcode(2) - def hasFollowUp(x: Int=0) = Bool(true) - def size(x: Int=0) = size - def data(x: Int=0) = data - def wmask(x: Int=0) = wmask + def hasData(x: Bogus = Bogus()) = !opcode(2) + def hasFollowUp(x: Bogus = Bogus()) = Bool(true) + def size(x: Bogus = Bogus()) = size + def data(x: Bogus = Bogus()) = data + def wmask(x: Bogus = Bogus()) = wmask } class TLBundleC(params: TLBundleParameters) @@ -161,16 +167,16 @@ class TLBundleC(params: TLBundleParameters) val address = UInt(width = params.addressBits) // to val data = UInt(width = params.dataBits) - def hasData(x: Int=0) = opcode(0) + def hasData(x: Bogus = Bogus()) = opcode(0) // opcode === TLMessages.AccessAckData || // opcode === TLMessages.ProbeAckData || // opcode === TLMessages.ReleaseData - def hasFollowUp(x: Int=0) = opcode(2) && !opcode(1) + def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && !opcode(1) // opcode === TLMessages.Release || // opcode === TLMessages.ReleaseData - def size(x: Int=0) = size - def data(x: Int=0) = data - def wmask(x: Int=0) = SInt(-1, width = params.dataBits/8).asUInt + def size(x: Bogus = Bogus()) = size + def data(x: Bogus = Bogus()) = data + def wmask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt } class TLBundleD(params: TLBundleParameters) @@ -184,15 +190,15 @@ class TLBundleD(params: TLBundleParameters) val sink = UInt(width = params.sinkBits) // from val data = UInt(width = params.dataBits) - def hasData(x: Int=0) = opcode(0) + def hasData(x: Bogus = Bogus()) = opcode(0) // opcode === TLMessages.AccessAckData || // opcode === TLMessages.GrantData - def hasFollowUp(x: Int=0) = !opcode(2) && opcode(1) + def hasFollowUp(x: Bogus = Bogus()) = !opcode(2) && opcode(1) // opcode === TLMessages.Grant || // opcode === TLMessages.GrantData - def size(x: Int=0) = size - def data(x: Int=0) = data - def wmask(x: Int=0) = SInt(-1, width = params.dataBits/8).asUInt + def size(x: Bogus = Bogus()) = size + def data(x: Bogus = Bogus()) = data + def wmask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt } class TLBundleE(params: TLBundleParameters) @@ -201,9 +207,9 @@ class TLBundleE(params: TLBundleParameters) { val sink = UInt(width = params.sourceBits) // to - def hasData(x: Int=0) = Bool(false) - def hasFollowUp(x: Int=0) = Bool(false) - def size(x: Int=0) = UInt(log2Up(params.dataBits/8)) + def hasData(x: Bogus = Bogus()) = Bool(false) + def hasFollowUp(x: Bogus = Bogus()) = Bool(false) + def size(x: Bogus = Bogus()) = UInt(log2Up(params.dataBits/8)) } class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) From 917a9c8e5d5395bc4d97da16c6d0d7414e515756 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 15:32:20 -0700 Subject: [PATCH 21/87] tilelink2: forward declarations for message constructors --- .../src/main/scala/tilelink2/Operations.scala | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 9ed177be..b4fd4e3e 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -56,7 +56,7 @@ class TLEdgeOut( def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.Acquire a.param := growPermissions a.size := lgSize @@ -70,7 +70,7 @@ class TLEdgeOut( def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = { require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.Release c.param := shrinkPermissions c.size := lgSize @@ -83,7 +83,7 @@ class TLEdgeOut( def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = { require (manager.anySupportAcquire) val legal = manager.supportsAcquire(toAddress, lgSize) - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.ReleaseData c.param := shrinkPermissions c.size := lgSize @@ -94,7 +94,7 @@ class TLEdgeOut( } def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt) = { - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.ProbeAck c.param := reportPermissions c.size := lgSize @@ -105,7 +105,7 @@ class TLEdgeOut( } def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt, data: UInt) = { - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.ProbeAckData c.param := reportPermissions c.size := lgSize @@ -116,7 +116,7 @@ class TLEdgeOut( } def GrantAck(toSink: UInt) = { - val e = new TLBundleE(bundle) + val e = Wire(new TLBundleE(bundle)) e.sink := toSink e } @@ -125,7 +125,7 @@ class TLEdgeOut( def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { require (manager.anySupportGet) val legal = manager.supportsGet(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.Get a.param := UInt(0) a.size := lgSize @@ -139,7 +139,7 @@ class TLEdgeOut( def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = { require (manager.anySupportPutFull) val legal = manager.supportsPutFull(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.PutFullData a.param := UInt(0) a.size := lgSize @@ -153,7 +153,7 @@ class TLEdgeOut( def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { require (manager.anySupportPutPartial) val legal = manager.supportsPutPartial(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.PutPartialData a.param := UInt(0) a.size := lgSize @@ -167,7 +167,7 @@ class TLEdgeOut( def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { require (manager.anySupportArithmetic) val legal = manager.supportsArithmetic(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.ArithmeticData a.param := atomic a.size := lgSize @@ -181,7 +181,7 @@ class TLEdgeOut( def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { require (manager.anySupportLogical) val legal = manager.supportsLogical(toAddress, lgSize) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.LogicalData a.param := atomic a.size := lgSize @@ -195,7 +195,7 @@ class TLEdgeOut( def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { require (manager.anySupportHint) val legal = manager.supportsHint(toAddress) - val a = new TLBundleA(bundle) + val a = Wire(new TLBundleA(bundle)) a.opcode := TLMessages.Hint a.param := param a.size := lgSize @@ -207,7 +207,7 @@ class TLEdgeOut( } def AccessAck(toAddress: UInt, lgSize: UInt) = { - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAck c.param := UInt(0) c.size := lgSize @@ -218,7 +218,7 @@ class TLEdgeOut( } def AccessAckError(toAddress: UInt, lgSize: UInt) = { - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAckError c.param := UInt(0) c.size := lgSize @@ -229,7 +229,7 @@ class TLEdgeOut( } def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt) = { - val c = new TLBundleC(bundle) + val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAckData c.param := UInt(0) c.size := lgSize @@ -249,7 +249,7 @@ class TLEdgeIn( def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { require (client.anySupportProbe) val legal = client.supportsProbe(fromAddress, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.Probe b.param := capPermissions b.size := lgSize @@ -261,7 +261,7 @@ class TLEdgeIn( } def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.Grant d.param := capPermissions d.size := lgSize @@ -272,7 +272,7 @@ class TLEdgeIn( } def GrantData(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.GrantData d.param := capPermissions d.size := lgSize @@ -283,7 +283,7 @@ class TLEdgeIn( } def ReleaseAck(toSource: UInt, lgSize: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.ReleaseAck d.param := UInt(0) d.size := lgSize @@ -297,7 +297,7 @@ class TLEdgeIn( def Get(fromAddress: UInt, toSource: UInt, lgSize: UInt) = { require (client.anySupportGet) val legal = client.supportsGet(toSource, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.Get b.param := UInt(0) b.size := lgSize @@ -311,7 +311,7 @@ class TLEdgeIn( def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt) = { require (client.anySupportPutFull) val legal = client.supportsPutFull(toSource, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.PutFullData b.param := UInt(0) b.size := lgSize @@ -325,7 +325,7 @@ class TLEdgeIn( def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { require (client.anySupportPutPartial) val legal = client.supportsPutPartial(toSource, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.PutPartialData b.param := UInt(0) b.size := lgSize @@ -339,7 +339,7 @@ class TLEdgeIn( def Arithmetic(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { require (client.anySupportArithmetic) val legal = client.supportsArithmetic(toSource, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.ArithmeticData b.param := atomic b.size := lgSize @@ -353,7 +353,7 @@ class TLEdgeIn( def Logical(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { require (client.anySupportLogical) val legal = client.supportsLogical(toSource, lgSize) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.LogicalData b.param := atomic b.size := lgSize @@ -367,7 +367,7 @@ class TLEdgeIn( def Hint(fromAddress: UInt, toSource: UInt, lgSize: UInt, param: UInt) = { require (client.anySupportHint) val legal = client.supportsHint(toSource) - val b = new TLBundleB(bundle) + val b = Wire(new TLBundleB(bundle)) b.opcode := TLMessages.Hint b.param := param b.size := lgSize @@ -379,7 +379,7 @@ class TLEdgeIn( } def AccessAck(toSource: UInt, lgSize: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.AccessAck d.param := UInt(0) d.size := lgSize @@ -390,7 +390,7 @@ class TLEdgeIn( } def AccessAckError(toSource: UInt, lgSize: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.AccessAckError d.param := UInt(0) d.size := lgSize @@ -401,7 +401,7 @@ class TLEdgeIn( } def AccessAck(toSource: UInt, lgSize: UInt, data: UInt) = { - val d = new TLBundleD(bundle) + val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.AccessAckData d.param := UInt(0) d.size := lgSize From 18e149098a739359db6ae95f8db9f5185c9f014e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 26 Aug 2016 15:48:48 -0700 Subject: [PATCH 22/87] tilelink2: connect abstract register-based modules to TileLink --- uncore/src/main/scala/tilelink2/GPIO.scala | 29 +++++ .../src/main/scala/tilelink2/RegField.scala | 4 + .../main/scala/tilelink2/RegisterRouter.scala | 122 ++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/GPIO.scala create mode 100644 uncore/src/main/scala/tilelink2/RegisterRouter.scala diff --git a/uncore/src/main/scala/tilelink2/GPIO.scala b/uncore/src/main/scala/tilelink2/GPIO.scala new file mode 100644 index 00000000..e4b8572f --- /dev/null +++ b/uncore/src/main/scala/tilelink2/GPIO.scala @@ -0,0 +1,29 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +case class GPIOParams(num: Int, address: Option[BigInt] = None) + +trait GPIOBundle +{ + val params: GPIOParams + val gpio = UInt(width = params.num) +} + +trait GPIOModule extends HasRegMap +{ + val params: GPIOParams + val io: GPIOBundle + + val state = RegInit(UInt(0)) + io.gpio := state + + regmap(0 -> Seq(RegField(params.num, state))) +} + +// Create a concrete TL2 version of the abstract GPIO slave +class TLGPIO(p: GPIOParams) extends TLRegisterRouter(p.address)( + new TLRegBundle(p, _) with GPIOBundle)( + new TLRegModule(p, _, _) with GPIOModule) diff --git a/uncore/src/main/scala/tilelink2/RegField.scala b/uncore/src/main/scala/tilelink2/RegField.scala index b8e638e3..509c7441 100644 --- a/uncore/src/main/scala/tilelink2/RegField.scala +++ b/uncore/src/main/scala/tilelink2/RegField.scala @@ -5,6 +5,10 @@ package uncore.tilelink2 import Chisel._ case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn) +{ + require (width > 0) +} + object RegField { type ReadFn = Bool => (Bool, UInt) diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala new file mode 100644 index 00000000..cda3426e --- /dev/null +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -0,0 +1,122 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +class TLRegisterNode(address: AddressSet, beatBytes: Int = 4) + extends TLManagerNode(beatBytes, TLManagerParameters( + address = Seq(address), + supportsGet = TransferSizes(1, beatBytes), + supportsPutPartial = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + fifoId = Some(0))) // requests are handled in order +{ + require (!address.strided) + + // Calling this method causes the matching TL2 bundle to be + // configured to route all requests to the listed RegFields. + def regmap(mapping: RegField.Map*) = { + val regmap = mapping.toList + require (!regmap.isEmpty) + + // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) + val flat = regmap.map { case (reg, fields) => + val offsets = fields.scanLeft(0)(_ + _.width).init + (offsets zip fields) map { case (o, f) => (reg, o, f) } + }.flatten + + // Confirm that no register is too big + require (flat.map(_._2).max <= beatBytes*8) + + // All registers must fit inside the device address space + val maxIndex = regmap.map(_._1).max + require (address.mask >= maxIndex*beatBytes) + + // Which register is touched? + val alignBits = log2Ceil(beatBytes) + val addressBits = log2Up(maxIndex+1) + val a = bundleIn(0).a // Must apply Queue !!! (so no change once started) + val d = bundleIn(0).d + val regIdx = a.bits.address(addressBits+alignBits-1, alignBits) + val regSel = UIntToOH(regIdx) + + // What is the access? + val opcode = a.bits.opcode + val read = a.valid && opcode === TLMessages.Get + val write = a.valid && (opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData) + val wmaskWide = Vec.tabulate(beatBytes*8) { i => a.bits.wmask(i/8) } .toBits.asUInt + val dataIn = a.bits.data & wmaskWide // zero undefined bits + + // The output values for each register + val dataOutAcc = Array.tabulate(maxIndex+1) { _ => UInt(0) } + // The ready state for read and write + val rReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) } + val wReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) } + + // Apply all the field methods + flat.foreach { case (reg, low, field) => + val high = low + field.width - 1 + val rfire = wmaskWide(high, low).orR() + val wfire = wmaskWide(high, low).andR() + val sel = regSel(reg) + val ren = read && sel && rfire + val wen = write && sel && wfire + val (rReady, rResult) = field.read(ren) + val wReady = field.write(wen, dataIn(high, low)) + dataOutAcc(reg) = dataOutAcc(reg) | (rResult << low) + rReadyAcc(reg) = rReadyAcc(reg) && (!rfire || rReady) + wReadyAcc(reg) = wReadyAcc(reg) && (!wfire || wReady) + } + + // Create the output data signal + val dataOut = Vec(dataOutAcc)(regIdx) + val rReady = Vec(rReadyAcc)(regIdx) + val wReady = Vec(wReadyAcc)(regIdx) + + val ready = (read && rReady) || (write && wReady) + a.ready := ready && d.ready + d.valid := a.valid && ready + + val edge = edgesIn(0) + d.bits := edge.AccessAck(a.bits.source, a.bits.size) + // avoid a Mux on the data bus by manually overriding two fields + d.bits.data := dataOut + d.bits.opcode := Mux(opcode === TLMessages.Get, TLMessages.AccessAck, TLMessages.AccessAckData) + } +} + +object TLRegisterNode +{ + def apply(address: AddressSet, beatBytes: Int = 4) = new TLRegisterNode(address, beatBytes) +} + +// These convenience methods below combine to make it possible to create a TL2 +// register mapped device from a totally abstract register mapped device. +// See GPIO.scala in this directory for an example + +abstract class TLRegFactory(address: AddressSet, beatBytes: Int) extends TLFactory +{ + val node = TLRegisterNode(address, beatBytes) +} + +class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle + +class TLRegModule[P, B <: Bundle](val params: P, val io: B, factory: TLRegFactory) + extends TLModule(factory) with HasRegMap +{ + def regmap(mapping: RegField.Map*) = factory.node.regmap(mapping:_*) +} + +class TLRegisterRouter[B <: Bundle, M <: TLModule] + (address: Option[BigInt] = None, size: BigInt = 4096, beatBytes: Int = 4) + (bundleBuilder: Vec[TLBundle] => B) + (moduleBuilder: (B, TLRegFactory) => M) + extends TLRegFactory(AddressSet(size-1, address), beatBytes) +{ + require (size % 4096 == 0) // devices should be 4K aligned + require (isPow2(size)) + require (size >= 4096) + + lazy val module = Module(moduleBuilder(bundleBuilder(node.bundleIn), this)) +} From dc1164a99669f95a80195d0669acc9d99565e005 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 29 Aug 2016 11:08:37 -0700 Subject: [PATCH 23/87] tilelink2: defer bundle construction until after Module base class instantiated --- uncore/src/main/scala/tilelink2/RegisterRouter.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index cda3426e..8d6b764a 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -102,16 +102,17 @@ abstract class TLRegFactory(address: AddressSet, beatBytes: Int) extends TLFacto class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle -class TLRegModule[P, B <: Bundle](val params: P, val io: B, factory: TLRegFactory) +class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, factory: TLRegFactory) extends TLModule(factory) with HasRegMap { + val io = bundleBuilder def regmap(mapping: RegField.Map*) = factory.node.regmap(mapping:_*) } class TLRegisterRouter[B <: Bundle, M <: TLModule] (address: Option[BigInt] = None, size: BigInt = 4096, beatBytes: Int = 4) (bundleBuilder: Vec[TLBundle] => B) - (moduleBuilder: (B, TLRegFactory) => M) + (moduleBuilder: (=> B, TLRegFactory) => M) extends TLRegFactory(AddressSet(size-1, address), beatBytes) { require (size % 4096 == 0) // devices should be 4K aligned From 594850eaae51090108cd57ab2dafc801c51b13cb Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 29 Aug 2016 12:44:11 -0700 Subject: [PATCH 24/87] tilelink2: assert-fail on something more user understandable --- uncore/src/main/scala/tilelink2/Nodes.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index a15b01c3..be3e7eb2 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -48,8 +48,8 @@ class TLBaseNode( lazy val edgesOut = clientPorts.map { n => new TLEdgeOut(clientParams.get, n.managerParams.get) } lazy val edgesIn = managerPorts.map { n => new TLEdgeIn (n.clientParams.get, managerParams.get) } - lazy val bundleOut = Vec(edgesOut.size, TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) - lazy val bundleIn = Vec(edgesIn .size, TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip + lazy val bundleOut = { require (!edgesOut.isEmpty); Vec(edgesOut.size, TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) } + lazy val bundleIn = { require (!edgesIn .isEmpty); Vec(edgesIn .size, TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip } } class TLClientNode( From 77cf186cf0cbd076e0678c221aee0f2af3a343bf Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 29 Aug 2016 17:02:04 -0700 Subject: [PATCH 25/87] tilelink2: make bundle parameterization reusable --- uncore/src/main/scala/tilelink2/Bundles.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 08a936a8..1e405955 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -4,14 +4,14 @@ package uncore.tilelink2 import Chisel._ -abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle +abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle { override def cloneType = { try { this.getClass.getConstructors.head.newInstance(params).asInstanceOf[this.type] } catch { case e: java.lang.IllegalArgumentException => - throwException("Unable to use TLBundleBase.cloneType on " + + throwException("Unable to use GenericParameterizedBundle.cloneType on " + this.getClass + ", probably because " + this.getClass + "() takes more than one argument. Consider overriding " + "cloneType() on " + this.getClass, e) @@ -19,6 +19,8 @@ abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle } } +abstract class TLBundleBase(params: TLBundleParameters) extends GenericParameterizedBundle(params) + // common combos in lazy policy: // Put + Acquire // Release + AccessAck From 967d8f108cc60183674a579593e6fde12839abbc Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 29 Aug 2016 15:33:10 -0700 Subject: [PATCH 26/87] tilelink2: support ready-valid enqueue+dequeue on register fields --- .../src/main/scala/tilelink2/RegField.scala | 220 ++++++++++++++++-- .../main/scala/tilelink2/RegisterRouter.scala | 96 +++----- 2 files changed, 228 insertions(+), 88 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/RegField.scala b/uncore/src/main/scala/tilelink2/RegField.scala index 509c7441..c9c4a577 100644 --- a/uncore/src/main/scala/tilelink2/RegField.scala +++ b/uncore/src/main/scala/tilelink2/RegField.scala @@ -4,38 +4,214 @@ package uncore.tilelink2 import Chisel._ -case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn) +case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt)) +object RegReadFn +{ + // (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt) + // iready may combinationally depend on oready + // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) + // effects must become visible only on the cycle after ovalid && oready + implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = + new RegReadFn(false, x) + // (ofire: Bool) => (data: UInt) + // effects must become visible on the cycle after ofire + implicit def apply(x: Bool => UInt) = + new RegReadFn(true, { case (_, oready) => + (Bool(true), Bool(true), x(oready)) + }) + // read from a register + implicit def apply(x: UInt) = + new RegReadFn(true, { case (_, _) => + (Bool(true), Bool(true), x) + }) + // noop + implicit def apply(x: Unit) = + new RegReadFn(true, { case (_, _) => + (Bool(true), Bool(true), UInt(0)) + }) +} + +case class RegWriteFn private(combinational: Boolean, fn: (Bool, Bool, UInt) => (Bool, Bool)) +object RegWriteFn +{ + // (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool) + // iready may combinationally depend on both oready and data + // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) + // effects must become visible only on the cycle after ovalid && oready + implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = + new RegWriteFn(false, x) + // (ofire: Bool, data: UInt) => () + // effects must become visible on the cycle after ofire + implicit def apply(x: (Bool, UInt) => Unit) = + new RegWriteFn(true, { case (_, oready, data) => + x(oready, data) + (Bool(true), Bool(true)) + }) + // updates a register + implicit def apply(x: UInt) = + new RegWriteFn(true, { case (_, oready, data) => + when (oready) { x := data } + (Bool(true), Bool(true)) + }) + // noop + implicit def apply(x: Unit) = + new RegWriteFn(true, { case (_, _, _) => + (Bool(true), Bool(true)) + }) +} + +case class RegField(width: Int, read: RegReadFn, write: RegWriteFn) { require (width > 0) + def pipelined = !read.combinational || !write.combinational } object RegField { - type ReadFn = Bool => (Bool, UInt) - type WriteFn = (Bool, UInt) => Bool type Map = (Int, Seq[RegField]) - - def apply(n: Int) : RegField = apply(n, noR, noW) - def apply(n: Int, rw: UInt) : RegField = apply(n, regR(rw), regW(rw)) - def apply(n: Int, r: UInt, w: UInt) : RegField = apply(n, regR(r), regW(w)) - def apply(n: Int, r: UInt, w: WriteFn) : RegField = apply(n, regR(r), w) - def apply(n: Int, r: ReadFn, w: UInt) : RegField = apply(n, r, regW(w)) - def R(n: Int, r: ReadFn) : RegField = apply(n, r, noW) - def R(n: Int, r: UInt) : RegField = R(n, regR(r)) - def W(n: Int, w: WriteFn) : RegField = apply(n, noR, w) - def W(n: Int, w: UInt) : RegField = W(n, regW(w)) - - private val noR = (en: Bool) => (Bool(true), UInt(0)) - private val noW = (en: Bool, in: UInt) => Bool(true) - private def regR(reg: UInt) = (en: Bool) => (Bool(true), reg) - private def regW(reg: UInt) = (en: Bool, in: UInt) => - { - when (en) { reg := in } - Bool(true) - } + def apply(n: Int) : RegField = apply(n, (), ()) + def apply(n: Int, rw: UInt) : RegField = apply(n, rw, rw) + def R(n: Int, r: RegReadFn) : RegField = apply(n, r, ()) + def W(n: Int, w: RegWriteFn) : RegField = apply(n, (), w) } trait HasRegMap { def regmap(mapping: RegField.Map*): Unit } + +case class RegFieldParams(indexBits: Int, maskBits: Int, extraBits: Int) + +class RegFieldInput(params: RegFieldParams) extends GenericParameterizedBundle(params) +{ + val read = Bool() + val index = UInt(width = params.indexBits) + val data = UInt(width = params.maskBits*8) + val mask = UInt(width = params.maskBits) + val extra = UInt(width = params.extraBits) +} + +class RegFieldOutput(params: RegFieldParams) extends GenericParameterizedBundle(params) +{ + val read = Bool() + val data = UInt(width = params.maskBits*8) + val extra = UInt(width = params.extraBits) +} + +object RegFieldHelper +{ + // Create a generic register-based device + def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegFieldInput], mapping: RegField.Map*) = { + val regmap = mapping.toList + require (!regmap.isEmpty) + + // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) + val flat = regmap.map { case (reg, fields) => + val offsets = fields.scanLeft(0)(_ + _.width).init + (offsets zip fields) map { case (o, f) => (reg, o, f) } + }.flatten + require (!flat.isEmpty) + + val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1) + val params = RegFieldParams(log2Up(endIndex), bytes, in.bits.params.extraBits) + + val out = Wire(Decoupled(new RegFieldOutput(params))) + val front = Wire(Decoupled(new RegFieldInput(params))) + front.bits := in.bits + + // Must this device pipeline the control channel? + val pipelined = flat.map(_._3.pipelined).reduce(_ || _) + val depth = concurrency.getOrElse(if (pipelined) 1 else 0) + require (depth >= 0) + require (!pipelined || depth > 0) + val back = if (depth > 0) Queue(front, depth, pipe = depth == 1) else front + + // Forward declaration of all flow control signals + val rivalid = Wire(Vec(flat.size, Bool())) + val wivalid = Wire(Vec(flat.size, Bool())) + val riready = Wire(Vec(flat.size, Bool())) + val wiready = Wire(Vec(flat.size, Bool())) + val rovalid = Wire(Vec(flat.size, Bool())) + val wovalid = Wire(Vec(flat.size, Bool())) + val roready = Wire(Vec(flat.size, Bool())) + val woready = Wire(Vec(flat.size, Bool())) + + // Per-register list of all control signals needed for data to flow + val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + + // The output values for each register + val dataOut = Array.tabulate(endIndex) { _ => UInt(0) } + + // Which bits are touched? + val frontMask = FillInterleaved(8, front.bits.mask) + val backMask = FillInterleaved(8, back .bits.mask) + + // Connect the fields + for (i <- 0 until flat.size) { + val (reg, low, field) = flat(i) + val high = low + field.width - 1 + // Confirm that no register is too big + require (high <= 8*bytes) + val rimask = frontMask(high, low).orR() + val wimask = frontMask(high, low).andR() + val romask = backMask(high, low).orR() + val womask = backMask(high, low).andR() + val data = if (field.write.combinational) back.bits.data else front.bits.data + val (f_riready, f_rovalid, f_data) = field.read.fn(rivalid(i) && rimask, roready(i) && romask) + val (f_wiready, f_wovalid) = field.write.fn(wivalid(i) && wimask, woready(i) && womask, data) + riready(i) := f_riready || !rimask + wiready(i) := f_wiready || !wimask + rovalid(i) := f_rovalid || !romask + wovalid(i) := f_wovalid || !womask + rifire(reg) = riready(i) +: rifire(reg) + wifire(reg) = wiready(i) +: wifire(reg) + rofire(reg) = rovalid(i) +: rofire(reg) + wofire(reg) = wovalid(i) +: wofire(reg) + dataOut(reg) = dataOut(reg) | (f_data << low) + } + + // Is the selected register ready? + val rifireMux = Vec(rifire.map(_.reduce(_ && _))) + val wifireMux = Vec(wifire.map(_.reduce(_ && _))) + val rofireMux = Vec(rofire.map(_.reduce(_ && _))) + val wofireMux = Vec(wofire.map(_.reduce(_ && _))) + val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index)) + val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index)) + + // Connect the pipeline + in.ready := front.ready && iready + front.valid := in.valid && iready + back.ready := out.ready && oready + out.valid := back.valid && oready + + // Which register is touched? + val frontSel = UIntToOH(front.bits.index) + val backSel = UIntToOH(back.bits.index) + + // Include the per-register one-hot selected criteria + for (reg <- 0 until endIndex) { + rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg) + wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg) + rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg) + wofire(reg) = (back.valid && out.ready && !back .bits.read && backSel (reg)) +: wofire(reg) + } + + // Connect the field's ivalid and oready + for (i <- 0 until flat.size) { + val (reg, _, _ ) = flat(i) + rivalid(i) := rifire(reg).filter(_ ne riready(i)).reduce(_ && _) + wivalid(i) := wifire(reg).filter(_ ne wiready(i)).reduce(_ && _) + roready(i) := rofire(reg).filter(_ ne rovalid(i)).reduce(_ && _) + woready(i) := wofire(reg).filter(_ ne wovalid(i)).reduce(_ && _) + } + + out.bits.read := back.bits.read + out.bits.data := Vec(dataOut)(back.bits.index) + out.bits.extra := back.bits.extra + + (endIndex, out) + } +} diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index 8d6b764a..cf9ae70f 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -4,7 +4,7 @@ package uncore.tilelink2 import Chisel._ -class TLRegisterNode(address: AddressSet, beatBytes: Int = 4) +class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) extends TLManagerNode(beatBytes, TLManagerParameters( address = Seq(address), supportsGet = TransferSizes(1, beatBytes), @@ -17,87 +17,51 @@ class TLRegisterNode(address: AddressSet, beatBytes: Int = 4) // Calling this method causes the matching TL2 bundle to be // configured to route all requests to the listed RegFields. def regmap(mapping: RegField.Map*) = { - val regmap = mapping.toList - require (!regmap.isEmpty) + val a = bundleIn(0).a + val d = bundleIn(0).d + val edge = edgesIn(0) + + val params = RegFieldParams(log2Up(address.mask+1), beatBytes, edge.bundle.sourceBits + edge.bundle.sizeBits) + val in = Wire(Decoupled(new RegFieldInput(params))) + in.bits.read := a.bits.opcode === TLMessages.Get + in.bits.index := a.bits.address >> log2Ceil(beatBytes) + in.bits.data := a.bits.data + in.bits.mask := a.bits.wmask + in.bits.extra := Cat(a.bits.source, a.bits.size) - // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) - val flat = regmap.map { case (reg, fields) => - val offsets = fields.scanLeft(0)(_ + _.width).init - (offsets zip fields) map { case (o, f) => (reg, o, f) } - }.flatten - - // Confirm that no register is too big - require (flat.map(_._2).max <= beatBytes*8) + // Invoke the register map builder + val (endIndex, out) = RegFieldHelper(beatBytes, concurrency, in, mapping:_*) // All registers must fit inside the device address space - val maxIndex = regmap.map(_._1).max - require (address.mask >= maxIndex*beatBytes) + require (address.mask >= (endIndex-1)*beatBytes) - // Which register is touched? - val alignBits = log2Ceil(beatBytes) - val addressBits = log2Up(maxIndex+1) - val a = bundleIn(0).a // Must apply Queue !!! (so no change once started) - val d = bundleIn(0).d - val regIdx = a.bits.address(addressBits+alignBits-1, alignBits) - val regSel = UIntToOH(regIdx) + // No flow control needed + in.valid := a.valid + a.ready := in.ready + d.valid := out.valid + out.ready := d.ready - // What is the access? - val opcode = a.bits.opcode - val read = a.valid && opcode === TLMessages.Get - val write = a.valid && (opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData) - val wmaskWide = Vec.tabulate(beatBytes*8) { i => a.bits.wmask(i/8) } .toBits.asUInt - val dataIn = a.bits.data & wmaskWide // zero undefined bits - - // The output values for each register - val dataOutAcc = Array.tabulate(maxIndex+1) { _ => UInt(0) } - // The ready state for read and write - val rReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) } - val wReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) } - - // Apply all the field methods - flat.foreach { case (reg, low, field) => - val high = low + field.width - 1 - val rfire = wmaskWide(high, low).orR() - val wfire = wmaskWide(high, low).andR() - val sel = regSel(reg) - val ren = read && sel && rfire - val wen = write && sel && wfire - val (rReady, rResult) = field.read(ren) - val wReady = field.write(wen, dataIn(high, low)) - dataOutAcc(reg) = dataOutAcc(reg) | (rResult << low) - rReadyAcc(reg) = rReadyAcc(reg) && (!rfire || rReady) - wReadyAcc(reg) = wReadyAcc(reg) && (!wfire || wReady) - } - - // Create the output data signal - val dataOut = Vec(dataOutAcc)(regIdx) - val rReady = Vec(rReadyAcc)(regIdx) - val wReady = Vec(wReadyAcc)(regIdx) - - val ready = (read && rReady) || (write && wReady) - a.ready := ready && d.ready - d.valid := a.valid && ready - - val edge = edgesIn(0) - d.bits := edge.AccessAck(a.bits.source, a.bits.size) + val sizeBits = edge.bundle.sizeBits + d.bits := edge.AccessAck(out.bits.extra >> sizeBits, out.bits.extra(sizeBits-1, 0)) // avoid a Mux on the data bus by manually overriding two fields - d.bits.data := dataOut - d.bits.opcode := Mux(opcode === TLMessages.Get, TLMessages.AccessAck, TLMessages.AccessAckData) + d.bits.data := out.bits.data + d.bits.opcode := Mux(out.bits.read, TLMessages.AccessAckData, TLMessages.AccessAck) } } object TLRegisterNode { - def apply(address: AddressSet, beatBytes: Int = 4) = new TLRegisterNode(address, beatBytes) + def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) = + new TLRegisterNode(address, concurrency, beatBytes) } // These convenience methods below combine to make it possible to create a TL2 // register mapped device from a totally abstract register mapped device. // See GPIO.scala in this directory for an example -abstract class TLRegFactory(address: AddressSet, beatBytes: Int) extends TLFactory +abstract class TLRegFactory(address: AddressSet, concurrency: Option[Int], beatBytes: Int) extends TLFactory { - val node = TLRegisterNode(address, beatBytes) + val node = TLRegisterNode(address, concurrency, beatBytes) } class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle @@ -110,10 +74,10 @@ class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, factory: T } class TLRegisterRouter[B <: Bundle, M <: TLModule] - (address: Option[BigInt] = None, size: BigInt = 4096, beatBytes: Int = 4) + (address: Option[BigInt] = None, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4) (bundleBuilder: Vec[TLBundle] => B) (moduleBuilder: (=> B, TLRegFactory) => M) - extends TLRegFactory(AddressSet(size-1, address), beatBytes) + extends TLRegFactory(AddressSet(size-1, address), concurrency, beatBytes) { require (size % 4096 == 0) // devices should be 4K aligned require (isPow2(size)) From 5f7711a0c0edcaace765f30bb5ed4394a6ea2ff8 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 29 Aug 2016 17:53:31 -0700 Subject: [PATCH 27/87] tilelink2: add an intermediate type for simple factories --- uncore/src/main/scala/tilelink2/Bases.scala | 6 ++++++ uncore/src/main/scala/tilelink2/RegisterRouter.scala | 2 +- uncore/src/main/scala/tilelink2/SRAM.scala | 2 +- uncore/src/main/scala/tilelink2/Xbar.scala | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index c9333886..dcd0caf3 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -39,6 +39,12 @@ abstract class TLFactory } } +// Use this if you have only one node => makes factory adapters possible +abstract class TLSimpleFactory extends TLFactory +{ + def node: TLBaseNode +} + abstract class TLModule(factory: TLFactory) extends Module { override def desiredName = factory.getClass.getName.split('.').last diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index cf9ae70f..35ff80d5 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -59,7 +59,7 @@ object TLRegisterNode // register mapped device from a totally abstract register mapped device. // See GPIO.scala in this directory for an example -abstract class TLRegFactory(address: AddressSet, concurrency: Option[Int], beatBytes: Int) extends TLFactory +abstract class TLRegFactory(address: AddressSet, concurrency: Option[Int], beatBytes: Int) extends TLSimpleFactory { val node = TLRegisterNode(address, concurrency, beatBytes) } diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala index 0b3ff2f5..77b10dbc 100644 --- a/uncore/src/main/scala/tilelink2/SRAM.scala +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -4,7 +4,7 @@ package uncore.tilelink2 import Chisel._ -class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLFactory +class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLSimpleFactory { val node = TLManagerNode(beatBytes, TLManagerParameters( address = List(address), diff --git a/uncore/src/main/scala/tilelink2/Xbar.scala b/uncore/src/main/scala/tilelink2/Xbar.scala index 20325196..f4ba477d 100644 --- a/uncore/src/main/scala/tilelink2/Xbar.scala +++ b/uncore/src/main/scala/tilelink2/Xbar.scala @@ -13,7 +13,7 @@ object TLXbar } } -class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extends TLFactory +class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extends TLSimpleFactory { def mapInputIds (ports: Seq[TLClientPortParameters ]) = assignRanges(ports.map(_.endSourceId)) def mapOutputIds(ports: Seq[TLManagerPortParameters]) = assignRanges(ports.map(_.endSinkId)) From 1a87eef3e253b94d5026cc1f56726db2695964d1 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 10:40:14 -0700 Subject: [PATCH 28/87] tilelink2: add atomic message types --- uncore/src/main/scala/tilelink2/Bundles.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 1e405955..a599b36e 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -85,10 +85,19 @@ object TLPermissions object TLAtomics { // Arithmetic types - def isArithmetic(x: UInt) = Bool(true) + val MIN = UInt(0) + val MAX = UInt(1) + val MINU = UInt(2) + val MAXU = UInt(3) + val ADD = UInt(4) + def isArithmetic(x: UInt) = x <= ADD // Logical types - def isLogical(x: UInt) = Bool(true) + val XOR = UInt(0) + val OR = UInt(1) + val AND = UInt(2) + val SWAP = UInt(3) + def isLogical(x: UInt) = x <= SWAP } class Bogus From dd27a60daa00b0fd930f14e9a144a2a0a5758ebc Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 10:40:54 -0700 Subject: [PATCH 29/87] tilelink2: use consistent in/out ports for TLSimpleFactories --- uncore/src/main/scala/tilelink2/RegisterRouter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index 35ff80d5..890e4a0b 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -64,7 +64,7 @@ abstract class TLRegFactory(address: AddressSet, concurrency: Option[Int], beatB val node = TLRegisterNode(address, concurrency, beatBytes) } -class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle +class TLRegBundle[P](val params: P, val in: Vec[TLBundle]) extends Bundle class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, factory: TLRegFactory) extends TLModule(factory) with HasRegMap From 32894a8e20e105e471224f589dfe416d899d6cb6 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 10:40:35 -0700 Subject: [PATCH 30/87] tilelink2: transfers must never exceed 4kB --- uncore/src/main/scala/tilelink2/Parameters.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index a6b07da9..503c4b85 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -50,6 +50,7 @@ case class TransferSizes(min: Int, max: Int) require (min != 0 || max == 0) require (max == 0 || isPow2(max)) require (min == 0 || isPow2(min)) + require (max <= TransferSizes.maxAllowed) def none = min == 0 def contains(x: Int) = isPow2(x) && min <= x && x <= max @@ -69,6 +70,7 @@ case class TransferSizes(min: Int, max: Int) object TransferSizes { def apply(x: Int) = new TransferSizes(x) val none = new TransferSizes(0) + val maxAllowed = 4096 // transfers larger than 4kB are forbidden in TL2 implicit def asBool(x: TransferSizes) = !x.none } From 534d7f6eb6bc045e1eb200561e109e1e878df47b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 11:46:05 -0700 Subject: [PATCH 31/87] tilelink2: implement SRAM manager --- uncore/src/main/scala/tilelink2/SRAM.scala | 46 +++++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala index 77b10dbc..49429e95 100644 --- a/uncore/src/main/scala/tilelink2/SRAM.scala +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -14,11 +14,53 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLSimpleFactory supportsPutFull = TransferSizes(1, beatBytes), fifoId = Some(0))) // requests are handled in order + // We require the address range to include an entire beat (for the write mask) + require ((address.mask & (beatBytes-1)) == beatBytes-1) + lazy val module = Module(new TLModule(this) { val io = new Bundle { val in = node.bundleIn } - - // do stuff + + 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 - (beatBytes-1)) + + val in = io.in(0) + val addrBits = (mask zip in.a.bits.address.toBools).filter(_._1).map(_._2) + val memAddress = Cat(addrBits.reverse) + val mem = SeqMem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8))) + + val d_full = RegInit(Bool(false)) + val d_read = Reg(Bool()) + val d_size = Reg(UInt()) + val d_source = Reg(UInt()) + val d_data = Wire(UInt()) + + // Flow control + when (in.d.fire()) { d_full := Bool(false) } + when (in.a.fire()) { d_full := Bool(true) } + in.d.valid := d_full + in.a.ready := in.d.ready || !d_full + + in.d.bits := node.edgesIn(0).AccessAck(d_source, d_size) + // avoid data-bus Mux + in.d.bits.data := d_data + in.d.bits.opcode := Mux(d_read, TLMessages.AccessAckData, TLMessages.AccessAck) + + val read = in.a.bits.opcode === TLMessages.Get + val rdata = Wire(Vec(beatBytes, Bits(width = 8))) + val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) } + d_data := Cat(rdata.reverse) + when (in.a.fire()) { + d_read := read + d_size := in.a.bits.size + d_source := in.a.bits.source + when (read) { + rdata := mem.read(memAddress) + } .otherwise { + mem.write(memAddress, wdata, in.a.bits.wmask.toBools) + } + } }) } From ec1f901a3882420edf1789f6b63180c13f79b9c2 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 14:38:26 -0700 Subject: [PATCH 32/87] tilelink2: move error from type into Bundle and add HintAck We need Grant with errors too. We also want to match response type to request type more easily. --- uncore/src/main/scala/tilelink2/Bundles.scala | 33 ++++---- uncore/src/main/scala/tilelink2/Monitor.scala | 28 +++---- .../src/main/scala/tilelink2/Operations.scala | 81 ++++++++++++------- 3 files changed, 80 insertions(+), 62 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index a599b36e..47fca838 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -34,25 +34,25 @@ object TLMessages val LogicalData = UInt(3) // . . val Get = UInt(4) // . . val Hint = UInt(5) // . . - val AccessAck = UInt(0) // . . - val AccessAckData = UInt(1) // . . - val AccessAckError = UInt(6) // . . val Acquire = UInt(6) // . val Probe = UInt(6) // . - val ProbeAck = UInt(2) // . - val ProbeAckData = UInt(3) // . - val Release = UInt(4) // . - val ReleaseData = UInt(5) // . -//val PutThroughData = UInt(7) // . // future extension ? - val Grant = UInt(2) // . - val GrantData = UInt(3) // . - val ReleaseAck = UInt(4) // . + val AccessAck = UInt(0) // . . + val AccessAckData = UInt(1) // . . + val HintAck = UInt(2) // . . +//val PutThroughData = UInt(3) // . // future extension ? + val ProbeAck = UInt(4) // . + val ProbeAckData = UInt(5) // . + val Release = UInt(6) // . + val ReleaseData = UInt(7) // . + val Grant = UInt(4) // . + val GrantData = UInt(5) // . + val ReleaseAck = UInt(6) // . val GrantAck = UInt(0) // . def isA(x: UInt) = x <= Acquire def isB(x: UInt) = x <= Probe def isC(x: UInt) = x <= ReleaseData - def isD(x: UInt) = x <= GrantData + def isD(x: UInt) = x <= ReleaseAck } object TLPermissions @@ -122,9 +122,6 @@ trait HasTLData extends HasTLOpcode def wmask(x: Bogus = Bogus()): UInt } -// !!! trait HasTLSource|Sink|Address -// !!! trait param: from and to perms - class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) with HasTLData @@ -177,12 +174,13 @@ class TLBundleC(params: TLBundleParameters) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to val data = UInt(width = params.dataBits) + val error = Bool() // AccessAck[Data] def hasData(x: Bogus = Bogus()) = opcode(0) // opcode === TLMessages.AccessAckData || // opcode === TLMessages.ProbeAckData || // opcode === TLMessages.ReleaseData - def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && !opcode(1) + def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && opcode(1) // opcode === TLMessages.Release || // opcode === TLMessages.ReleaseData def size(x: Bogus = Bogus()) = size @@ -200,11 +198,12 @@ class TLBundleD(params: TLBundleParameters) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from val data = UInt(width = params.dataBits) + val error = Bool() // AccessAck[Data], Grant[Data] def hasData(x: Bogus = Bogus()) = opcode(0) // opcode === TLMessages.AccessAckData || // opcode === TLMessages.GrantData - def hasFollowUp(x: Bogus = Bogus()) = !opcode(2) && opcode(1) + def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && !opcode(1) // opcode === TLMessages.Grant || // opcode === TLMessages.GrantData def size(x: Bogus = Bogus()) = size diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index bd8863bf..7598edd2 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -183,19 +183,19 @@ object TLMonitor assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param")(sourceInfo) } - when (bundle.opcode === TLMessages.AccessAckError) { - assert (address_ok, "'C' channel AccessAckError carries unmanaged address")(sourceInfo) - // source is ignored - assert (is_aligned, "'C' channel AccessAckError address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'C' channel AccessAckError carries invalid param")(sourceInfo) - } - when (bundle.opcode === TLMessages.AccessAckData) { assert (address_ok, "'C' channel AccessAckData carries unmanaged address")(sourceInfo) // source is ignored assert (is_aligned, "'C' channel AccessAckData address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param")(sourceInfo) } + + when (bundle.opcode === TLMessages.HintAck) { + assert (address_ok, "'C' channel HintAck carries unmanaged address")(sourceInfo) + // source is ignored + assert (is_aligned, "'C' channel HintAck address not aligned to size")(sourceInfo) + assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param")(sourceInfo) + } } def legalizeD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { @@ -232,19 +232,19 @@ object TLMonitor assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param")(sourceInfo) } - when (bundle.opcode === TLMessages.AccessAckError) { - assert (source_ok, "'D' channel AccessAckError carries invalid source ID")(sourceInfo) - // sink is ignored - // size is ignored - assert (bundle.param === UInt(0), "'D' channel AccessAckError carries invalid param")(sourceInfo) - } - when (bundle.opcode === TLMessages.AccessAckData) { assert (source_ok, "'D' channel AccessAckData carries invalid source ID")(sourceInfo) // sink is ignored // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param")(sourceInfo) } + + when (bundle.opcode === TLMessages.HintAck) { + assert (source_ok, "'D' channel HintAck carries invalid source ID")(sourceInfo) + // sink is ignored + // size is ignored + assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param")(sourceInfo) + } } def legalizeE(bundle: TLBundleE, edge: TLEdgeOut, sourceInfo: SourceInfo) = { diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index b4fd4e3e..9baa760a 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -12,7 +12,7 @@ class TLEdge( def isAligned(address: UInt, lgSize: UInt) = if (maxLgSize == 0) Bool(true) else { val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } - (address & mask.toBits.asUInt) === UInt(0) + (address & Cat(mask.reverse)) === UInt(0) } // This gets used everywhere, so make the smallest circuit possible ... @@ -34,7 +34,7 @@ class TLEdge( } } } - Vec(helper(lgBytes).map(_._1)).toBits.asUInt + Cat(helper(lgBytes).map(_._1).reverse) } def numBeats(bundle: HasTLOpcode) = { @@ -43,7 +43,7 @@ class TLEdge( val cutoff = log2Ceil(manager.beatBytes) val small = size <= UInt(cutoff) val decode = Vec.tabulate (1+maxLgSize-cutoff) { i => UInt(i + cutoff) === size } - Mux(!hasData || small, UInt(1), decode.toBits.asUInt) + Mux(!hasData || small, UInt(1), Cat(decode.reverse)) } } @@ -77,6 +77,7 @@ class TLEdgeOut( c.source := fromSource c.address := toAddress c.data := UInt(0) + c.error := Bool(false) (legal, c) } @@ -90,6 +91,7 @@ class TLEdgeOut( c.source := fromSource c.address := toAddress c.data := data + c.error := Bool(false) (legal, c) } @@ -101,6 +103,7 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := UInt(0) + c.error := Bool(false) c } @@ -112,6 +115,7 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := data + c.error := Bool(false) c } @@ -206,7 +210,8 @@ class TLEdgeOut( (legal, a) } - def AccessAck(toAddress: UInt, lgSize: UInt) = { + def AccessAck(toAddress: UInt, lgSize: UInt): TLBundleC = AccessAck(toAddress, lgSize, Bool(false)) + def AccessAck(toAddress: UInt, lgSize: UInt, error: Bool) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAck c.param := UInt(0) @@ -214,21 +219,12 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := UInt(0) + c.error := error c } - def AccessAckError(toAddress: UInt, lgSize: UInt) = { - val c = Wire(new TLBundleC(bundle)) - c.opcode := TLMessages.AccessAckError - c.param := UInt(0) - c.size := lgSize - c.source := UInt(0) - c.address := toAddress - c.data := UInt(0) - c - } - - def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt) = { + def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt): TLBundleC = AccessAck(toAddress, lgSize, data, Bool(false)) + def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt, error: Bool) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAckData c.param := UInt(0) @@ -236,6 +232,19 @@ class TLEdgeOut( c.source := UInt(0) c.address := toAddress c.data := data + c.error := error + c + } + + def HintAck(toAddress: UInt, lgSize: UInt) = { + val c = Wire(new TLBundleC(bundle)) + c.opcode := TLMessages.HintAck + c.param := UInt(0) + c.size := lgSize + c.source := UInt(0) + c.address := toAddress + c.data := UInt(0) + c.error := Bool(false) c } } @@ -260,7 +269,8 @@ class TLEdgeIn( (legal, b) } - def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { + def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt): TLBundleD = Grant(fromSink, toSource, lgSize, capPermissions, Bool(false)) + def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.Grant d.param := capPermissions @@ -268,10 +278,12 @@ class TLEdgeIn( d.source := toSource d.sink := fromSink d.data := UInt(0) + d.error := error d } - def GrantData(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt) = { + def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt): TLBundleD = Grant(fromSink, toSource, lgSize, capPermissions, data, Bool(false)) + def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.GrantData d.param := capPermissions @@ -279,6 +291,7 @@ class TLEdgeIn( d.source := toSource d.sink := fromSink d.data := data + d.error := error d } @@ -290,6 +303,7 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := UInt(0) + d.error := Bool(false) d } @@ -378,7 +392,8 @@ class TLEdgeIn( (legal, b) } - def AccessAck(toSource: UInt, lgSize: UInt) = { + def AccessAck(toSource: UInt, lgSize: UInt): TLBundleD = AccessAck(toSource, lgSize, Bool(false)) + def AccessAck(toSource: UInt, lgSize: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.AccessAck d.param := UInt(0) @@ -386,21 +401,12 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := UInt(0) + d.error := error d } - def AccessAckError(toSource: UInt, lgSize: UInt) = { - val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.AccessAckError - d.param := UInt(0) - d.size := lgSize - d.source := toSource - d.sink := UInt(0) - d.data := UInt(0) - d - } - - def AccessAck(toSource: UInt, lgSize: UInt, data: UInt) = { + def AccessAck(toSource: UInt, lgSize: UInt, data: UInt): TLBundleD = AccessAck(toSource, lgSize, data, Bool(false)) + def AccessAck(toSource: UInt, lgSize: UInt, data: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) d.opcode := TLMessages.AccessAckData d.param := UInt(0) @@ -408,6 +414,19 @@ class TLEdgeIn( d.source := toSource d.sink := UInt(0) d.data := data + d.error := error + d + } + + def HintAck(toSource: UInt, lgSize: UInt) = { + val d = Wire(new TLBundleD(bundle)) + d.opcode := TLMessages.HintAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := UInt(0) + d.data := UInt(0) + d.error := Bool(false) d } } From edb17d1e342f7fecfc9efeccfe5ff5ef1538ff5b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 14:43:07 -0700 Subject: [PATCH 33/87] tilelink2: document allowed (and required) response messages --- uncore/src/main/scala/tilelink2/Bundles.scala | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 47fca838..437df198 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -28,24 +28,24 @@ abstract class TLBundleBase(params: TLBundleParameters) extends GenericParameter object TLMessages { // A B C D E - val PutFullData = UInt(0) // . . - val PutPartialData = UInt(1) // . . - val ArithmeticData = UInt(2) // . . - val LogicalData = UInt(3) // . . - val Get = UInt(4) // . . - val Hint = UInt(5) // . . - val Acquire = UInt(6) // . - val Probe = UInt(6) // . + val PutFullData = UInt(0) // . . => AccessAck + val PutPartialData = UInt(1) // . . => AccessAck + val ArithmeticData = UInt(2) // . . => AccessAckData + val LogicalData = UInt(3) // . . => AccessAckData + val Get = UInt(4) // . . => AccessAckData + val Hint = UInt(5) // . . => HintAck + val Acquire = UInt(6) // . => Grant[Data] + val Probe = UInt(6) // . => ProbeAck[Data] val AccessAck = UInt(0) // . . val AccessAckData = UInt(1) // . . val HintAck = UInt(2) // . . //val PutThroughData = UInt(3) // . // future extension ? val ProbeAck = UInt(4) // . val ProbeAckData = UInt(5) // . - val Release = UInt(6) // . - val ReleaseData = UInt(7) // . - val Grant = UInt(4) // . - val GrantData = UInt(5) // . + val Release = UInt(6) // . => ReleaseAck + val ReleaseData = UInt(7) // . => ReleaseAck + val Grant = UInt(4) // . => GrantAck + val GrantData = UInt(5) // . => GrantAck val ReleaseAck = UInt(6) // . val GrantAck = UInt(0) // . From fa472e38fb2b0a9d41ce024505a1bed2baf12551 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 14:54:13 -0700 Subject: [PATCH 34/87] tilelink2: monitor error line legality --- uncore/src/main/scala/tilelink2/Monitor.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index 7598edd2..8c289473 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -150,6 +150,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat")(sourceInfo) assert (is_aligned, "'C' channel ProbeAck address not aligned to size")(sourceInfo) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param")(sourceInfo) + assert (!bundle.error, "'C' channel Probe carries an error")(sourceInfo) } when (bundle.opcode === TLMessages.ProbeAckData) { @@ -158,6 +159,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat")(sourceInfo) assert (is_aligned, "'C' channel ProbeAckData address not aligned to size")(sourceInfo) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param")(sourceInfo) + assert (!bundle.error, "'C' channel ProbeData carries an error")(sourceInfo) } when (bundle.opcode === TLMessages.Release) { @@ -166,6 +168,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat")(sourceInfo) assert (is_aligned, "'C' channel Release address not aligned to size")(sourceInfo) assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param")(sourceInfo) + assert (!bundle.error, "'C' channel Release carries an error")(sourceInfo) } when (bundle.opcode === TLMessages.ReleaseData) { @@ -174,6 +177,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat")(sourceInfo) assert (is_aligned, "'C' channel ReleaseData address not aligned to size")(sourceInfo) assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param")(sourceInfo) + assert (!bundle.error, "'C' channel ReleaseData carries an error")(sourceInfo) } when (bundle.opcode === TLMessages.AccessAck) { @@ -195,6 +199,7 @@ object TLMonitor // source is ignored assert (is_aligned, "'C' channel HintAck address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param")(sourceInfo) + assert (!bundle.error, "'C' channel HintAck carries an error")(sourceInfo) } } @@ -209,6 +214,7 @@ object TLMonitor // sink is ignored assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat")(sourceInfo) assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param")(sourceInfo) + assert (!bundle.error, "'D' channel ReleaseAck carries an error")(sourceInfo) } when (bundle.opcode === TLMessages.Grant) { @@ -244,6 +250,7 @@ object TLMonitor // sink is ignored // size is ignored assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param")(sourceInfo) + assert (!bundle.error, "'D' channel HintAck carries an error")(sourceInfo) } } From 7347b0c4dd7a915f24fa3dbb393bf6cb9096cdc2 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 15:01:49 -0700 Subject: [PATCH 35/87] tilelink2: TLLegacy converts from legacy TileLink to TileLink2 --- uncore/src/main/scala/tilelink2/Legacy.scala | 107 +++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/Legacy.scala diff --git a/uncore/src/main/scala/tilelink2/Legacy.scala b/uncore/src/main/scala/tilelink2/Legacy.scala new file mode 100644 index 00000000..dcb9215b --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Legacy.scala @@ -0,0 +1,107 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import cde.Parameters +import uncore.tilelink._ +import uncore.constants._ + +class TLLegacy(implicit val p: Parameters) extends TLSimpleFactory with HasTileLinkParameters +{ + val outer_p = p + // TL legacy clients don't support anything fancy + val node = TLClientNode(TLClientParameters( + sourceId = IdRange(0, 1 << tlClientXactIdBits))) + + lazy val module = Module(new TLModule(this) with HasTileLinkParameters { + val p = outer_p + val io = new Bundle { + val legacy = new ClientUncachedTileLinkIO()(p).flip + val out = node.bundleOut + } + + // TL legacy is dumb. All managers must support it's accesses. + val edge = node.edgesOut(0) + require (edge.manager.beatBytes == tlDataBytes) + require (edge.manager.allSupportGet .contains(TransferSizes(tlDataBytes))) + require (edge.manager.allSupportGet .contains(TransferSizes(tlDataBeats * tlDataBytes))) + require (edge.manager.allSupportPutPartial.contains(TransferSizes(tlDataBytes))) + require (edge.manager.allSupportPutPartial.contains(TransferSizes(tlDataBeats * tlDataBytes))) + require (edge.manager.allSupportArithmetic.contains(TransferSizes(4, tlDataBytes))) + require (edge.manager.allSupportLogical .contains(TransferSizes(4, tlDataBytes))) + require (edge.manager.allSupportHint) + // TL legacy will not generate PutFull, Acquire + + // Must be able to fit TL2 sink_id into TL legacy + require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId) + + val out = io.out(0) + out.a.valid := io.legacy.acquire.valid + out.d.ready := io.legacy.grant .ready + io.legacy.acquire.ready := out.a.ready + io.legacy.grant .valid := out.d.valid + + val source = io.legacy.acquire.bits.client_xact_id + val data = io.legacy.acquire.bits.data + val wmask = io.legacy.acquire.bits.wmask() + val address = io.legacy.acquire.bits.full_addr() + + val beat = UInt(log2Ceil(tlDataBytes)) + val block = UInt(log2Ceil(tlDataBytes*tlDataBeats)) + + out.a.bits := MuxLookup(io.legacy.acquire.bits.a_type, new TLBundleA(edge.bundle), Array( + Acquire.getType -> edge.Get (source, address, beat) ._2, + Acquire.getBlockType -> edge.Get (source, address, block)._2, + Acquire.putType -> edge.Put (source, address, beat, data, wmask)._2, + Acquire.putBlockType -> edge.Put (source, address, block, data, wmask)._2, + Acquire.getPrefetchType -> edge.Hint(source, address, block, UInt(0))._2, + Acquire.putPrefetchType -> edge.Hint(source, address, block, UInt(1))._2, + Acquire.putAtomicType -> MuxLookup(io.legacy.acquire.bits.op_code(), new TLBundleA(edge.bundle), Array( + MemoryOpConstants.M_XA_SWAP -> edge.Logical(source, address, beat, data, TLAtomics.SWAP)._2, + MemoryOpConstants.M_XA_XOR -> edge.Logical(source, address, beat, data, TLAtomics.XOR) ._2, + MemoryOpConstants.M_XA_OR -> edge.Logical(source, address, beat, data, TLAtomics.OR) ._2, + MemoryOpConstants.M_XA_AND -> edge.Logical(source, address, beat, data, TLAtomics.AND) ._2, + MemoryOpConstants.M_XA_ADD -> edge.Arithmetic(source, address, beat, data, TLAtomics.ADD)._2, + MemoryOpConstants.M_XA_MIN -> edge.Arithmetic(source, address, beat, data, TLAtomics.MIN)._2, + MemoryOpConstants.M_XA_MAX -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAX)._2, + MemoryOpConstants.M_XA_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2, + MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2)))) + + val beatMask = UInt(tlDataBytes-1) + val blockMask = UInt(tlDataBytes*tlDataBeats-1) + val addressMask = MuxLookup(io.legacy.acquire.bits.a_type, beatMask, Array( + Acquire.getType -> beatMask, + Acquire.getBlockType -> blockMask, + Acquire.putType -> beatMask, + Acquire.putBlockType -> blockMask, + Acquire.getPrefetchType -> blockMask, + Acquire.putPrefetchType -> blockMask, + Acquire.putAtomicType -> beatMask)) + + // Get rid of some unneeded muxes + out.a.bits.source := source + out.a.bits.data := data + out.a.bits.address := address & ~addressMask + + // TL legacy does not support bus errors + assert (!out.d.bits.error) + + // Recreate the beat address counter + val beatCounter = RegInit(UInt(0, width = tlBeatAddrBits)) + when (out.d.fire() && out.d.bits.hasData() && out.d.bits.size === block) { + beatCounter := beatCounter + UInt(1) + } + + val grant = io.legacy.grant.bits + grant.g_type := MuxLookup(out.d.bits.opcode, Grant.prefetchAckType, Array( + TLMessages.AccessAck -> Grant.putAckType, + TLMessages.AccessAckData -> Mux(out.d.bits.size === beat, Grant.getDataBeatType, Grant.getDataBlockType), + TLMessages.HintAck -> Grant.prefetchAckType)) + grant.is_builtin_type := Bool(true) + grant.client_xact_id := out.d.bits.source + grant.manager_xact_id := out.d.bits.sink + grant.data := out.d.bits.data + grant.addr_beat := beatCounter + }) +} From 5f6ca0bd0d653724d2afab2f3ce1485398d864b7 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 15:06:37 -0700 Subject: [PATCH 36/87] tilelink2: rename wmask => mask since it also applies to reads --- uncore/src/main/scala/tilelink2/Bundles.scala | 14 ++++---- uncore/src/main/scala/tilelink2/Monitor.scala | 32 +++++++++---------- .../src/main/scala/tilelink2/Operations.scala | 32 +++++++++---------- .../main/scala/tilelink2/RegisterRouter.scala | 2 +- uncore/src/main/scala/tilelink2/SRAM.scala | 2 +- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 437df198..06b00a6f 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -119,7 +119,7 @@ trait HasTLOpcode trait HasTLData extends HasTLOpcode { def data(x: Bogus = Bogus()): UInt - def wmask(x: Bogus = Bogus()): UInt + def mask(x: Bogus = Bogus()): UInt } class TLBundleA(params: TLBundleParameters) @@ -131,7 +131,7 @@ class TLBundleA(params: TLBundleParameters) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to - val wmask = UInt(width = params.dataBits/8) + val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) def hasData(x: Bogus = Bogus()) = !opcode(2) @@ -142,7 +142,7 @@ class TLBundleA(params: TLBundleParameters) def hasFollowUp(x: Bogus = Bogus()) = Bool(true) def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data - def wmask(x: Bogus = Bogus()) = wmask + def mask(x: Bogus = Bogus()) = mask } class TLBundleB(params: TLBundleParameters) @@ -154,14 +154,14 @@ class TLBundleB(params: TLBundleParameters) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val address = UInt(width = params.addressBits) // from - val wmask = UInt(width = params.dataBits/8) + val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) def hasData(x: Bogus = Bogus()) = !opcode(2) def hasFollowUp(x: Bogus = Bogus()) = Bool(true) def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data - def wmask(x: Bogus = Bogus()) = wmask + def mask(x: Bogus = Bogus()) = mask } class TLBundleC(params: TLBundleParameters) @@ -185,7 +185,7 @@ class TLBundleC(params: TLBundleParameters) // opcode === TLMessages.ReleaseData def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data - def wmask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt + def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt } class TLBundleD(params: TLBundleParameters) @@ -208,7 +208,7 @@ class TLBundleD(params: TLBundleParameters) // opcode === TLMessages.GrantData def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data - def wmask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt + def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt } class TLBundleE(params: TLBundleParameters) diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index 8c289473..37f0f655 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -13,7 +13,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) - val wmask = edge.fullMask(bundle.address, bundle.size) + val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Acquire) { assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager")(sourceInfo) @@ -21,7 +21,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat")(sourceInfo) assert (is_aligned, "'A' channel Acquire address not aligned to size")(sourceInfo) assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param")(sourceInfo) - assert (bundle.wmask === SInt(-1).asUInt, "'A' channel Acquire contains invalid wmask")(sourceInfo) + assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.Get) { @@ -29,7 +29,7 @@ object TLMonitor assert (source_ok, "'A' channel Get carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel Get address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel Get carries invalid param")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel Get contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel Get contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.PutFullData) { @@ -37,7 +37,7 @@ object TLMonitor assert (source_ok, "'A' channel PutFull carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel PutFull address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel PutFull contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel PutFull contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.PutPartialData) { @@ -45,7 +45,7 @@ object TLMonitor assert (source_ok, "'A' channel PutPartial carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel PutPartial address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.wmask & ~wmask) === UInt(0), "'A' channel PutPartial contains invalid wmask")(sourceInfo) + assert ((bundle.mask & ~mask) === UInt(0), "'A' channel PutPartial contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.ArithmeticData) { @@ -53,7 +53,7 @@ object TLMonitor assert (source_ok, "'A' channel Arithmetic carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel Arithmetic address not aligned to size")(sourceInfo) assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel Arithmetic contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel Arithmetic contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.LogicalData) { @@ -61,14 +61,14 @@ object TLMonitor assert (source_ok, "'A' channel Logical carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel Logical address not aligned to size")(sourceInfo) assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel Logical contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel Logical contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.Hint) { assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager")(sourceInfo) assert (source_ok, "'A' channel Hint carries invalid source ID")(sourceInfo) assert (is_aligned, "'A' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel Hint contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel Hint contains invalid mask")(sourceInfo) } } @@ -78,7 +78,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) - val wmask = edge.fullMask(bundle.address, bundle.size) + val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client")(sourceInfo) @@ -86,7 +86,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat")(sourceInfo) assert (is_aligned, "'B' channel Probe address not aligned to size")(sourceInfo) assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param")(sourceInfo) - assert (bundle.wmask === SInt(-1).asUInt, "'B' channel Probe contains invalid wmask")(sourceInfo) + assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.Get) { @@ -94,7 +94,7 @@ object TLMonitor assert (address_ok, "'B' channel Get carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel Get address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel Get carries invalid param")(sourceInfo) - assert (bundle.wmask === wmask, "'A' channel Get contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'A' channel Get contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.PutFullData) { @@ -102,7 +102,7 @@ object TLMonitor assert (address_ok, "'B' channel PutFull carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel PutFull address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.wmask === wmask, "'B' channel PutFull contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'B' channel PutFull contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.PutPartialData) { @@ -110,7 +110,7 @@ object TLMonitor assert (address_ok, "'B' channel PutPartial carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel PutPartial address not aligned to size")(sourceInfo) assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.wmask & ~wmask) === UInt(0), "'B' channel PutPartial contains invalid wmask")(sourceInfo) + assert ((bundle.mask & ~mask) === UInt(0), "'B' channel PutPartial contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.ArithmeticData) { @@ -118,7 +118,7 @@ object TLMonitor assert (address_ok, "'B' channel Arithmetic carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel Arithmetic address not aligned to size")(sourceInfo) assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === wmask, "'B' channel Arithmetic contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'B' channel Arithmetic contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.LogicalData) { @@ -126,14 +126,14 @@ object TLMonitor assert (address_ok, "'B' channel Logical carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel Logical address not aligned to size")(sourceInfo) assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.wmask === wmask, "'B' channel Logical contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'B' channel Logical contains invalid mask")(sourceInfo) } when (bundle.opcode === TLMessages.Hint) { assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client")(sourceInfo) assert (address_ok, "'B' channel Hint carries unmanaged address")(sourceInfo) assert (is_aligned, "'B' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.wmask === wmask, "'B' channel Hint contains invalid wmask")(sourceInfo) + assert (bundle.mask === mask, "'B' channel Hint contains invalid mask")(sourceInfo) } } diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index 9baa760a..bf9ca7f1 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -62,7 +62,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := SInt(-1).asUInt + a.mask := SInt(-1).asUInt a.data := UInt(0) (legal, a) } @@ -135,7 +135,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := fullMask(toAddress, lgSize) + a.mask := fullMask(toAddress, lgSize) a.data := UInt(0) (legal, a) } @@ -149,12 +149,12 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := fullMask(toAddress, lgSize) + a.mask := fullMask(toAddress, lgSize) a.data := data (legal, a) } - def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, mask : UInt) = { require (manager.anySupportPutPartial) val legal = manager.supportsPutPartial(toAddress, lgSize) val a = Wire(new TLBundleA(bundle)) @@ -163,7 +163,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := wmask + a.mask := mask a.data := data (legal, a) } @@ -177,7 +177,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := fullMask(toAddress, lgSize) + a.mask := fullMask(toAddress, lgSize) a.data := data (legal, a) } @@ -191,7 +191,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := fullMask(toAddress, lgSize) + a.mask := fullMask(toAddress, lgSize) a.data := data (legal, a) } @@ -205,7 +205,7 @@ class TLEdgeOut( a.size := lgSize a.source := fromSource a.address := toAddress - a.wmask := fullMask(toAddress, lgSize) + a.mask := fullMask(toAddress, lgSize) a.data := UInt(0) (legal, a) } @@ -264,7 +264,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := SInt(-1).asUInt + b.mask := SInt(-1).asUInt b.data := UInt(0) (legal, b) } @@ -317,7 +317,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.mask := fullMask(fromAddress, lgSize) b.data := UInt(0) (legal, b) } @@ -331,12 +331,12 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.mask := fullMask(fromAddress, lgSize) b.data := data (legal, b) } - def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, wmask: UInt) = { + def Put(fromAddress: UInt, toSource: UInt, lgSize: UInt, data: UInt, mask : UInt) = { require (client.anySupportPutPartial) val legal = client.supportsPutPartial(toSource, lgSize) val b = Wire(new TLBundleB(bundle)) @@ -345,7 +345,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := wmask + b.mask := mask b.data := data (legal, b) } @@ -359,7 +359,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.mask := fullMask(fromAddress, lgSize) b.data := data (legal, b) } @@ -373,7 +373,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.mask := fullMask(fromAddress, lgSize) b.data := data (legal, b) } @@ -387,7 +387,7 @@ class TLEdgeIn( b.size := lgSize b.source := toSource b.address := fromAddress - b.wmask := fullMask(fromAddress, lgSize) + b.mask := fullMask(fromAddress, lgSize) b.data := UInt(0) (legal, b) } diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index 890e4a0b..1e0933ff 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -26,7 +26,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB in.bits.read := a.bits.opcode === TLMessages.Get in.bits.index := a.bits.address >> log2Ceil(beatBytes) in.bits.data := a.bits.data - in.bits.mask := a.bits.wmask + in.bits.mask := a.bits.mask in.bits.extra := Cat(a.bits.source, a.bits.size) // Invoke the register map builder diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala index 49429e95..352faeef 100644 --- a/uncore/src/main/scala/tilelink2/SRAM.scala +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -59,7 +59,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLSimpleFactory when (read) { rdata := mem.read(memAddress) } .otherwise { - mem.write(memAddress, wdata, in.a.bits.wmask.toBools) + mem.write(memAddress, wdata, in.a.bits.mask.toBools) } } }) From f0cfd81820edf59d82331ede319999082ece4ba4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 15:52:04 -0700 Subject: [PATCH 37/87] tilelink2: add an adapter to add support for Hints to devices --- .../main/scala/tilelink2/HintHandler.scala | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/HintHandler.scala diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala new file mode 100644 index 00000000..16ca6a4f --- /dev/null +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -0,0 +1,49 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +// Acks Hints for managers that don't support them or Acks all Hints if !passthrough +class TLHintHandler(passthrough: Boolean = true) extends TLSimpleFactory +{ + val node = TLAdapterNode( + clientFn = { case Seq(c) => c.copy(clients = c.clients .map(_.copy(supportsHint = true))) }, + managerFn = { case Seq(m) => m.copy(managers = m.managers.map(_.copy(supportsHint = true))) }) + + lazy val module = Module(new TLModule(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val in = io.in(0) + val out = io.out(0) + val edgeIn = node.edgesIn(0) + val edgeOut = node.edgesOut(0) + + val handleA = if (passthrough) !edgeOut.manager.supportsHint(in.a.bits.address) else Bool(true) + val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint + + // Prioritize existing D traffic over HintAck + in.d.valid := out.d.valid || (bypassD && in.a.valid) + out.d.ready := in.d.ready + in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits.source, in.a.bits.size)) + + in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) + out.a.valid := in.a.valid && !bypassD + out.a.bits := in.a.bits + + val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source) else Bool(true) + val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint + + // Prioritize existing C traffic over HintAck + out.c.valid := in.c.valid || (bypassC && in.b.valid) + in.c.ready := out.c.ready + out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits.address, out.b.bits.size)) + + out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) + in.b.valid := out.b.valid && !bypassC + in.b.bits := out.b.bits + }) +} From a72f7115ae5355e598cc2f61f1a9d419de1017e3 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 16:02:46 -0700 Subject: [PATCH 38/87] tilelink2: optimize support testing circuits --- .../src/main/scala/tilelink2/Parameters.scala | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 503c4b85..6a8170c9 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -136,6 +136,7 @@ case class TLManagerParameters( case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes: Int) { + require (!managers.isEmpty) require (isPow2(beatBytes)) // Require disjoint ranges for Ids and addresses @@ -182,8 +183,10 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes def containsById(id: UInt) = findById(id).reduce(_ || _) private def safety_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { - (find(address) zip managers.map(member(_).containsLg(lgSize))) - .map { case (m, s) => m && s } reduce (_ || _) + val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) + if (allSame) member(managers(0)).containsLg(lgSize) else { + Mux1H(find(address), managers.map(member(_).containsLg(lgSize))) + } } // Check for support of a given operation at a specific address @@ -194,8 +197,9 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ def supportsHint(address: UInt) = { - (find(address) zip managers.map(_.supportsHint)) - .map { case (m, b) => m && Bool(b) } reduce (_ || _) + if (allSupportHint) Bool(true) else { + Mux1H(find(address), managers.map(m => Bool(m.supportsHint))) + } } } @@ -220,6 +224,8 @@ case class TLClientParameters( } case class TLClientPortParameters(clients: Seq[TLClientParameters]) { + require (!clients.isEmpty) + // Require disjoint ranges for Ids clients.combinations(2).foreach({ case Seq(x,y) => require (!x.sourceId.overlaps(y.sourceId)) @@ -255,8 +261,10 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { def contains(id: UInt) = find(id).reduce(_ || _) private def safety_helper(member: TLClientParameters => TransferSizes)(id: UInt, lgSize: UInt) = { - (find(id) zip clients.map(member(_).containsLg(lgSize))) - .map { case (m, s) => m && s } reduce (_ || _) + val allSame = clients.map(member(_) == member(clients(0))).reduce(_ && _) + if (allSame) member(clients(0)).containsLg(lgSize) else { + Mux1H(find(id), clients.map(member(_).containsLg(lgSize))) + } } // Check for support of a given operation at a specific id @@ -267,8 +275,9 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutPartial = safety_helper(_.supportsPutPartial) _ def supportsHint(id: UInt) = { - (find(id) zip clients.map(_.supportsHint)) - .map { case (m, b) => m && Bool(b) } reduce (_ || _) + if (allSupportHint) Bool(true) else { + Mux1H(find(id), clients.map(c => Bool(c.supportsHint))) + } } } From cc8112d02e4762eeae15f58292c36f7c319b2c42 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 16:10:42 -0700 Subject: [PATCH 39/87] tilelink2: pass E through the HintHandler --- uncore/src/main/scala/tilelink2/HintHandler.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index 16ca6a4f..53c2ca0b 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -45,5 +45,10 @@ class TLHintHandler(passthrough: Boolean = true) extends TLSimpleFactory out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) in.b.valid := out.b.valid && !bypassC in.b.bits := out.b.bits + + // Pass E through unchanged + out.e.valid := in.e.valid + in.e.ready := out.e.ready + out.e.bits := in.e.bits }) } From eac4d44131325c1a11c7f3e520a675003500ac49 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 16:16:45 -0700 Subject: [PATCH 40/87] tilelink2: don't apply HintHandler to B=>C by default --- .../main/scala/tilelink2/HintHandler.scala | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index 53c2ca0b..e32df111 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -5,11 +5,11 @@ package uncore.tilelink2 import Chisel._ // Acks Hints for managers that don't support them or Acks all Hints if !passthrough -class TLHintHandler(passthrough: Boolean = true) extends TLSimpleFactory +class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends TLSimpleFactory { val node = TLAdapterNode( - clientFn = { case Seq(c) => c.copy(clients = c.clients .map(_.copy(supportsHint = true))) }, - managerFn = { case Seq(m) => m.copy(managers = m.managers.map(_.copy(supportsHint = true))) }) + clientFn = { case Seq(c) => if (supportClients) c.copy(clients = c.clients .map(_.copy(supportsHint = true))) else c }, + managerFn = { case Seq(m) => if (supportManagers) m.copy(managers = m.managers.map(_.copy(supportsHint = true))) else m }) lazy val module = Module(new TLModule(this) { val io = new Bundle { @@ -22,29 +22,49 @@ class TLHintHandler(passthrough: Boolean = true) extends TLSimpleFactory val edgeIn = node.edgesIn(0) val edgeOut = node.edgesOut(0) - val handleA = if (passthrough) !edgeOut.manager.supportsHint(in.a.bits.address) else Bool(true) - val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint + if (supportManagers) { + val handleA = if (passthrough) !edgeOut.manager.supportsHint(in.a.bits.address) else Bool(true) + val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint - // Prioritize existing D traffic over HintAck - in.d.valid := out.d.valid || (bypassD && in.a.valid) - out.d.ready := in.d.ready - in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits.source, in.a.bits.size)) + // Prioritize existing D traffic over HintAck + in.d.valid := out.d.valid || (bypassD && in.a.valid) + out.d.ready := in.d.ready + in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits.source, in.a.bits.size)) - in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) - out.a.valid := in.a.valid && !bypassD - out.a.bits := in.a.bits - - val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source) else Bool(true) - val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint + in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) + out.a.valid := in.a.valid && !bypassD + out.a.bits := in.a.bits + } else { + out.a.valid := in.a.valid + in.a.ready := out.a.ready + out.a.bits := in.a.bits - // Prioritize existing C traffic over HintAck - out.c.valid := in.c.valid || (bypassC && in.b.valid) - in.c.ready := out.c.ready - out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits.address, out.b.bits.size)) - - out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) - in.b.valid := out.b.valid && !bypassC - in.b.bits := out.b.bits + in.d.valid := out.d.valid + out.d.ready := in.d.ready + in.d.bits := out.d.bits + } + + if (supportClients) { + val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source) else Bool(true) + val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint + + // Prioritize existing C traffic over HintAck + out.c.valid := in.c.valid || (bypassC && in.b.valid) + in.c.ready := out.c.ready + out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits.address, out.b.bits.size)) + + out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) + in.b.valid := out.b.valid && !bypassC + in.b.bits := out.b.bits + } else { + in.b.valid := out.b.valid + out.b.ready := in.b.ready + in.b.bits := out.b.bits + + out.c.valid := in.c.valid + in.c.ready := out.c.ready + out.c.bits := in.c.bits + } // Pass E through unchanged out.e.valid := in.e.valid From 5b31fb81fe3d5657455e5640dc10fe62a0354c2d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 30 Aug 2016 19:26:01 -0700 Subject: [PATCH 41/87] tilelink2: IDNode needs to be specialized for output vs. input passthrough --- uncore/src/main/scala/tilelink2/Bases.scala | 12 +++++---- uncore/src/main/scala/tilelink2/Nodes.scala | 30 ++++++++++++++++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index dcd0caf3..17954db4 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -29,12 +29,14 @@ abstract class TLFactory } } bindings.foreach { case (x, i, y, j, s) => - TLMonitor.legalize(y.bundleOut(j), y.edgesOut(j), x.bundleIn(i), x.edgesIn(i), s) - x.bundleIn(i).<>(y.bundleOut(j))(s) + val in = x.connectIn(i) + val out = y.connectOut(j) + TLMonitor.legalize(out, y.edgesOut(j), in, x.edgesIn(i), s) + in.<>(out)(s) val mask = ~UInt(x.edgesIn(i).manager.beatBytes - 1) - x.bundleIn (i).a.bits.address.:=(mask & y.bundleOut(j).a.bits.address)(s) - y.bundleOut(j).b.bits.address.:=(mask & x.bundleIn (i).b.bits.address)(s) - x.bundleIn (i).c.bits.address.:=(mask & y.bundleOut(j).c.bits.address)(s) + in .a.bits.address.:=(mask & out.a.bits.address)(s) + out.b.bits.address.:=(mask & in .b.bits.address)(s) + in .c.bits.address.:=(mask & out.c.bits.address)(s) } } } diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index be3e7eb2..9328fad6 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -50,6 +50,9 @@ class TLBaseNode( lazy val bundleOut = { require (!edgesOut.isEmpty); Vec(edgesOut.size, TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) } lazy val bundleIn = { require (!edgesIn .isEmpty); Vec(edgesIn .size, TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip } + + def connectOut = bundleOut + def connectIn = bundleIn } class TLClientNode( @@ -109,13 +112,32 @@ object TLAdapterNode numManagerPorts: Range.Inclusive = 1 to 1) = new TLAdapterNode(clientFn, managerFn, numClientPorts, numManagerPorts) } -class TLIDNode extends TLBaseNode( +class TLOutputNode extends TLBaseNode( clientFn = Some({case Seq(x) => x}), managerFn = Some({case Seq(x) => x}), numClientPorts = 1 to 1, numManagerPorts = 1 to 1) - -object TLIDNode { - def apply() = new TLIDNode() + override def connectOut = bundleOut + override def connectIn = bundleOut +} + +object TLOutputNode +{ + def apply() = new TLOutputNode() +} + +class TLInputNode extends TLBaseNode( + clientFn = Some({case Seq(x) => x}), + managerFn = Some({case Seq(x) => x}), + numClientPorts = 1 to 1, + numManagerPorts = 1 to 1) +{ + override def connectOut = bundleIn + override def connectIn = bundleIn +} + +object TLInputNode +{ + def apply() = new TLInputNode() } From f99a3dbec7595ad02a302606b5e3b625bef4a4ba Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 10:25:46 -0700 Subject: [PATCH 42/87] tilelink2: rename Factory=>LazyModule and TLModule=>LazyModuleImp --- uncore/src/main/scala/tilelink2/Bases.scala | 22 +++++++------------ .../main/scala/tilelink2/HintHandler.scala | 4 ++-- uncore/src/main/scala/tilelink2/Legacy.scala | 4 ++-- .../main/scala/tilelink2/RegisterRouter.scala | 14 ++++++------ uncore/src/main/scala/tilelink2/SRAM.scala | 4 ++-- uncore/src/main/scala/tilelink2/Xbar.scala | 4 ++-- 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index 17954db4..ee36f273 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -6,7 +6,7 @@ import Chisel._ import scala.collection.mutable.ListBuffer import chisel3.internal.sourceinfo.SourceInfo -abstract class TLFactory +abstract class LazyModule { private val bindings = ListBuffer[(TLBaseNode, Int, TLBaseNode, Int, SourceInfo)]() @@ -15,17 +15,17 @@ abstract class TLFactory bindings += ((manager, i, client, j, sourceInfo)) } - def module: TLModule + def module: LazyModuleImp protected[tilelink2] def instantiate() = { - // Find all TLFactory members of self + // Find all LazyModule members of self for (m <- getClass.getMethods) { if (m.getParameterTypes.isEmpty && !java.lang.reflect.Modifier.isStatic(m.getModifiers) && !(m.getName contains '$') && - classOf[TLFactory].isAssignableFrom(m.getReturnType)) { + classOf[LazyModule].isAssignableFrom(m.getReturnType)) { // ... and force their lazy module members to exist - m.invoke(this).asInstanceOf[TLFactory].module + m.invoke(this).asInstanceOf[LazyModule].module } } bindings.foreach { case (x, i, y, j, s) => @@ -41,14 +41,8 @@ abstract class TLFactory } } -// Use this if you have only one node => makes factory adapters possible -abstract class TLSimpleFactory extends TLFactory +abstract class LazyModuleImp(outer: LazyModule) extends Module { - def node: TLBaseNode -} - -abstract class TLModule(factory: TLFactory) extends Module -{ - override def desiredName = factory.getClass.getName.split('.').last - factory.instantiate() + override def desiredName = outer.getClass.getName.split('.').last + outer.instantiate() } diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index e32df111..584716a8 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -5,13 +5,13 @@ package uncore.tilelink2 import Chisel._ // Acks Hints for managers that don't support them or Acks all Hints if !passthrough -class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends TLSimpleFactory +class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule { val node = TLAdapterNode( clientFn = { case Seq(c) => if (supportClients) c.copy(clients = c.clients .map(_.copy(supportsHint = true))) else c }, managerFn = { case Seq(m) => if (supportManagers) m.copy(managers = m.managers.map(_.copy(supportsHint = true))) else m }) - lazy val module = Module(new TLModule(this) { + lazy val module = Module(new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut diff --git a/uncore/src/main/scala/tilelink2/Legacy.scala b/uncore/src/main/scala/tilelink2/Legacy.scala index dcb9215b..9aae31db 100644 --- a/uncore/src/main/scala/tilelink2/Legacy.scala +++ b/uncore/src/main/scala/tilelink2/Legacy.scala @@ -7,14 +7,14 @@ import cde.Parameters import uncore.tilelink._ import uncore.constants._ -class TLLegacy(implicit val p: Parameters) extends TLSimpleFactory with HasTileLinkParameters +class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkParameters { val outer_p = p // TL legacy clients don't support anything fancy val node = TLClientNode(TLClientParameters( sourceId = IdRange(0, 1 << tlClientXactIdBits))) - lazy val module = Module(new TLModule(this) with HasTileLinkParameters { + lazy val module = Module(new LazyModuleImp(this) with HasTileLinkParameters { val p = outer_p val io = new Bundle { val legacy = new ClientUncachedTileLinkIO()(p).flip diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index 1e0933ff..de511705 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -59,25 +59,25 @@ object TLRegisterNode // register mapped device from a totally abstract register mapped device. // See GPIO.scala in this directory for an example -abstract class TLRegFactory(address: AddressSet, concurrency: Option[Int], beatBytes: Int) extends TLSimpleFactory +abstract class TLRegisterRouterBase(address: AddressSet, concurrency: Option[Int], beatBytes: Int) extends LazyModule { val node = TLRegisterNode(address, concurrency, beatBytes) } class TLRegBundle[P](val params: P, val in: Vec[TLBundle]) extends Bundle -class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, factory: TLRegFactory) - extends TLModule(factory) with HasRegMap +class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, router: TLRegisterRouterBase) + extends LazyModuleImp(router) with HasRegMap { val io = bundleBuilder - def regmap(mapping: RegField.Map*) = factory.node.regmap(mapping:_*) + def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*) } -class TLRegisterRouter[B <: Bundle, M <: TLModule] +class TLRegisterRouter[B <: Bundle, M <: LazyModuleImp] (address: Option[BigInt] = None, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4) (bundleBuilder: Vec[TLBundle] => B) - (moduleBuilder: (=> B, TLRegFactory) => M) - extends TLRegFactory(AddressSet(size-1, address), concurrency, beatBytes) + (moduleBuilder: (=> B, TLRegisterRouterBase) => M) + extends TLRegisterRouterBase(AddressSet(size-1, address), concurrency, beatBytes) { require (size % 4096 == 0) // devices should be 4K aligned require (isPow2(size)) diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala index 352faeef..5c499cf4 100644 --- a/uncore/src/main/scala/tilelink2/SRAM.scala +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -4,7 +4,7 @@ package uncore.tilelink2 import Chisel._ -class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLSimpleFactory +class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule { val node = TLManagerNode(beatBytes, TLManagerParameters( address = List(address), @@ -17,7 +17,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends TLSimpleFactory // We require the address range to include an entire beat (for the write mask) require ((address.mask & (beatBytes-1)) == beatBytes-1) - lazy val module = Module(new TLModule(this) { + lazy val module = Module(new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn } diff --git a/uncore/src/main/scala/tilelink2/Xbar.scala b/uncore/src/main/scala/tilelink2/Xbar.scala index f4ba477d..19bd5df1 100644 --- a/uncore/src/main/scala/tilelink2/Xbar.scala +++ b/uncore/src/main/scala/tilelink2/Xbar.scala @@ -13,7 +13,7 @@ object TLXbar } } -class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extends TLSimpleFactory +class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extends LazyModule { def mapInputIds (ports: Seq[TLClientPortParameters ]) = assignRanges(ports.map(_.endSourceId)) def mapOutputIds(ports: Seq[TLManagerPortParameters]) = assignRanges(ports.map(_.endSinkId)) @@ -65,7 +65,7 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend TLManagerPortParameters(managers, seq(0).beatBytes) }) - lazy val module = Module(new TLModule(this) { + lazy val module = Module(new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut From 8d54ae8508efd3b875638423d928db9f2004129d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 10:37:30 -0700 Subject: [PATCH 43/87] tilelink2: move TL-specific stuff out of the LazyModule base classes --- uncore/src/main/scala/tilelink2/Bases.scala | 16 ++-------- uncore/src/main/scala/tilelink2/Nodes.scala | 34 +++++++++++++-------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/Bases.scala index ee36f273..3187c71b 100644 --- a/uncore/src/main/scala/tilelink2/Bases.scala +++ b/uncore/src/main/scala/tilelink2/Bases.scala @@ -8,11 +8,10 @@ import chisel3.internal.sourceinfo.SourceInfo abstract class LazyModule { - private val bindings = ListBuffer[(TLBaseNode, Int, TLBaseNode, Int, SourceInfo)]() + private val bindings = ListBuffer[() => Unit]() def tl(manager: TLBaseNode, client: TLBaseNode)(implicit sourceInfo: SourceInfo) = { - val (i, j) = manager.edge(client) - bindings += ((manager, i, client, j, sourceInfo)) + bindings += manager.edge(client) } def module: LazyModuleImp @@ -28,16 +27,7 @@ abstract class LazyModule m.invoke(this).asInstanceOf[LazyModule].module } } - bindings.foreach { case (x, i, y, j, s) => - val in = x.connectIn(i) - val out = y.connectOut(j) - TLMonitor.legalize(out, y.edgesOut(j), in, x.edgesIn(i), s) - in.<>(out)(s) - val mask = ~UInt(x.edgesIn(i).manager.beatBytes - 1) - in .a.bits.address.:=(mask & out.a.bits.address)(s) - out.b.bits.address.:=(mask & in .b.bits.address)(s) - in .c.bits.address.:=(mask & out.c.bits.address)(s) - } + bindings.foreach { f => f () } } } diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index 9328fad6..a13b30e7 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -4,6 +4,7 @@ package uncore.tilelink2 import Chisel._ import scala.collection.mutable.ListBuffer +import chisel3.internal.sourceinfo.SourceInfo class TLBaseNode( private val clientFn: Option[Seq[TLClientPortParameters] => TLClientPortParameters], @@ -28,18 +29,6 @@ class TLBaseNode( private var clientRealized = false private var managerRealized = false - protected[tilelink2] def edge(x: TLBaseNode) = { - require (!noManagers) - require (!managerRealized) - require (!x.noClients) - require (!x.clientRealized) - val i = accManagerPorts.size - val j = x.accClientPorts.size - accManagerPorts += x - x.accClientPorts += this - (i, j) - } - private lazy val clientPorts = { clientRealized = true; require (numClientPorts.contains(accClientPorts.size)); accClientPorts.result() } private lazy val managerPorts = { managerRealized = true; require (numManagerPorts.contains(accManagerPorts.size)); accManagerPorts.result() } private lazy val clientParams : Option[TLClientPortParameters] = clientFn.map(_(managerPorts.map(_.clientParams.get))) @@ -53,6 +42,27 @@ class TLBaseNode( def connectOut = bundleOut def connectIn = bundleIn + + protected[tilelink2] def edge(x: TLBaseNode)(implicit sourceInfo: SourceInfo) = { + require (!noManagers) + require (!managerRealized) + require (!x.noClients) + require (!x.clientRealized) + val i = accManagerPorts.size + val j = x.accClientPorts.size + accManagerPorts += x + x.accClientPorts += this + () => { + val in = connectIn(i) + val out = x.connectOut(j) + TLMonitor.legalize(out, x.edgesOut(j), in, edgesIn(i), sourceInfo) + in <> out + val mask = ~UInt(edgesIn(i).manager.beatBytes - 1) + in .a.bits.address := (mask & out.a.bits.address) + out.b.bits.address := (mask & in .b.bits.address) + in .c.bits.address := (mask & out.c.bits.address) + } + } } class TLClientNode( From 05221d7073e4e1628afa8c71ce40eb2ee54d9f31 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 10:38:00 -0700 Subject: [PATCH 44/87] tilelink2: rename Bases.scala to LazyModule.scala --- uncore/src/main/scala/tilelink2/{Bases.scala => LazyModule.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename uncore/src/main/scala/tilelink2/{Bases.scala => LazyModule.scala} (100%) diff --git a/uncore/src/main/scala/tilelink2/Bases.scala b/uncore/src/main/scala/tilelink2/LazyModule.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Bases.scala rename to uncore/src/main/scala/tilelink2/LazyModule.scala From c785375276fc5e4b2ae6fecb7e0f94386b5e99c2 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 10:43:34 -0700 Subject: [PATCH 45/87] tilelink2: use 'connect' instead of TL-specific 'tl' to connect nodes --- uncore/src/main/scala/tilelink2/LazyModule.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/LazyModule.scala b/uncore/src/main/scala/tilelink2/LazyModule.scala index 3187c71b..82847846 100644 --- a/uncore/src/main/scala/tilelink2/LazyModule.scala +++ b/uncore/src/main/scala/tilelink2/LazyModule.scala @@ -10,8 +10,11 @@ abstract class LazyModule { private val bindings = ListBuffer[() => Unit]() - def tl(manager: TLBaseNode, client: TLBaseNode)(implicit sourceInfo: SourceInfo) = { - bindings += manager.edge(client) + // Use as: connect(source -> sink, source2 -> sink2, ...) + def connect(edges: (TLBaseNode, TLBaseNode)*)(implicit sourceInfo: SourceInfo) = { + edges.foreach { case (source, sink) => + bindings += sink.edge(source) + } } def module: LazyModuleImp From 69b3de92a8cd000a520611f4ec7662d73df3e3be Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 12:17:55 -0700 Subject: [PATCH 46/87] tilelink2: decouple BaseNode from TileLink bus (so it can be reused) --- .../src/main/scala/tilelink2/LazyModule.scala | 4 +- uncore/src/main/scala/tilelink2/Nodes.scala | 73 ++++++++++--------- .../src/main/scala/tilelink2/Operations.scala | 24 ++++++ 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/LazyModule.scala b/uncore/src/main/scala/tilelink2/LazyModule.scala index 82847846..f4934e7c 100644 --- a/uncore/src/main/scala/tilelink2/LazyModule.scala +++ b/uncore/src/main/scala/tilelink2/LazyModule.scala @@ -11,9 +11,9 @@ abstract class LazyModule private val bindings = ListBuffer[() => Unit]() // Use as: connect(source -> sink, source2 -> sink2, ...) - def connect(edges: (TLBaseNode, TLBaseNode)*)(implicit sourceInfo: SourceInfo) = { + def connect[PO, PI, EO, EI, B <: Bundle](edges: (BaseNode[PO, PI, EO, EI, B], BaseNode[PO, PI, EO, EI, B])*)(implicit sourceInfo: SourceInfo) = { edges.foreach { case (source, sink) => - bindings += sink.edge(source) + bindings += (source edge sink) } } diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index a13b30e7..22ad3a94 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -6,9 +6,22 @@ import Chisel._ import scala.collection.mutable.ListBuffer import chisel3.internal.sourceinfo.SourceInfo -class TLBaseNode( - private val clientFn: Option[Seq[TLClientPortParameters] => TLClientPortParameters], - private val managerFn: Option[Seq[TLManagerPortParameters] => TLManagerPortParameters], +// PI = PortInputParameters +// PO = PortOutputParameters +// EI = EdgeInput +// EO = EdgeOutput +abstract class NodeImp[PO, PI, EO, EI, B <: Bundle] +{ + def edgeO(po: PO, pi: PI): EO + def edgeI(po: PO, pi: PI): EI + def bundleO(eo: Seq[EO]): Vec[B] + def bundleI(ei: Seq[EI]): Vec[B] + def connect(bo: B, eo: EO, bi: B, ei: EI)(implicit sourceInfo: SourceInfo): Unit +} + +class BaseNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])( + private val clientFn: Option[Seq[PO] => PO], + private val managerFn: Option[Seq[PI] => PI], private val numClientPorts: Range.Inclusive, private val numManagerPorts: Range.Inclusive) { @@ -24,50 +37,44 @@ class TLBaseNode( require (noClients || clientFn.isDefined) require (noManagers || managerFn.isDefined) - private val accClientPorts = ListBuffer[TLBaseNode]() - private val accManagerPorts = ListBuffer[TLBaseNode]() + private val accClientPorts = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() + private val accManagerPorts = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() private var clientRealized = false private var managerRealized = false private lazy val clientPorts = { clientRealized = true; require (numClientPorts.contains(accClientPorts.size)); accClientPorts.result() } private lazy val managerPorts = { managerRealized = true; require (numManagerPorts.contains(accManagerPorts.size)); accManagerPorts.result() } - private lazy val clientParams : Option[TLClientPortParameters] = clientFn.map(_(managerPorts.map(_.clientParams.get))) - private lazy val managerParams : Option[TLManagerPortParameters] = managerFn.map(_(clientPorts.map(_.managerParams.get))) + private lazy val clientParams : Option[PO] = clientFn.map(_(managerPorts.map(_.clientParams.get))) + private lazy val managerParams : Option[PI] = managerFn.map(_(clientPorts.map(_.managerParams.get))) - lazy val edgesOut = clientPorts.map { n => new TLEdgeOut(clientParams.get, n.managerParams.get) } - lazy val edgesIn = managerPorts.map { n => new TLEdgeIn (n.clientParams.get, managerParams.get) } + lazy val edgesOut = clientPorts.map { n => imp.edgeO(clientParams.get, n.managerParams.get) } + lazy val edgesIn = managerPorts.map { n => imp.edgeI(n.clientParams.get, managerParams.get) } - lazy val bundleOut = { require (!edgesOut.isEmpty); Vec(edgesOut.size, TLBundle(edgesOut.map(_.bundle).reduce(_.union(_)))) } - lazy val bundleIn = { require (!edgesIn .isEmpty); Vec(edgesIn .size, TLBundle(edgesIn .map(_.bundle).reduce(_.union(_)))).flip } + lazy val bundleOut = imp.bundleO(edgesOut) + lazy val bundleIn = imp.bundleI(edgesIn) def connectOut = bundleOut def connectIn = bundleIn - protected[tilelink2] def edge(x: TLBaseNode)(implicit sourceInfo: SourceInfo) = { - require (!noManagers) - require (!managerRealized) - require (!x.noClients) - require (!x.clientRealized) - val i = accManagerPorts.size - val j = x.accClientPorts.size - accManagerPorts += x - x.accClientPorts += this + // source.edge(sink) + protected[tilelink2] def edge(x: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = { + require (!noClients) + require (!clientRealized) + require (!x.noManagers) + require (!x.managerRealized) + val i = x.accManagerPorts.size + val o = accClientPorts.size + accClientPorts += x + x.accManagerPorts += this () => { - val in = connectIn(i) - val out = x.connectOut(j) - TLMonitor.legalize(out, x.edgesOut(j), in, edgesIn(i), sourceInfo) - in <> out - val mask = ~UInt(edgesIn(i).manager.beatBytes - 1) - in .a.bits.address := (mask & out.a.bits.address) - out.b.bits.address := (mask & in .b.bits.address) - in .c.bits.address := (mask & out.c.bits.address) + imp.connect(connectOut(o), edgesOut(o), x.connectIn(i), x.edgesIn(i)) } } } class TLClientNode( params: TLClientParameters, - numPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + numPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( clientFn = Some {case Seq() => TLClientPortParameters(Seq(params))}, managerFn = None, numClientPorts = numPorts, @@ -86,7 +93,7 @@ object TLClientNode class TLManagerNode( beatBytes: Int, params: TLManagerParameters, - numPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + numPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( clientFn = None, managerFn = Some {case Seq() => TLManagerPortParameters(Seq(params), beatBytes)}, numClientPorts = 0 to 0, @@ -107,7 +114,7 @@ class TLAdapterNode( clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, numClientPorts: Range.Inclusive = 1 to 1, - numManagerPorts: Range.Inclusive = 1 to 1) extends TLBaseNode( + numManagerPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( clientFn = Some(clientFn), managerFn = Some(managerFn), numClientPorts = numClientPorts, @@ -122,7 +129,7 @@ object TLAdapterNode numManagerPorts: Range.Inclusive = 1 to 1) = new TLAdapterNode(clientFn, managerFn, numClientPorts, numManagerPorts) } -class TLOutputNode extends TLBaseNode( +class TLOutputNode extends BaseNode(TLImp)( clientFn = Some({case Seq(x) => x}), managerFn = Some({case Seq(x) => x}), numClientPorts = 1 to 1, @@ -137,7 +144,7 @@ object TLOutputNode def apply() = new TLOutputNode() } -class TLInputNode extends TLBaseNode( +class TLInputNode extends BaseNode(TLImp)( clientFn = Some({case Seq(x) => x}), managerFn = Some({case Seq(x) => x}), numClientPorts = 1 to 1, diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index bf9ca7f1..d1847311 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -3,6 +3,7 @@ package uncore.tilelink2 import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo class TLEdge( client: TLClientPortParameters, @@ -430,3 +431,26 @@ class TLEdgeIn( d } } + +object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] +{ + def edgeO(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(po, pi) + def edgeI(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(po, pi) + def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = { + require (!eo.isEmpty) + Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_)))) + } + def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = { + require (!ei.isEmpty) + Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip + } + + def connect(bo: TLBundle, eo: TLEdgeOut, bi: TLBundle, ei: TLEdgeIn)(implicit sourceInfo: SourceInfo): Unit = { + TLMonitor.legalize(bo, eo, bi, ei, sourceInfo) + bi <> bo + val mask = ~UInt(ei.manager.beatBytes - 1) + bi.a.bits.address := (mask & bo.a.bits.address) + bo.b.bits.address := (mask & bi.b.bits.address) + bi.c.bits.address := (mask & bo.c.bits.address) + } +} From ee3e31cb23dce19daf576eb575f9ad3aae2909b0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 13:30:06 -0700 Subject: [PATCH 47/87] tilelink2: refactor TLNodes into a seperate file --- uncore/src/main/scala/tilelink2/Nodes.scala | 157 ++++++------------ .../src/main/scala/tilelink2/Operations.scala | 23 --- uncore/src/main/scala/tilelink2/TLNodes.scala | 46 +++++ 3 files changed, 98 insertions(+), 128 deletions(-) create mode 100644 uncore/src/main/scala/tilelink2/TLNodes.scala diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index 22ad3a94..6fbb3dee 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -20,36 +20,36 @@ abstract class NodeImp[PO, PI, EO, EI, B <: Bundle] } class BaseNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])( - private val clientFn: Option[Seq[PO] => PO], - private val managerFn: Option[Seq[PI] => PI], - private val numClientPorts: Range.Inclusive, - private val numManagerPorts: Range.Inclusive) + private val oFn: Option[Seq[PO] => PO], + private val iFn: Option[Seq[PI] => PI], + private val numPO: Range.Inclusive, + private val numPI: Range.Inclusive) { // At least 0 ports must be supported - require (!numClientPorts.isEmpty) - require (!numManagerPorts.isEmpty) - require (numClientPorts.start >= 0) - require (numManagerPorts.start >= 0) + require (!numPO.isEmpty) + require (!numPI.isEmpty) + require (numPO.start >= 0) + require (numPI.start >= 0) - val noClients = numClientPorts.size == 1 && numClientPorts.contains(0) - val noManagers = numManagerPorts.size == 1 && numManagerPorts.contains(0) + val noOs = numPO.size == 1 && numPO.contains(0) + val noIs = numPI.size == 1 && numPI.contains(0) - require (noClients || clientFn.isDefined) - require (noManagers || managerFn.isDefined) + require (noOs || oFn.isDefined) + require (noIs || iFn.isDefined) - private val accClientPorts = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() - private val accManagerPorts = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() - private var clientRealized = false - private var managerRealized = false + private val accPO = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() + private val accPI = ListBuffer[BaseNode[PO, PI, EO, EI, B]]() + private var oRealized = false + private var iRealized = false - private lazy val clientPorts = { clientRealized = true; require (numClientPorts.contains(accClientPorts.size)); accClientPorts.result() } - private lazy val managerPorts = { managerRealized = true; require (numManagerPorts.contains(accManagerPorts.size)); accManagerPorts.result() } - private lazy val clientParams : Option[PO] = clientFn.map(_(managerPorts.map(_.clientParams.get))) - private lazy val managerParams : Option[PI] = managerFn.map(_(clientPorts.map(_.managerParams.get))) + private lazy val oPorts = { oRealized = true; require (numPO.contains(accPO.size)); accPO.result() } + private lazy val iPorts = { iRealized = true; require (numPI.contains(accPI.size)); accPI.result() } + private lazy val oParams : Option[PO] = oFn.map(_(iPorts.map(_.oParams.get))) + private lazy val iParams : Option[PI] = iFn.map(_(oPorts.map(_.iParams.get))) + + lazy val edgesOut = oPorts.map { n => imp.edgeO(oParams.get, n.iParams.get) } + lazy val edgesIn = iPorts.map { n => imp.edgeI(n.oParams.get, iParams.get) } - lazy val edgesOut = clientPorts.map { n => imp.edgeO(clientParams.get, n.managerParams.get) } - lazy val edgesIn = managerPorts.map { n => imp.edgeI(n.clientParams.get, managerParams.get) } - lazy val bundleOut = imp.bundleO(edgesOut) lazy val bundleIn = imp.bundleI(edgesIn) @@ -58,103 +58,50 @@ class BaseNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])( // source.edge(sink) protected[tilelink2] def edge(x: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = { - require (!noClients) - require (!clientRealized) - require (!x.noManagers) - require (!x.managerRealized) - val i = x.accManagerPorts.size - val o = accClientPorts.size - accClientPorts += x - x.accManagerPorts += this + require (!noOs) + require (!oRealized) + require (!x.noIs) + require (!x.iRealized) + val i = x.accPI.size + val o = accPO.size + accPO += x + x.accPI += this () => { imp.connect(connectOut(o), edgesOut(o), x.connectIn(i), x.edgesIn(i)) } } } -class TLClientNode( - params: TLClientParameters, - numPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( - clientFn = Some {case Seq() => TLClientPortParameters(Seq(params))}, - managerFn = None, - numClientPorts = numPorts, - numManagerPorts = 0 to 0) -{ - require(numPorts.end >= 1) -} - -object TLClientNode -{ - def apply( - params: TLClientParameters, - numPorts: Range.Inclusive = 1 to 1) = new TLClientNode(params, numPorts) -} - -class TLManagerNode( - beatBytes: Int, - params: TLManagerParameters, - numPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( - clientFn = None, - managerFn = Some {case Seq() => TLManagerPortParameters(Seq(params), beatBytes)}, - numClientPorts = 0 to 0, - numManagerPorts = numPorts) -{ - require(numPorts.end >= 1) -} - -object TLManagerNode -{ - def apply( - beatBytes: Int, - params: TLManagerParameters, - numPorts: Range.Inclusive = 1 to 1) = new TLManagerNode(beatBytes, params, numPorts) -} - -class TLAdapterNode( - clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, - managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, - numClientPorts: Range.Inclusive = 1 to 1, - numManagerPorts: Range.Inclusive = 1 to 1) extends BaseNode(TLImp)( - clientFn = Some(clientFn), - managerFn = Some(managerFn), - numClientPorts = numClientPorts, - numManagerPorts = numManagerPorts) - -object TLAdapterNode -{ - def apply( - clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, - managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, - numClientPorts: Range.Inclusive = 1 to 1, - numManagerPorts: Range.Inclusive = 1 to 1) = new TLAdapterNode(clientFn, managerFn, numClientPorts, numManagerPorts) -} - -class TLOutputNode extends BaseNode(TLImp)( - clientFn = Some({case Seq(x) => x}), - managerFn = Some({case Seq(x) => x}), - numClientPorts = 1 to 1, - numManagerPorts = 1 to 1) +class OutputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) + extends BaseNode(imp)(Some{case Seq(x) => x}, Some{case Seq(x) => x}, 1 to 1, 1 to 1) { override def connectOut = bundleOut override def connectIn = bundleOut } -object TLOutputNode -{ - def apply() = new TLOutputNode() -} - -class TLInputNode extends BaseNode(TLImp)( - clientFn = Some({case Seq(x) => x}), - managerFn = Some({case Seq(x) => x}), - numClientPorts = 1 to 1, - numManagerPorts = 1 to 1) +class InputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) + extends BaseNode(imp)(Some{case Seq(x) => x}, Some{case Seq(x) => x}, 1 to 1, 1 to 1) { override def connectOut = bundleIn override def connectIn = bundleIn } -object TLInputNode +class SourceNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1) + extends BaseNode(imp)(Some{case Seq() => po}, None, num, 0 to 0) { - def apply() = new TLInputNode() + require (num.end >= 1) +} + +class SinkNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1) + extends BaseNode(imp)(None, Some{case Seq() => pi}, 0 to 0, num) +{ + require (num.end >= 1) +} + +class InteriorNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) + (oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive) + extends BaseNode(imp)(Some(oFn), Some(iFn), numPO, numPI) +{ + require (numPO.end >= 1) + require (numPI.end >= 1) } diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Operations.scala index d1847311..6fd61796 100644 --- a/uncore/src/main/scala/tilelink2/Operations.scala +++ b/uncore/src/main/scala/tilelink2/Operations.scala @@ -431,26 +431,3 @@ class TLEdgeIn( d } } - -object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] -{ - def edgeO(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(po, pi) - def edgeI(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(po, pi) - def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = { - require (!eo.isEmpty) - Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_)))) - } - def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = { - require (!ei.isEmpty) - Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip - } - - def connect(bo: TLBundle, eo: TLEdgeOut, bi: TLBundle, ei: TLEdgeIn)(implicit sourceInfo: SourceInfo): Unit = { - TLMonitor.legalize(bo, eo, bi, ei, sourceInfo) - bi <> bo - val mask = ~UInt(ei.manager.beatBytes - 1) - bi.a.bits.address := (mask & bo.a.bits.address) - bo.b.bits.address := (mask & bi.b.bits.address) - bi.c.bits.address := (mask & bo.c.bits.address) - } -} diff --git a/uncore/src/main/scala/tilelink2/TLNodes.scala b/uncore/src/main/scala/tilelink2/TLNodes.scala new file mode 100644 index 00000000..08001759 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/TLNodes.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import scala.collection.mutable.ListBuffer +import chisel3.internal.sourceinfo.SourceInfo + +object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] +{ + def edgeO(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(po, pi) + def edgeI(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(po, pi) + def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = { + require (!eo.isEmpty) + Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_)))) + } + def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = { + require (!ei.isEmpty) + Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip + } + + def connect(bo: TLBundle, eo: TLEdgeOut, bi: TLBundle, ei: TLEdgeIn)(implicit sourceInfo: SourceInfo): Unit = { + TLMonitor.legalize(bo, eo, bi, ei, sourceInfo) + bi <> bo + val mask = ~UInt(ei.manager.beatBytes - 1) + bi.a.bits.address := (mask & bo.a.bits.address) + bo.b.bits.address := (mask & bi.b.bits.address) + bi.c.bits.address := (mask & bo.c.bits.address) + } +} + +case class TLOutputNode() extends OutputNode(TLImp) +case class TLInputNode() extends InputNode(TLImp) + +case class TLClientNode(params: TLClientParameters, numPorts: Range.Inclusive = 1 to 1) + extends SourceNode(TLImp)(TLClientPortParameters(Seq(params)), numPorts) + +case class TLManagerNode(beatBytes: Int, params: TLManagerParameters, numPorts: Range.Inclusive = 1 to 1) + extends SinkNode(TLImp)(TLManagerPortParameters(Seq(params), beatBytes), numPorts) + +case class TLAdapterNode( + clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, + managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, + numClientPorts: Range.Inclusive = 1 to 1, + numManagerPorts: Range.Inclusive = 1 to 1) + extends InteriorNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts) From d6727abbbc3942ab425de49347bc4418bd9f05a4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 13:30:46 -0700 Subject: [PATCH 48/87] tilelink2: rename Operations to Edges (as it only includes Edges) --- uncore/src/main/scala/tilelink2/{Operations.scala => Edges.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename uncore/src/main/scala/tilelink2/{Operations.scala => Edges.scala} (100%) diff --git a/uncore/src/main/scala/tilelink2/Operations.scala b/uncore/src/main/scala/tilelink2/Edges.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Operations.scala rename to uncore/src/main/scala/tilelink2/Edges.scala From ae2bc4da215827f0c6910281ef5c96a73bb37e4d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 13:37:20 -0700 Subject: [PATCH 49/87] tilelink2: refactor RegField into interface and implementation --- .../src/main/scala/tilelink2/RegField.scala | 136 +---------------- .../src/main/scala/tilelink2/RegMapper.scala | 143 ++++++++++++++++++ .../main/scala/tilelink2/RegisterRouter.scala | 6 +- 3 files changed, 147 insertions(+), 138 deletions(-) create mode 100644 uncore/src/main/scala/tilelink2/RegMapper.scala diff --git a/uncore/src/main/scala/tilelink2/RegField.scala b/uncore/src/main/scala/tilelink2/RegField.scala index c9c4a577..b546cafc 100644 --- a/uncore/src/main/scala/tilelink2/RegField.scala +++ b/uncore/src/main/scala/tilelink2/RegField.scala @@ -80,138 +80,4 @@ trait HasRegMap def regmap(mapping: RegField.Map*): Unit } -case class RegFieldParams(indexBits: Int, maskBits: Int, extraBits: Int) - -class RegFieldInput(params: RegFieldParams) extends GenericParameterizedBundle(params) -{ - val read = Bool() - val index = UInt(width = params.indexBits) - val data = UInt(width = params.maskBits*8) - val mask = UInt(width = params.maskBits) - val extra = UInt(width = params.extraBits) -} - -class RegFieldOutput(params: RegFieldParams) extends GenericParameterizedBundle(params) -{ - val read = Bool() - val data = UInt(width = params.maskBits*8) - val extra = UInt(width = params.extraBits) -} - -object RegFieldHelper -{ - // Create a generic register-based device - def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegFieldInput], mapping: RegField.Map*) = { - val regmap = mapping.toList - require (!regmap.isEmpty) - - // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) - val flat = regmap.map { case (reg, fields) => - val offsets = fields.scanLeft(0)(_ + _.width).init - (offsets zip fields) map { case (o, f) => (reg, o, f) } - }.flatten - require (!flat.isEmpty) - - val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1) - val params = RegFieldParams(log2Up(endIndex), bytes, in.bits.params.extraBits) - - val out = Wire(Decoupled(new RegFieldOutput(params))) - val front = Wire(Decoupled(new RegFieldInput(params))) - front.bits := in.bits - - // Must this device pipeline the control channel? - val pipelined = flat.map(_._3.pipelined).reduce(_ || _) - val depth = concurrency.getOrElse(if (pipelined) 1 else 0) - require (depth >= 0) - require (!pipelined || depth > 0) - val back = if (depth > 0) Queue(front, depth, pipe = depth == 1) else front - - // Forward declaration of all flow control signals - val rivalid = Wire(Vec(flat.size, Bool())) - val wivalid = Wire(Vec(flat.size, Bool())) - val riready = Wire(Vec(flat.size, Bool())) - val wiready = Wire(Vec(flat.size, Bool())) - val rovalid = Wire(Vec(flat.size, Bool())) - val wovalid = Wire(Vec(flat.size, Bool())) - val roready = Wire(Vec(flat.size, Bool())) - val woready = Wire(Vec(flat.size, Bool())) - - // Per-register list of all control signals needed for data to flow - val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } - val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } - val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } - val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } - - // The output values for each register - val dataOut = Array.tabulate(endIndex) { _ => UInt(0) } - - // Which bits are touched? - val frontMask = FillInterleaved(8, front.bits.mask) - val backMask = FillInterleaved(8, back .bits.mask) - - // Connect the fields - for (i <- 0 until flat.size) { - val (reg, low, field) = flat(i) - val high = low + field.width - 1 - // Confirm that no register is too big - require (high <= 8*bytes) - val rimask = frontMask(high, low).orR() - val wimask = frontMask(high, low).andR() - val romask = backMask(high, low).orR() - val womask = backMask(high, low).andR() - val data = if (field.write.combinational) back.bits.data else front.bits.data - val (f_riready, f_rovalid, f_data) = field.read.fn(rivalid(i) && rimask, roready(i) && romask) - val (f_wiready, f_wovalid) = field.write.fn(wivalid(i) && wimask, woready(i) && womask, data) - riready(i) := f_riready || !rimask - wiready(i) := f_wiready || !wimask - rovalid(i) := f_rovalid || !romask - wovalid(i) := f_wovalid || !womask - rifire(reg) = riready(i) +: rifire(reg) - wifire(reg) = wiready(i) +: wifire(reg) - rofire(reg) = rovalid(i) +: rofire(reg) - wofire(reg) = wovalid(i) +: wofire(reg) - dataOut(reg) = dataOut(reg) | (f_data << low) - } - - // Is the selected register ready? - val rifireMux = Vec(rifire.map(_.reduce(_ && _))) - val wifireMux = Vec(wifire.map(_.reduce(_ && _))) - val rofireMux = Vec(rofire.map(_.reduce(_ && _))) - val wofireMux = Vec(wofire.map(_.reduce(_ && _))) - val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index)) - val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index)) - - // Connect the pipeline - in.ready := front.ready && iready - front.valid := in.valid && iready - back.ready := out.ready && oready - out.valid := back.valid && oready - - // Which register is touched? - val frontSel = UIntToOH(front.bits.index) - val backSel = UIntToOH(back.bits.index) - - // Include the per-register one-hot selected criteria - for (reg <- 0 until endIndex) { - rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg) - wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg) - rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg) - wofire(reg) = (back.valid && out.ready && !back .bits.read && backSel (reg)) +: wofire(reg) - } - - // Connect the field's ivalid and oready - for (i <- 0 until flat.size) { - val (reg, _, _ ) = flat(i) - rivalid(i) := rifire(reg).filter(_ ne riready(i)).reduce(_ && _) - wivalid(i) := wifire(reg).filter(_ ne wiready(i)).reduce(_ && _) - roready(i) := rofire(reg).filter(_ ne rovalid(i)).reduce(_ && _) - woready(i) := wofire(reg).filter(_ ne wovalid(i)).reduce(_ && _) - } - - out.bits.read := back.bits.read - out.bits.data := Vec(dataOut)(back.bits.index) - out.bits.extra := back.bits.extra - - (endIndex, out) - } -} +// See GPIO.scala for an example of how to use regmap diff --git a/uncore/src/main/scala/tilelink2/RegMapper.scala b/uncore/src/main/scala/tilelink2/RegMapper.scala new file mode 100644 index 00000000..c6b517b5 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/RegMapper.scala @@ -0,0 +1,143 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +// A bus agnostic register interface to a register-based device + +case class RegMapperParams(indexBits: Int, maskBits: Int, extraBits: Int) + +class RegMapperInput(params: RegMapperParams) extends GenericParameterizedBundle(params) +{ + val read = Bool() + val index = UInt(width = params.indexBits) + val data = UInt(width = params.maskBits*8) + val mask = UInt(width = params.maskBits) + val extra = UInt(width = params.extraBits) +} + +class RegMapperOutput(params: RegMapperParams) extends GenericParameterizedBundle(params) +{ + val read = Bool() + val data = UInt(width = params.maskBits*8) + val extra = UInt(width = params.extraBits) +} + +object RegMapper +{ + // Create a generic register-based device + def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = { + val regmap = mapping.toList + require (!regmap.isEmpty) + + // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) + val flat = regmap.map { case (reg, fields) => + val offsets = fields.scanLeft(0)(_ + _.width).init + (offsets zip fields) map { case (o, f) => (reg, o, f) } + }.flatten + require (!flat.isEmpty) + + val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1) + val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits) + + val out = Wire(Decoupled(new RegMapperOutput(params))) + val front = Wire(Decoupled(new RegMapperInput(params))) + front.bits := in.bits + + // Must this device pipeline the control channel? + val pipelined = flat.map(_._3.pipelined).reduce(_ || _) + val depth = concurrency.getOrElse(if (pipelined) 1 else 0) + require (depth >= 0) + require (!pipelined || depth > 0) + val back = if (depth > 0) Queue(front, depth, pipe = depth == 1) else front + + // Forward declaration of all flow control signals + val rivalid = Wire(Vec(flat.size, Bool())) + val wivalid = Wire(Vec(flat.size, Bool())) + val riready = Wire(Vec(flat.size, Bool())) + val wiready = Wire(Vec(flat.size, Bool())) + val rovalid = Wire(Vec(flat.size, Bool())) + val wovalid = Wire(Vec(flat.size, Bool())) + val roready = Wire(Vec(flat.size, Bool())) + val woready = Wire(Vec(flat.size, Bool())) + + // Per-register list of all control signals needed for data to flow + val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) } + + // The output values for each register + val dataOut = Array.tabulate(endIndex) { _ => UInt(0) } + + // Which bits are touched? + val frontMask = FillInterleaved(8, front.bits.mask) + val backMask = FillInterleaved(8, back .bits.mask) + + // Connect the fields + for (i <- 0 until flat.size) { + val (reg, low, field) = flat(i) + val high = low + field.width - 1 + // Confirm that no register is too big + require (high <= 8*bytes) + val rimask = frontMask(high, low).orR() + val wimask = frontMask(high, low).andR() + val romask = backMask(high, low).orR() + val womask = backMask(high, low).andR() + val data = if (field.write.combinational) back.bits.data else front.bits.data + val (f_riready, f_rovalid, f_data) = field.read.fn(rivalid(i) && rimask, roready(i) && romask) + val (f_wiready, f_wovalid) = field.write.fn(wivalid(i) && wimask, woready(i) && womask, data) + riready(i) := f_riready || !rimask + wiready(i) := f_wiready || !wimask + rovalid(i) := f_rovalid || !romask + wovalid(i) := f_wovalid || !womask + rifire(reg) = riready(i) +: rifire(reg) + wifire(reg) = wiready(i) +: wifire(reg) + rofire(reg) = rovalid(i) +: rofire(reg) + wofire(reg) = wovalid(i) +: wofire(reg) + dataOut(reg) = dataOut(reg) | (f_data << low) + } + + // Is the selected register ready? + val rifireMux = Vec(rifire.map(_.reduce(_ && _))) + val wifireMux = Vec(wifire.map(_.reduce(_ && _))) + val rofireMux = Vec(rofire.map(_.reduce(_ && _))) + val wofireMux = Vec(wofire.map(_.reduce(_ && _))) + val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index)) + val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index)) + + // Connect the pipeline + in.ready := front.ready && iready + front.valid := in.valid && iready + back.ready := out.ready && oready + out.valid := back.valid && oready + + // Which register is touched? + val frontSel = UIntToOH(front.bits.index) + val backSel = UIntToOH(back.bits.index) + + // Include the per-register one-hot selected criteria + for (reg <- 0 until endIndex) { + rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg) + wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg) + rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg) + wofire(reg) = (back.valid && out.ready && !back .bits.read && backSel (reg)) +: wofire(reg) + } + + // Connect the field's ivalid and oready + for (i <- 0 until flat.size) { + val (reg, _, _ ) = flat(i) + rivalid(i) := rifire(reg).filter(_ ne riready(i)).reduce(_ && _) + wivalid(i) := wifire(reg).filter(_ ne wiready(i)).reduce(_ && _) + roready(i) := rofire(reg).filter(_ ne rovalid(i)).reduce(_ && _) + woready(i) := wofire(reg).filter(_ ne wovalid(i)).reduce(_ && _) + } + + out.bits.read := back.bits.read + out.bits.data := Vec(dataOut)(back.bits.index) + out.bits.extra := back.bits.extra + + (endIndex, out) + } +} diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index de511705..70923787 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -21,8 +21,8 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB val d = bundleIn(0).d val edge = edgesIn(0) - val params = RegFieldParams(log2Up(address.mask+1), beatBytes, edge.bundle.sourceBits + edge.bundle.sizeBits) - val in = Wire(Decoupled(new RegFieldInput(params))) + val params = RegMapperParams(log2Up(address.mask+1), beatBytes, edge.bundle.sourceBits + edge.bundle.sizeBits) + val in = Wire(Decoupled(new RegMapperInput(params))) in.bits.read := a.bits.opcode === TLMessages.Get in.bits.index := a.bits.address >> log2Ceil(beatBytes) in.bits.data := a.bits.data @@ -30,7 +30,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB in.bits.extra := Cat(a.bits.source, a.bits.size) // Invoke the register map builder - val (endIndex, out) = RegFieldHelper(beatBytes, concurrency, in, mapping:_*) + val (endIndex, out) = RegMapper(beatBytes, concurrency, in, mapping:_*) // All registers must fit inside the device address space require (address.mask >= (endIndex-1)*beatBytes) From 9cd2991fb3e0c5f55cd194605b125ccbaf67598b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 14:49:18 -0700 Subject: [PATCH 50/87] tilelink2: AddressSet always has an assigned base address The consensus seems to be that TileLink should not be assigning addresses dynamically. The reasons: 1. We can come up with another scheme for assigning addresses that is independent of TileLink. This decoupling is good, because it would allow us to use the same mechanism for different buses in the SoC. 2. The informational flow of addresses is more likely to naturally follow the module hierarchy than the TileLike bus topology. Thus, it seems better to pass address parameterization using Module constructors. 3. Addresses are still checked by TileLink, so using a Module-centric flow for addresses will not pose a correctness concern. 4. An address need only be provided to a slave on its construction and TileLink parameterization spreads this globally. Thus, the burden to manually assign an address is low. --- uncore/src/main/scala/tilelink2/GPIO.scala | 2 +- .../src/main/scala/tilelink2/Parameters.scala | 26 +++++++++---------- .../main/scala/tilelink2/RegisterRouter.scala | 4 +-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/GPIO.scala b/uncore/src/main/scala/tilelink2/GPIO.scala index e4b8572f..a9050882 100644 --- a/uncore/src/main/scala/tilelink2/GPIO.scala +++ b/uncore/src/main/scala/tilelink2/GPIO.scala @@ -4,7 +4,7 @@ package uncore.tilelink2 import Chisel._ -case class GPIOParams(num: Int, address: Option[BigInt] = None) +case class GPIOParams(num: Int, address: BigInt) trait GPIOBundle { diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 6a8170c9..7482a32c 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -75,30 +75,28 @@ object TransferSizes { implicit def asBool(x: TransferSizes) = !x.none } -// AddressSets specify the mask of bits consumed by the manager -// The base address used by the crossbar for routing -case class AddressSet(mask: BigInt, base: Option[BigInt] = None) +// AddressSets specify the address space managed by the manager +// Base is the base address, and mask are the bits consumed by the manager +// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff +// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ... +case class AddressSet(base: BigInt, mask: BigInt) { // Forbid misaligned base address (and empty sets) - require (base == None || (base.get & mask) == 0) + require ((base & mask) == 0) - def contains(x: BigInt) = ((x ^ base.get) & ~mask) == 0 - def contains(x: UInt) = ((x ^ UInt(base.get)) & ~UInt(mask)) === UInt(0) + def contains(x: BigInt) = ((x ^ base) & ~mask) == 0 + def contains(x: UInt) = ((x ^ UInt(base)) & ~UInt(mask)) === UInt(0) // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) - // if base = None, it will be auto-assigned and thus not overlap anything - def overlaps(x: AddressSet) = (base, x.base) match { - case (Some(tbase), Some(xbase)) => (~(mask | x.mask) & (tbase ^ xbase)) == 0 - case _ => false - } + def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0 // contains iff bitwise: x.mask => mask && contains(x.base) - def contains(x: AddressSet) = ((x.mask | (base.get ^ x.base.get)) & ~mask) == 0 + def contains(x: AddressSet) = ((x.mask | (base ^ x.base)) & ~mask) == 0 // 1 less than the number of bytes to which the manager should be aligned def alignment1 = ((mask + 1) & ~mask) - 1 - def max = base.get | mask + def max = base | mask - // A strided slave has serves discontiguous ranges + // A strided slave serves discontiguous ranges def strided = alignment1 != mask } diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index 70923787..a9d33695 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -74,10 +74,10 @@ class TLRegModule[P, B <: Bundle](val params: P, bundleBuilder: => B, router: TL } class TLRegisterRouter[B <: Bundle, M <: LazyModuleImp] - (address: Option[BigInt] = None, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4) + (base: BigInt, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4) (bundleBuilder: Vec[TLBundle] => B) (moduleBuilder: (=> B, TLRegisterRouterBase) => M) - extends TLRegisterRouterBase(AddressSet(size-1, address), concurrency, beatBytes) + extends TLRegisterRouterBase(AddressSet(base, size-1), concurrency, beatBytes) { require (size % 4096 == 0) // devices should be 4K aligned require (isPow2(size)) From 50f0dee69ea1e849cbb62f353b3868bc77b95462 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 15:47:07 -0700 Subject: [PATCH 51/87] tilelink2: add an IdentityNode for adapters that change nothing --- uncore/src/main/scala/tilelink2/Nodes.scala | 7 ++++--- uncore/src/main/scala/tilelink2/TLNodes.scala | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/uncore/src/main/scala/tilelink2/Nodes.scala index 6fbb3dee..1679c17b 100644 --- a/uncore/src/main/scala/tilelink2/Nodes.scala +++ b/uncore/src/main/scala/tilelink2/Nodes.scala @@ -72,15 +72,16 @@ class BaseNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B])( } } -class OutputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) +class IdentityNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) extends BaseNode(imp)(Some{case Seq(x) => x}, Some{case Seq(x) => x}, 1 to 1, 1 to 1) + +class OutputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) { override def connectOut = bundleOut override def connectIn = bundleOut } -class InputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) - extends BaseNode(imp)(Some{case Seq(x) => x}, Some{case Seq(x) => x}, 1 to 1, 1 to 1) +class InputNode[PO, PI, EO, EI, B <: Bundle](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) { override def connectOut = bundleIn override def connectIn = bundleIn diff --git a/uncore/src/main/scala/tilelink2/TLNodes.scala b/uncore/src/main/scala/tilelink2/TLNodes.scala index 08001759..270d3cab 100644 --- a/uncore/src/main/scala/tilelink2/TLNodes.scala +++ b/uncore/src/main/scala/tilelink2/TLNodes.scala @@ -29,6 +29,7 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL } } +case class TLIdentityNode() extends IdentityNode(TLImp) case class TLOutputNode() extends OutputNode(TLImp) case class TLInputNode() extends InputNode(TLImp) From 4a401fc480f7fa3c5c4e0ebb895adfcd40c502cf Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 15:53:25 -0700 Subject: [PATCH 52/87] tilelink2: add a Buffer adapter to insert pipeline stages --- uncore/src/main/scala/tilelink2/Buffer.scala | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/Buffer.scala diff --git a/uncore/src/main/scala/tilelink2/Buffer.scala b/uncore/src/main/scala/tilelink2/Buffer.scala new file mode 100644 index 00000000..dd749d9e --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Buffer.scala @@ -0,0 +1,30 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ + +class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule +{ + val node = TLIdentityNode() + + lazy val module = Module(new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val in = io.in(0) + val out = io.out(0) + + out.a <> Queue(in .a, entries, pipe) + in .d <> Queue(out.d, entries, pipe) + + val edge = node.edgesOut(0) // same as edgeIn(0) + if (edge.manager.anySupportAcquire && edge.client.anySupportProbe) { + in .b <> Queue(out.b, entries, pipe) + out.c <> Queue(in .c, entries, pipe) + out.e <> Queue(out.e, entries, pipe) + } + }) +} From 18e7d4cd65492c1e23be4e0323299e152ab36cee Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 16:45:18 -0700 Subject: [PATCH 53/87] tilelink2: make it possible to write Node-only adapters --- uncore/src/main/scala/tilelink2/Buffer.scala | 11 +++++++++++ uncore/src/main/scala/tilelink2/HintHandler.scala | 11 +++++++++++ uncore/src/main/scala/tilelink2/LazyModule.scala | 6 ++++++ uncore/src/main/scala/tilelink2/package.scala | 8 ++++++++ 4 files changed, 36 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/package.scala diff --git a/uncore/src/main/scala/tilelink2/Buffer.scala b/uncore/src/main/scala/tilelink2/Buffer.scala index dd749d9e..8c13fc80 100644 --- a/uncore/src/main/scala/tilelink2/Buffer.scala +++ b/uncore/src/main/scala/tilelink2/Buffer.scala @@ -28,3 +28,14 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule } }) } + +object TLBuffer +{ + // applied to the TL source node; connect (TLBuffer(x.node) -> y.node) + def apply(x: TLBaseNode, entries: Int = 2, pipe: Boolean = false)(implicit lazyModule: LazyModule): TLBaseNode = { + val buffer = new TLBuffer(entries, pipe) + lazyModule.addChild(buffer) + lazyModule.connect(x -> buffer.node) + buffer.node + } +} diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index 584716a8..1215be66 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -72,3 +72,14 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.e.bits := in.e.bits }) } + +object TLHintHandler +{ + // applied to the TL source node; connect (TLHintHandler(x.node) -> y.node) + def apply(x: TLBaseNode, supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit lazyModule: LazyModule): TLBaseNode = { + val hints = new TLHintHandler(supportManagers, supportClients, passthrough) + lazyModule.addChild(hints) + lazyModule.connect(x -> hints.node) + hints.node + } +} diff --git a/uncore/src/main/scala/tilelink2/LazyModule.scala b/uncore/src/main/scala/tilelink2/LazyModule.scala index f4934e7c..a12427a5 100644 --- a/uncore/src/main/scala/tilelink2/LazyModule.scala +++ b/uncore/src/main/scala/tilelink2/LazyModule.scala @@ -9,6 +9,7 @@ import chisel3.internal.sourceinfo.SourceInfo abstract class LazyModule { private val bindings = ListBuffer[() => Unit]() + private val extraChildren = ListBuffer[LazyModule]() // Use as: connect(source -> sink, source2 -> sink2, ...) def connect[PO, PI, EO, EI, B <: Bundle](edges: (BaseNode[PO, PI, EO, EI, B], BaseNode[PO, PI, EO, EI, B])*)(implicit sourceInfo: SourceInfo) = { @@ -25,13 +26,18 @@ abstract class LazyModule if (m.getParameterTypes.isEmpty && !java.lang.reflect.Modifier.isStatic(m.getModifiers) && !(m.getName contains '$') && + !(m.getName == "lazyModule") && classOf[LazyModule].isAssignableFrom(m.getReturnType)) { // ... and force their lazy module members to exist m.invoke(this).asInstanceOf[LazyModule].module } } + extraChildren.foreach { _.module } bindings.foreach { f => f () } } + + implicit val lazyModule = this + def addChild(x: LazyModule) = extraChildren += x } abstract class LazyModuleImp(outer: LazyModule) extends Module diff --git a/uncore/src/main/scala/tilelink2/package.scala b/uncore/src/main/scala/tilelink2/package.scala new file mode 100644 index 00000000..501fdccb --- /dev/null +++ b/uncore/src/main/scala/tilelink2/package.scala @@ -0,0 +1,8 @@ +package uncore + +import Chisel._ + +package object tilelink2 +{ + type TLBaseNode = BaseNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] +} From ab998c08f1b0b20b863b7de745920a08d836eab3 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 31 Aug 2016 17:44:48 -0700 Subject: [PATCH 54/87] tilelink2: save some hardware in HintHandler if no BCE --- .../src/main/scala/tilelink2/HintHandler.scala | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index 1215be66..99e94194 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -22,6 +22,10 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f val edgeIn = node.edgesIn(0) val edgeOut = node.edgesOut(0) + // Don't add support for clients if there is no BCE channel + val bce = edgeOut.manager.anySupportAcquire && edgeIn.client.anySupportProbe + require (!supportClients || bce) + if (supportManagers) { val handleA = if (passthrough) !edgeOut.manager.supportsHint(in.a.bits.address) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint @@ -56,7 +60,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) in.b.valid := out.b.valid && !bypassC in.b.bits := out.b.bits - } else { + } else if (bce) { in.b.valid := out.b.valid out.b.ready := in.b.ready in.b.bits := out.b.bits @@ -66,10 +70,12 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.c.bits := in.c.bits } - // Pass E through unchanged - out.e.valid := in.e.valid - in.e.ready := out.e.ready - out.e.bits := in.e.bits + if (bce) { + // Pass E through unchanged + out.e.valid := in.e.valid + in.e.ready := out.e.ready + out.e.bits := in.e.bits + } }) } From c411a3e77f17b0eebcf572acc60345b1af57b5f3 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 1 Sep 2016 11:12:59 -0700 Subject: [PATCH 55/87] tilelink2: simpler sizes requirement for users to understand --- uncore/src/main/scala/tilelink2/Parameters.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/uncore/src/main/scala/tilelink2/Parameters.scala index 7482a32c..26e799ec 100644 --- a/uncore/src/main/scala/tilelink2/Parameters.scala +++ b/uncore/src/main/scala/tilelink2/Parameters.scala @@ -47,7 +47,7 @@ case class TransferSizes(min: Int, max: Int) def this(x: Int) = this(x, x) require (min <= max) - require (min != 0 || max == 0) + require (min >= 0 && max >= 0) require (max == 0 || isPow2(max)) require (min == 0 || isPow2(min)) require (max <= TransferSizes.maxAllowed) @@ -175,6 +175,8 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes // Synthesizable lookup methods def find(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _))) def findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id))) + + // !!! need a cheaper version of find, where we assume a valid address match exists // Does this Port manage this ID/address? def contains(address: UInt) = find(address).reduce(_ || _) From e652cd155b56116d857e374a69ed898ee80c6a56 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 1 Sep 2016 11:13:36 -0700 Subject: [PATCH 56/87] tilelink2: edge parameters on the same link had better match --- uncore/src/main/scala/tilelink2/TLNodes.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/uncore/src/main/scala/tilelink2/TLNodes.scala b/uncore/src/main/scala/tilelink2/TLNodes.scala index 270d3cab..27342d9e 100644 --- a/uncore/src/main/scala/tilelink2/TLNodes.scala +++ b/uncore/src/main/scala/tilelink2/TLNodes.scala @@ -20,6 +20,7 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL } def connect(bo: TLBundle, eo: TLEdgeOut, bi: TLBundle, ei: TLEdgeIn)(implicit sourceInfo: SourceInfo): Unit = { + require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters]) TLMonitor.legalize(bo, eo, bi, ei, sourceInfo) bi <> bo val mask = ~UInt(ei.manager.beatBytes - 1) From 935b53f3bfabfb2e02a11808cc30d83aabc8e78a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 1 Sep 2016 11:34:56 -0700 Subject: [PATCH 57/87] tilelink2: explicitly check that fixed fields never change in multibeat --- uncore/src/main/scala/tilelink2/Bundles.scala | 8 + uncore/src/main/scala/tilelink2/Monitor.scala | 140 ++++++++++++++++-- 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 06b00a6f..88b742d7 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -126,11 +126,13 @@ class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) with HasTLData { + // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) // amo_opcode || perms || hint val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to + // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) @@ -149,11 +151,13 @@ class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) with HasTLData { + // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val address = UInt(width = params.addressBits) // from + // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) @@ -168,11 +172,13 @@ class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) with HasTLData { + // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to + // variable fields during multibeat: val data = UInt(width = params.dataBits) val error = Bool() // AccessAck[Data] @@ -192,11 +198,13 @@ class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) with HasTLData { + // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 2) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from + // variable fields during multibeat: val data = UInt(width = params.dataBits) val error = Bool() // AccessAck[Data], Grant[Data] diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index 37f0f655..e2291163 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -7,7 +7,7 @@ import chisel3.internal.sourceinfo.SourceInfo object TLMonitor { - def legalizeA(bundle: TLBundleA, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + def legalizeFormatA(bundle: TLBundleA, edge: TLEdgeOut, sourceInfo: SourceInfo) = { assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode")(sourceInfo) // Reuse these subexpressions to save some firrtl lines @@ -72,7 +72,7 @@ object TLMonitor } } - def legalizeB(bundle: TLBundleB, edge: TLEdgeIn, sourceInfo: SourceInfo) = { + def legalizeFormatB(bundle: TLBundleB, edge: TLEdgeIn, sourceInfo: SourceInfo) = { assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode")(sourceInfo) // Reuse these subexpressions to save some firrtl lines @@ -137,7 +137,7 @@ object TLMonitor } } - def legalizeC(bundle: TLBundleC, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + def legalizeFormatC(bundle: TLBundleC, edge: TLEdgeOut, sourceInfo: SourceInfo) = { assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode")(sourceInfo) val source_ok = edge.client.contains(bundle.source) @@ -203,7 +203,7 @@ object TLMonitor } } - def legalizeD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { + def legalizeFormatD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode")(sourceInfo) val source_ok = edge.client.contains(bundle.source) @@ -254,15 +254,135 @@ object TLMonitor } } - def legalizeE(bundle: TLBundleE, edge: TLEdgeOut, sourceInfo: SourceInfo) = { + def legalizeFormatE(bundle: TLBundleE, edge: TLEdgeOut, sourceInfo: SourceInfo) = { assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID")(sourceInfo) } + def legalizeFormat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { + when (bundleOut.a.valid) { legalizeFormatA(bundleOut.a.bits, edgeOut, sourceInfo) } + when (bundleIn .b.valid) { legalizeFormatB(bundleIn .b.bits, edgeIn, sourceInfo) } + when (bundleOut.c.valid) { legalizeFormatC(bundleOut.c.bits, edgeOut, sourceInfo) } + when (bundleIn .d.valid) { legalizeFormatD(bundleIn .d.bits, edgeIn, sourceInfo) } + when (bundleOut.e.valid) { legalizeFormatE(bundleOut.e.bits, edgeOut, sourceInfo) } + } + + def legalizeMultibeatA(a: DecoupledIO[TLBundleA], edge: TLEdgeOut, sourceInfo: SourceInfo) = { + val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + val opcode = Reg(UInt()) + val param = Reg(UInt()) + val size = Reg(UInt()) + val source = Reg(UInt()) + val address = Reg(UInt()) + when (a.valid && counter =/= UInt(0)) { + assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation")(sourceInfo) + assert (a.bits.param === param, "'A' channel param changed within multibeat operation")(sourceInfo) + assert (a.bits.size === size, "'A' channel size changed within multibeat operation")(sourceInfo) + assert (a.bits.source === source, "'A' channel source changed within multibeat operation")(sourceInfo) + assert (a.bits.address=== address,"'A' channel address changed with multibeat operation")(sourceInfo) + } + when (a.fire()) { + counter := counter - UInt(1) + when (counter === UInt(0)) { + counter := edge.numBeats(a.bits) - UInt(1) + opcode := a.bits.opcode + param := a.bits.param + size := a.bits.size + source := a.bits.source + address := a.bits.address + } + } + } + + def legalizeMultibeatB(b: DecoupledIO[TLBundleB], edge: TLEdgeIn, sourceInfo: SourceInfo) = { + val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + val opcode = Reg(UInt()) + val param = Reg(UInt()) + val size = Reg(UInt()) + val source = Reg(UInt()) + val address = Reg(UInt()) + when (b.valid && counter =/= UInt(0)) { + assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation")(sourceInfo) + assert (b.bits.param === param, "'B' channel param changed within multibeat operation")(sourceInfo) + assert (b.bits.size === size, "'B' channel size changed within multibeat operation")(sourceInfo) + assert (b.bits.source === source, "'B' channel source changed within multibeat operation")(sourceInfo) + assert (b.bits.address=== address,"'B' channel address changed with multibeat operation")(sourceInfo) + } + when (b.fire()) { + counter := counter - UInt(1) + when (counter === UInt(0)) { + counter := edge.numBeats(b.bits) - UInt(1) + opcode := b.bits.opcode + param := b.bits.param + size := b.bits.size + source := b.bits.source + address := b.bits.address + } + } + } + + def legalizeMultibeatC(c: DecoupledIO[TLBundleC], edge: TLEdgeOut, sourceInfo: SourceInfo) = { + val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + val opcode = Reg(UInt()) + val param = Reg(UInt()) + val size = Reg(UInt()) + val source = Reg(UInt()) + val address = Reg(UInt()) + when (c.valid && counter =/= UInt(0)) { + assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation")(sourceInfo) + assert (c.bits.param === param, "'C' channel param changed within multibeat operation")(sourceInfo) + assert (c.bits.size === size, "'C' channel size changed within multibeat operation")(sourceInfo) + assert (c.bits.source === source, "'C' channel source changed within multibeat operation")(sourceInfo) + assert (c.bits.address=== address,"'C' channel address changed with multibeat operation")(sourceInfo) + } + when (c.fire()) { + counter := counter - UInt(1) + when (counter === UInt(0)) { + counter := edge.numBeats(c.bits) - UInt(1) + opcode := c.bits.opcode + param := c.bits.param + size := c.bits.size + source := c.bits.source + address := c.bits.address + } + } + } + + def legalizeMultibeatD(d: DecoupledIO[TLBundleD], edge: TLEdgeIn, sourceInfo: SourceInfo) = { + val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) + val opcode = Reg(UInt()) + val param = Reg(UInt()) + val size = Reg(UInt()) + val source = Reg(UInt()) + val sink = Reg(UInt()) + when (d.valid && counter =/= UInt(0)) { + assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation")(sourceInfo) + assert (d.bits.param === param, "'D' channel param changed within multibeat operation")(sourceInfo) + assert (d.bits.size === size, "'D' channel size changed within multibeat operation")(sourceInfo) + assert (d.bits.source === source, "'D' channel source changed within multibeat operation")(sourceInfo) + assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation")(sourceInfo) + } + when (d.fire()) { + counter := counter - UInt(1) + when (counter === UInt(0)) { + counter := edge.numBeats(d.bits) - UInt(1) + opcode := d.bits.opcode + param := d.bits.param + size := d.bits.size + source := d.bits.source + sink := d.bits.sink + } + } + } + + def legalizeMultibeat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { + legalizeMultibeatA(bundleOut.a, edgeOut, sourceInfo) + legalizeMultibeatB(bundleOut.b, edgeIn, sourceInfo) + legalizeMultibeatC(bundleOut.c, edgeOut, sourceInfo) + legalizeMultibeatD(bundleOut.d, edgeIn, sourceInfo) + } + def legalize(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { - when (bundleOut.a.valid) { legalizeA(bundleOut.a.bits, edgeOut, sourceInfo) } - when (bundleIn .b.valid) { legalizeB(bundleIn .b.bits, edgeIn, sourceInfo) } - when (bundleOut.c.valid) { legalizeC(bundleOut.c.bits, edgeOut, sourceInfo) } - when (bundleIn .d.valid) { legalizeD(bundleIn .d.bits, edgeIn, sourceInfo) } - when (bundleOut.e.valid) { legalizeE(bundleOut.e.bits, edgeOut, sourceInfo) } + legalizeFormat(bundleOut, edgeOut, bundleIn, edgeIn, sourceInfo) + legalizeMultibeat(bundleOut, edgeOut, bundleIn, edgeIn, sourceInfo) } } From 2069ca5d8d66a127eaaf116dd5337e5eecdfde04 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 11:12:25 -0700 Subject: [PATCH 58/87] tilelink2: pass sourceInfo using implicits in Monitor --- uncore/src/main/scala/tilelink2/Monitor.scala | 391 +++++++++--------- uncore/src/main/scala/tilelink2/TLNodes.scala | 2 +- 2 files changed, 197 insertions(+), 196 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/uncore/src/main/scala/tilelink2/Monitor.scala index e2291163..b30a989e 100644 --- a/uncore/src/main/scala/tilelink2/Monitor.scala +++ b/uncore/src/main/scala/tilelink2/Monitor.scala @@ -7,73 +7,73 @@ import chisel3.internal.sourceinfo.SourceInfo object TLMonitor { - def legalizeFormatA(bundle: TLBundleA, edge: TLEdgeOut, sourceInfo: SourceInfo) = { - assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode")(sourceInfo) - + def legalizeFormatA(bundle: TLBundleA, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { + assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode") + // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Acquire) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel Acquire carries invalid source ID")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat")(sourceInfo) - assert (is_aligned, "'A' channel Acquire address not aligned to size")(sourceInfo) - assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param")(sourceInfo) - assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask")(sourceInfo) + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager") + assert (source_ok, "'A' channel Acquire carries invalid source ID") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat") + assert (is_aligned, "'A' channel Acquire address not aligned to size") + assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param") + assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask") } when (bundle.opcode === TLMessages.Get) { - assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel Get carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel Get address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'A' channel Get carries invalid param")(sourceInfo) - assert (bundle.mask === mask, "'A' channel Get contains invalid mask")(sourceInfo) + assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager") + assert (source_ok, "'A' channel Get carries invalid source ID") + assert (is_aligned, "'A' channel Get address not aligned to size") + assert (bundle.param === UInt(0), "'A' channel Get carries invalid param") + assert (bundle.mask === mask, "'A' channel Get contains invalid mask") } when (bundle.opcode === TLMessages.PutFullData) { - assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel PutFull carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel PutFull address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.mask === mask, "'A' channel PutFull contains invalid mask")(sourceInfo) + assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager") + assert (source_ok, "'A' channel PutFull carries invalid source ID") + assert (is_aligned, "'A' channel PutFull address not aligned to size") + assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param") + assert (bundle.mask === mask, "'A' channel PutFull contains invalid mask") } when (bundle.opcode === TLMessages.PutPartialData) { - assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel PutPartial carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel PutPartial address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.mask & ~mask) === UInt(0), "'A' channel PutPartial contains invalid mask")(sourceInfo) + assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager") + assert (source_ok, "'A' channel PutPartial carries invalid source ID") + 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") } when (bundle.opcode === TLMessages.ArithmeticData) { - assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel Arithmetic carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel Arithmetic address not aligned to size")(sourceInfo) - assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.mask === mask, "'A' channel Arithmetic contains invalid mask")(sourceInfo) + assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager") + assert (source_ok, "'A' channel Arithmetic carries invalid source ID") + assert (is_aligned, "'A' channel Arithmetic address not aligned to size") + assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param") + assert (bundle.mask === mask, "'A' channel Arithmetic contains invalid mask") } - + when (bundle.opcode === TLMessages.LogicalData) { - assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel Logical carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel Logical address not aligned to size")(sourceInfo) - assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.mask === mask, "'A' channel Logical contains invalid mask")(sourceInfo) + assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager") + assert (source_ok, "'A' channel Logical carries invalid source ID") + assert (is_aligned, "'A' channel Logical address not aligned to size") + assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param") + assert (bundle.mask === mask, "'A' channel Logical contains invalid mask") } - + when (bundle.opcode === TLMessages.Hint) { - assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager")(sourceInfo) - assert (source_ok, "'A' channel Hint carries invalid source ID")(sourceInfo) - assert (is_aligned, "'A' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.mask === mask, "'A' channel Hint contains invalid mask")(sourceInfo) + assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager") + assert (source_ok, "'A' channel Hint carries invalid source ID") + assert (is_aligned, "'A' channel Hint address not aligned to size") + assert (bundle.mask === mask, "'A' channel Hint contains invalid mask") } } - def legalizeFormatB(bundle: TLBundleB, edge: TLEdgeIn, sourceInfo: SourceInfo) = { - assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode")(sourceInfo) + def legalizeFormatB(bundle: TLBundleB, edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { + assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode") // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) @@ -81,192 +81,192 @@ object TLMonitor val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Probe) { - assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel Probe carries unmanaged address")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat")(sourceInfo) - assert (is_aligned, "'B' channel Probe address not aligned to size")(sourceInfo) - assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param")(sourceInfo) - assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask")(sourceInfo) + assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client") + assert (address_ok, "'B' channel Probe carries unmanaged address") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat") + assert (is_aligned, "'B' channel Probe address not aligned to size") + assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param") + assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask") } when (bundle.opcode === TLMessages.Get) { - assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel Get carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel Get address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'B' channel Get carries invalid param")(sourceInfo) - assert (bundle.mask === mask, "'A' channel Get contains invalid mask")(sourceInfo) + assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client") + assert (address_ok, "'B' channel Get carries unmanaged address") + assert (is_aligned, "'B' channel Get address not aligned to size") + assert (bundle.param === UInt(0), "'B' channel Get carries invalid param") + assert (bundle.mask === mask, "'A' channel Get contains invalid mask") } when (bundle.opcode === TLMessages.PutFullData) { - assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel PutFull carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel PutFull address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param")(sourceInfo) - assert (bundle.mask === mask, "'B' channel PutFull contains invalid mask")(sourceInfo) + assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client") + assert (address_ok, "'B' channel PutFull carries unmanaged address") + assert (is_aligned, "'B' channel PutFull address not aligned to size") + assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param") + assert (bundle.mask === mask, "'B' channel PutFull contains invalid mask") } when (bundle.opcode === TLMessages.PutPartialData) { - assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel PutPartial carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel PutPartial address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param")(sourceInfo) - assert ((bundle.mask & ~mask) === UInt(0), "'B' channel PutPartial contains invalid mask")(sourceInfo) + assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client") + assert (address_ok, "'B' channel PutPartial carries unmanaged address") + 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") } when (bundle.opcode === TLMessages.ArithmeticData) { - assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel Arithmetic carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel Arithmetic address not aligned to size")(sourceInfo) - assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param")(sourceInfo) - assert (bundle.mask === mask, "'B' channel Arithmetic contains invalid mask")(sourceInfo) + assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client") + assert (address_ok, "'B' channel Arithmetic carries unmanaged address") + assert (is_aligned, "'B' channel Arithmetic address not aligned to size") + assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param") + assert (bundle.mask === mask, "'B' channel Arithmetic contains invalid mask") } - + when (bundle.opcode === TLMessages.LogicalData) { - assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel Logical carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel Logical address not aligned to size")(sourceInfo) - assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param")(sourceInfo) - assert (bundle.mask === mask, "'B' channel Logical contains invalid mask")(sourceInfo) + assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client") + assert (address_ok, "'B' channel Logical carries unmanaged address") + assert (is_aligned, "'B' channel Logical address not aligned to size") + assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param") + assert (bundle.mask === mask, "'B' channel Logical contains invalid mask") } - + when (bundle.opcode === TLMessages.Hint) { - assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client")(sourceInfo) - assert (address_ok, "'B' channel Hint carries unmanaged address")(sourceInfo) - assert (is_aligned, "'B' channel Hint address not aligned to size")(sourceInfo) - assert (bundle.mask === mask, "'B' channel Hint contains invalid mask")(sourceInfo) + assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client") + assert (address_ok, "'B' channel Hint carries unmanaged address") + assert (is_aligned, "'B' channel Hint address not aligned to size") + assert (bundle.mask === mask, "'B' channel Hint contains invalid mask") } } - def legalizeFormatC(bundle: TLBundleC, edge: TLEdgeOut, sourceInfo: SourceInfo) = { - assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode")(sourceInfo) - + def legalizeFormatC(bundle: TLBundleC, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { + assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode") + val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) val address_ok = edge.manager.contains(bundle.source) when (bundle.opcode === TLMessages.ProbeAck) { - assert (address_ok, "'C' channel ProbeAck carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel ProbeAck carries unmanaged address") // source is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat")(sourceInfo) - assert (is_aligned, "'C' channel ProbeAck address not aligned to size")(sourceInfo) - assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param")(sourceInfo) - assert (!bundle.error, "'C' channel Probe carries an error")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat") + assert (is_aligned, "'C' channel ProbeAck address not aligned to size") + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param") + assert (!bundle.error, "'C' channel Probe carries an error") } - + when (bundle.opcode === TLMessages.ProbeAckData) { - assert (address_ok, "'C' channel ProbeAckData carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel ProbeAckData carries unmanaged address") // source is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat")(sourceInfo) - assert (is_aligned, "'C' channel ProbeAckData address not aligned to size")(sourceInfo) - assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param")(sourceInfo) - assert (!bundle.error, "'C' channel ProbeData carries an error")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat") + assert (is_aligned, "'C' channel ProbeAckData address not aligned to size") + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param") + assert (!bundle.error, "'C' channel ProbeData carries an error") } - + when (bundle.opcode === TLMessages.Release) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager")(sourceInfo) - assert (source_ok, "'C' channel Release carries invalid source ID")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat")(sourceInfo) - assert (is_aligned, "'C' channel Release address not aligned to size")(sourceInfo) - assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param")(sourceInfo) - assert (!bundle.error, "'C' channel Release carries an error")(sourceInfo) + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager") + assert (source_ok, "'C' channel Release carries invalid source ID") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat") + assert (is_aligned, "'C' channel Release address not aligned to size") + assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param") + assert (!bundle.error, "'C' channel Release carries an error") } - + when (bundle.opcode === TLMessages.ReleaseData) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager")(sourceInfo) - assert (source_ok, "'C' channel ReleaseData carries invalid source ID")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat")(sourceInfo) - assert (is_aligned, "'C' channel ReleaseData address not aligned to size")(sourceInfo) - assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param")(sourceInfo) - assert (!bundle.error, "'C' channel ReleaseData carries an error")(sourceInfo) + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager") + assert (source_ok, "'C' channel ReleaseData carries invalid source ID") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat") + assert (is_aligned, "'C' channel ReleaseData address not aligned to size") + assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param") + assert (!bundle.error, "'C' channel ReleaseData carries an error") } - + when (bundle.opcode === TLMessages.AccessAck) { - assert (address_ok, "'C' channel AccessAck carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel AccessAck carries unmanaged address") // source is ignored - assert (is_aligned, "'C' channel AccessAck address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param")(sourceInfo) + assert (is_aligned, "'C' channel AccessAck address not aligned to size") + assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param") } - + when (bundle.opcode === TLMessages.AccessAckData) { - assert (address_ok, "'C' channel AccessAckData carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel AccessAckData carries unmanaged address") // source is ignored - assert (is_aligned, "'C' channel AccessAckData address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param")(sourceInfo) + assert (is_aligned, "'C' channel AccessAckData address not aligned to size") + assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param") } - + when (bundle.opcode === TLMessages.HintAck) { - assert (address_ok, "'C' channel HintAck carries unmanaged address")(sourceInfo) + assert (address_ok, "'C' channel HintAck carries unmanaged address") // source is ignored - assert (is_aligned, "'C' channel HintAck address not aligned to size")(sourceInfo) - assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param")(sourceInfo) - assert (!bundle.error, "'C' channel HintAck carries an error")(sourceInfo) + assert (is_aligned, "'C' channel HintAck address not aligned to size") + assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param") + assert (!bundle.error, "'C' channel HintAck carries an error") } } - def legalizeFormatD(bundle: TLBundleD, edge: TLEdgeIn, sourceInfo: SourceInfo) = { - assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode")(sourceInfo) - + def legalizeFormatD(bundle: TLBundleD, edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { + assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode") + val source_ok = edge.client.contains(bundle.source) val sink_ok = edge.manager.containsById(bundle.sink) - + when (bundle.opcode === TLMessages.ReleaseAck) { - assert (source_ok, "'D' channel ReleaseAck carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel ReleaseAck carries invalid source ID") // sink is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat")(sourceInfo) - assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param")(sourceInfo) - assert (!bundle.error, "'D' channel ReleaseAck carries an error")(sourceInfo) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat") + assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param") + assert (!bundle.error, "'D' channel ReleaseAck carries an error") } - + when (bundle.opcode === TLMessages.Grant) { - assert (source_ok, "'D' channel Grant carries invalid source ID")(sourceInfo) - assert (sink_ok, "'D' channel Grant carries invalid sink ID")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat")(sourceInfo) - assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param")(sourceInfo) + assert (source_ok, "'D' channel Grant carries invalid source ID") + assert (sink_ok, "'D' channel Grant carries invalid sink ID") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat") + assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param") } - + when (bundle.opcode === TLMessages.GrantData) { - assert (source_ok, "'D' channel GrantData carries invalid source ID")(sourceInfo) - assert (sink_ok, "'D' channel GrantData carries invalid sink ID")(sourceInfo) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat")(sourceInfo) - assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param")(sourceInfo) + assert (source_ok, "'D' channel GrantData carries invalid source ID") + assert (sink_ok, "'D' channel GrantData carries invalid sink ID") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat") + assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param") } - + when (bundle.opcode === TLMessages.AccessAck) { - assert (source_ok, "'D' channel AccessAck carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel AccessAck carries invalid source ID") // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param")(sourceInfo) + assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param") } - + when (bundle.opcode === TLMessages.AccessAckData) { - assert (source_ok, "'D' channel AccessAckData carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel AccessAckData carries invalid source ID") // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param")(sourceInfo) + assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param") } - + when (bundle.opcode === TLMessages.HintAck) { - assert (source_ok, "'D' channel HintAck carries invalid source ID")(sourceInfo) + assert (source_ok, "'D' channel HintAck carries invalid source ID") // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param")(sourceInfo) - assert (!bundle.error, "'D' channel HintAck carries an error")(sourceInfo) + assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param") + assert (!bundle.error, "'D' channel HintAck carries an error") } } - def legalizeFormatE(bundle: TLBundleE, edge: TLEdgeOut, sourceInfo: SourceInfo) = { - assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID")(sourceInfo) + def legalizeFormatE(bundle: TLBundleE, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { + assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID") } - - def legalizeFormat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { - when (bundleOut.a.valid) { legalizeFormatA(bundleOut.a.bits, edgeOut, sourceInfo) } - when (bundleIn .b.valid) { legalizeFormatB(bundleIn .b.bits, edgeIn, sourceInfo) } - when (bundleOut.c.valid) { legalizeFormatC(bundleOut.c.bits, edgeOut, sourceInfo) } - when (bundleIn .d.valid) { legalizeFormatD(bundleIn .d.bits, edgeIn, sourceInfo) } - when (bundleOut.e.valid) { legalizeFormatE(bundleOut.e.bits, edgeOut, sourceInfo) } + + def legalizeFormat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { + when (bundleOut.a.valid) { legalizeFormatA(bundleOut.a.bits, edgeOut) } + when (bundleIn .b.valid) { legalizeFormatB(bundleIn .b.bits, edgeIn) } + when (bundleOut.c.valid) { legalizeFormatC(bundleOut.c.bits, edgeOut) } + when (bundleIn .d.valid) { legalizeFormatD(bundleIn .d.bits, edgeIn) } + when (bundleOut.e.valid) { legalizeFormatE(bundleOut.e.bits, edgeOut) } } - - def legalizeMultibeatA(a: DecoupledIO[TLBundleA], edge: TLEdgeOut, sourceInfo: SourceInfo) = { + + def legalizeMultibeatA(a: DecoupledIO[TLBundleA], edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -274,11 +274,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (a.valid && counter =/= UInt(0)) { - assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation")(sourceInfo) - assert (a.bits.param === param, "'A' channel param changed within multibeat operation")(sourceInfo) - assert (a.bits.size === size, "'A' channel size changed within multibeat operation")(sourceInfo) - assert (a.bits.source === source, "'A' channel source changed within multibeat operation")(sourceInfo) - assert (a.bits.address=== address,"'A' channel address changed with multibeat operation")(sourceInfo) + assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation") + assert (a.bits.param === param, "'A' channel param changed within multibeat operation") + assert (a.bits.size === size, "'A' channel size changed within multibeat operation") + assert (a.bits.source === source, "'A' channel source changed within multibeat operation") + assert (a.bits.address=== address,"'A' channel address changed with multibeat operation") } when (a.fire()) { counter := counter - UInt(1) @@ -292,8 +292,8 @@ object TLMonitor } } } - - def legalizeMultibeatB(b: DecoupledIO[TLBundleB], edge: TLEdgeIn, sourceInfo: SourceInfo) = { + + def legalizeMultibeatB(b: DecoupledIO[TLBundleB], edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -301,11 +301,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (b.valid && counter =/= UInt(0)) { - assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation")(sourceInfo) - assert (b.bits.param === param, "'B' channel param changed within multibeat operation")(sourceInfo) - assert (b.bits.size === size, "'B' channel size changed within multibeat operation")(sourceInfo) - assert (b.bits.source === source, "'B' channel source changed within multibeat operation")(sourceInfo) - assert (b.bits.address=== address,"'B' channel address changed with multibeat operation")(sourceInfo) + assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation") + assert (b.bits.param === param, "'B' channel param changed within multibeat operation") + assert (b.bits.size === size, "'B' channel size changed within multibeat operation") + assert (b.bits.source === source, "'B' channel source changed within multibeat operation") + assert (b.bits.address=== address,"'B' channel address changed with multibeat operation") } when (b.fire()) { counter := counter - UInt(1) @@ -319,8 +319,8 @@ object TLMonitor } } } - - def legalizeMultibeatC(c: DecoupledIO[TLBundleC], edge: TLEdgeOut, sourceInfo: SourceInfo) = { + + def legalizeMultibeatC(c: DecoupledIO[TLBundleC], edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -328,11 +328,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (c.valid && counter =/= UInt(0)) { - assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation")(sourceInfo) - assert (c.bits.param === param, "'C' channel param changed within multibeat operation")(sourceInfo) - assert (c.bits.size === size, "'C' channel size changed within multibeat operation")(sourceInfo) - assert (c.bits.source === source, "'C' channel source changed within multibeat operation")(sourceInfo) - assert (c.bits.address=== address,"'C' channel address changed with multibeat operation")(sourceInfo) + assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation") + assert (c.bits.param === param, "'C' channel param changed within multibeat operation") + assert (c.bits.size === size, "'C' channel size changed within multibeat operation") + assert (c.bits.source === source, "'C' channel source changed within multibeat operation") + assert (c.bits.address=== address,"'C' channel address changed with multibeat operation") } when (c.fire()) { counter := counter - UInt(1) @@ -346,8 +346,8 @@ object TLMonitor } } } - - def legalizeMultibeatD(d: DecoupledIO[TLBundleD], edge: TLEdgeIn, sourceInfo: SourceInfo) = { + + def legalizeMultibeatD(d: DecoupledIO[TLBundleD], edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer))) val opcode = Reg(UInt()) val param = Reg(UInt()) @@ -355,11 +355,11 @@ object TLMonitor val source = Reg(UInt()) val sink = Reg(UInt()) when (d.valid && counter =/= UInt(0)) { - assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation")(sourceInfo) - assert (d.bits.param === param, "'D' channel param changed within multibeat operation")(sourceInfo) - assert (d.bits.size === size, "'D' channel size changed within multibeat operation")(sourceInfo) - assert (d.bits.source === source, "'D' channel source changed within multibeat operation")(sourceInfo) - assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation")(sourceInfo) + assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation") + assert (d.bits.param === param, "'D' channel param changed within multibeat operation") + assert (d.bits.size === size, "'D' channel size changed within multibeat operation") + assert (d.bits.source === source, "'D' channel source changed within multibeat operation") + assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation") } when (d.fire()) { counter := counter - UInt(1) @@ -373,16 +373,17 @@ object TLMonitor } } } - - def legalizeMultibeat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { - legalizeMultibeatA(bundleOut.a, edgeOut, sourceInfo) - legalizeMultibeatB(bundleOut.b, edgeIn, sourceInfo) - legalizeMultibeatC(bundleOut.c, edgeOut, sourceInfo) - legalizeMultibeatD(bundleOut.d, edgeIn, sourceInfo) + + def legalizeMultibeat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { + legalizeMultibeatA(bundleOut.a, edgeOut) + legalizeMultibeatB(bundleOut.b, edgeIn) + legalizeMultibeatC(bundleOut.c, edgeOut) + legalizeMultibeatD(bundleOut.d, edgeIn) } - - def legalize(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn, sourceInfo: SourceInfo) = { - legalizeFormat(bundleOut, edgeOut, bundleIn, edgeIn, sourceInfo) - legalizeMultibeat(bundleOut, edgeOut, bundleIn, edgeIn, sourceInfo) + + def legalize(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { + legalizeFormat (bundleOut, edgeOut, bundleIn, edgeIn) + legalizeMultibeat(bundleOut, edgeOut, bundleIn, edgeIn) + // !!! validate source uniqueness } } diff --git a/uncore/src/main/scala/tilelink2/TLNodes.scala b/uncore/src/main/scala/tilelink2/TLNodes.scala index 27342d9e..05353cdc 100644 --- a/uncore/src/main/scala/tilelink2/TLNodes.scala +++ b/uncore/src/main/scala/tilelink2/TLNodes.scala @@ -21,7 +21,7 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL def connect(bo: TLBundle, eo: TLEdgeOut, bi: TLBundle, ei: TLEdgeIn)(implicit sourceInfo: SourceInfo): Unit = { require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters]) - TLMonitor.legalize(bo, eo, bi, ei, sourceInfo) + TLMonitor.legalize(bo, eo, bi, ei) bi <> bo val mask = ~UInt(ei.manager.beatBytes - 1) bi.a.bits.address := (mask & bo.a.bits.address) From 3d84795641380bd79a546bf1c65595ff2eb8b1b0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 11:13:43 -0700 Subject: [PATCH 59/87] tilelink2: use LazyModule(new ...) just like Chisel Module(new ...) --- uncore/src/main/scala/tilelink2/Buffer.scala | 7 +-- .../main/scala/tilelink2/HintHandler.scala | 7 +-- .../src/main/scala/tilelink2/LazyModule.scala | 55 ++++++++++++------- uncore/src/main/scala/tilelink2/Legacy.scala | 4 +- .../main/scala/tilelink2/RegisterRouter.scala | 2 +- uncore/src/main/scala/tilelink2/SRAM.scala | 4 +- uncore/src/main/scala/tilelink2/Xbar.scala | 4 +- 7 files changed, 47 insertions(+), 36 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Buffer.scala b/uncore/src/main/scala/tilelink2/Buffer.scala index 8c13fc80..c35a395f 100644 --- a/uncore/src/main/scala/tilelink2/Buffer.scala +++ b/uncore/src/main/scala/tilelink2/Buffer.scala @@ -8,7 +8,7 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule { val node = TLIdentityNode() - lazy val module = Module(new LazyModuleImp(this) { + lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut @@ -26,15 +26,14 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule out.c <> Queue(in .c, entries, pipe) out.e <> Queue(out.e, entries, pipe) } - }) + } } object TLBuffer { // applied to the TL source node; connect (TLBuffer(x.node) -> y.node) def apply(x: TLBaseNode, entries: Int = 2, pipe: Boolean = false)(implicit lazyModule: LazyModule): TLBaseNode = { - val buffer = new TLBuffer(entries, pipe) - lazyModule.addChild(buffer) + val buffer = LazyModule(new TLBuffer(entries, pipe)) lazyModule.connect(x -> buffer.node) buffer.node } diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/uncore/src/main/scala/tilelink2/HintHandler.scala index 99e94194..edca9f20 100644 --- a/uncore/src/main/scala/tilelink2/HintHandler.scala +++ b/uncore/src/main/scala/tilelink2/HintHandler.scala @@ -11,7 +11,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f clientFn = { case Seq(c) => if (supportClients) c.copy(clients = c.clients .map(_.copy(supportsHint = true))) else c }, managerFn = { case Seq(m) => if (supportManagers) m.copy(managers = m.managers.map(_.copy(supportsHint = true))) else m }) - lazy val module = Module(new LazyModuleImp(this) { + lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut @@ -76,15 +76,14 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f in.e.ready := out.e.ready out.e.bits := in.e.bits } - }) + } } object TLHintHandler { // applied to the TL source node; connect (TLHintHandler(x.node) -> y.node) def apply(x: TLBaseNode, supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit lazyModule: LazyModule): TLBaseNode = { - val hints = new TLHintHandler(supportManagers, supportClients, passthrough) - lazyModule.addChild(hints) + val hints = LazyModule(new TLHintHandler(supportManagers, supportClients, passthrough)) lazyModule.connect(x -> hints.node) hints.node } diff --git a/uncore/src/main/scala/tilelink2/LazyModule.scala b/uncore/src/main/scala/tilelink2/LazyModule.scala index a12427a5..83386f30 100644 --- a/uncore/src/main/scala/tilelink2/LazyModule.scala +++ b/uncore/src/main/scala/tilelink2/LazyModule.scala @@ -3,45 +3,58 @@ package uncore.tilelink2 import Chisel._ -import scala.collection.mutable.ListBuffer -import chisel3.internal.sourceinfo.SourceInfo +import chisel3.internal.sourceinfo._ abstract class LazyModule { - private val bindings = ListBuffer[() => Unit]() - private val extraChildren = ListBuffer[LazyModule]() + protected[tilelink2] var bindings = List[() => Unit]() + protected[tilelink2] var children = List[LazyModule]() + protected[tilelink2] var info: SourceInfo = UnlocatableSourceInfo + protected[tilelink2] val parent = LazyModule.stack.headOption + + LazyModule.stack = this :: LazyModule.stack + parent.foreach(p => p.children = this :: p.children) // Use as: connect(source -> sink, source2 -> sink2, ...) def connect[PO, PI, EO, EI, B <: Bundle](edges: (BaseNode[PO, PI, EO, EI, B], BaseNode[PO, PI, EO, EI, B])*)(implicit sourceInfo: SourceInfo) = { edges.foreach { case (source, sink) => - bindings += (source edge sink) + bindings = (source edge sink) :: bindings } } def module: LazyModuleImp + implicit val lazyModule = this protected[tilelink2] def instantiate() = { - // Find all LazyModule members of self - for (m <- getClass.getMethods) { - if (m.getParameterTypes.isEmpty && - !java.lang.reflect.Modifier.isStatic(m.getModifiers) && - !(m.getName contains '$') && - !(m.getName == "lazyModule") && - classOf[LazyModule].isAssignableFrom(m.getReturnType)) { - // ... and force their lazy module members to exist - m.invoke(this).asInstanceOf[LazyModule].module - } + children.reverse.foreach { c => + // !!! fix chisel3 so we can pass the desired sourceInfo + // implicit val sourceInfo = c.module.outer.info + Module(c.module) } - extraChildren.foreach { _.module } - bindings.foreach { f => f () } + bindings.reverse.foreach { f => f () } } - - implicit val lazyModule = this - def addChild(x: LazyModule) = extraChildren += x } -abstract class LazyModuleImp(outer: LazyModule) extends Module +object LazyModule { + protected[tilelink2] var stack = List[LazyModule]() + + def apply[T <: LazyModule](bc: T)(implicit sourceInfo: SourceInfo): T = { + // Make sure the user put LazyModule around modules in the correct order + // If this require fails, probably some grandchild was missing a LazyModule + // ... or you applied LazyModule twice + require (!stack.isEmpty && (stack.head eq bc)) + stack = stack.tail + bc.info = sourceInfo + bc + } +} + +abstract class LazyModuleImp(val outer: LazyModule) extends Module +{ + // .module had better not be accessed while LazyModules are still being built! + require (LazyModule.stack.isEmpty) + override def desiredName = outer.getClass.getName.split('.').last outer.instantiate() } diff --git a/uncore/src/main/scala/tilelink2/Legacy.scala b/uncore/src/main/scala/tilelink2/Legacy.scala index 9aae31db..c66f48c6 100644 --- a/uncore/src/main/scala/tilelink2/Legacy.scala +++ b/uncore/src/main/scala/tilelink2/Legacy.scala @@ -14,7 +14,7 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa val node = TLClientNode(TLClientParameters( sourceId = IdRange(0, 1 << tlClientXactIdBits))) - lazy val module = Module(new LazyModuleImp(this) with HasTileLinkParameters { + lazy val module = new LazyModuleImp(this) with HasTileLinkParameters { val p = outer_p val io = new Bundle { val legacy = new ClientUncachedTileLinkIO()(p).flip @@ -103,5 +103,5 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa grant.manager_xact_id := out.d.bits.sink grant.data := out.d.bits.data grant.addr_beat := beatCounter - }) + } } diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/uncore/src/main/scala/tilelink2/RegisterRouter.scala index a9d33695..17c473ad 100644 --- a/uncore/src/main/scala/tilelink2/RegisterRouter.scala +++ b/uncore/src/main/scala/tilelink2/RegisterRouter.scala @@ -83,5 +83,5 @@ class TLRegisterRouter[B <: Bundle, M <: LazyModuleImp] require (isPow2(size)) require (size >= 4096) - lazy val module = Module(moduleBuilder(bundleBuilder(node.bundleIn), this)) + lazy val module = moduleBuilder(bundleBuilder(node.bundleIn), this) } diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/uncore/src/main/scala/tilelink2/SRAM.scala index 5c499cf4..b20c6922 100644 --- a/uncore/src/main/scala/tilelink2/SRAM.scala +++ b/uncore/src/main/scala/tilelink2/SRAM.scala @@ -17,7 +17,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule // We require the address range to include an entire beat (for the write mask) require ((address.mask & (beatBytes-1)) == beatBytes-1) - lazy val module = Module(new LazyModuleImp(this) { + lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn } @@ -62,5 +62,5 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule mem.write(memAddress, wdata, in.a.bits.mask.toBools) } } - }) + } } diff --git a/uncore/src/main/scala/tilelink2/Xbar.scala b/uncore/src/main/scala/tilelink2/Xbar.scala index 19bd5df1..aa3dbd1c 100644 --- a/uncore/src/main/scala/tilelink2/Xbar.scala +++ b/uncore/src/main/scala/tilelink2/Xbar.scala @@ -65,7 +65,7 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend TLManagerPortParameters(managers, seq(0).beatBytes) }) - lazy val module = Module(new LazyModuleImp(this) { + lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn val out = node.bundleOut @@ -207,5 +207,5 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend muxState } - }) + } } From ecc3c2a4b2344279983dee5ac9e031763a23d9d3 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 11:52:47 -0700 Subject: [PATCH 60/87] tilelink2: more efficient one-hot circuits --- uncore/src/main/scala/tilelink2/Edges.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Edges.scala b/uncore/src/main/scala/tilelink2/Edges.scala index 6fd61796..cd1a2449 100644 --- a/uncore/src/main/scala/tilelink2/Edges.scala +++ b/uncore/src/main/scala/tilelink2/Edges.scala @@ -12,8 +12,9 @@ class TLEdge( { def isAligned(address: UInt, lgSize: UInt) = if (maxLgSize == 0) Bool(true) else { - val mask = Vec.tabulate(maxLgSize) { UInt(_) < lgSize } - (address & Cat(mask.reverse)) === UInt(0) + val ones = UInt((1 << maxLgSize) - 1) + val mask = (ones << lgSize)(maxLgSize*2-1, maxLgSize) + (address & mask) === UInt(0) } // This gets used everywhere, so make the smallest circuit possible ... @@ -43,8 +44,8 @@ class TLEdge( val size = bundle.size() val cutoff = log2Ceil(manager.beatBytes) val small = size <= UInt(cutoff) - val decode = Vec.tabulate (1+maxLgSize-cutoff) { i => UInt(i + cutoff) === size } - Mux(!hasData || small, UInt(1), Cat(decode.reverse)) + val decode = UIntToOH(size, maxLgSize+1) >> cutoff + Mux(!hasData || small, UInt(1), decode) } } From b004d54d71d18b09443ed66a87019abb22a11b06 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 15:03:49 -0700 Subject: [PATCH 61/87] tilelink2: add a Fragmenter adapter God that was a pain in the ass! --- .../src/main/scala/tilelink2/Fragmenter.scala | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 uncore/src/main/scala/tilelink2/Fragmenter.scala diff --git a/uncore/src/main/scala/tilelink2/Fragmenter.scala b/uncore/src/main/scala/tilelink2/Fragmenter.scala new file mode 100644 index 00000000..5dd6f8f4 --- /dev/null +++ b/uncore/src/main/scala/tilelink2/Fragmenter.scala @@ -0,0 +1,255 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import scala.math.{min,max} + +// minSize: minimum size of transfers supported by all outward managers +// maxSize: maximum size of transfers supported after the Fragmenter is applied +// alwaysMin: fragment all requests down to minSize (else fragment to maximum supported by manager) +// Fragmenter modifies: PutFull, PutPartial, LogicalData, Get, Hint +// Fragmenter passes: ArithmeticData (truncated to minSize if alwaysMin) +// Fragmenter breaks: Acquire (and thus cuts BCE channels) +class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) extends LazyModule +{ + require (isPow2 (maxSize)) + require (isPow2 (minSize)) + require (minSize < maxSize) + require (maxSize <= TransferSizes.maxAllowed) + + val fragmentBits = log2Ceil(maxSize / minSize) + + def expandTransfer(x: TransferSizes) = if (!x) x else { + require (x.max >= minSize) // validate that we can apply the fragmenter correctly + TransferSizes(x.min, maxSize) + } + def shrinkTransfer(x: TransferSizes) = + if (!alwaysMin) x else + if (x.min <= minSize) TransferSizes(x.min, minSize) else + TransferSizes.none + def mapManager(m: TLManagerParameters) = m.copy( + supportsAcquire = TransferSizes.none, // this adapter breaks acquires + supportsArithmetic = shrinkTransfer(m.supportsArithmetic), + supportsLogical = expandTransfer(m.supportsLogical), + supportsGet = expandTransfer(m.supportsGet), + supportsPutFull = expandTransfer(m.supportsPutFull), + supportsPutPartial = expandTransfer(m.supportsPutPartial)) + def mapClient(c: TLClientParameters) = c.copy( + sourceId = IdRange(c.sourceId.start << fragmentBits, c.sourceId.end << fragmentBits), + // since we break Acquires, none of these work either: + supportsProbe = TransferSizes.none, + supportsArithmetic = TransferSizes.none, + supportsLogical = TransferSizes.none, + supportsGet = TransferSizes.none, + supportsPutFull = TransferSizes.none, + supportsPutPartial = TransferSizes.none, + supportsHint = false) + + 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)) }) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + // All managers must share a common FIFO domain (responses might end up interleaved) + val manager = node.edgesOut(0).manager + val managers = manager.managers + val beatBytes = manager.beatBytes + val fifoId = managers(0).fifoId + require (fifoId.isDefined && managers.map(_.fifoId == fifoId).reduce(_ && _)) + + // We don't support fragmenting to sub-beat accesses + require (minSize >= beatBytes) + + /* The Fragmenter is a bit tricky, because there are 5 sizes in play: + * max size -- the maximum transfer size possible + * orig size -- the original pre-fragmenter size + * frag size -- the modified post-fragmenter size + * min size -- the threshold below which frag=orig + * beat size -- the amount transfered on any given beat + * + * The relationships are as follows: + * max >= orig >= frag + * max > min >= beat + * It IS possible that orig <= min (then frag=orig; ie: no fragmentation) + * + * The fragment# (sent via TL.source) is measured in multiples of min size. + * Meanwhile, to track the progress, counters measure in multiples of beat size. + * + * Here is an example of a bus with max=256, min=8, beat=4 and a device supporting 16. + * + * in.A out.A (frag#) out.D (frag#) in.D gen# ack# + * get64 get16 6 ackD16 6 ackD64 12 15 + * ackD16 6 ackD64 14 + * ackD16 6 ackD64 13 + * ackD16 6 ackD64 12 + * get16 4 ackD16 4 ackD64 8 11 + * ackD16 4 ackD64 10 + * ackD16 4 ackD64 9 + * ackD16 4 ackD64 8 + * get16 2 ackD16 2 ackD64 4 7 + * ackD16 2 ackD64 6 + * ackD16 2 ackD64 5 + * ackD16 2 ackD64 4 + * get16 0 ackD16 0 ackD64 0 3 + * ackD16 0 ackD64 2 + * ackD16 0 ackD64 1 + * ackD16 0 ackD64 0 + * + * get8 get8 0 ackD8 0 ackD8 0 1 + * ackD8 0 ackD8 0 + * + * get4 get4 0 ackD4 0 ackD4 0 0 + * get1 get1 0 ackD1 0 ackD1 0 0 + * + * put64 put16 6 15 + * put64 put16 6 14 + * put64 put16 6 13 + * put64 put16 6 ack16 6 12 12 + * put64 put16 4 11 + * put64 put16 4 10 + * put64 put16 4 9 + * put64 put16 4 ack16 4 8 8 + * put64 put16 2 7 + * put64 put16 2 6 + * put64 put16 2 5 + * put64 put16 2 ack16 2 4 4 + * put64 put16 0 3 + * put64 put16 0 2 + * put64 put16 0 1 + * put64 put16 0 ack16 0 ack64 0 0 + * + * put8 put8 0 1 + * put8 put8 0 ack8 0 ack8 0 0 + * + * put4 put4 0 ack4 0 ack4 0 0 + * put1 put1 0 ack1 0 ack1 0 0 + */ + + val in = io.in(0) + val out = io.out(0) + + // Do there exist A messages with Data? (we don't count Arithmetic, because it is never fragmented) + val aDataYes = manager.anySupportLogical || manager.anySupportPutFull || manager.anySupportPutPartial + // Do there exist A messages without Data? + val aDataNo = manager.anySupportGet || manager.anySupportHint + // Do there eixst D messages with Data? + val dDataYes = manager.anySupportGet || manager.anySupportLogical + // Do there exist D messages without Data? + val dDataNo = manager.anySupportPutFull || manager.anySupportPutPartial || manager.anySupportHint + + val counterBits = log2Up(maxSize/beatBytes) + val maxDownSize = if (alwaysMin) minSize else manager.maxTransfer + + def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x) + def UIntToOH1(x: UInt, width: Int) = (UInt((1 << width) - 1) << x)(width*2-1, width) + + // First, handle the return path + val acknum = RegInit(UInt(0, width = counterBits)) + val dOrig = Reg(UInt()) + val dFragnum = out.d.bits.source(fragmentBits-1, 0) + val dFirst = acknum === UInt(0) + val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1) + val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Ceil(maxDownSize)) + + // It is important to optimize this to a constant if we know certain operaitons + // will never exist. This allows synthesis to eliminate the Muxes. + val dHasData = if (!dDataYes) Bool(false) else if (!dDataNo) Bool(true) else out.d.bits.hasData() + + // calculate new acknum + val acknum_fragment = dFragnum << log2Ceil(minSize/beatBytes) + val acknum_size = dsizeOH1 >> log2Ceil(beatBytes) + assert (!out.d.valid || (acknum_fragment & acknum_size) === UInt(0)) + val dFirst_acknum = acknum_fragment | Mux(dHasData, acknum_size, UInt(0)) + val ack_decrement = Mux(dHasData, UInt(1), dsizeOH >> log2Ceil(beatBytes)) + // calculate the original size + val dFirst_size = OH1ToUInt((dFragnum << log2Ceil(minSize)) | dsizeOH1) + + when (out.d.fire()) { + acknum := Mux(dFirst, dFirst_acknum, acknum - ack_decrement) + when (dFirst) { dOrig := dFirst_size } + } + + // Swallow up non-data ack fragments + val drop = (out.d.bits.opcode === TLMessages.AccessAck) && (dFragnum =/= UInt(0)) + out.d.ready := in.d.ready || drop + in.d.valid := out.d.valid && drop + in.d.bits := out.d.bits // pass most stuff unchanged + in.d.bits.source := out.d.bits.source >> fragmentBits + in.d.bits.size := Mux(dFirst, dFirst_size, dOrig) + + // What maximum transfer sizes do downstream devices support? + val maxArithmetics = managers.map(_.supportsArithmetic.max) + val maxLogicals = managers.map(_.supportsLogical.max) + val maxGets = managers.map(_.supportsGet.max) + val maxPutFulls = managers.map(_.supportsPutFull.max) + val maxPutPartials = managers.map(_.supportsPutPartial.max) + val maxHints = managers.map(m => if (m.supportsHint) maxDownSize else 0) + + // We assume that the request is valid => size 0 is impossible + val lgMinSize = UInt(log2Ceil(minSize)) + val maxLgArithmetics = maxArithmetics.map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) + val maxLgLogicals = maxLogicals .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) + val maxLgGets = maxGets .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) + val maxLgPutFulls = maxPutFulls .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) + 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))) + + // If this is infront of a single manager, these become constants + val find = manager.find(in.a.bits.address) + val maxLgArithmetic = Mux1H(find, maxLgArithmetics) + val maxLgLogical = Mux1H(find, maxLgLogicals) + val maxLgGet = Mux1H(find, maxLgGets) + val maxLgPutFull = Mux1H(find, maxLgPutFulls) + val maxLgPutPartial = Mux1H(find, maxLgPutPartials) + val maxLgHint = Mux1H(find, maxLgHints) + + val limit = if (alwaysMin) lgMinSize else + MuxLookup(in.a.bits.opcode, lgMinSize, Array( + TLMessages.PutFullData -> maxLgPutFull, + TLMessages.PutPartialData -> maxLgPutPartial, + TLMessages.ArithmeticData -> maxLgArithmetic, + TLMessages.LogicalData -> maxLgLogical, + TLMessages.Get -> maxLgGet, + TLMessages.Hint -> maxLgHint)) + + val aOrig = in.a.bits.size + val aFrag = Mux(aOrig > limit, limit, aOrig) + val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize)) + val aFragOH1 = UIntToOH1(aFrag, log2Ceil(maxDownSize)) + + // Statically optimize the case where hasData is a constant + val aHasData = if (!aDataYes) Bool(false) else if (!aDataNo) Bool(true) else out.a.bits.hasData() + val aMask = Mux(aHasData, UInt(0), aFragOH1) + + val gennum = RegInit(UInt(0, width = counterBits)) + val aFirst = gennum === UInt(0) + val old_gennum1 = Mux(aFirst, aOrigOH1 >> log2Ceil(beatBytes), gennum - UInt(1)) + val new_gennum = ~(~old_gennum1 | (aMask >> log2Ceil(beatBytes))) // ~(~x|y) is width safe + val aFragnum = ~(~(old_gennum1 >> log2Ceil(minSize/beatBytes)) | (aFragOH1 >> log2Ceil(minSize))) + + when (out.d.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.source := Cat(in.a.bits.source, aFragnum) + out.a.bits.size := aFrag + } +} + +object TLFragmenter +{ + // applied to the TL source node; connect (TLFragmenter(x.node, 256, 4) -> y.node) + def apply(x: TLBaseNode, minSize: Int, maxSize: Int, alwaysMin: Boolean = false)(implicit lazyModule: LazyModule): TLBaseNode = { + val fragmenter = LazyModule(new TLFragmenter(minSize, maxSize, alwaysMin)) + lazyModule.connect(x -> fragmenter.node) + fragmenter.node + } +} From 5db7ae262bc91453e7a30cc43c3118a878f2815f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 19:30:07 -0700 Subject: [PATCH 62/87] 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 + } +} From 11b0272d917c25706cc837382abc9b2c511321d1 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 19:55:08 -0700 Subject: [PATCH 63/87] tilelink2: create optimized hasData method on edges (statically evaluates if known) --- uncore/src/main/scala/tilelink2/Bundles.scala | 17 ++++++++ uncore/src/main/scala/tilelink2/Edges.scala | 41 ++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/uncore/src/main/scala/tilelink2/Bundles.scala index 88b742d7..0c0a95e4 100644 --- a/uncore/src/main/scala/tilelink2/Bundles.scala +++ b/uncore/src/main/scala/tilelink2/Bundles.scala @@ -106,12 +106,24 @@ object Bogus def apply() = new Bogus } +object ChannelType { + sealed trait T + case object A extends T + case object B extends T + case object C extends T + case object D extends T + case object E extends T + val cases = Seq(A, B, C, D, E) +} + trait HasTLOpcode { // The data field in this message has value def hasData(x: Bogus = Bogus()): Bool // This message requires a response def hasFollowUp(x: Bogus = Bogus()): Bool + // What channel type is this? + def channelType(x: Bogus = Bogus()): ChannelType.T // The size field of the opcode def size(x: Bogus = Bogus()): UInt } @@ -142,6 +154,7 @@ class TLBundleA(params: TLBundleParameters) // opcode === TLMessages.ArithmeticData || // opcode === TLMessages.LogicalData def hasFollowUp(x: Bogus = Bogus()) = Bool(true) + def channelType(x: Bogus = Bogus()) = ChannelType.A def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data def mask(x: Bogus = Bogus()) = mask @@ -163,6 +176,7 @@ class TLBundleB(params: TLBundleParameters) def hasData(x: Bogus = Bogus()) = !opcode(2) def hasFollowUp(x: Bogus = Bogus()) = Bool(true) + def channelType(x: Bogus = Bogus()) = ChannelType.B def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data def mask(x: Bogus = Bogus()) = mask @@ -189,6 +203,7 @@ class TLBundleC(params: TLBundleParameters) def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && opcode(1) // opcode === TLMessages.Release || // opcode === TLMessages.ReleaseData + def channelType(x: Bogus = Bogus()) = ChannelType.C def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt @@ -214,6 +229,7 @@ class TLBundleD(params: TLBundleParameters) def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && !opcode(1) // opcode === TLMessages.Grant || // opcode === TLMessages.GrantData + def channelType(x: Bogus = Bogus()) = ChannelType.D def size(x: Bogus = Bogus()) = size def data(x: Bogus = Bogus()) = data def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt @@ -227,6 +243,7 @@ class TLBundleE(params: TLBundleParameters) def hasData(x: Bogus = Bogus()) = Bool(false) def hasFollowUp(x: Bogus = Bogus()) = Bool(false) + def channelType(x: Bogus = Bogus()) = ChannelType.E def size(x: Bogus = Bogus()) = UInt(log2Up(params.dataBits/8)) } diff --git a/uncore/src/main/scala/tilelink2/Edges.scala b/uncore/src/main/scala/tilelink2/Edges.scala index cd1a2449..0d178560 100644 --- a/uncore/src/main/scala/tilelink2/Edges.scala +++ b/uncore/src/main/scala/tilelink2/Edges.scala @@ -39,8 +39,47 @@ class TLEdge( Cat(helper(lgBytes).map(_._1).reverse) } + def staticHasData(bundle: HasTLOpcode): Option[Boolean] = { + bundle.channelType() match { + case ChannelType.A => { + // Do there exist A messages with Data? + val aDataYes = manager.anySupportArithmetic || manager.anySupportLogical || manager.anySupportPutFull || manager.anySupportPutPartial + // Do there exist A messages without Data? + val aDataNo = manager.anySupportAcquire || manager.anySupportGet || manager.anySupportHint + // Statically optimize the case where hasData is a constant + if (!aDataYes) Some(false) else if (!aDataNo) Some(true) else None + } + case ChannelType.B => { + // Do there exist B messages with Data? + val bDataYes = client.anySupportArithmetic || client.anySupportLogical || client.anySupportPutFull || client.anySupportPutPartial + // Do there exist B messages without Data? + val bDataNo = client.anySupportProbe || client.anySupportGet || client.anySupportHint + // Statically optimize the case where hasData is a constant + if (!bDataYes) Some(false) else if (!bDataNo) Some(true) else None + } + case ChannelType.C => { + // Do there eixst C messages with Data? + val cDataYes = client.anySupportGet || client.anySupportArithmetic || client.anySupportLogical || client.anySupportProbe + // Do there exist C messages without Data? + val cDataNo = client.anySupportPutFull || client.anySupportPutPartial || client.anySupportHint || client.anySupportProbe + if (!cDataYes) Some(false) else if (!cDataNo) Some(true) else None + } + case ChannelType.D => { + // Do there eixst D messages with Data? + val dDataYes = manager.anySupportGet || manager.anySupportArithmetic || manager.anySupportLogical || manager.anySupportAcquire + // Do there exist D messages without Data? + val dDataNo = manager.anySupportPutFull || manager.anySupportPutPartial || manager.anySupportHint || manager.anySupportAcquire + if (!dDataYes) Some(false) else if (!dDataNo) Some(true) else None + } + case ChannelType.E => Some(false) + } + } + + def hasData(bundle: HasTLOpcode): Bool = + staticHasData(bundle).map(Bool(_)).getOrElse(bundle.hasData()) + def numBeats(bundle: HasTLOpcode) = { - val hasData = bundle.hasData() + val hasData = this.hasData(bundle) val size = bundle.size() val cutoff = log2Ceil(manager.beatBytes) val small = size <= UInt(cutoff) From e034775bfac8c2d118264e0e7f45caa9c254f093 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 20:10:40 -0700 Subject: [PATCH 64/87] tilelink2: use the fancy new hasData functions --- .../src/main/scala/tilelink2/Fragmenter.scala | 18 ++--------------- .../src/main/scala/tilelink2/Narrower.scala | 20 ++++++++++++------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/uncore/src/main/scala/tilelink2/Fragmenter.scala b/uncore/src/main/scala/tilelink2/Fragmenter.scala index 5dd6f8f4..7d308ae3 100644 --- a/uncore/src/main/scala/tilelink2/Fragmenter.scala +++ b/uncore/src/main/scala/tilelink2/Fragmenter.scala @@ -134,15 +134,6 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val in = io.in(0) val out = io.out(0) - // Do there exist A messages with Data? (we don't count Arithmetic, because it is never fragmented) - val aDataYes = manager.anySupportLogical || manager.anySupportPutFull || manager.anySupportPutPartial - // Do there exist A messages without Data? - val aDataNo = manager.anySupportGet || manager.anySupportHint - // Do there eixst D messages with Data? - val dDataYes = manager.anySupportGet || manager.anySupportLogical - // Do there exist D messages without Data? - val dDataNo = manager.anySupportPutFull || manager.anySupportPutPartial || manager.anySupportHint - val counterBits = log2Up(maxSize/beatBytes) val maxDownSize = if (alwaysMin) minSize else manager.maxTransfer @@ -156,10 +147,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val dFirst = acknum === UInt(0) val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1) val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Ceil(maxDownSize)) - - // It is important to optimize this to a constant if we know certain operaitons - // will never exist. This allows synthesis to eliminate the Muxes. - val dHasData = if (!dDataYes) Bool(false) else if (!dDataNo) Bool(true) else out.d.bits.hasData() + val dHasData = node.edgesOut(0).hasData(out.d.bits) // calculate new acknum val acknum_fragment = dFragnum << log2Ceil(minSize/beatBytes) @@ -222,9 +210,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val aFrag = Mux(aOrig > limit, limit, aOrig) val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize)) val aFragOH1 = UIntToOH1(aFrag, log2Ceil(maxDownSize)) - - // Statically optimize the case where hasData is a constant - val aHasData = if (!aDataYes) Bool(false) else if (!aDataNo) Bool(true) else out.a.bits.hasData() + val aHasData = node.edgesIn(0).hasData(in.a.bits) val aMask = Mux(aHasData, UInt(0), aFragOH1) val gennum = RegInit(UInt(0, width = counterBits)) diff --git a/uncore/src/main/scala/tilelink2/Narrower.scala b/uncore/src/main/scala/tilelink2/Narrower.scala index 83a5b6ce..39e5c092 100644 --- a/uncore/src/main/scala/tilelink2/Narrower.scala +++ b/uncore/src/main/scala/tilelink2/Narrower.scala @@ -32,7 +32,7 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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() + val hasData = edge.hasData(in) // decoded_size = 1111 (for smallest), 0101, 0001 (for largest) val sizeOH1 = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) @@ -46,9 +46,12 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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)) + if (edge.staticHasData(in) == Some(false)) { + (Bool(true), UInt(0), UInt(0)) + } else { + val select = Cat(mask.reverse) & new_filter + (last, Mux1H(select, dataSlices), Mux1H(select, maskSlices)) + } } def merge(in: HasTLData, fire: Bool): (Bool, UInt) = { @@ -57,7 +60,7 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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 last = count === limit || !edge.hasData(in) 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)) @@ -69,8 +72,11 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule when (last) { count := UInt(0) } } - // !!! if never data - (last, Mux1H(limit, cases)) + if (edge.staticHasData(in) == Some(false)) { + (Bool(true), UInt(0)) + } else { + (last, Mux1H(limit, cases)) + } } val in = io.in(0) From 4746cf00ce8d2a1554e8d8d64e67d6b7b4074cfc Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 20:17:42 -0700 Subject: [PATCH 65/87] tilelink2: move files to new uncore directory --- .../main/scala => src/main/scala/uncore}/tilelink2/Buffer.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Bundles.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Edges.scala | 0 .../scala => src/main/scala/uncore}/tilelink2/Fragmenter.scala | 0 .../src/main/scala => src/main/scala/uncore}/tilelink2/GPIO.scala | 0 .../scala => src/main/scala/uncore}/tilelink2/HintHandler.scala | 0 .../scala => src/main/scala/uncore}/tilelink2/LazyModule.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Legacy.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Monitor.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Narrower.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/Nodes.scala | 0 .../scala => src/main/scala/uncore}/tilelink2/Parameters.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/RegField.scala | 0 .../scala => src/main/scala/uncore}/tilelink2/RegMapper.scala | 0 .../main/scala/uncore}/tilelink2/RegisterRouter.scala | 0 .../src/main/scala => src/main/scala/uncore}/tilelink2/SRAM.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/TLNodes.scala | 0 .../src/main/scala => src/main/scala/uncore}/tilelink2/Xbar.scala | 0 .../main/scala => src/main/scala/uncore}/tilelink2/package.scala | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Buffer.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Bundles.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Edges.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Fragmenter.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/GPIO.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/HintHandler.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/LazyModule.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Legacy.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Monitor.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Narrower.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Nodes.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Parameters.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/RegField.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/RegMapper.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/RegisterRouter.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/SRAM.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/TLNodes.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/Xbar.scala (100%) rename {uncore/src/main/scala => src/main/scala/uncore}/tilelink2/package.scala (100%) diff --git a/uncore/src/main/scala/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Buffer.scala rename to src/main/scala/uncore/tilelink2/Buffer.scala diff --git a/uncore/src/main/scala/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Bundles.scala rename to src/main/scala/uncore/tilelink2/Bundles.scala diff --git a/uncore/src/main/scala/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Edges.scala rename to src/main/scala/uncore/tilelink2/Edges.scala diff --git a/uncore/src/main/scala/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Fragmenter.scala rename to src/main/scala/uncore/tilelink2/Fragmenter.scala diff --git a/uncore/src/main/scala/tilelink2/GPIO.scala b/src/main/scala/uncore/tilelink2/GPIO.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/GPIO.scala rename to src/main/scala/uncore/tilelink2/GPIO.scala diff --git a/uncore/src/main/scala/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/HintHandler.scala rename to src/main/scala/uncore/tilelink2/HintHandler.scala diff --git a/uncore/src/main/scala/tilelink2/LazyModule.scala b/src/main/scala/uncore/tilelink2/LazyModule.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/LazyModule.scala rename to src/main/scala/uncore/tilelink2/LazyModule.scala diff --git a/uncore/src/main/scala/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Legacy.scala rename to src/main/scala/uncore/tilelink2/Legacy.scala diff --git a/uncore/src/main/scala/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Monitor.scala rename to src/main/scala/uncore/tilelink2/Monitor.scala diff --git a/uncore/src/main/scala/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Narrower.scala rename to src/main/scala/uncore/tilelink2/Narrower.scala diff --git a/uncore/src/main/scala/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Nodes.scala rename to src/main/scala/uncore/tilelink2/Nodes.scala diff --git a/uncore/src/main/scala/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Parameters.scala rename to src/main/scala/uncore/tilelink2/Parameters.scala diff --git a/uncore/src/main/scala/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/RegField.scala rename to src/main/scala/uncore/tilelink2/RegField.scala diff --git a/uncore/src/main/scala/tilelink2/RegMapper.scala b/src/main/scala/uncore/tilelink2/RegMapper.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/RegMapper.scala rename to src/main/scala/uncore/tilelink2/RegMapper.scala diff --git a/uncore/src/main/scala/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/RegisterRouter.scala rename to src/main/scala/uncore/tilelink2/RegisterRouter.scala diff --git a/uncore/src/main/scala/tilelink2/SRAM.scala b/src/main/scala/uncore/tilelink2/SRAM.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/SRAM.scala rename to src/main/scala/uncore/tilelink2/SRAM.scala diff --git a/uncore/src/main/scala/tilelink2/TLNodes.scala b/src/main/scala/uncore/tilelink2/TLNodes.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/TLNodes.scala rename to src/main/scala/uncore/tilelink2/TLNodes.scala diff --git a/uncore/src/main/scala/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/Xbar.scala rename to src/main/scala/uncore/tilelink2/Xbar.scala diff --git a/uncore/src/main/scala/tilelink2/package.scala b/src/main/scala/uncore/tilelink2/package.scala similarity index 100% rename from uncore/src/main/scala/tilelink2/package.scala rename to src/main/scala/uncore/tilelink2/package.scala From 6a378e79e381f39e17ffa619041de496ecb74d81 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 21:42:37 -0700 Subject: [PATCH 66/87] tilelink2: allow 0-stage backpressure in combinational regmap --- .../scala/uncore/tilelink2/RegField.scala | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala index b546cafc..2dded47e 100644 --- a/src/main/scala/uncore/tilelink2/RegField.scala +++ b/src/main/scala/uncore/tilelink2/RegField.scala @@ -10,14 +10,20 @@ object RegReadFn // (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt) // iready may combinationally depend on oready // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) - // effects must become visible only on the cycle after ovalid && oready + // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = new RegReadFn(false, x) - // (ofire: Bool) => (data: UInt) - // effects must become visible on the cycle after ofire - implicit def apply(x: Bool => UInt) = + // (ready: Bool) => (valid: Bool, data: UInt) + // valid must not combinationally depend on ready + // effects must become visible on the cycle after valid && ready + // ready is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) + // ... which is irrelevant if you can service the read immediately + // ... if irrevocable, you may start reading on rising ready and raise valid when done + // ... otherwise, use the more general in&out ready-valid method above + implicit def apply(x: Bool => (Bool, UInt)) = new RegReadFn(true, { case (_, oready) => - (Bool(true), Bool(true), x(oready)) + val (ovalid, data) = x(oready) + (Bool(true), ovalid, data) }) // read from a register implicit def apply(x: UInt) = @@ -37,15 +43,20 @@ object RegWriteFn // (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool) // iready may combinationally depend on both oready and data // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) - // effects must become visible only on the cycle after ovalid && oready + // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = new RegWriteFn(false, x) - // (ofire: Bool, data: UInt) => () - // effects must become visible on the cycle after ofire - implicit def apply(x: (Bool, UInt) => Unit) = + // (valid: Bool, data: UInt) => (ready: Bool) + // ready may combinationally depend on data (but not valid) + // effects must become visible on the cycle after valid && ready + // valid is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) + // ... which is irrelevant if you can service the write immediately + // ... if irrevocable, you may start writing on rising valid and raise ready when done + // ... otherwise, use the more general in&out ready-valid method above + implicit def apply(x: (Bool, UInt) => Bool) = + // combinational => data valid on oready new RegWriteFn(true, { case (_, oready, data) => - x(oready, data) - (Bool(true), Bool(true)) + (Bool(true), x(oready, data)) }) // updates a register implicit def apply(x: UInt) = From 81162a2dc9d09e6e4c9d1d313fc292a968e79660 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 22:34:51 -0700 Subject: [PATCH 67/87] tilelink2: support attaching a DecoupledIO directly to a register --- .../scala/uncore/tilelink2/RegField.scala | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala index 2dded47e..af50717a 100644 --- a/src/main/scala/uncore/tilelink2/RegField.scala +++ b/src/main/scala/uncore/tilelink2/RegField.scala @@ -25,16 +25,12 @@ object RegReadFn val (ovalid, data) = x(oready) (Bool(true), ovalid, data) }) + // read from a DecoupledIO (only safe if there is a consistent source of data) + implicit def apply(x: DecoupledIO[UInt]):RegReadFn = RegReadFn(ready => { x.ready := ready; (x.valid, x.bits) }) // read from a register - implicit def apply(x: UInt) = - new RegReadFn(true, { case (_, _) => - (Bool(true), Bool(true), x) - }) + implicit def apply(x: UInt):RegReadFn = RegReadFn(ready => (Bool(true), x)) // noop - implicit def apply(x: Unit) = - new RegReadFn(true, { case (_, _) => - (Bool(true), Bool(true), UInt(0)) - }) + implicit def apply(x: Unit):RegReadFn = RegReadFn(UInt(0)) } case class RegWriteFn private(combinational: Boolean, fn: (Bool, Bool, UInt) => (Bool, Bool)) @@ -58,17 +54,12 @@ object RegWriteFn new RegWriteFn(true, { case (_, oready, data) => (Bool(true), x(oready, data)) }) + // write to a DecoupledIO (only safe if there is a consistent sink draining data) + implicit def apply(x: DecoupledIO[UInt]): RegWriteFn = RegWriteFn((valid, data) => { x.valid := valid; x.bits := data; x.ready }) // updates a register - implicit def apply(x: UInt) = - new RegWriteFn(true, { case (_, oready, data) => - when (oready) { x := data } - (Bool(true), Bool(true)) - }) + implicit def apply(x: UInt): RegWriteFn = RegWriteFn((valid, data) => { when (valid) { x := data }; Bool(true) }) // noop - implicit def apply(x: Unit) = - new RegWriteFn(true, { case (_, _, _) => - (Bool(true), Bool(true)) - }) + implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) }) } case class RegField(width: Int, read: RegReadFn, write: RegWriteFn) From a1fc01fd6d9589e710f58a4eda44f1a05d017cf4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 22:41:42 -0700 Subject: [PATCH 68/87] tilelink2: prevent mapping the same register twice --- src/main/scala/uncore/tilelink2/RegMapper.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/uncore/tilelink2/RegMapper.scala b/src/main/scala/uncore/tilelink2/RegMapper.scala index c6b517b5..d3f7a559 100644 --- a/src/main/scala/uncore/tilelink2/RegMapper.scala +++ b/src/main/scala/uncore/tilelink2/RegMapper.scala @@ -31,6 +31,11 @@ object RegMapper val regmap = mapping.toList require (!regmap.isEmpty) + // Ensure no register appears twice + regmap.combinations(2).foreach { case Seq((reg1, _), (reg2, _)) => + require (reg1 != reg2) + } + // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField) val flat = regmap.map { case (reg, fields) => val offsets = fields.scanLeft(0)(_ + _.width).init From 834307063943ae5398ce8ecf63c3979aa379fa57 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 22:48:00 -0700 Subject: [PATCH 69/87] tilelink2: detect 1-bit overflow in register definitions --- src/main/scala/uncore/tilelink2/RegMapper.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/RegMapper.scala b/src/main/scala/uncore/tilelink2/RegMapper.scala index d3f7a559..033d507b 100644 --- a/src/main/scala/uncore/tilelink2/RegMapper.scala +++ b/src/main/scala/uncore/tilelink2/RegMapper.scala @@ -85,7 +85,7 @@ object RegMapper val (reg, low, field) = flat(i) val high = low + field.width - 1 // Confirm that no register is too big - require (high <= 8*bytes) + require (high < 8*bytes) val rimask = frontMask(high, low).orR() val wimask = frontMask(high, low).andR() val romask = backMask(high, low).orR() From e3b35438419e4a5ce76d72422d80935009bea1e9 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 23:01:15 -0700 Subject: [PATCH 70/87] tilelink2: ensure RegFields don't exceed their bounds --- src/main/scala/uncore/tilelink2/RegMapper.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegMapper.scala b/src/main/scala/uncore/tilelink2/RegMapper.scala index 033d507b..f7e34e5d 100644 --- a/src/main/scala/uncore/tilelink2/RegMapper.scala +++ b/src/main/scala/uncore/tilelink2/RegMapper.scala @@ -92,7 +92,7 @@ object RegMapper val womask = backMask(high, low).andR() val data = if (field.write.combinational) back.bits.data else front.bits.data val (f_riready, f_rovalid, f_data) = field.read.fn(rivalid(i) && rimask, roready(i) && romask) - val (f_wiready, f_wovalid) = field.write.fn(wivalid(i) && wimask, woready(i) && womask, data) + val (f_wiready, f_wovalid) = field.write.fn(wivalid(i) && wimask, woready(i) && womask, data(high, low)) riready(i) := f_riready || !rimask wiready(i) := f_wiready || !wimask rovalid(i) := f_rovalid || !romask @@ -101,7 +101,7 @@ object RegMapper wifire(reg) = wiready(i) +: wifire(reg) rofire(reg) = rovalid(i) +: rofire(reg) wofire(reg) = wovalid(i) +: wofire(reg) - dataOut(reg) = dataOut(reg) | (f_data << low) + dataOut(reg) = dataOut(reg) | ((f_data << low) & (~UInt(0, width = high+1))) } // Is the selected register ready? From 68e64a9859b364623bf9531105d59f93a1a91e7f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 16:17:20 -0700 Subject: [PATCH 71/87] tilelink2: clarify ready-valid use of RegisterRouter --- src/main/scala/uncore/tilelink2/RegField.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala index af50717a..444a3c62 100644 --- a/src/main/scala/uncore/tilelink2/RegField.scala +++ b/src/main/scala/uncore/tilelink2/RegField.scala @@ -10,16 +10,17 @@ object RegReadFn // (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt) // iready may combinationally depend on oready // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) + // iready must eventually go high without requiring ivalid to go high + // ovalid must eventually go high without requiring oready to go high // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = new RegReadFn(false, x) // (ready: Bool) => (valid: Bool, data: UInt) // valid must not combinationally depend on ready + // valid must eventually go high without requiring ready to go high + // => this means that reading cannot trigger creation of the output data + // if you need this, use the more general i&o ready-valid method above // effects must become visible on the cycle after valid && ready - // ready is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) - // ... which is irrelevant if you can service the read immediately - // ... if irrevocable, you may start reading on rising ready and raise valid when done - // ... otherwise, use the more general in&out ready-valid method above implicit def apply(x: Bool => (Bool, UInt)) = new RegReadFn(true, { case (_, oready) => val (ovalid, data) = x(oready) @@ -39,16 +40,15 @@ object RegWriteFn // (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool) // iready may combinationally depend on both oready and data // all other combinational dependencies forbidden (e.g. ovalid <= ivalid) + // iready must eventually go high without requiring ivalid to go high + // ovalid must eventually go high without requiring oready to go high // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = new RegWriteFn(false, x) // (valid: Bool, data: UInt) => (ready: Bool) // ready may combinationally depend on data (but not valid) + // ready must eventually go high without requiring valid to go high // effects must become visible on the cycle after valid && ready - // valid is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) - // ... which is irrelevant if you can service the write immediately - // ... if irrevocable, you may start writing on rising valid and raise ready when done - // ... otherwise, use the more general in&out ready-valid method above implicit def apply(x: (Bool, UInt) => Bool) = // combinational => data valid on oready new RegWriteFn(true, { case (_, oready, data) => From cb54df0a8a56d2702c01c63b7803025b41490130 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 16:47:18 -0700 Subject: [PATCH 72/87] tilelink2: tie off unused channels --- src/main/scala/uncore/tilelink2/Buffer.scala | 7 +++++++ src/main/scala/uncore/tilelink2/Fragmenter.scala | 8 ++++++++ src/main/scala/uncore/tilelink2/HintHandler.scala | 8 ++++++++ src/main/scala/uncore/tilelink2/Legacy.scala | 5 +++++ src/main/scala/uncore/tilelink2/Narrower.scala | 7 +++++++ src/main/scala/uncore/tilelink2/RegisterRouter.scala | 5 +++++ src/main/scala/uncore/tilelink2/SRAM.scala | 5 +++++ 7 files changed, 45 insertions(+) diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index c35a395f..3c9c8456 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -25,6 +25,13 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule in .b <> Queue(out.b, entries, pipe) out.c <> Queue(in .c, entries, pipe) out.e <> Queue(out.e, entries, pipe) + } else { + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) } } } diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 7d308ae3..c719b875 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -227,6 +227,14 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten out.a.bits := in.a.bits out.a.bits.source := Cat(in.a.bits.source, aFragnum) out.a.bits.size := aFrag + + // Tie off unused channels + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) } } diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index edca9f20..ed1c12be 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -68,6 +68,11 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.c.valid := in.c.valid in.c.ready := out.c.ready out.c.bits := in.c.bits + } else { + in.b.valid := Bool(false) + in.c.ready := Bool(true) + out.b.ready := Bool(true) + out.c.valid := Bool(false) } if (bce) { @@ -75,6 +80,9 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.e.valid := in.e.valid in.e.ready := out.e.ready out.e.bits := in.e.bits + } else { + in.e.ready := Bool(true) + out.e.valid := Bool(false) } } } diff --git a/src/main/scala/uncore/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala index c66f48c6..e4b8b2b2 100644 --- a/src/main/scala/uncore/tilelink2/Legacy.scala +++ b/src/main/scala/uncore/tilelink2/Legacy.scala @@ -103,5 +103,10 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa grant.manager_xact_id := out.d.bits.sink grant.data := out.d.bits.data grant.addr_beat := beatCounter + + // Tie off unused channels + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) } } diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 39e5c092..169dd727 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -108,6 +108,13 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule in.e.ready := out.e.ready out.e.valid := in.e.valid out.e.bits := in.e.bits + } else { + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) } } } diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index 17c473ad..e39788e4 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -46,6 +46,11 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB // avoid a Mux on the data bus by manually overriding two fields d.bits.data := out.bits.data d.bits.opcode := Mux(out.bits.read, TLMessages.AccessAckData, TLMessages.AccessAck) + + // Tie off unused channels + bundleIn(0).b.valid := Bool(false) + bundleIn(0).c.ready := Bool(true) + bundleIn(0).e.ready := Bool(true) } } diff --git a/src/main/scala/uncore/tilelink2/SRAM.scala b/src/main/scala/uncore/tilelink2/SRAM.scala index b20c6922..28639223 100644 --- a/src/main/scala/uncore/tilelink2/SRAM.scala +++ b/src/main/scala/uncore/tilelink2/SRAM.scala @@ -62,5 +62,10 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule 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) } } From 1a081b4dd59c51323150daf2093382169ae4ae2b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 16:54:16 -0700 Subject: [PATCH 73/87] tilelink2: Monitor should report which TL connection was the problem --- src/main/scala/uncore/tilelink2/Monitor.scala | 305 +++++++++--------- 1 file changed, 156 insertions(+), 149 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 71e2f933..97132d97 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -3,12 +3,19 @@ package uncore.tilelink2 import Chisel._ -import chisel3.internal.sourceinfo.SourceInfo +import chisel3.internal.sourceinfo.{SourceInfo, SourceLine} object TLMonitor { + def extra(implicit sourceInfo: SourceInfo) = { + sourceInfo match { + case SourceLine(filename, line, col) => s" (connected at $filename:$line:$col)" + case _ => "" + } + } + def legalizeFormatA(bundle: TLBundleA, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { - assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode") + assert (TLMessages.isA(bundle.opcode), "'A' channel has invalid opcode" + extra) // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) @@ -16,65 +23,65 @@ object TLMonitor val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Acquire) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager") - assert (source_ok, "'A' channel Acquire carries invalid source ID") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat") - assert (is_aligned, "'A' channel Acquire address not aligned to size") - assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param") - assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask") + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) + assert (source_ok, "'A' channel Acquire carries invalid source ID" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat" + extra) + assert (is_aligned, "'A' channel Acquire address not aligned to size" + extra) + assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param" + extra) + assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Get) { - assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager") - assert (source_ok, "'A' channel Get carries invalid source ID") - assert (is_aligned, "'A' channel Get address not aligned to size") - assert (bundle.param === UInt(0), "'A' channel Get carries invalid param") - assert (bundle.mask === mask, "'A' channel Get contains invalid mask") + assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager" + extra) + assert (source_ok, "'A' channel Get carries invalid source ID" + extra) + assert (is_aligned, "'A' channel Get address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'A' channel Get carries invalid param" + extra) + assert (bundle.mask === mask, "'A' channel Get contains invalid mask" + extra) } when (bundle.opcode === TLMessages.PutFullData) { - assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager") - assert (source_ok, "'A' channel PutFull carries invalid source ID") - assert (is_aligned, "'A' channel PutFull address not aligned to size") - assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param") - assert (bundle.mask === mask, "'A' channel PutFull contains invalid mask") + assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager" + extra) + assert (source_ok, "'A' channel PutFull carries invalid source ID" + extra) + assert (is_aligned, "'A' channel PutFull address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param" + extra) + assert (bundle.mask === mask, "'A' channel PutFull contains invalid mask" + extra) } when (bundle.opcode === TLMessages.PutPartialData) { - assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager") - assert (source_ok, "'A' channel PutPartial carries invalid source ID") - 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") + assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager" + extra) + assert (source_ok, "'A' channel PutPartial carries invalid source ID" + extra) + assert (is_aligned, "'A' channel PutPartial address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra) + assert ((bundle.mask & ~mask) === UInt(0), "'A' channel PutPartial contains invalid mask" + extra) + assert (bundle.mask =/= UInt(0), "'A' channel PutPartial has a zero mask" + extra) } when (bundle.opcode === TLMessages.ArithmeticData) { - assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager") - assert (source_ok, "'A' channel Arithmetic carries invalid source ID") - assert (is_aligned, "'A' channel Arithmetic address not aligned to size") - assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param") - assert (bundle.mask === mask, "'A' channel Arithmetic contains invalid mask") + assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager" + extra) + assert (source_ok, "'A' channel Arithmetic carries invalid source ID" + extra) + assert (is_aligned, "'A' channel Arithmetic address not aligned to size" + extra) + assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param" + extra) + assert (bundle.mask === mask, "'A' channel Arithmetic contains invalid mask" + extra) } when (bundle.opcode === TLMessages.LogicalData) { - assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager") - assert (source_ok, "'A' channel Logical carries invalid source ID") - assert (is_aligned, "'A' channel Logical address not aligned to size") - assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param") - assert (bundle.mask === mask, "'A' channel Logical contains invalid mask") + assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager" + extra) + assert (source_ok, "'A' channel Logical carries invalid source ID" + extra) + assert (is_aligned, "'A' channel Logical address not aligned to size" + extra) + assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param" + extra) + assert (bundle.mask === mask, "'A' channel Logical contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Hint) { - assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager") - assert (source_ok, "'A' channel Hint carries invalid source ID") - assert (is_aligned, "'A' channel Hint address not aligned to size") - assert (bundle.mask === mask, "'A' channel Hint contains invalid mask") + assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager" + extra) + assert (source_ok, "'A' channel Hint carries invalid source ID" + extra) + assert (is_aligned, "'A' channel Hint address not aligned to size" + extra) + assert (bundle.mask === mask, "'A' channel Hint contains invalid mask" + extra) } } def legalizeFormatB(bundle: TLBundleB, edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { - assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode") + assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode" + extra) // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) @@ -82,182 +89,182 @@ object TLMonitor val mask = edge.fullMask(bundle.address, bundle.size) when (bundle.opcode === TLMessages.Probe) { - assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client") - assert (address_ok, "'B' channel Probe carries unmanaged address") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat") - assert (is_aligned, "'B' channel Probe address not aligned to size") - assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param") - assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask") + assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client" + extra) + assert (address_ok, "'B' channel Probe carries unmanaged address" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat" + extra) + assert (is_aligned, "'B' channel Probe address not aligned to size" + extra) + assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param" + extra) + assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Get) { - assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client") - assert (address_ok, "'B' channel Get carries unmanaged address") - assert (is_aligned, "'B' channel Get address not aligned to size") - assert (bundle.param === UInt(0), "'B' channel Get carries invalid param") - assert (bundle.mask === mask, "'A' channel Get contains invalid mask") + assert (edge.client.supportsGet(bundle.source, bundle.size), "'B' channel carries Get type unsupported by client" + extra) + assert (address_ok, "'B' channel Get carries unmanaged address" + extra) + assert (is_aligned, "'B' channel Get address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'B' channel Get carries invalid param" + extra) + assert (bundle.mask === mask, "'A' channel Get contains invalid mask" + extra) } when (bundle.opcode === TLMessages.PutFullData) { - assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client") - assert (address_ok, "'B' channel PutFull carries unmanaged address") - assert (is_aligned, "'B' channel PutFull address not aligned to size") - assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param") - assert (bundle.mask === mask, "'B' channel PutFull contains invalid mask") + assert (edge.client.supportsPutFull(bundle.source, bundle.size), "'B' channel carries PutFull type unsupported by client" + extra) + assert (address_ok, "'B' channel PutFull carries unmanaged address" + extra) + assert (is_aligned, "'B' channel PutFull address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'B' channel PutFull carries invalid param" + extra) + assert (bundle.mask === mask, "'B' channel PutFull contains invalid mask" + extra) } when (bundle.opcode === TLMessages.PutPartialData) { - assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client") - assert (address_ok, "'B' channel PutPartial carries unmanaged address") - 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") + assert (edge.client.supportsPutPartial(bundle.source, bundle.size), "'B' channel carries PutPartial type unsupported by client" + extra) + assert (address_ok, "'B' channel PutPartial carries unmanaged address" + extra) + assert (is_aligned, "'B' channel PutPartial address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'B' channel PutPartial carries invalid param" + extra) + assert ((bundle.mask & ~mask) === UInt(0), "'B' channel PutPartial contains invalid mask" + extra) + assert (bundle.mask =/= UInt(0), "'B' channel PutPartial has a zero mask" + extra) } when (bundle.opcode === TLMessages.ArithmeticData) { - assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client") - assert (address_ok, "'B' channel Arithmetic carries unmanaged address") - assert (is_aligned, "'B' channel Arithmetic address not aligned to size") - assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param") - assert (bundle.mask === mask, "'B' channel Arithmetic contains invalid mask") + assert (edge.client.supportsArithmetic(bundle.source, bundle.size), "'B' channel carries Arithmetic type unsupported by client" + extra) + assert (address_ok, "'B' channel Arithmetic carries unmanaged address" + extra) + assert (is_aligned, "'B' channel Arithmetic address not aligned to size" + extra) + assert (TLAtomics.isArithmetic(bundle.param), "'B' channel Arithmetic carries invalid opcode param" + extra) + assert (bundle.mask === mask, "'B' channel Arithmetic contains invalid mask" + extra) } when (bundle.opcode === TLMessages.LogicalData) { - assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client") - assert (address_ok, "'B' channel Logical carries unmanaged address") - assert (is_aligned, "'B' channel Logical address not aligned to size") - assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param") - assert (bundle.mask === mask, "'B' channel Logical contains invalid mask") + assert (edge.client.supportsLogical(bundle.source, bundle.size), "'B' channel carries Logical type unsupported by client" + extra) + assert (address_ok, "'B' channel Logical carries unmanaged address" + extra) + assert (is_aligned, "'B' channel Logical address not aligned to size" + extra) + assert (TLAtomics.isLogical(bundle.param), "'B' channel Logical carries invalid opcode param" + extra) + assert (bundle.mask === mask, "'B' channel Logical contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Hint) { - assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client") - assert (address_ok, "'B' channel Hint carries unmanaged address") - assert (is_aligned, "'B' channel Hint address not aligned to size") - assert (bundle.mask === mask, "'B' channel Hint contains invalid mask") + assert (edge.client.supportsHint(bundle.source), "'B' channel carries Hint type unsupported by client" + extra) + assert (address_ok, "'B' channel Hint carries unmanaged address" + extra) + assert (is_aligned, "'B' channel Hint address not aligned to size" + extra) + assert (bundle.mask === mask, "'B' channel Hint contains invalid mask" + extra) } } def legalizeFormatC(bundle: TLBundleC, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { - assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode") + assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode" + extra) val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) val address_ok = edge.manager.contains(bundle.source) when (bundle.opcode === TLMessages.ProbeAck) { - assert (address_ok, "'C' channel ProbeAck carries unmanaged address") + assert (address_ok, "'C' channel ProbeAck carries unmanaged address" + extra) // source is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat") - assert (is_aligned, "'C' channel ProbeAck address not aligned to size") - assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param") - assert (!bundle.error, "'C' channel Probe carries an error") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat" + extra) + assert (is_aligned, "'C' channel ProbeAck address not aligned to size" + extra) + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param" + extra) + assert (!bundle.error, "'C' channel Probe carries an error" + extra) } when (bundle.opcode === TLMessages.ProbeAckData) { - assert (address_ok, "'C' channel ProbeAckData carries unmanaged address") + assert (address_ok, "'C' channel ProbeAckData carries unmanaged address" + extra) // source is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat") - assert (is_aligned, "'C' channel ProbeAckData address not aligned to size") - assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param") - assert (!bundle.error, "'C' channel ProbeData carries an error") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat" + extra) + assert (is_aligned, "'C' channel ProbeAckData address not aligned to size" + extra) + assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param" + extra) + assert (!bundle.error, "'C' channel ProbeData carries an error" + extra) } when (bundle.opcode === TLMessages.Release) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager") - assert (source_ok, "'C' channel Release carries invalid source ID") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat") - assert (is_aligned, "'C' channel Release address not aligned to size") - assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param") - assert (!bundle.error, "'C' channel Release carries an error") + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager" + extra) + assert (source_ok, "'C' channel Release carries invalid source ID" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat" + extra) + assert (is_aligned, "'C' channel Release address not aligned to size" + extra) + assert (TLPermissions.isShrink(bundle.param), "'C' channel Release carries invalid shrink param" + extra) + assert (!bundle.error, "'C' channel Release carries an error" + extra) } when (bundle.opcode === TLMessages.ReleaseData) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager") - assert (source_ok, "'C' channel ReleaseData carries invalid source ID") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat") - assert (is_aligned, "'C' channel ReleaseData address not aligned to size") - assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param") - assert (!bundle.error, "'C' channel ReleaseData carries an error") + assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager" + extra) + assert (source_ok, "'C' channel ReleaseData carries invalid source ID" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat" + extra) + assert (is_aligned, "'C' channel ReleaseData address not aligned to size" + extra) + assert (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param" + extra) + assert (!bundle.error, "'C' channel ReleaseData carries an error" + extra) } when (bundle.opcode === TLMessages.AccessAck) { - assert (address_ok, "'C' channel AccessAck carries unmanaged address") + assert (address_ok, "'C' channel AccessAck carries unmanaged address" + extra) // source is ignored - assert (is_aligned, "'C' channel AccessAck address not aligned to size") - assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param") + assert (is_aligned, "'C' channel AccessAck address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param" + extra) } when (bundle.opcode === TLMessages.AccessAckData) { - assert (address_ok, "'C' channel AccessAckData carries unmanaged address") + assert (address_ok, "'C' channel AccessAckData carries unmanaged address" + extra) // source is ignored - assert (is_aligned, "'C' channel AccessAckData address not aligned to size") - assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param") + assert (is_aligned, "'C' channel AccessAckData address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param" + extra) } when (bundle.opcode === TLMessages.HintAck) { - assert (address_ok, "'C' channel HintAck carries unmanaged address") + assert (address_ok, "'C' channel HintAck carries unmanaged address" + extra) // source is ignored - assert (is_aligned, "'C' channel HintAck address not aligned to size") - assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param") - assert (!bundle.error, "'C' channel HintAck carries an error") + assert (is_aligned, "'C' channel HintAck address not aligned to size" + extra) + assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param" + extra) + assert (!bundle.error, "'C' channel HintAck carries an error" + extra) } } def legalizeFormatD(bundle: TLBundleD, edge: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { - assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode") + assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode" + extra) val source_ok = edge.client.contains(bundle.source) val sink_ok = edge.manager.containsById(bundle.sink) when (bundle.opcode === TLMessages.ReleaseAck) { - assert (source_ok, "'D' channel ReleaseAck carries invalid source ID") + assert (source_ok, "'D' channel ReleaseAck carries invalid source ID" + extra) // sink is ignored - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat") - assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param") - assert (!bundle.error, "'D' channel ReleaseAck carries an error") + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat" + extra) + assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param" + extra) + assert (!bundle.error, "'D' channel ReleaseAck carries an error" + extra) } when (bundle.opcode === TLMessages.Grant) { - assert (source_ok, "'D' channel Grant carries invalid source ID") - assert (sink_ok, "'D' channel Grant carries invalid sink ID") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat") - assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param") + assert (source_ok, "'D' channel Grant carries invalid source ID" + extra) + assert (sink_ok, "'D' channel Grant carries invalid sink ID" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat" + extra) + assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param" + extra) } when (bundle.opcode === TLMessages.GrantData) { - assert (source_ok, "'D' channel GrantData carries invalid source ID") - assert (sink_ok, "'D' channel GrantData carries invalid sink ID") - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat") - assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param") + assert (source_ok, "'D' channel GrantData carries invalid source ID" + extra) + assert (sink_ok, "'D' channel GrantData carries invalid sink ID" + extra) + assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat" + extra) + assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param" + extra) } when (bundle.opcode === TLMessages.AccessAck) { - assert (source_ok, "'D' channel AccessAck carries invalid source ID") + assert (source_ok, "'D' channel AccessAck carries invalid source ID" + extra) // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param") + assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param" + extra) } when (bundle.opcode === TLMessages.AccessAckData) { - assert (source_ok, "'D' channel AccessAckData carries invalid source ID") + assert (source_ok, "'D' channel AccessAckData carries invalid source ID" + extra) // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param") + assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param" + extra) } when (bundle.opcode === TLMessages.HintAck) { - assert (source_ok, "'D' channel HintAck carries invalid source ID") + assert (source_ok, "'D' channel HintAck carries invalid source ID" + extra) // sink is ignored // size is ignored - assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param") - assert (!bundle.error, "'D' channel HintAck carries an error") + assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param" + extra) + assert (!bundle.error, "'D' channel HintAck carries an error" + extra) } } def legalizeFormatE(bundle: TLBundleE, edge: TLEdgeOut)(implicit sourceInfo: SourceInfo) = { - assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID") + assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID" + extra) } def legalizeFormat(bundleOut: TLBundle, edgeOut: TLEdgeOut, bundleIn: TLBundle, edgeIn: TLEdgeIn)(implicit sourceInfo: SourceInfo) = { @@ -276,11 +283,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (a.valid && counter =/= UInt(0)) { - assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation") - assert (a.bits.param === param, "'A' channel param changed within multibeat operation") - assert (a.bits.size === size, "'A' channel size changed within multibeat operation") - assert (a.bits.source === source, "'A' channel source changed within multibeat operation") - assert (a.bits.address=== address,"'A' channel address changed with multibeat operation") + assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation" + extra) + assert (a.bits.param === param, "'A' channel param changed within multibeat operation" + extra) + assert (a.bits.size === size, "'A' channel size changed within multibeat operation" + extra) + assert (a.bits.source === source, "'A' channel source changed within multibeat operation" + extra) + assert (a.bits.address=== address,"'A' channel address changed with multibeat operation" + extra) } when (a.fire()) { counter := counter - UInt(1) @@ -303,11 +310,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (b.valid && counter =/= UInt(0)) { - assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation") - assert (b.bits.param === param, "'B' channel param changed within multibeat operation") - assert (b.bits.size === size, "'B' channel size changed within multibeat operation") - assert (b.bits.source === source, "'B' channel source changed within multibeat operation") - assert (b.bits.address=== address,"'B' channel address changed with multibeat operation") + assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation" + extra) + assert (b.bits.param === param, "'B' channel param changed within multibeat operation" + extra) + assert (b.bits.size === size, "'B' channel size changed within multibeat operation" + extra) + assert (b.bits.source === source, "'B' channel source changed within multibeat operation" + extra) + assert (b.bits.address=== address,"'B' channel address changed with multibeat operation" + extra) } when (b.fire()) { counter := counter - UInt(1) @@ -330,11 +337,11 @@ object TLMonitor val source = Reg(UInt()) val address = Reg(UInt()) when (c.valid && counter =/= UInt(0)) { - assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation") - assert (c.bits.param === param, "'C' channel param changed within multibeat operation") - assert (c.bits.size === size, "'C' channel size changed within multibeat operation") - assert (c.bits.source === source, "'C' channel source changed within multibeat operation") - assert (c.bits.address=== address,"'C' channel address changed with multibeat operation") + assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation" + extra) + assert (c.bits.param === param, "'C' channel param changed within multibeat operation" + extra) + assert (c.bits.size === size, "'C' channel size changed within multibeat operation" + extra) + assert (c.bits.source === source, "'C' channel source changed within multibeat operation" + extra) + assert (c.bits.address=== address,"'C' channel address changed with multibeat operation" + extra) } when (c.fire()) { counter := counter - UInt(1) @@ -357,11 +364,11 @@ object TLMonitor val source = Reg(UInt()) val sink = Reg(UInt()) when (d.valid && counter =/= UInt(0)) { - assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation") - assert (d.bits.param === param, "'D' channel param changed within multibeat operation") - assert (d.bits.size === size, "'D' channel size changed within multibeat operation") - assert (d.bits.source === source, "'D' channel source changed within multibeat operation") - assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation") + assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation" + extra) + assert (d.bits.param === param, "'D' channel param changed within multibeat operation" + extra) + assert (d.bits.size === size, "'D' channel size changed within multibeat operation" + extra) + assert (d.bits.source === source, "'D' channel source changed within multibeat operation" + extra) + assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation" + extra) } when (d.fire()) { counter := counter - UInt(1) From fb262558eefbc6f43d7d46e42f7253f425b3efc6 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 17:03:10 -0700 Subject: [PATCH 74/87] tilelink2: helper objects should pass source line from where they were invoked --- src/main/scala/uncore/tilelink2/Buffer.scala | 3 ++- src/main/scala/uncore/tilelink2/Fragmenter.scala | 3 ++- src/main/scala/uncore/tilelink2/HintHandler.scala | 3 ++- src/main/scala/uncore/tilelink2/Narrower.scala | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index 3c9c8456..26392d2b 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -3,6 +3,7 @@ package uncore.tilelink2 import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule { @@ -39,7 +40,7 @@ class TLBuffer(entries: Int = 2, pipe: Boolean = false) extends LazyModule object TLBuffer { // applied to the TL source node; connect (TLBuffer(x.node) -> y.node) - def apply(x: TLBaseNode, entries: Int = 2, pipe: Boolean = false)(implicit lazyModule: LazyModule): TLBaseNode = { + def apply(x: TLBaseNode, entries: Int = 2, pipe: Boolean = false)(implicit lazyModule: LazyModule, sourceInfo: SourceInfo): TLBaseNode = { val buffer = LazyModule(new TLBuffer(entries, pipe)) lazyModule.connect(x -> buffer.node) buffer.node diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index c719b875..94fdda7d 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -3,6 +3,7 @@ package uncore.tilelink2 import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo import scala.math.{min,max} // minSize: minimum size of transfers supported by all outward managers @@ -241,7 +242,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten object TLFragmenter { // applied to the TL source node; connect (TLFragmenter(x.node, 256, 4) -> y.node) - def apply(x: TLBaseNode, minSize: Int, maxSize: Int, alwaysMin: Boolean = false)(implicit lazyModule: LazyModule): TLBaseNode = { + def apply(x: TLBaseNode, minSize: Int, maxSize: Int, alwaysMin: Boolean = false)(implicit lazyModule: LazyModule, sourceInfo: SourceInfo): TLBaseNode = { val fragmenter = LazyModule(new TLFragmenter(minSize, maxSize, alwaysMin)) lazyModule.connect(x -> fragmenter.node) fragmenter.node diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index ed1c12be..1ae934d0 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -3,6 +3,7 @@ package uncore.tilelink2 import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo // Acks Hints for managers that don't support them or Acks all Hints if !passthrough class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule @@ -90,7 +91,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f object TLHintHandler { // applied to the TL source node; connect (TLHintHandler(x.node) -> y.node) - def apply(x: TLBaseNode, supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit lazyModule: LazyModule): TLBaseNode = { + def apply(x: TLBaseNode, supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit lazyModule: LazyModule, sourceInfo: SourceInfo): TLBaseNode = { val hints = LazyModule(new TLHintHandler(supportManagers, supportClients, passthrough)) lazyModule.connect(x -> hints.node) hints.node diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 169dd727..7d705753 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -3,6 +3,7 @@ package uncore.tilelink2 import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo // innBeatBytes => the bus width after the adapter class TLNarrower(innerBeatBytes: Int) extends LazyModule @@ -122,7 +123,7 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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 = { + def apply(x: TLBaseNode, innerBeatBytes: Int)(implicit lazyModule: LazyModule, sourceInfo: SourceInfo): TLBaseNode = { val narrower = LazyModule(new TLNarrower(innerBeatBytes)) lazyModule.connect(x -> narrower.node) narrower.node From df32cc388726fbdaf17b99a84c01171c5f12e6c9 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 17:48:45 -0700 Subject: [PATCH 75/87] tilelink2: be careful; apply Andrew's masking trick everywhere --- src/main/scala/uncore/tilelink2/Legacy.scala | 2 +- src/main/scala/uncore/tilelink2/Parameters.scala | 8 ++++---- src/main/scala/uncore/tilelink2/TLNodes.scala | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala index e4b8b2b2..ed051ae6 100644 --- a/src/main/scala/uncore/tilelink2/Legacy.scala +++ b/src/main/scala/uncore/tilelink2/Legacy.scala @@ -82,7 +82,7 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa // Get rid of some unneeded muxes out.a.bits.source := source out.a.bits.data := data - out.a.bits.address := address & ~addressMask + out.a.bits.address := ~(~address | addressMask) // TL legacy does not support bus errors assert (!out.d.bits.error) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 26e799ec..138ff9a5 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -33,8 +33,8 @@ case class IdRange(start: Int, end: Int) def contains(x: Int) = start <= x && x < end def contains(x: UInt) = if (start+1 == end) { UInt(start) === x } - else if (((end-1) & ~start) == end-start-1) - { ((UInt(start) ^ x) & ~UInt(end-start-1)) === UInt(0) } + else if (isPow2(end-start) && ((end | start) & (end-start-1)) == 0) + { ~(~(UInt(start) ^ x) | UInt(end-start-1)) === UInt(0) } else { UInt(start) <= x && x < UInt(end) } def shift(x: Int) = IdRange(start+x, end+x) @@ -84,8 +84,8 @@ case class AddressSet(base: BigInt, mask: BigInt) // Forbid misaligned base address (and empty sets) require ((base & mask) == 0) - def contains(x: BigInt) = ((x ^ base) & ~mask) == 0 - def contains(x: UInt) = ((x ^ UInt(base)) & ~UInt(mask)) === UInt(0) + def contains(x: BigInt) = ~(~(x ^ base) | mask) == 0 + def contains(x: UInt) = ~(~(x ^ UInt(base)) | UInt(mask)) === UInt(0) // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0 diff --git a/src/main/scala/uncore/tilelink2/TLNodes.scala b/src/main/scala/uncore/tilelink2/TLNodes.scala index 05353cdc..f9685a0a 100644 --- a/src/main/scala/uncore/tilelink2/TLNodes.scala +++ b/src/main/scala/uncore/tilelink2/TLNodes.scala @@ -23,10 +23,10 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters]) TLMonitor.legalize(bo, eo, bi, ei) bi <> bo - val mask = ~UInt(ei.manager.beatBytes - 1) - bi.a.bits.address := (mask & bo.a.bits.address) - bo.b.bits.address := (mask & bi.b.bits.address) - bi.c.bits.address := (mask & bo.c.bits.address) + val mask = UInt(ei.manager.beatBytes - 1) + bi.a.bits.address := ~(mask | ~bo.a.bits.address) + bo.b.bits.address := ~(mask | ~bi.b.bits.address) + bi.c.bits.address := ~(mask | ~bo.c.bits.address) } } From a0c25880c7d4a18aa9ef9f5dd927fa045962c50f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 18:22:12 -0700 Subject: [PATCH 76/87] tilelink2: Monitor should check mask of reconstructed request --- src/main/scala/uncore/tilelink2/Edges.scala | 20 ++++++++++++++++++- src/main/scala/uncore/tilelink2/Monitor.scala | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 0d178560..6c156ab6 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -20,12 +20,13 @@ class TLEdge( // This gets used everywhere, so make the smallest circuit possible ... def fullMask(address: UInt, lgSize: UInt) = { val lgBytes = log2Ceil(manager.beatBytes) + val sizeOH = UIntToOH(lgSize, lgBytes) def helper(i: Int): Seq[(Bool, Bool)] = { if (i == 0) { Seq((lgSize >= UInt(lgBytes), Bool(true))) } else { val sub = helper(i-1) - val size = lgSize === UInt(lgBytes - i) + val size = sizeOH(lgBytes - i) val bit = address(lgBytes - i) val nbit = !bit Seq.tabulate (1 << i) { j => @@ -39,6 +40,23 @@ class TLEdge( Cat(helper(lgBytes).map(_._1).reverse) } + def lowAddress(mask: UInt) = { + // Almost OHToUInt, but any bit in low => use low address + def helper(mask: UInt, width: Int): UInt = { + if (width <= 1) { + UInt(0) + } else if (width == 2) { + ~mask(0, 0) + } else { + val mid = 1 << (log2Up(width)-1) + val hi = mask(width-1, mid) + val lo = mask(mid-1, 0) + Cat(!lo.orR, helper(hi | lo, mid)) + } + } + helper(mask, bundle.dataBits/8) + } + def staticHasData(bundle: HasTLOpcode): Option[Boolean] = { bundle.channelType() match { case ChannelType.A => { diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 97132d97..8f974a8a 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -20,7 +20,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) - val mask = edge.fullMask(bundle.address, bundle.size) + val mask = edge.fullMask(bundle.address | edge.lowAddress(bundle.mask), bundle.size) when (bundle.opcode === TLMessages.Acquire) { assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) @@ -86,7 +86,7 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) val is_aligned = edge.isAligned(bundle.address, bundle.size) - val mask = edge.fullMask(bundle.address, bundle.size) + val mask = edge.fullMask(bundle.address | edge.lowAddress(bundle.mask), bundle.size) when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client" + extra) From 0faa8c40510a9385d2888424fc19c05201d9b332 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 18:40:19 -0700 Subject: [PATCH 77/87] tilelink2: fix Xbar bug where Mux1H broke FSM if only one manager --- src/main/scala/uncore/tilelink2/Xbar.scala | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala index aa3dbd1c..e37e3134 100644 --- a/src/main/scala/uncore/tilelink2/Xbar.scala +++ b/src/main/scala/uncore/tilelink2/Xbar.scala @@ -108,7 +108,7 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend // The crossbar cross-connection state; defined later val grantedAIO = Wire(Vec(in .size, Vec(out.size, Bool()))) - val grantedBOI = Wire(Vec(out.size, Vec( in.size, Bool()))) + val grantedBOI = Wire(Vec(out.size, Vec(in .size, Bool()))) val grantedCIO = Wire(Vec(in .size, Vec(out.size, Bool()))) val grantedDOI = Wire(Vec(out.size, Vec(in .size, Bool()))) val grantedEIO = Wire(Vec(in .size, Vec(out.size, Bool()))) @@ -148,7 +148,7 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend val requestAIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.a.valid && o.manager.contains(i.a.bits.address) }) }) val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i .contains(o.b.bits.source) }) }) val requestCIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.c.valid && o.manager.contains(i.c.bits.address) }) }) - val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.b.bits.source) }) }) + val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.d.bits.source) }) }) val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o .contains(i.e.bits.sink) }) }) val beatsA = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) }) @@ -191,8 +191,15 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend // Apply policy to select which requester wins val winners = Vec(policy(requests, idle)) + // Winners must be a subset of requests + assert ((winners zip requests).map { case (w,r) => !w || r } .reduce(_ && _)) + // There must be only one winner + val prefixOR = winners.scanLeft(Bool(false))(_ || _).init + assert ((prefixOR zip winners).map { case (p,w) => !p || !w }.reduce(_ && _)) + // Supposing we take the winner as input, how many beats must be sent? - val initBeats = Mux1H(winners, beats) + val maskedBeats = (winners zip beats).map { case (w,b) => Mux(w, b, UInt(0)) } + val initBeats = maskedBeats.reduceLeft(_ | _) // no winner => 0 beats // What is the counter state before progress? val todoBeats = Mux(idle, initBeats, beatsLeft) // Apply progress and register the result From 757d46279e6ca28d3fc2bdcd24e42af37eb0268b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 19:48:21 -0700 Subject: [PATCH 78/87] tilelink2: expand data correctly in D channel narrower --- src/main/scala/uncore/tilelink2/Narrower.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 7d705753..2a345dc1 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -4,6 +4,7 @@ package uncore.tilelink2 import Chisel._ import chisel3.internal.sourceinfo.SourceInfo +import scala.math.{min,max} // innBeatBytes => the bus width after the adapter class TLNarrower(innerBeatBytes: Int) extends LazyModule @@ -62,10 +63,6 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule val first = count === UInt(0) val limit = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) val last = count === limit || !edge.hasData(in) - 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 @@ -73,10 +70,18 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule when (last) { count := UInt(0) } } + val cases = Seq.tabulate(log2Ceil(ratio)+1) { i => + val pow = 1 << i + Fill(1 << (log2Ceil(ratio)-i), data(pow*outerBeatBytes*8-1, 0)) + } + val mux = Vec.tabulate(log2Ceil(edge.maxTransfer)+1) { lgSize => + cases(min(max(lgSize - log2Ceil(outerBeatBytes), 0), log2Ceil(ratio))) + } + if (edge.staticHasData(in) == Some(false)) { (Bool(true), UInt(0)) } else { - (last, Mux1H(limit, cases)) + (last, mux(in.size())) } } From 9f45212c95849888fd97e268a4a7a81099ab7488 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 20:52:47 -0700 Subject: [PATCH 79/87] tilelink2: Fragmenter needs to update subaddress --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 94fdda7d..be140c53 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -167,7 +167,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten // Swallow up non-data ack fragments val drop = (out.d.bits.opcode === TLMessages.AccessAck) && (dFragnum =/= UInt(0)) out.d.ready := in.d.ready || drop - in.d.valid := out.d.valid && drop + in.d.valid := out.d.valid && !drop in.d.bits := out.d.bits // pass most stuff unchanged in.d.bits.source := out.d.bits.source >> fragmentBits in.d.bits.size := Mux(dFirst, dFirst_size, dOrig) @@ -220,12 +220,13 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val new_gennum = ~(~old_gennum1 | (aMask >> log2Ceil(beatBytes))) // ~(~x|y) is width safe val aFragnum = ~(~(old_gennum1 >> log2Ceil(minSize/beatBytes)) | (aFragOH1 >> log2Ceil(minSize))) - when (out.d.fire()) { gennum := new_gennum } + 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.address := in.a.bits.address | (~aFragnum << log2Ceil(minSize) & aOrigOH1) out.a.bits.source := Cat(in.a.bits.source, aFragnum) out.a.bits.size := aFrag From cf0291061dc50e09cb1d5bf560ef3816fc9ec760 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 4 Sep 2016 21:54:23 -0700 Subject: [PATCH 80/87] tilelink2: fix a bug in UIntToOH1 triggered if the size was too big --- src/main/scala/uncore/tilelink2/Edges.scala | 3 +-- src/main/scala/uncore/tilelink2/Fragmenter.scala | 2 +- src/main/scala/uncore/tilelink2/Narrower.scala | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 6c156ab6..eca8d307 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -12,8 +12,7 @@ class TLEdge( { def isAligned(address: UInt, lgSize: UInt) = if (maxLgSize == 0) Bool(true) else { - val ones = UInt((1 << maxLgSize) - 1) - val mask = (ones << lgSize)(maxLgSize*2-1, maxLgSize) + val mask = ~(SInt(-1, width=maxLgSize).asUInt << lgSize)(maxLgSize-1, 0) (address & mask) === UInt(0) } diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index be140c53..4eb68b0c 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -139,7 +139,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxDownSize = if (alwaysMin) minSize else manager.maxTransfer def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x) - def UIntToOH1(x: UInt, width: Int) = (UInt((1 << width) - 1) << x)(width*2-1, width) + def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) // First, handle the return path val acknum = RegInit(UInt(0, width = counterBits)) diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 2a345dc1..9fbfac6b 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -26,7 +26,7 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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 UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None def split(in: HasTLData, fire: Bool): (Bool, UInt, UInt) = { @@ -96,7 +96,7 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule out.a.bits.mask := amask val (dlast, ddata) = merge(out.d.bits, out.d.fire()) - out.d.ready := in.d.ready + out.d.ready := in.d.ready || !dlast in.d.valid := out.d.valid && dlast in.d.bits := out.d.bits in.d.bits.data := ddata From ded246fb9531b3ae6dacfaba6ef7ba791f799862 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 5 Sep 2016 19:45:16 -0700 Subject: [PATCH 81/87] tilelink2: relax max transfer size; the real requirement is not exceeding alignment --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 1 - src/main/scala/uncore/tilelink2/Parameters.scala | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index 4eb68b0c..f9472f48 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -17,7 +17,6 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten require (isPow2 (maxSize)) require (isPow2 (minSize)) require (minSize < maxSize) - require (maxSize <= TransferSizes.maxAllowed) val fragmentBits = log2Ceil(maxSize / minSize) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 138ff9a5..9a909261 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -50,7 +50,6 @@ case class TransferSizes(min: Int, max: Int) require (min >= 0 && max >= 0) require (max == 0 || isPow2(max)) require (min == 0 || isPow2(min)) - require (max <= TransferSizes.maxAllowed) def none = min == 0 def contains(x: Int) = isPow2(x) && min <= x && x <= max @@ -70,7 +69,6 @@ case class TransferSizes(min: Int, max: Int) object TransferSizes { def apply(x: Int) = new TransferSizes(x) val none = new TransferSizes(0) - val maxAllowed = 4096 // transfers larger than 4kB are forbidden in TL2 implicit def asBool(x: TransferSizes) = !x.none } @@ -130,6 +128,11 @@ case class TLManagerParameters( supportsGet.max, supportsPutFull.max, supportsPutPartial.max).max + + // The device had better not support a transfer larger than it's alignment + address.foreach({ case a => + require (a.alignment1 >= maxTransfer-1) + }) } case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes: Int) From 3167539331d1bb49c9a2a91939ebbdb900595c57 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 5 Sep 2016 20:42:16 -0700 Subject: [PATCH 82/87] tilelink2: Narrower must be little-endian --- src/main/scala/uncore/tilelink2/Narrower.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 9fbfac6b..4f0401c3 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -59,20 +59,21 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule 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 data = Cat(in.data(), rdata) val first = count === UInt(0) val limit = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) val last = count === limit || !edge.hasData(in) when (fire) { - rdata := data + rdata := data >> outerBeatBytes*8 count := count + UInt(1) when (last) { count := UInt(0) } } val cases = Seq.tabulate(log2Ceil(ratio)+1) { i => - val pow = 1 << i - Fill(1 << (log2Ceil(ratio)-i), data(pow*outerBeatBytes*8-1, 0)) + val high = innerBeatBytes*8 + val take = (1 << i)*outerBeatBytes*8 + Fill(1 << (log2Ceil(ratio)-i), data(high-1, high-take)) } val mux = Vec.tabulate(log2Ceil(edge.maxTransfer)+1) { lgSize => cases(min(max(lgSize - log2Ceil(outerBeatBytes), 0), log2Ceil(ratio))) From 56170c605c178d315d9defca4f6d4d701f8b9759 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 5 Sep 2016 21:12:51 -0700 Subject: [PATCH 83/87] tilelink2: be more forgiving in what Legacy TL requires --- src/main/scala/uncore/tilelink2/Legacy.scala | 29 ++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala index ed051ae6..b155176b 100644 --- a/src/main/scala/uncore/tilelink2/Legacy.scala +++ b/src/main/scala/uncore/tilelink2/Legacy.scala @@ -24,14 +24,27 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa // TL legacy is dumb. All managers must support it's accesses. val edge = node.edgesOut(0) require (edge.manager.beatBytes == tlDataBytes) - require (edge.manager.allSupportGet .contains(TransferSizes(tlDataBytes))) - require (edge.manager.allSupportGet .contains(TransferSizes(tlDataBeats * tlDataBytes))) - require (edge.manager.allSupportPutPartial.contains(TransferSizes(tlDataBytes))) - require (edge.manager.allSupportPutPartial.contains(TransferSizes(tlDataBeats * tlDataBytes))) - require (edge.manager.allSupportArithmetic.contains(TransferSizes(4, tlDataBytes))) - require (edge.manager.allSupportLogical .contains(TransferSizes(4, tlDataBytes))) - require (edge.manager.allSupportHint) - // TL legacy will not generate PutFull, Acquire + edge.manager.managers.foreach { m => + // If a slave supports read at all, it must support all TL Legacy requires + if (m.supportsGet) { + require (m.supportsGet.contains(TransferSizes(tlDataBytes))) + require (m.supportsGet.contains(TransferSizes(tlDataBeats * tlDataBytes))) + } + // Likewise, any put support must mean full put support + if (m.supportsPutPartial) { + require (m.supportsPutPartial.contains(TransferSizes(tlDataBytes))) + require (m.supportsPutPartial.contains(TransferSizes(tlDataBeats * tlDataBytes))) + } + // Any atomic support => must support 32-bit up to beat size of all types + if (m.supportsArithmetic || m.supportsLogical) { + require (m.supportsArithmetic.contains(TransferSizes(4, tlDataBytes))) + require (m.supportsLogical .contains(TransferSizes(4, tlDataBytes))) + } + // We straight-up require hints + require (edge.manager.allSupportHint) + } + // TL legacy will not generate PutFull + // During conversion from TL Legacy, we won't support Acquire // Must be able to fit TL2 sink_id into TL legacy require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId) From 314d6ebd6f30599509f8e538a0db95d8704dd090 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 5 Sep 2016 22:10:28 -0700 Subject: [PATCH 84/87] tilelink2: stricter TransferSizes requirements --- src/main/scala/uncore/tilelink2/Fragmenter.scala | 2 +- src/main/scala/uncore/tilelink2/Parameters.scala | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index f9472f48..cec91c59 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -26,7 +26,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten } def shrinkTransfer(x: TransferSizes) = if (!alwaysMin) x else - if (x.min <= minSize) TransferSizes(x.min, minSize) else + if (x.min <= minSize) TransferSizes(x.min, min(minSize, x.max)) else TransferSizes.none def mapManager(m: TLManagerParameters) = m.copy( supportsAcquire = TransferSizes.none, // this adapter breaks acquires diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 9a909261..0fb438ab 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -50,6 +50,7 @@ case class TransferSizes(min: Int, max: Int) require (min >= 0 && max >= 0) require (max == 0 || isPow2(max)) require (min == 0 || isPow2(min)) + require (max == 0 || min != 0) // 0 is forbidden unless (0,0) def none = min == 0 def contains(x: Int) = isPow2(x) && min <= x && x <= max From 54ab14cd9dd49ce37da33a190a382a0aefa0d7a4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 5 Sep 2016 22:11:03 -0700 Subject: [PATCH 85/87] tilelink2: statically optimize numBeats for simple managers --- src/main/scala/uncore/tilelink2/Edges.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index eca8d307..7b65cabf 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -99,7 +99,7 @@ class TLEdge( val hasData = this.hasData(bundle) val size = bundle.size() val cutoff = log2Ceil(manager.beatBytes) - val small = size <= UInt(cutoff) + val small = if (manager.maxTransfer <= manager.beatBytes) Bool(true) else size <= UInt(cutoff) val decode = UIntToOH(size, maxLgSize+1) >> cutoff Mux(!hasData || small, UInt(1), decode) } From aae4230627978c228fafe7929235607b7e080d1c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 6 Sep 2016 13:12:33 -0700 Subject: [PATCH 86/87] tilelink2: fix bugs found by Megan in Legacy converter --- src/main/scala/uncore/tilelink2/Legacy.scala | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala index b155176b..91041169 100644 --- a/src/main/scala/uncore/tilelink2/Legacy.scala +++ b/src/main/scala/uncore/tilelink2/Legacy.scala @@ -7,15 +7,17 @@ import cde.Parameters import uncore.tilelink._ import uncore.constants._ +// Instantiate 'val p' before HasTileLinkParameters tries to use it +abstract class LegacyLazyModuleImp(module: LazyModule)(implicit val p: Parameters) + extends LazyModuleImp(module) with HasTileLinkParameters + class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkParameters { - val outer_p = p // TL legacy clients don't support anything fancy val node = TLClientNode(TLClientParameters( sourceId = IdRange(0, 1 << tlClientXactIdBits))) - lazy val module = new LazyModuleImp(this) with HasTileLinkParameters { - val p = outer_p + lazy val module = new LegacyLazyModuleImp(this) { val io = new Bundle { val legacy = new ClientUncachedTileLinkIO()(p).flip val out = node.bundleOut @@ -63,14 +65,9 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa val beat = UInt(log2Ceil(tlDataBytes)) val block = UInt(log2Ceil(tlDataBytes*tlDataBeats)) - out.a.bits := MuxLookup(io.legacy.acquire.bits.a_type, new TLBundleA(edge.bundle), Array( - Acquire.getType -> edge.Get (source, address, beat) ._2, - Acquire.getBlockType -> edge.Get (source, address, block)._2, - Acquire.putType -> edge.Put (source, address, beat, data, wmask)._2, - Acquire.putBlockType -> edge.Put (source, address, block, data, wmask)._2, - Acquire.getPrefetchType -> edge.Hint(source, address, block, UInt(0))._2, - Acquire.putPrefetchType -> edge.Hint(source, address, block, UInt(1))._2, - Acquire.putAtomicType -> MuxLookup(io.legacy.acquire.bits.op_code(), new TLBundleA(edge.bundle), Array( + // Only create atomic messages if TL2 managers support them + val atomics = if (edge.manager.anySupportLogical) { + MuxLookup(io.legacy.acquire.bits.op_code(), Wire(new TLBundleA(edge.bundle)), Array( MemoryOpConstants.M_XA_SWAP -> edge.Logical(source, address, beat, data, TLAtomics.SWAP)._2, MemoryOpConstants.M_XA_XOR -> edge.Logical(source, address, beat, data, TLAtomics.XOR) ._2, MemoryOpConstants.M_XA_OR -> edge.Logical(source, address, beat, data, TLAtomics.OR) ._2, @@ -79,7 +76,19 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa MemoryOpConstants.M_XA_MIN -> edge.Arithmetic(source, address, beat, data, TLAtomics.MIN)._2, MemoryOpConstants.M_XA_MAX -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAX)._2, MemoryOpConstants.M_XA_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2, - MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2)))) + MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2)) + } else { + Wire(new TLBundleA(edge.bundle)) + } + + out.a.bits := MuxLookup(io.legacy.acquire.bits.a_type, Wire(new TLBundleA(edge.bundle)), Array( + Acquire.getType -> edge.Get (source, address, beat) ._2, + Acquire.getBlockType -> edge.Get (source, address, block)._2, + Acquire.putType -> edge.Put (source, address, beat, data, wmask)._2, + Acquire.putBlockType -> edge.Put (source, address, block, data, wmask)._2, + Acquire.getPrefetchType -> edge.Hint(source, address, block, UInt(0))._2, + Acquire.putPrefetchType -> edge.Hint(source, address, block, UInt(1))._2, + Acquire.putAtomicType -> atomics)) val beatMask = UInt(tlDataBytes-1) val blockMask = UInt(tlDataBytes*tlDataBeats-1) From d2421654c408b758fffb9f87d3ee0bf026e41796 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 6 Sep 2016 23:46:44 -0700 Subject: [PATCH 87/87] tilelink2: refactor address into addr_hi on ABC and addr_lo on CD We need addr_lo in order to properly convert widths. As part of the refactoring, move all methods out of the Bundles --- src/main/scala/uncore/tilelink2/Bundles.scala | 135 ++----- src/main/scala/uncore/tilelink2/Edges.scala | 352 ++++++++++++------ .../scala/uncore/tilelink2/Fragmenter.scala | 13 +- .../scala/uncore/tilelink2/HintHandler.scala | 6 +- .../scala/uncore/tilelink2/LazyModule.scala | 2 +- src/main/scala/uncore/tilelink2/Legacy.scala | 4 +- src/main/scala/uncore/tilelink2/Monitor.scala | 81 ++-- .../scala/uncore/tilelink2/Narrower.scala | 29 +- .../scala/uncore/tilelink2/Parameters.scala | 22 +- .../uncore/tilelink2/RegisterRouter.scala | 23 +- src/main/scala/uncore/tilelink2/SRAM.scala | 9 +- src/main/scala/uncore/tilelink2/TLNodes.scala | 4 - src/main/scala/uncore/tilelink2/Xbar.scala | 10 +- src/main/scala/uncore/tilelink2/package.scala | 2 + 14 files changed, 378 insertions(+), 314 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala index 0c0a95e4..e071c466 100644 --- a/src/main/scala/uncore/tilelink2/Bundles.scala +++ b/src/main/scala/uncore/tilelink2/Bundles.scala @@ -100,151 +100,72 @@ object TLAtomics def isLogical(x: UInt) = x <= SWAP } -class Bogus -object Bogus -{ - def apply() = new Bogus -} +sealed trait TLChannel +sealed trait TLDataChannel extends TLChannel +sealed trait TLAddrChannel extends TLDataChannel -object ChannelType { - sealed trait T - case object A extends T - case object B extends T - case object C extends T - case object D extends T - case object E extends T - val cases = Seq(A, B, C, D, E) -} - -trait HasTLOpcode -{ - // The data field in this message has value - def hasData(x: Bogus = Bogus()): Bool - // This message requires a response - def hasFollowUp(x: Bogus = Bogus()): Bool - // What channel type is this? - def channelType(x: Bogus = Bogus()): ChannelType.T - // The size field of the opcode - def size(x: Bogus = Bogus()): UInt -} - -trait HasTLData extends HasTLOpcode -{ - def data(x: Bogus = Bogus()): UInt - def mask(x: Bogus = Bogus()): UInt -} - -class TLBundleA(params: TLBundleParameters) - extends TLBundleBase(params) - with HasTLData +final class TLBundleA(params: TLBundleParameters) + extends TLBundleBase(params) with TLAddrChannel { // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) // amo_opcode || perms || hint val size = UInt(width = params.sizeBits) - val source = UInt(width = params.sourceBits) // from - val address = UInt(width = params.addressBits) // to + val source = UInt(width = params.sourceBits) // from + val addr_hi = UInt(width = params.addrHiBits) // to // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) - - def hasData(x: Bogus = Bogus()) = !opcode(2) -// opcode === TLMessages.PutFullData || -// opcode === TLMessages.PutPartialData || -// opcode === TLMessages.ArithmeticData || -// opcode === TLMessages.LogicalData - def hasFollowUp(x: Bogus = Bogus()) = Bool(true) - def channelType(x: Bogus = Bogus()) = ChannelType.A - def size(x: Bogus = Bogus()) = size - def data(x: Bogus = Bogus()) = data - def mask(x: Bogus = Bogus()) = mask } -class TLBundleB(params: TLBundleParameters) - extends TLBundleBase(params) - with HasTLData +final class TLBundleB(params: TLBundleParameters) + extends TLBundleBase(params) with TLAddrChannel { // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) - val source = UInt(width = params.sourceBits) // to - val address = UInt(width = params.addressBits) // from + val source = UInt(width = params.sourceBits) // to + val addr_hi = UInt(width = params.addrHiBits) // from // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) - - def hasData(x: Bogus = Bogus()) = !opcode(2) - def hasFollowUp(x: Bogus = Bogus()) = Bool(true) - def channelType(x: Bogus = Bogus()) = ChannelType.B - def size(x: Bogus = Bogus()) = size - def data(x: Bogus = Bogus()) = data - def mask(x: Bogus = Bogus()) = mask } -class TLBundleC(params: TLBundleParameters) - extends TLBundleBase(params) - with HasTLData +final class TLBundleC(params: TLBundleParameters) + extends TLBundleBase(params) with TLAddrChannel { // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) - val source = UInt(width = params.sourceBits) // from - val address = UInt(width = params.addressBits) // to + val source = UInt(width = params.sourceBits) // from + val addr_hi = UInt(width = params.addrHiBits) // to + val addr_lo = UInt(width = params.addrLoBits) // instead of mask // variable fields during multibeat: val data = UInt(width = params.dataBits) val error = Bool() // AccessAck[Data] - - def hasData(x: Bogus = Bogus()) = opcode(0) -// opcode === TLMessages.AccessAckData || -// opcode === TLMessages.ProbeAckData || -// opcode === TLMessages.ReleaseData - def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && opcode(1) -// opcode === TLMessages.Release || -// opcode === TLMessages.ReleaseData - def channelType(x: Bogus = Bogus()) = ChannelType.C - def size(x: Bogus = Bogus()) = size - def data(x: Bogus = Bogus()) = data - def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt } -class TLBundleD(params: TLBundleParameters) - extends TLBundleBase(params) - with HasTLData +final class TLBundleD(params: TLBundleParameters) + extends TLBundleBase(params) with TLDataChannel { // fixed fields during multibeat: - val opcode = UInt(width = 3) - val param = UInt(width = 2) - val size = UInt(width = params.sizeBits) - val source = UInt(width = params.sourceBits) // to - val sink = UInt(width = params.sinkBits) // from + val opcode = UInt(width = 3) + val param = UInt(width = 2) + val size = UInt(width = params.sizeBits) + val source = UInt(width = params.sourceBits) // to + val sink = UInt(width = params.sinkBits) // from + val addr_lo = UInt(width = params.addrLoBits) // instead of mask // variable fields during multibeat: - val data = UInt(width = params.dataBits) - val error = Bool() // AccessAck[Data], Grant[Data] - - def hasData(x: Bogus = Bogus()) = opcode(0) -// opcode === TLMessages.AccessAckData || -// opcode === TLMessages.GrantData - def hasFollowUp(x: Bogus = Bogus()) = opcode(2) && !opcode(1) -// opcode === TLMessages.Grant || -// opcode === TLMessages.GrantData - def channelType(x: Bogus = Bogus()) = ChannelType.D - def size(x: Bogus = Bogus()) = size - def data(x: Bogus = Bogus()) = data - def mask(x: Bogus = Bogus()) = SInt(-1, width = params.dataBits/8).asUInt + val data = UInt(width = params.dataBits) + val error = Bool() // AccessAck[Data], Grant[Data] } -class TLBundleE(params: TLBundleParameters) - extends TLBundleBase(params) - with HasTLOpcode +final class TLBundleE(params: TLBundleParameters) + extends TLBundleBase(params) with TLChannel { val sink = UInt(width = params.sourceBits) // to - - def hasData(x: Bogus = Bogus()) = Bool(false) - def hasFollowUp(x: Bogus = Bogus()) = Bool(false) - def channelType(x: Bogus = Bogus()) = ChannelType.E - def size(x: Bogus = Bogus()) = UInt(log2Up(params.dataBits/8)) } class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 7b65cabf..75053b88 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -10,14 +10,22 @@ class TLEdge( manager: TLManagerPortParameters) extends TLEdgeParameters(client, manager) { - def isAligned(address: UInt, lgSize: UInt) = + def isHiAligned(addr_hi: UInt, lgSize: UInt): Bool = { if (maxLgSize == 0) Bool(true) else { - val mask = ~(SInt(-1, width=maxLgSize).asUInt << lgSize)(maxLgSize-1, 0) - (address & mask) === UInt(0) + val mask = UIntToOH1(lgSize, maxLgSize) >> log2Ceil(manager.beatBytes) + (addr_hi & mask) === UInt(0) } + } + + def isLoAligned(addr_lo: UInt, lgSize: UInt): Bool = { + if (maxLgSize == 0) Bool(true) else { + val mask = UIntToOH1(lgSize, maxLgSize) + (addr_lo & mask) === UInt(0) + } + } // This gets used everywhere, so make the smallest circuit possible ... - def fullMask(address: UInt, lgSize: UInt) = { + def mask(addr_lo: UInt, lgSize: UInt): UInt = { val lgBytes = log2Ceil(manager.beatBytes) val sizeOH = UIntToOH(lgSize, lgBytes) def helper(i: Int): Seq[(Bool, Bool)] = { @@ -26,7 +34,7 @@ class TLEdge( } else { val sub = helper(i-1) val size = sizeOH(lgBytes - i) - val bit = address(lgBytes - i) + val bit = addr_lo(lgBytes - i) val nbit = !bit Seq.tabulate (1 << i) { j => val (sub_acc, sub_eq) = sub(j/2) @@ -39,8 +47,8 @@ class TLEdge( Cat(helper(lgBytes).map(_._1).reverse) } - def lowAddress(mask: UInt) = { - // Almost OHToUInt, but any bit in low => use low address + def addr_lo(mask: UInt): UInt = { + // Almost OHToUInt, but bits set => bits not set def helper(mask: UInt, width: Int): UInt = { if (width <= 1) { UInt(0) @@ -56,9 +64,9 @@ class TLEdge( helper(mask, bundle.dataBits/8) } - def staticHasData(bundle: HasTLOpcode): Option[Boolean] = { - bundle.channelType() match { - case ChannelType.A => { + def staticHasData(bundle: TLChannel): Option[Boolean] = { + bundle match { + case _:TLBundleA => { // Do there exist A messages with Data? val aDataYes = manager.anySupportArithmetic || manager.anySupportLogical || manager.anySupportPutFull || manager.anySupportPutPartial // Do there exist A messages without Data? @@ -66,7 +74,7 @@ class TLEdge( // Statically optimize the case where hasData is a constant if (!aDataYes) Some(false) else if (!aDataNo) Some(true) else None } - case ChannelType.B => { + case _:TLBundleB => { // Do there exist B messages with Data? val bDataYes = client.anySupportArithmetic || client.anySupportLogical || client.anySupportPutFull || client.anySupportPutPartial // Do there exist B messages without Data? @@ -74,34 +82,119 @@ class TLEdge( // Statically optimize the case where hasData is a constant if (!bDataYes) Some(false) else if (!bDataNo) Some(true) else None } - case ChannelType.C => { + case _:TLBundleC => { // Do there eixst C messages with Data? val cDataYes = client.anySupportGet || client.anySupportArithmetic || client.anySupportLogical || client.anySupportProbe // Do there exist C messages without Data? val cDataNo = client.anySupportPutFull || client.anySupportPutPartial || client.anySupportHint || client.anySupportProbe if (!cDataYes) Some(false) else if (!cDataNo) Some(true) else None } - case ChannelType.D => { + case _:TLBundleD => { // Do there eixst D messages with Data? val dDataYes = manager.anySupportGet || manager.anySupportArithmetic || manager.anySupportLogical || manager.anySupportAcquire // Do there exist D messages without Data? val dDataNo = manager.anySupportPutFull || manager.anySupportPutPartial || manager.anySupportHint || manager.anySupportAcquire if (!dDataYes) Some(false) else if (!dDataNo) Some(true) else None } - case ChannelType.E => Some(false) + case _:TLBundleE => Some(false) } } - def hasData(bundle: HasTLOpcode): Bool = - staticHasData(bundle).map(Bool(_)).getOrElse(bundle.hasData()) + def hasFollowUp(x: TLChannel): Bool = { + x match { + case a: TLBundleA => Bool(true) + case b: TLBundleB => Bool(true) + case c: TLBundleC => c.opcode(2) && c.opcode(1) + // opcode === TLMessages.Release || + // opcode === TLMessages.ReleaseData + case d: TLBundleD => d.opcode(2) && !d.opcode(1) + // opcode === TLMessages.Grant || + // opcode === TLMessages.GrantData + case e: TLBundleE => Bool(false) + } + } - def numBeats(bundle: HasTLOpcode) = { - val hasData = this.hasData(bundle) - val size = bundle.size() - val cutoff = log2Ceil(manager.beatBytes) - val small = if (manager.maxTransfer <= manager.beatBytes) Bool(true) else size <= UInt(cutoff) - val decode = UIntToOH(size, maxLgSize+1) >> cutoff - Mux(!hasData || small, UInt(1), decode) + def hasData(x: TLChannel): Bool = { + val opdata = x match { + case a: TLBundleA => !a.opcode(2) + // opcode === TLMessages.PutFullData || + // opcode === TLMessages.PutPartialData || + // opcode === TLMessages.ArithmeticData || + // opcode === TLMessages.LogicalData + case b: TLBundleB => !b.opcode(2) + // opcode === TLMessages.PutFullData || + // opcode === TLMessages.PutPartialData || + // opcode === TLMessages.ArithmeticData || + // opcode === TLMessages.LogicalData + case c: TLBundleC => c.opcode(0) + // opcode === TLMessages.AccessAckData || + // opcode === TLMessages.ProbeAckData || + // opcode === TLMessages.ReleaseData + case d: TLBundleD => d.opcode(0) + // opcode === TLMessages.AccessAckData || + // opcode === TLMessages.GrantData + case e: TLBundleE => Bool(false) + } + staticHasData(x).map(Bool(_)).getOrElse(opdata) + } + + def size(x: TLDataChannel): UInt = { + x match { + case a: TLBundleA => a.size + case b: TLBundleB => b.size + case c: TLBundleC => c.size + case d: TLBundleD => d.size + } + } + + def data(x: TLDataChannel): UInt = { + x match { + case a: TLBundleA => a.data + case b: TLBundleB => b.data + case c: TLBundleC => c.data + case d: TLBundleD => d.data + } + } + + def mask(x: TLDataChannel): UInt = { + x match { + case a: TLBundleA => a.mask + case b: TLBundleB => b.mask + case c: TLBundleC => mask(c.addr_lo, c.size) + case d: TLBundleD => mask(d.addr_lo, d.size) + } + } + + def addr_lo(x: TLDataChannel): UInt = { + x match { + case a: TLBundleA => addr_lo(a.mask) + case b: TLBundleB => addr_lo(b.mask) + case c: TLBundleC => c.addr_lo + case d: TLBundleD => d.addr_lo + } + } + + def address(x: TLAddrChannel): UInt = { + val hi = x match { + case a: TLBundleA => a.addr_hi + case b: TLBundleB => b.addr_hi + case c: TLBundleC => c.addr_hi + } + if (manager.beatBytes == 1) hi else Cat(hi, addr_lo(x)) + } + + def numBeats(x: TLChannel): UInt = { + x match { + case _: TLBundleE => UInt(1) + case bundle: TLDataChannel => { + val hasData = this.hasData(bundle) + val size = this.size(bundle) + val cutoff = log2Ceil(manager.beatBytes) + val small = if (manager.maxTransfer <= manager.beatBytes) Bool(true) else size <= UInt(cutoff) + val decode = UIntToOH(size, maxLgSize+1) >> cutoff + Mux(!hasData || small, UInt(1), decode) + } + } } } @@ -119,7 +212,7 @@ class TLEdgeOut( a.param := growPermissions a.size := lgSize a.source := fromSource - a.address := toAddress + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) a.mask := SInt(-1).asUInt a.data := UInt(0) (legal, a) @@ -133,7 +226,8 @@ class TLEdgeOut( c.param := shrinkPermissions c.size := lgSize c.source := fromSource - c.address := toAddress + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := UInt(0) c.error := Bool(false) (legal, c) @@ -147,31 +241,34 @@ class TLEdgeOut( c.param := shrinkPermissions c.size := lgSize c.source := fromSource - c.address := toAddress + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := data c.error := Bool(false) (legal, c) } - def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt) = { + def ProbeAck(fromSource: UInt, toAddress: UInt, lgSize: UInt, reportPermissions: UInt) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.ProbeAck c.param := reportPermissions c.size := lgSize - c.source := UInt(0) - c.address := toAddress + c.source := fromSource + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := UInt(0) c.error := Bool(false) c } - def ProbeAck(toAddress: UInt, lgSize: UInt, reportPermissions: UInt, data: UInt) = { + def ProbeAck(fromSource: UInt, toAddress: UInt, lgSize: UInt, reportPermissions: UInt, data: UInt) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.ProbeAckData c.param := reportPermissions c.size := lgSize - c.source := UInt(0) - c.address := toAddress + c.source := fromSource + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := data c.error := Bool(false) c @@ -192,8 +289,8 @@ class TLEdgeOut( a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress - a.mask := fullMask(toAddress, lgSize) + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + a.mask := mask(toAddress, lgSize) a.data := UInt(0) (legal, a) } @@ -206,8 +303,8 @@ class TLEdgeOut( a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress - a.mask := fullMask(toAddress, lgSize) + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + a.mask := mask(toAddress, lgSize) a.data := data (legal, a) } @@ -220,7 +317,7 @@ class TLEdgeOut( a.param := UInt(0) a.size := lgSize a.source := fromSource - a.address := toAddress + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) a.mask := mask a.data := data (legal, a) @@ -234,8 +331,8 @@ class TLEdgeOut( a.param := atomic a.size := lgSize a.source := fromSource - a.address := toAddress - a.mask := fullMask(toAddress, lgSize) + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + a.mask := mask(toAddress, lgSize) a.data := data (legal, a) } @@ -248,8 +345,8 @@ class TLEdgeOut( a.param := atomic a.size := lgSize a.source := fromSource - a.address := toAddress - a.mask := fullMask(toAddress, lgSize) + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + a.mask := mask(toAddress, lgSize) a.data := data (legal, a) } @@ -262,45 +359,53 @@ class TLEdgeOut( a.param := param a.size := lgSize a.source := fromSource - a.address := toAddress - a.mask := fullMask(toAddress, lgSize) + a.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + a.mask := mask(toAddress, lgSize) a.data := UInt(0) (legal, a) } - def AccessAck(toAddress: UInt, lgSize: UInt): TLBundleC = AccessAck(toAddress, lgSize, Bool(false)) - def AccessAck(toAddress: UInt, lgSize: UInt, error: Bool) = { + def AccessAck(b: TLBundleB): TLBundleC = AccessAck(b.source, address(b), b.size) + def AccessAck(b: TLBundleB, error: Bool): TLBundleC = AccessAck(b.source, address(b), b.size, error) + def AccessAck(fromSource: UInt, toAddress: UInt, lgSize: UInt): TLBundleC = AccessAck(fromSource, toAddress, lgSize, Bool(false)) + def AccessAck(fromSource: UInt, toAddress: UInt, lgSize: UInt, error: Bool) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAck c.param := UInt(0) c.size := lgSize - c.source := UInt(0) - c.address := toAddress + c.source := fromSource + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := UInt(0) c.error := error c } - def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt): TLBundleC = AccessAck(toAddress, lgSize, data, Bool(false)) - def AccessAck(toAddress: UInt, lgSize: UInt, data: UInt, error: Bool) = { + def AccessAck(b: TLBundleB, data: UInt): TLBundleC = AccessAck(b.source, address(b), b.size, data) + def AccessAck(b: TLBundleB, data: UInt, error: Bool): TLBundleC = AccessAck(b.source, address(b), b.size, data, error) + def AccessAck(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt): TLBundleC = AccessAck(fromSource, toAddress, lgSize, data, Bool(false)) + def AccessAck(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, error: Bool) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.AccessAckData c.param := UInt(0) c.size := lgSize - c.source := UInt(0) - c.address := toAddress + c.source := fromSource + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := data c.error := error c } - def HintAck(toAddress: UInt, lgSize: UInt) = { + def HintAck(b: TLBundleB): TLBundleC = HintAck(b.source, address(b), b.size) + def HintAck(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { val c = Wire(new TLBundleC(bundle)) c.opcode := TLMessages.HintAck c.param := UInt(0) c.size := lgSize - c.source := UInt(0) - c.address := toAddress + c.source := fromSource + c.addr_hi := toAddress >> log2Ceil(manager.beatBytes) + c.addr_lo := toAddress c.data := UInt(0) c.error := Bool(false) c @@ -321,47 +426,50 @@ class TLEdgeIn( b.param := capPermissions b.size := lgSize b.source := toSource - b.address := fromAddress + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) b.mask := SInt(-1).asUInt b.data := UInt(0) (legal, b) } - def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt): TLBundleD = Grant(fromSink, toSource, lgSize, capPermissions, Bool(false)) - def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, error: Bool) = { + def Grant(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt): TLBundleD = Grant(fromAddress, fromSink, toSource, lgSize, capPermissions, Bool(false)) + def Grant(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.Grant - d.param := capPermissions - d.size := lgSize - d.source := toSource - d.sink := fromSink - d.data := UInt(0) - d.error := error + d.opcode := TLMessages.Grant + d.param := capPermissions + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := UInt(0) + d.error := error d } - def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt): TLBundleD = Grant(fromSink, toSource, lgSize, capPermissions, data, Bool(false)) - def Grant(fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt, error: Bool) = { + def Grant(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt): TLBundleD = Grant(fromAddress, fromSink, toSource, lgSize, capPermissions, data, Bool(false)) + def Grant(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt, data: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.GrantData - d.param := capPermissions - d.size := lgSize - d.source := toSource - d.sink := fromSink - d.data := data - d.error := error + d.opcode := TLMessages.GrantData + d.param := capPermissions + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := data + d.error := error d } - def ReleaseAck(toSource: UInt, lgSize: UInt) = { + def ReleaseAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.ReleaseAck - d.param := UInt(0) - d.size := lgSize - d.source := toSource - d.sink := UInt(0) - d.data := UInt(0) - d.error := Bool(false) + d.opcode := TLMessages.ReleaseAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := UInt(0) + d.error := Bool(false) d } @@ -374,8 +482,8 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress - b.mask := fullMask(fromAddress, lgSize) + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) + b.mask := mask(fromAddress, lgSize) b.data := UInt(0) (legal, b) } @@ -388,8 +496,8 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress - b.mask := fullMask(fromAddress, lgSize) + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) + b.mask := mask(fromAddress, lgSize) b.data := data (legal, b) } @@ -402,7 +510,7 @@ class TLEdgeIn( b.param := UInt(0) b.size := lgSize b.source := toSource - b.address := fromAddress + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) b.mask := mask b.data := data (legal, b) @@ -416,8 +524,8 @@ class TLEdgeIn( b.param := atomic b.size := lgSize b.source := toSource - b.address := fromAddress - b.mask := fullMask(fromAddress, lgSize) + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) + b.mask := mask(fromAddress, lgSize) b.data := data (legal, b) } @@ -430,8 +538,8 @@ class TLEdgeIn( b.param := atomic b.size := lgSize b.source := toSource - b.address := fromAddress - b.mask := fullMask(fromAddress, lgSize) + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) + b.mask := mask(fromAddress, lgSize) b.data := data (legal, b) } @@ -444,47 +552,55 @@ class TLEdgeIn( b.param := param b.size := lgSize b.source := toSource - b.address := fromAddress - b.mask := fullMask(fromAddress, lgSize) + b.addr_hi := fromAddress >> log2Ceil(manager.beatBytes) + b.mask := mask(fromAddress, lgSize) b.data := UInt(0) (legal, b) } - def AccessAck(toSource: UInt, lgSize: UInt): TLBundleD = AccessAck(toSource, lgSize, Bool(false)) - def AccessAck(toSource: UInt, lgSize: UInt, error: Bool) = { + def AccessAck(a: TLBundleA, fromSink: UInt): TLBundleD = AccessAck(address(a), fromSink, a.source, a.size) + def AccessAck(a: TLBundleA, fromSink: UInt, error: Bool): TLBundleD = AccessAck(address(a), fromSink, a.source, a.size, error) + def AccessAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt): TLBundleD = AccessAck(fromAddress, fromSink, toSource, lgSize, Bool(false)) + def AccessAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.AccessAck - d.param := UInt(0) - d.size := lgSize - d.source := toSource - d.sink := UInt(0) - d.data := UInt(0) - d.error := error + d.opcode := TLMessages.AccessAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := UInt(0) + d.error := error d } - def AccessAck(toSource: UInt, lgSize: UInt, data: UInt): TLBundleD = AccessAck(toSource, lgSize, data, Bool(false)) - def AccessAck(toSource: UInt, lgSize: UInt, data: UInt, error: Bool) = { + def AccessAck(a: TLBundleA, fromSink: UInt, data: UInt): TLBundleD = AccessAck(address(a), fromSink, a.source, a.size, data) + def AccessAck(a: TLBundleA, fromSink: UInt, data: UInt, error: Bool): TLBundleD = AccessAck(address(a), fromSink, a.source, a.size, data, error) + def AccessAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, data: UInt): TLBundleD = AccessAck(fromAddress, fromSink, toSource, lgSize, data, Bool(false)) + def AccessAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt, data: UInt, error: Bool) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.AccessAckData - d.param := UInt(0) - d.size := lgSize - d.source := toSource - d.sink := UInt(0) - d.data := data - d.error := error + d.opcode := TLMessages.AccessAckData + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := data + d.error := error d } - def HintAck(toSource: UInt, lgSize: UInt) = { + def HintAck(a: TLBundleA, sink: UInt = UInt(0)): TLBundleD = HintAck(address(a), sink, a.source, a.size) + def HintAck(fromAddress: UInt, fromSink: UInt, toSource: UInt, lgSize: UInt) = { val d = Wire(new TLBundleD(bundle)) - d.opcode := TLMessages.HintAck - d.param := UInt(0) - d.size := lgSize - d.source := toSource - d.sink := UInt(0) - d.data := UInt(0) - d.error := Bool(false) + d.opcode := TLMessages.HintAck + d.param := UInt(0) + d.size := lgSize + d.source := toSource + d.sink := fromSink + d.addr_lo := fromAddress + d.data := UInt(0) + d.error := Bool(false) d } } diff --git a/src/main/scala/uncore/tilelink2/Fragmenter.scala b/src/main/scala/uncore/tilelink2/Fragmenter.scala index cec91c59..6364f72a 100644 --- a/src/main/scala/uncore/tilelink2/Fragmenter.scala +++ b/src/main/scala/uncore/tilelink2/Fragmenter.scala @@ -57,7 +57,9 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten } // All managers must share a common FIFO domain (responses might end up interleaved) - val manager = node.edgesOut(0).manager + val edgeOut = node.edgesOut(0) + val edgeIn = node.edgesIn(0) + val manager = edgeOut.manager val managers = manager.managers val beatBytes = manager.beatBytes val fifoId = managers(0).fifoId @@ -137,9 +139,6 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val counterBits = log2Up(maxSize/beatBytes) val maxDownSize = if (alwaysMin) minSize else manager.maxTransfer - def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x) - def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) - // First, handle the return path val acknum = RegInit(UInt(0, width = counterBits)) val dOrig = Reg(UInt()) @@ -147,7 +146,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val dFirst = acknum === UInt(0) val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1) val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Ceil(maxDownSize)) - val dHasData = node.edgesOut(0).hasData(out.d.bits) + val dHasData = edgeOut.hasData(out.d.bits) // calculate new acknum val acknum_fragment = dFragnum << log2Ceil(minSize/beatBytes) @@ -189,7 +188,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) // If this is infront of a single manager, these become constants - val find = manager.find(in.a.bits.address) + val find = manager.find(edgeIn.address(in.a.bits)) val maxLgArithmetic = Mux1H(find, maxLgArithmetics) val maxLgLogical = Mux1H(find, maxLgLogicals) val maxLgGet = Mux1H(find, maxLgGets) @@ -225,7 +224,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten out.a.valid := in.a.valid in.a.ready := out.a.ready && !delay out.a.bits := in.a.bits - out.a.bits.address := in.a.bits.address | (~aFragnum << log2Ceil(minSize) & aOrigOH1) + 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/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index 1ae934d0..0222991e 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -28,13 +28,13 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f require (!supportClients || bce) if (supportManagers) { - val handleA = if (passthrough) !edgeOut.manager.supportsHint(in.a.bits.address) else Bool(true) + val handleA = if (passthrough) !edgeOut.manager.supportsHint(edgeIn.address(in.a.bits)) else Bool(true) val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint // Prioritize existing D traffic over HintAck in.d.valid := out.d.valid || (bypassD && in.a.valid) out.d.ready := in.d.ready - in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits.source, in.a.bits.size)) + in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits)) in.a.ready := Mux(bypassD, in.d.ready && !out.d.valid, out.a.ready) out.a.valid := in.a.valid && !bypassD @@ -56,7 +56,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f // Prioritize existing C traffic over HintAck out.c.valid := in.c.valid || (bypassC && in.b.valid) in.c.ready := out.c.ready - out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits.address, out.b.bits.size)) + out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits)) out.b.ready := Mux(bypassC, out.c.ready && !in.c.valid, in.b.ready) in.b.valid := out.b.valid && !bypassC diff --git a/src/main/scala/uncore/tilelink2/LazyModule.scala b/src/main/scala/uncore/tilelink2/LazyModule.scala index 83386f30..8504e711 100644 --- a/src/main/scala/uncore/tilelink2/LazyModule.scala +++ b/src/main/scala/uncore/tilelink2/LazyModule.scala @@ -50,7 +50,7 @@ object LazyModule } } -abstract class LazyModuleImp(val outer: LazyModule) extends Module +abstract class LazyModuleImp(outer: LazyModule) extends Module { // .module had better not be accessed while LazyModules are still being built! require (LazyModule.stack.isEmpty) diff --git a/src/main/scala/uncore/tilelink2/Legacy.scala b/src/main/scala/uncore/tilelink2/Legacy.scala index 91041169..d21503cb 100644 --- a/src/main/scala/uncore/tilelink2/Legacy.scala +++ b/src/main/scala/uncore/tilelink2/Legacy.scala @@ -104,14 +104,14 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa // Get rid of some unneeded muxes out.a.bits.source := source out.a.bits.data := data - out.a.bits.address := ~(~address | addressMask) + out.a.bits.addr_hi := ~(~address | addressMask) >> log2Ceil(tlDataBytes) // TL legacy does not support bus errors assert (!out.d.bits.error) // Recreate the beat address counter val beatCounter = RegInit(UInt(0, width = tlBeatAddrBits)) - when (out.d.fire() && out.d.bits.hasData() && out.d.bits.size === block) { + when (out.d.fire() && edge.hasData(out.d.bits) && out.d.bits.size === block) { beatCounter := beatCounter + UInt(1) } diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 8f974a8a..a74a6c20 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -19,20 +19,20 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val source_ok = edge.client.contains(bundle.source) - val is_aligned = edge.isAligned(bundle.address, bundle.size) - val mask = edge.fullMask(bundle.address | edge.lowAddress(bundle.mask), bundle.size) + val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) + val mask = edge.mask(edge.addr_lo(bundle.mask), bundle.size) when (bundle.opcode === TLMessages.Acquire) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) + assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) assert (source_ok, "'A' channel Acquire carries invalid source ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat" + extra) assert (is_aligned, "'A' channel Acquire address not aligned to size" + extra) assert (TLPermissions.isGrow(bundle.param), "'A' channel Acquire carries invalid grow param" + extra) - assert (bundle.mask === SInt(-1).asUInt, "'A' channel Acquire contains invalid mask" + extra) + assert (~bundle.mask === UInt(0), "'A' channel Acquire contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Get) { - assert (edge.manager.supportsGet(bundle.address, bundle.size), "'A' channel carries Get type unsupported by manager" + extra) + assert (edge.manager.supportsGet(edge.address(bundle), bundle.size), "'A' channel carries Get type unsupported by manager" + extra) assert (source_ok, "'A' channel Get carries invalid source ID" + extra) assert (is_aligned, "'A' channel Get address not aligned to size" + extra) assert (bundle.param === UInt(0), "'A' channel Get carries invalid param" + extra) @@ -40,7 +40,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.PutFullData) { - assert (edge.manager.supportsPutFull(bundle.address, bundle.size), "'A' channel carries PutFull type unsupported by manager" + extra) + assert (edge.manager.supportsPutFull(edge.address(bundle), bundle.size), "'A' channel carries PutFull type unsupported by manager" + extra) assert (source_ok, "'A' channel PutFull carries invalid source ID" + extra) assert (is_aligned, "'A' channel PutFull address not aligned to size" + extra) assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param" + extra) @@ -48,7 +48,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.PutPartialData) { - assert (edge.manager.supportsPutPartial(bundle.address, bundle.size), "'A' channel carries PutPartial type unsupported by manager" + extra) + assert (edge.manager.supportsPutPartial(edge.address(bundle), bundle.size), "'A' channel carries PutPartial type unsupported by manager" + extra) assert (source_ok, "'A' channel PutPartial carries invalid source ID" + extra) assert (is_aligned, "'A' channel PutPartial address not aligned to size" + extra) assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra) @@ -57,7 +57,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.ArithmeticData) { - assert (edge.manager.supportsArithmetic(bundle.address, bundle.size), "'A' channel carries Arithmetic type unsupported by manager" + extra) + assert (edge.manager.supportsArithmetic(edge.address(bundle), bundle.size), "'A' channel carries Arithmetic type unsupported by manager" + extra) assert (source_ok, "'A' channel Arithmetic carries invalid source ID" + extra) assert (is_aligned, "'A' channel Arithmetic address not aligned to size" + extra) assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param" + extra) @@ -65,7 +65,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.LogicalData) { - assert (edge.manager.supportsLogical(bundle.address, bundle.size), "'A' channel carries Logical type unsupported by manager" + extra) + assert (edge.manager.supportsLogical(edge.address(bundle), bundle.size), "'A' channel carries Logical type unsupported by manager" + extra) assert (source_ok, "'A' channel Logical carries invalid source ID" + extra) assert (is_aligned, "'A' channel Logical address not aligned to size" + extra) assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param" + extra) @@ -73,7 +73,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.Hint) { - assert (edge.manager.supportsHint(bundle.address), "'A' channel carries Hint type unsupported by manager" + extra) + assert (edge.manager.supportsHint(edge.address(bundle)), "'A' channel carries Hint type unsupported by manager" + extra) assert (source_ok, "'A' channel Hint carries invalid source ID" + extra) assert (is_aligned, "'A' channel Hint address not aligned to size" + extra) assert (bundle.mask === mask, "'A' channel Hint contains invalid mask" + extra) @@ -85,8 +85,8 @@ object TLMonitor // Reuse these subexpressions to save some firrtl lines val address_ok = edge.manager.contains(bundle.source) - val is_aligned = edge.isAligned(bundle.address, bundle.size) - val mask = edge.fullMask(bundle.address | edge.lowAddress(bundle.mask), bundle.size) + val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) + val mask = edge.mask(edge.addr_lo(bundle.mask), bundle.size) when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client" + extra) @@ -94,7 +94,7 @@ object TLMonitor assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat" + extra) assert (is_aligned, "'B' channel Probe address not aligned to size" + extra) assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param" + extra) - assert (bundle.mask === SInt(-1).asUInt, "'B' channel Probe contains invalid mask" + extra) + assert (~bundle.mask === UInt(0).asUInt, "'B' channel Probe contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Get) { @@ -150,12 +150,12 @@ object TLMonitor assert (TLMessages.isC(bundle.opcode), "'C' channel has invalid opcode" + extra) val source_ok = edge.client.contains(bundle.source) - val is_aligned = edge.isAligned(bundle.address, bundle.size) + val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) && edge.isLoAligned(bundle.addr_lo, bundle.size) val address_ok = edge.manager.contains(bundle.source) when (bundle.opcode === TLMessages.ProbeAck) { assert (address_ok, "'C' channel ProbeAck carries unmanaged address" + extra) - // source is ignored + assert (source_ok, "'C' channel ProbeAck carries invalid source ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAck smaller than a beat" + extra) assert (is_aligned, "'C' channel ProbeAck address not aligned to size" + extra) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAck carries invalid report param" + extra) @@ -164,7 +164,7 @@ object TLMonitor when (bundle.opcode === TLMessages.ProbeAckData) { assert (address_ok, "'C' channel ProbeAckData carries unmanaged address" + extra) - // source is ignored + assert (source_ok, "'C' channel ProbeAckData carries invalid source ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat" + extra) assert (is_aligned, "'C' channel ProbeAckData address not aligned to size" + extra) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param" + extra) @@ -172,7 +172,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.Release) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries Release type unsupported by manager" + extra) + assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'C' channel carries Release type unsupported by manager" + extra) assert (source_ok, "'C' channel Release carries invalid source ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat" + extra) assert (is_aligned, "'C' channel Release address not aligned to size" + extra) @@ -181,7 +181,7 @@ object TLMonitor } when (bundle.opcode === TLMessages.ReleaseData) { - assert (edge.manager.supportsAcquire(bundle.address, bundle.size), "'C' channel carries ReleaseData type unsupported by manager" + extra) + assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'C' channel carries ReleaseData type unsupported by manager" + extra) assert (source_ok, "'C' channel ReleaseData carries invalid source ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat" + extra) assert (is_aligned, "'C' channel ReleaseData address not aligned to size" + extra) @@ -191,21 +191,21 @@ object TLMonitor when (bundle.opcode === TLMessages.AccessAck) { assert (address_ok, "'C' channel AccessAck carries unmanaged address" + extra) - // source is ignored + assert (source_ok, "'C' channel AccessAck carries invalid source ID" + extra) assert (is_aligned, "'C' channel AccessAck address not aligned to size" + extra) assert (bundle.param === UInt(0), "'C' channel AccessAck carries invalid param" + extra) } when (bundle.opcode === TLMessages.AccessAckData) { assert (address_ok, "'C' channel AccessAckData carries unmanaged address" + extra) - // source is ignored + assert (source_ok, "'C' channel AccessAckData carries invalid source ID" + extra) assert (is_aligned, "'C' channel AccessAckData address not aligned to size" + extra) assert (bundle.param === UInt(0), "'C' channel AccessAckData carries invalid param" + extra) } when (bundle.opcode === TLMessages.HintAck) { assert (address_ok, "'C' channel HintAck carries unmanaged address" + extra) - // source is ignored + assert (source_ok, "'C' channel HintAck carries invalid source ID" + extra) assert (is_aligned, "'C' channel HintAck address not aligned to size" + extra) assert (bundle.param === UInt(0), "'C' channel HintAck carries invalid param" + extra) assert (!bundle.error, "'C' channel HintAck carries an error" + extra) @@ -216,11 +216,13 @@ object TLMonitor assert (TLMessages.isD(bundle.opcode), "'D' channel has invalid opcode" + extra) val source_ok = edge.client.contains(bundle.source) + val is_aligned = edge.isLoAligned(bundle.addr_lo, bundle.size) val sink_ok = edge.manager.containsById(bundle.sink) when (bundle.opcode === TLMessages.ReleaseAck) { assert (source_ok, "'D' channel ReleaseAck carries invalid source ID" + extra) - // sink is ignored + assert (is_aligned, "'D' channel ReleaseAck address not aligned to size" + extra) + assert (sink_ok, "'D' channel ReleaseAck carries invalid sink ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel ReleaseAck smaller than a beat" + extra) assert (bundle.param === UInt(0), "'D' channel ReleaseeAck carries invalid param" + extra) assert (!bundle.error, "'D' channel ReleaseAck carries an error" + extra) @@ -228,6 +230,7 @@ object TLMonitor when (bundle.opcode === TLMessages.Grant) { assert (source_ok, "'D' channel Grant carries invalid source ID" + extra) + assert (is_aligned, "'D' channel Grant address not aligned to size" + extra) assert (sink_ok, "'D' channel Grant carries invalid sink ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel Grant smaller than a beat" + extra) assert (TLPermissions.isCap(bundle.param), "'D' channel Grant carries invalid cap param" + extra) @@ -235,6 +238,7 @@ object TLMonitor when (bundle.opcode === TLMessages.GrantData) { assert (source_ok, "'D' channel GrantData carries invalid source ID" + extra) + assert (is_aligned, "'D' channel GrantData address not aligned to size" + extra) assert (sink_ok, "'D' channel GrantData carries invalid sink ID" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'D' channel GrantData smaller than a beat" + extra) assert (TLPermissions.isCap(bundle.param), "'D' channel GrantData carries invalid cap param" + extra) @@ -242,21 +246,24 @@ object TLMonitor when (bundle.opcode === TLMessages.AccessAck) { assert (source_ok, "'D' channel AccessAck carries invalid source ID" + extra) - // sink is ignored + assert (is_aligned, "'D' channel AccessAck address not aligned to size" + extra) + assert (sink_ok, "'D' channel AccessAck carries invalid sink ID" + extra) // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAck carries invalid param" + extra) } when (bundle.opcode === TLMessages.AccessAckData) { assert (source_ok, "'D' channel AccessAckData carries invalid source ID" + extra) - // sink is ignored + assert (is_aligned, "'D' channel AccessAckData address not aligned to size" + extra) + assert (sink_ok, "'D' channel AccessAckData carries invalid sink ID" + extra) // size is ignored assert (bundle.param === UInt(0), "'D' channel AccessAckData carries invalid param" + extra) } when (bundle.opcode === TLMessages.HintAck) { assert (source_ok, "'D' channel HintAck carries invalid source ID" + extra) - // sink is ignored + assert (is_aligned, "'D' channel HintAck address not aligned to size" + extra) + assert (sink_ok, "'D' channel HintAck carries invalid sink ID" + extra) // size is ignored assert (bundle.param === UInt(0), "'D' channel HintAck carries invalid param" + extra) assert (!bundle.error, "'D' channel HintAck carries an error" + extra) @@ -281,13 +288,13 @@ object TLMonitor val param = Reg(UInt()) val size = Reg(UInt()) val source = Reg(UInt()) - val address = Reg(UInt()) + val addr_hi = Reg(UInt()) when (a.valid && counter =/= UInt(0)) { assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation" + extra) assert (a.bits.param === param, "'A' channel param changed within multibeat operation" + extra) assert (a.bits.size === size, "'A' channel size changed within multibeat operation" + extra) assert (a.bits.source === source, "'A' channel source changed within multibeat operation" + extra) - assert (a.bits.address=== address,"'A' channel address changed with multibeat operation" + extra) + assert (a.bits.addr_hi=== addr_hi,"'A' channel addr_hi changed with multibeat operation" + extra) } when (a.fire()) { counter := counter - UInt(1) @@ -297,7 +304,7 @@ object TLMonitor param := a.bits.param size := a.bits.size source := a.bits.source - address := a.bits.address + addr_hi := a.bits.addr_hi } } } @@ -308,13 +315,13 @@ object TLMonitor val param = Reg(UInt()) val size = Reg(UInt()) val source = Reg(UInt()) - val address = Reg(UInt()) + val addr_hi = Reg(UInt()) when (b.valid && counter =/= UInt(0)) { assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation" + extra) assert (b.bits.param === param, "'B' channel param changed within multibeat operation" + extra) assert (b.bits.size === size, "'B' channel size changed within multibeat operation" + extra) assert (b.bits.source === source, "'B' channel source changed within multibeat operation" + extra) - assert (b.bits.address=== address,"'B' channel address changed with multibeat operation" + extra) + assert (b.bits.addr_hi=== addr_hi,"'B' channel addr_hi changed with multibeat operation" + extra) } when (b.fire()) { counter := counter - UInt(1) @@ -324,7 +331,7 @@ object TLMonitor param := b.bits.param size := b.bits.size source := b.bits.source - address := b.bits.address + addr_hi := b.bits.addr_hi } } } @@ -335,13 +342,15 @@ object TLMonitor val param = Reg(UInt()) val size = Reg(UInt()) val source = Reg(UInt()) - val address = Reg(UInt()) + val addr_hi = Reg(UInt()) + val addr_lo = Reg(UInt()) when (c.valid && counter =/= UInt(0)) { assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation" + extra) assert (c.bits.param === param, "'C' channel param changed within multibeat operation" + extra) assert (c.bits.size === size, "'C' channel size changed within multibeat operation" + extra) assert (c.bits.source === source, "'C' channel source changed within multibeat operation" + extra) - assert (c.bits.address=== address,"'C' channel address changed with multibeat operation" + extra) + assert (c.bits.addr_hi=== addr_hi,"'C' channel addr_hi changed with multibeat operation" + extra) + assert (c.bits.addr_lo=== addr_lo,"'C' channel addr_lo changed with multibeat operation" + extra) } when (c.fire()) { counter := counter - UInt(1) @@ -351,7 +360,8 @@ object TLMonitor param := c.bits.param size := c.bits.size source := c.bits.source - address := c.bits.address + addr_hi := c.bits.addr_hi + addr_lo := c.bits.addr_lo } } } @@ -363,12 +373,14 @@ object TLMonitor val size = Reg(UInt()) val source = Reg(UInt()) val sink = Reg(UInt()) + val addr_lo = Reg(UInt()) when (d.valid && counter =/= UInt(0)) { assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation" + extra) assert (d.bits.param === param, "'D' channel param changed within multibeat operation" + extra) assert (d.bits.size === size, "'D' channel size changed within multibeat operation" + extra) assert (d.bits.source === source, "'D' channel source changed within multibeat operation" + extra) assert (d.bits.sink === sink, "'D' channel sink changed with multibeat operation" + extra) + assert (d.bits.addr_lo=== addr_lo,"'C' channel addr_lo changed with multibeat operation" + extra) } when (d.fire()) { counter := counter - UInt(1) @@ -379,6 +391,7 @@ object TLMonitor size := d.bits.size source := d.bits.source sink := d.bits.sink + addr_lo := d.bits.addr_lo } } } diff --git a/src/main/scala/uncore/tilelink2/Narrower.scala b/src/main/scala/uncore/tilelink2/Narrower.scala index 4f0401c3..599386d9 100644 --- a/src/main/scala/uncore/tilelink2/Narrower.scala +++ b/src/main/scala/uncore/tilelink2/Narrower.scala @@ -19,25 +19,25 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule val out = node.bundleOut } - val edge = node.edgesOut(0) - val outerBeatBytes = edge.manager.beatBytes + val edgeOut = node.edgesOut(0) + val edgeIn = node.edgesIn(0) + val outerBeatBytes = edgeOut.manager.beatBytes require (outerBeatBytes < innerBeatBytes) val ratio = innerBeatBytes / outerBeatBytes - val bce = edge.manager.anySupportAcquire && edge.client.anySupportProbe + val bce = edgeOut.manager.anySupportAcquire && edgeIn.client.anySupportProbe - def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) 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) } + def split(edge: TLEdge, in: TLDataChannel, fire: Bool): (Bool, UInt, UInt) = { + val dataSlices = Vec.tabulate (ratio) { i => edge.data(in)((i+1)*outerBeatBytes*8-1, i*outerBeatBytes*8) } + val maskSlices = Vec.tabulate (ratio) { i => edge.mask(in)((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 = edge.hasData(in) // decoded_size = 1111 (for smallest), 0101, 0001 (for largest) - val sizeOH1 = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) + val sizeOH1 = UIntToOH1(edge.size(in), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) val decoded_size = Seq.tabulate(ratio) { i => trailingZeros(i).map(!sizeOH1(_)).getOrElse(Bool(true)) } val first = filter(ratio-1) @@ -56,12 +56,12 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule } } - def merge(in: HasTLData, fire: Bool): (Bool, UInt) = { + def merge(edge: TLEdge, in: TLDataChannel, fire: Bool): (Bool, UInt) = { val count = RegInit(UInt(0, width = log2Ceil(ratio))) val rdata = Reg(UInt(width = (ratio-1)*outerBeatBytes*8)) - val data = Cat(in.data(), rdata) + val data = Cat(edge.data(in), rdata) val first = count === UInt(0) - val limit = UIntToOH1(in.size(), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) + val limit = UIntToOH1(edge.size(in), log2Ceil(innerBeatBytes)) >> log2Ceil(outerBeatBytes) val last = count === limit || !edge.hasData(in) when (fire) { @@ -82,21 +82,22 @@ class TLNarrower(innerBeatBytes: Int) extends LazyModule if (edge.staticHasData(in) == Some(false)) { (Bool(true), UInt(0)) } else { - (last, mux(in.size())) + (last, mux(edge.size(in))) } } val in = io.in(0) val out = io.out(0) - val (alast, adata, amask) = split(in.a.bits, out.a.fire()) + val (alast, adata, amask) = split(edgeIn, 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.addr_hi := Cat(in.a.bits.addr_hi, edgeIn.addr_lo(in.a.bits) >> log2Ceil(outerBeatBytes)) out.a.bits.data := adata out.a.bits.mask := amask - val (dlast, ddata) = merge(out.d.bits, out.d.fire()) + val (dlast, ddata) = merge(edgeOut, out.d.bits, out.d.fire()) out.d.ready := in.d.ready || !dlast in.d.valid := out.d.valid && dlast in.d.bits := out.d.bits diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 0fb438ab..355fdb3a 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -286,23 +286,25 @@ case class TLClientPortParameters(clients: Seq[TLClientParameters]) { } case class TLBundleParameters( - addressBits: Int, - dataBits: Int, - sourceBits: Int, - sinkBits: Int, - sizeBits: Int) + addrHiBits: Int, + dataBits: Int, + sourceBits: Int, + sinkBits: Int, + sizeBits: Int) { // Chisel has issues with 0-width wires - require (addressBits >= 1) - require (dataBits >= 1) + require (addrHiBits >= 1) + require (dataBits >= 8) require (sourceBits >= 1) require (sinkBits >= 1) require (sizeBits >= 1) require (isPow2(dataBits)) - + + val addrLoBits = log2Up(dataBits/8) + def union(x: TLBundleParameters) = TLBundleParameters( - max(addressBits, x.addressBits), + max(addrHiBits, x.addrHiBits), max(dataBits, x.dataBits), max(sourceBits, x.sourceBits), max(sinkBits, x.sinkBits), @@ -320,7 +322,7 @@ case class TLEdgeParameters( require (maxTransfer >= manager.beatBytes) val bundle = TLBundleParameters( - addressBits = log2Up(manager.maxAddress + 1), + addrHiBits = log2Up(manager.maxAddress + 1) - log2Up(manager.beatBytes), dataBits = manager.beatBytes * 8, sourceBits = log2Up(client.endSourceId), sinkBits = log2Up(manager.endSinkId), diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index e39788e4..e455efda 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -20,14 +20,20 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB val a = bundleIn(0).a val d = bundleIn(0).d val edge = edgesIn(0) - - val params = RegMapperParams(log2Up(address.mask+1), beatBytes, edge.bundle.sourceBits + edge.bundle.sizeBits) + + // Please forgive me ... + val baseEnd = 0 + val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd) + val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd) + val (addrLoEnd, addrLoOff) = (log2Ceil(beatBytes) + sourceEnd, sourceEnd) + + val params = RegMapperParams(log2Up(address.mask+1), beatBytes, addrLoEnd) val in = Wire(Decoupled(new RegMapperInput(params))) in.bits.read := a.bits.opcode === TLMessages.Get - in.bits.index := a.bits.address >> log2Ceil(beatBytes) + in.bits.index := a.bits.addr_hi in.bits.data := a.bits.data in.bits.mask := a.bits.mask - in.bits.extra := Cat(a.bits.source, a.bits.size) + in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size) // Invoke the register map builder val (endIndex, out) = RegMapper(beatBytes, concurrency, in, mapping:_*) @@ -41,8 +47,13 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB d.valid := out.valid out.ready := d.ready - val sizeBits = edge.bundle.sizeBits - d.bits := edge.AccessAck(out.bits.extra >> sizeBits, out.bits.extra(sizeBits-1, 0)) + // We must restore the size and addr_lo to enable width adapters to work + d.bits := edge.AccessAck( + fromAddress = out.bits.extra(addrLoEnd-1, addrLoOff), + fromSink = UInt(0), // our unique sink id + toSource = out.bits.extra(sourceEnd-1, sourceOff), + lgSize = out.bits.extra(sizeEnd-1, sizeOff)) + // avoid a Mux on the data bus by manually overriding two fields d.bits.data := out.bits.data d.bits.opcode := Mux(out.bits.read, TLMessages.AccessAckData, TLMessages.AccessAck) diff --git a/src/main/scala/uncore/tilelink2/SRAM.scala b/src/main/scala/uncore/tilelink2/SRAM.scala index 28639223..07d107df 100644 --- a/src/main/scala/uncore/tilelink2/SRAM.scala +++ b/src/main/scala/uncore/tilelink2/SRAM.scala @@ -24,10 +24,10 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule 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 - (beatBytes-1)) + val mask = bigBits(address.mask >> log2Ceil(beatBytes)) val in = io.in(0) - val addrBits = (mask zip in.a.bits.address.toBools).filter(_._1).map(_._2) + val addrBits = (mask zip in.a.bits.addr_hi.toBools).filter(_._1).map(_._2) val memAddress = Cat(addrBits.reverse) val mem = SeqMem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8))) @@ -35,6 +35,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule val d_read = Reg(Bool()) val d_size = Reg(UInt()) val d_source = Reg(UInt()) + val d_addr = Reg(UInt()) val d_data = Wire(UInt()) // Flow control @@ -43,7 +44,8 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule in.d.valid := d_full in.a.ready := in.d.ready || !d_full - in.d.bits := node.edgesIn(0).AccessAck(d_source, d_size) + val edge = node.edgesIn(0) + in.d.bits := edge.AccessAck(d_addr, UInt(0), d_source, d_size) // avoid data-bus Mux in.d.bits.data := d_data in.d.bits.opcode := Mux(d_read, TLMessages.AccessAckData, TLMessages.AccessAck) @@ -56,6 +58,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule d_read := read d_size := in.a.bits.size d_source := in.a.bits.source + d_addr := edge.addr_lo(in.a.bits) when (read) { rdata := mem.read(memAddress) } .otherwise { diff --git a/src/main/scala/uncore/tilelink2/TLNodes.scala b/src/main/scala/uncore/tilelink2/TLNodes.scala index f9685a0a..88a27042 100644 --- a/src/main/scala/uncore/tilelink2/TLNodes.scala +++ b/src/main/scala/uncore/tilelink2/TLNodes.scala @@ -23,10 +23,6 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters]) TLMonitor.legalize(bo, eo, bi, ei) bi <> bo - val mask = UInt(ei.manager.beatBytes - 1) - bi.a.bits.address := ~(mask | ~bo.a.bits.address) - bo.b.bits.address := ~(mask | ~bi.b.bits.address) - bi.c.bits.address := ~(mask | ~bo.c.bits.address) } } diff --git a/src/main/scala/uncore/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala index e37e3134..9302ea10 100644 --- a/src/main/scala/uncore/tilelink2/Xbar.scala +++ b/src/main/scala/uncore/tilelink2/Xbar.scala @@ -145,11 +145,11 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend in(i).e.ready := Mux1C(grantedEIO(i), out.map(_.e.ready)) } - val requestAIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.a.valid && o.manager.contains(i.a.bits.address) }) }) - val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i .contains(o.b.bits.source) }) }) - val requestCIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.c.valid && o.manager.contains(i.c.bits.address) }) }) - val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.d.bits.source) }) }) - val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o .contains(i.e.bits.sink) }) }) + val requestAIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.a.valid && o.manager.contains(o.address(i.a.bits)) }) }) + val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i .contains(o.b.bits.source) }) }) + val requestCIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.c.valid && o.manager.contains(o.address(i.c.bits)) }) }) + val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.d.bits.source) }) }) + val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o .contains(i.e.bits.sink) }) }) val beatsA = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) }) val beatsB = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) }) diff --git a/src/main/scala/uncore/tilelink2/package.scala b/src/main/scala/uncore/tilelink2/package.scala index 501fdccb..621fc288 100644 --- a/src/main/scala/uncore/tilelink2/package.scala +++ b/src/main/scala/uncore/tilelink2/package.scala @@ -5,4 +5,6 @@ import Chisel._ package object tilelink2 { type TLBaseNode = BaseNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] + def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x) + def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) }