From f2e438833c3023b31d30bc32616de2e9e5e5790f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 14:30:19 -0700 Subject: [PATCH 1/7] tilelink2 Nodes: generalize a node into inner and outer halves This lets us create nodes which transform from one bus to another. --- .../scala/uncore/tilelink2/IntNodes.scala | 19 +- src/main/scala/uncore/tilelink2/Nodes.scala | 162 ++++++++++++------ .../scala/uncore/tilelink2/Parameters.scala | 12 +- src/main/scala/uncore/tilelink2/TLNodes.scala | 17 +- 4 files changed, 128 insertions(+), 82 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/IntNodes.scala b/src/main/scala/uncore/tilelink2/IntNodes.scala index 5ddfcd5b..acf1cdc8 100644 --- a/src/main/scala/uncore/tilelink2/IntNodes.scala +++ b/src/main/scala/uncore/tilelink2/IntNodes.scala @@ -23,13 +23,13 @@ object IntRange case class IntSourceParameters( range: IntRange, - nodePath: Seq[IntBaseNode] = Seq()) + nodePath: Seq[RootNode] = Seq()) { val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") } case class IntSinkParameters( - nodePath: Seq[IntBaseNode] = Seq()) + nodePath: Seq[RootNode] = Seq()) { val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") } @@ -49,8 +49,8 @@ case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters) object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]] { - def edgeO(po: IntSourcePortParameters, pi: IntSinkPortParameters): IntEdge = IntEdge(po, pi) - def edgeI(po: IntSourcePortParameters, pi: IntSinkPortParameters): IntEdge = IntEdge(po, pi) + def edgeO(pd: IntSourcePortParameters, pu: IntSinkPortParameters): IntEdge = IntEdge(pd, pu) + def edgeI(pd: IntSourcePortParameters, pu: IntSinkPortParameters): IntEdge = IntEdge(pd, pu) def bundleO(eo: Seq[IntEdge]): Vec[Vec[Bool]] = { if (eo.isEmpty) Vec(0, Vec(0, Bool())) else Vec(eo.size, Vec(eo.map(_.source.num).max, Bool())) @@ -60,18 +60,17 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In Vec(ei.size, Vec(ei.map(_.source.num).max, Bool())).flip } - def connect(bo: => Vec[Bool], eo: => IntEdge, bi: => Vec[Bool], ei: => IntEdge)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { + def connect(bo: => Vec[Bool], bi: => Vec[Bool], ei: => IntEdge)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { (None, () => { - require (eo == ei) // Cannot use bulk connect, because the widths could differ (bo zip bi) foreach { case (o, i) => i := o } }) } - override def mixO(po: IntSourcePortParameters, node: IntBaseNode): IntSourcePortParameters = - po.copy(sources = po.sources.map { s => s.copy (nodePath = node +: s.nodePath) }) - override def mixI(pi: IntSinkPortParameters, node: IntBaseNode): IntSinkPortParameters = - pi.copy(sinks = pi.sinks.map { s => s.copy (nodePath = node +: s.nodePath) }) + override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters = + pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) }) + override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters = + pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) }) } case class IntIdentityNode() extends IdentityNode(IntImp) diff --git a/src/main/scala/uncore/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala index 99e13158..93c89e13 100644 --- a/src/main/scala/uncore/tilelink2/Nodes.scala +++ b/src/main/scala/uncore/tilelink2/Nodes.scala @@ -6,22 +6,32 @@ import Chisel._ import scala.collection.mutable.ListBuffer import chisel3.internal.sourceinfo.SourceInfo -// PI = PortInputParameters -// PO = PortOutputParameters -// EI = EdgeInput -// EO = EdgeOutput -abstract class NodeImp[PO, PI, EO, EI, B <: Data] +// DI = Downwards flowing Parameters received on the inner side of the node +// UI = Upwards flowing Parameters generated by the inner side of the node +// EI = Edge Parameters describing a connection on the inner side of the node +// BI = Bundle type used when connecting to the inner side of the node +trait InwardNodeImp[DI, UI, EI, BI <: Data] { - 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): (Option[LazyModule], () => Unit) - // If you want to track parameters as they flow through nodes, overload these: - def mixO(po: PO, node: BaseNode[PO, PI, EO, EI, B]): PO = po - def mixI(pi: PI, node: BaseNode[PO, PI, EO, EI, B]): PI = pi + def edgeI(pd: DI, pu: UI): EI + def bundleI(ei: Seq[EI]): Vec[BI] + def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu + def connect(bo: => BI, bi: => BI, e: => EI)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) } +// DO = Downwards flowing Parameters generated by the outner side of the node +// UO = Upwards flowing Parameters received on the outner side of the node +// EO = Edge Parameters describing a connection on the outer side of the node +// BO = Bundle type used when connecting to the outer side of the node +trait OutwardNodeImp[DO, UO, EO, BO <: Data] +{ + def edgeO(pd: DO, pu: UO): EO + def bundleO(eo: Seq[EO]): Vec[BO] + def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd +} + +abstract class NodeImp[D, U, EO, EI, B <: Data] + extends Object with InwardNodeImp[D, U, EI, B] with OutwardNodeImp[D, U, EO, B] + abstract class RootNode { // You cannot create a Node outside a LazyModule! @@ -39,87 +49,125 @@ abstract class RootNode protected[tilelink2] def inputs: Seq[RootNode] } -class BaseNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])( - private val oFn: (Int, Seq[PO]) => Seq[PO], - private val iFn: (Int, Seq[PI]) => Seq[PI], - private val numPO: Range.Inclusive, - private val numPI: Range.Inclusive) extends RootNode +trait InwardNode[DI, UI, BI <: Data] extends RootNode { - // At least 0 ports must be supported - require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}") + protected[tilelink2] val numPI: Range.Inclusive require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}") - require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}") require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}") - val noOs = numPO.size == 1 && numPO.contains(0) - val noIs = numPI.size == 1 && numPI.contains(0) - - private val accPO = ListBuffer[(Int, BaseNode[PO, PI, EO, EI, B])]() - private val accPI = ListBuffer[(Int, BaseNode[PO, PI, EO, EI, B])]() - private var oRealized = false + private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI])]() private var iRealized = false - private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}") + protected[tilelink2] def iPushed = accPI.size + protected[tilelink2] def iPush(index: Int, node: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo) { + val info = sourceLine(sourceInfo, " at ", "") + val noIs = numPI.size == 1 && numPI.contains(0) + require (!noIs, s"${name}${lazyModule.line} was incorrectly connected as a sink" + info) + require (!iRealized, s"${name}${lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info) + accPI += ((index, node)) + } + private def reqI() = require(numPI.contains(accPI.size), s"${name} has ${accPI.size} inputs, expected ${numPI}${lazyModule.line}") - protected def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}") + protected[tilelink2] lazy val iPorts = { iRealized = true; reqI(); accPI.result() } - private lazy val oPorts = { oRealized = true; reqO(); accPO.result() } - private lazy val iPorts = { iRealized = true; reqI(); accPI.result() } + protected[tilelink2] val iParams: Seq[UI] + protected[tilelink2] def iConnect: Vec[BI] +} +trait OutwardNode[DO, UO, BO <: Data] extends RootNode +{ + protected[tilelink2] val numPO: Range.Inclusive + require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}") + require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}") + + private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO])]() + private var oRealized = false + + protected[tilelink2] def oPushed = accPO.size + protected[tilelink2] def oPush(index: Int, node: InwardNode [DO, UO, BO])(implicit sourceInfo: SourceInfo) { + val info = sourceLine(sourceInfo, " at ", "") + val noOs = numPO.size == 1 && numPO.contains(0) + require (!noOs, s"${name}${lazyModule.line} was incorrectly connected as a source" + info) + require (!oRealized, s"${name}${lazyModule.line} was incorrectly connected as a source after it's .module was used" + info) + accPO += ((index, node)) + } + + private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}") + protected[tilelink2] lazy val oPorts = { oRealized = true; reqO(); accPO.result() } + + protected[tilelink2] val oParams: Seq[DO] + protected[tilelink2] def oConnect: Vec[BO] +} + +class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( + inner: InwardNodeImp [DI, UI, EI, BI], + outer: OutwardNodeImp[DO, UO, EO, BO])( + private val dFn: (Int, Seq[DI]) => Seq[DO], + private val uFn: (Int, Seq[UO]) => Seq[UI], + protected[tilelink2] val numPO: Range.Inclusive, + protected[tilelink2] val numPI: Range.Inclusive) + extends RootNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] +{ + // meta-data for printing the node graph protected[tilelink2] def outputs = oPorts.map(_._2) protected[tilelink2] def inputs = iPorts.map(_._2) - private lazy val oParams : Seq[PO] = { - val o = oFn(oPorts.size, iPorts.map{ case (i, n) => n.oParams(i) }) + private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}") + protected[tilelink2] lazy val oParams: Seq[DO] = { + val o = dFn(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) }) reqE(oPorts.size, o.size) - o.map(imp.mixO(_, this)) + o.map(outer.mixO(_, this)) } - private lazy val iParams : Seq[PI] = { - val i = iFn(iPorts.size, oPorts.map{ case (o, n) => n.iParams(o) }) + protected[tilelink2] lazy val iParams: Seq[UI] = { + val i = uFn(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) }) reqE(i.size, iPorts.size) - i.map(imp.mixI(_, this)) + i.map(inner.mixI(_, this)) } - lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => imp.edgeO(o, n.iParams(i)) } - lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => imp.edgeI(n.oParams(o), i) } + lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => outer.edgeO(o, n.iParams(i)) } + lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => inner.edgeI(n.oParams(o), i) } - lazy val bundleOut = imp.bundleO(edgesOut) - lazy val bundleIn = imp.bundleI(edgesIn) + lazy val bundleOut = outer.bundleO(edgesOut) + lazy val bundleIn = inner.bundleI(edgesIn) - def connectOut = bundleOut - def connectIn = bundleIn + def oConnect = bundleOut + def iConnect = bundleIn - def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo): Option[LazyModule] = { + // connects the outward part of a node with the inward part of this node + def := (y: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = { val x = this // x := y val info = sourceLine(sourceInfo, " at ", "") require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info) - require (!y.noOs, s"${y.name}${y.lazyModule.line} was incorrectly connected as a source" + info) - require (!y.oRealized, s"${y.name}${y.lazyModule.line} was incorrectly connected as a source after it's .module was used" + info) - require (!x.noIs, s"${x.name}${x.lazyModule.line} was incorrectly connected as a sink" + info) - require (!x.iRealized, s"${x.name}${x.lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info) - val i = x.accPI.size - val o = y.accPO.size - y.accPO += ((i, x)) - x.accPI += ((o, y)) - val (out, binding) = imp.connect(y.connectOut(o), y.edgesOut(o), x.connectIn(i), x.edgesIn(i)) + val i = x.iPushed + val o = y.oPushed + y.oPush(i, x) + x.iPush(o, y) + val (out, binding) = inner.connect(y.oConnect(o), x.iConnect(i), x.edgesIn(i)) LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings out } } +class BaseNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( + oFn: (Int, Seq[D]) => Seq[D], + iFn: (Int, Seq[U]) => Seq[U], + numPO: Range.Inclusive, + numPI: Range.Inclusive) + extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI) + class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends BaseNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999) class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) { - override def connectOut = bundleOut - override def connectIn = bundleOut + override def oConnect = bundleOut + override def iConnect = bundleOut } class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) { - override def connectOut = bundleIn - override def connectIn = bundleIn + override def oConnect = bundleIn + override def iConnect = bundleIn } class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index d226ef89..463ac2e3 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -146,10 +146,10 @@ object AddressSet case class TLManagerParameters( address: Seq[AddressSet], - sinkId: IdRange = IdRange(0, 1), - regionType: RegionType.T = RegionType.GET_EFFECTS, - executable: Boolean = false, // processor can execute from this memory - nodePath: Seq[TLBaseNode] = Seq(), + sinkId: IdRange = IdRange(0, 1), + regionType: RegionType.T = RegionType.GET_EFFECTS, + executable: Boolean = false, // processor can execute from this memory + nodePath: Seq[RootNode] = Seq(), // Supports both Acquire+Release+Finish of these sizes supportsAcquire: TransferSizes = TransferSizes.none, supportsArithmetic: TransferSizes = TransferSizes.none, @@ -292,8 +292,8 @@ case class TLManagerPortParameters( } case class TLClientParameters( - sourceId: IdRange = IdRange(0,1), - nodePath: Seq[TLBaseNode] = Seq(), + sourceId: IdRange = IdRange(0,1), + nodePath: Seq[RootNode] = Seq(), // Supports both Probe+Grant of these sizes supportsProbe: TransferSizes = TransferSizes.none, supportsArithmetic: TransferSizes = TransferSizes.none, diff --git a/src/main/scala/uncore/tilelink2/TLNodes.scala b/src/main/scala/uncore/tilelink2/TLNodes.scala index 2ab3738d..84c1405e 100644 --- a/src/main/scala/uncore/tilelink2/TLNodes.scala +++ b/src/main/scala/uncore/tilelink2/TLNodes.scala @@ -8,8 +8,8 @@ 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 edgeO(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(pd, pu) + def edgeI(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(pd, pu) def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = { require (!eo.isEmpty) Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_)))) @@ -19,19 +19,18 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip } - def connect(bo: => TLBundle, eo: => TLEdgeOut, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { - val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => eo, sourceInfo)) + def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { + val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => ei, sourceInfo)) (Some(monitor), () => { - require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters]) bi <> bo monitor.module.io.in := TLBundleSnoop(bo) }) } - override def mixO(po: TLClientPortParameters, node: TLBaseNode): TLClientPortParameters = - po.copy(clients = po.clients.map { c => c.copy (nodePath = node +: c.nodePath) }) - override def mixI(pi: TLManagerPortParameters, node: TLBaseNode): TLManagerPortParameters = - pi.copy(managers = pi.managers.map { m => m.copy (nodePath = node +: m.nodePath) }) + override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters = + pd.copy(clients = pd.clients.map { c => c.copy (nodePath = node +: c.nodePath) }) + override def mixI(pu: TLManagerPortParameters, node: InwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLManagerPortParameters = + pu.copy(managers = pu.managers.map { m => m.copy (nodePath = node +: m.nodePath) }) } case class TLIdentityNode() extends IdentityNode(TLImp) From cfdb8ca797c7d56fd6f151b6e8d3a10888a158d8 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 14:33:54 -0700 Subject: [PATCH 2/7] tilelink2 LazyModule: remove obsolete connect method --- src/main/scala/uncore/tilelink2/LazyModule.scala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/LazyModule.scala b/src/main/scala/uncore/tilelink2/LazyModule.scala index 87398092..8f4f0949 100644 --- a/src/main/scala/uncore/tilelink2/LazyModule.scala +++ b/src/main/scala/uncore/tilelink2/LazyModule.scala @@ -16,11 +16,6 @@ abstract class LazyModule 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 <: Data](edges: (BaseNode[PO, PI, EO, EI, B], BaseNode[PO, PI, EO, EI, B])*)(implicit sourceInfo: SourceInfo) = { - edges.foreach { case (source, sink) => sink := source } - } - def name = getClass.getName.split('.').last def line = sourceLine(info) From 754fcf98312b55cce6d718b89dc2f3a1445de6c1 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 14:33:10 -0700 Subject: [PATCH 3/7] tilelink2: rename BaseNode to SimpleNode --- src/main/scala/uncore/tilelink2/Nodes.scala | 10 +++++----- src/main/scala/uncore/tilelink2/package.scala | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala index 93c89e13..d65339df 100644 --- a/src/main/scala/uncore/tilelink2/Nodes.scala +++ b/src/main/scala/uncore/tilelink2/Nodes.scala @@ -148,7 +148,7 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( } } -class BaseNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( +class SimpleNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( oFn: (Int, Seq[D]) => Seq[D], iFn: (Int, Seq[U]) => Seq[U], numPO: Range.Inclusive, @@ -156,7 +156,7 @@ class BaseNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI) class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) - extends BaseNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999) + extends SimpleNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999) class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp) { @@ -171,20 +171,20 @@ class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) exte } class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1) - extends BaseNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0) + extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0) { require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}") } class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1) - extends BaseNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num) + extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num) { require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}") } class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) (oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive) - extends BaseNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI) + extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI) { require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}") require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}") diff --git a/src/main/scala/uncore/tilelink2/package.scala b/src/main/scala/uncore/tilelink2/package.scala index 232e491d..b0dd6338 100644 --- a/src/main/scala/uncore/tilelink2/package.scala +++ b/src/main/scala/uncore/tilelink2/package.scala @@ -5,8 +5,8 @@ import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInf package object tilelink2 { - type TLBaseNode = BaseNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] - type IntBaseNode = BaseNode[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]] + type TLBaseNode = SimpleNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] + type IntBaseNode = SimpleNode[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]] 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) def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None From 02ce8c2ca4b4e5f4e1a48e2c2bdce4fe945a1390 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 14:34:52 -0700 Subject: [PATCH 4/7] tilelink2 Nodes: rename RootNode => BaseNode --- src/main/scala/uncore/tilelink2/IntNodes.scala | 4 ++-- src/main/scala/uncore/tilelink2/LazyModule.scala | 2 +- src/main/scala/uncore/tilelink2/Nodes.scala | 12 ++++++------ src/main/scala/uncore/tilelink2/Parameters.scala | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/IntNodes.scala b/src/main/scala/uncore/tilelink2/IntNodes.scala index acf1cdc8..0d46300c 100644 --- a/src/main/scala/uncore/tilelink2/IntNodes.scala +++ b/src/main/scala/uncore/tilelink2/IntNodes.scala @@ -23,13 +23,13 @@ object IntRange case class IntSourceParameters( range: IntRange, - nodePath: Seq[RootNode] = Seq()) + nodePath: Seq[BaseNode] = Seq()) { val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") } case class IntSinkParameters( - nodePath: Seq[RootNode] = Seq()) + nodePath: Seq[BaseNode] = Seq()) { val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") } diff --git a/src/main/scala/uncore/tilelink2/LazyModule.scala b/src/main/scala/uncore/tilelink2/LazyModule.scala index 8f4f0949..f85af894 100644 --- a/src/main/scala/uncore/tilelink2/LazyModule.scala +++ b/src/main/scala/uncore/tilelink2/LazyModule.scala @@ -9,7 +9,7 @@ abstract class LazyModule { protected[tilelink2] var bindings = List[() => Unit]() protected[tilelink2] var children = List[LazyModule]() - protected[tilelink2] var nodes = List[RootNode]() + protected[tilelink2] var nodes = List[BaseNode]() protected[tilelink2] var info: SourceInfo = UnlocatableSourceInfo protected[tilelink2] val parent = LazyModule.stack.headOption diff --git a/src/main/scala/uncore/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala index d65339df..9a4c0497 100644 --- a/src/main/scala/uncore/tilelink2/Nodes.scala +++ b/src/main/scala/uncore/tilelink2/Nodes.scala @@ -32,7 +32,7 @@ trait OutwardNodeImp[DO, UO, EO, BO <: Data] abstract class NodeImp[D, U, EO, EI, B <: Data] extends Object with InwardNodeImp[D, U, EI, B] with OutwardNodeImp[D, U, EO, B] -abstract class RootNode +abstract class BaseNode { // You cannot create a Node outside a LazyModule! require (!LazyModule.stack.isEmpty) @@ -45,11 +45,11 @@ abstract class RootNode def colour = "blue" def omitGraphML = outputs.isEmpty && inputs.isEmpty - protected[tilelink2] def outputs: Seq[RootNode] - protected[tilelink2] def inputs: Seq[RootNode] + protected[tilelink2] def outputs: Seq[BaseNode] + protected[tilelink2] def inputs: Seq[BaseNode] } -trait InwardNode[DI, UI, BI <: Data] extends RootNode +trait InwardNode[DI, UI, BI <: Data] extends BaseNode { protected[tilelink2] val numPI: Range.Inclusive require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}") @@ -74,7 +74,7 @@ trait InwardNode[DI, UI, BI <: Data] extends RootNode protected[tilelink2] def iConnect: Vec[BI] } -trait OutwardNode[DO, UO, BO <: Data] extends RootNode +trait OutwardNode[DO, UO, BO <: Data] extends BaseNode { protected[tilelink2] val numPO: Range.Inclusive require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}") @@ -106,7 +106,7 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( private val uFn: (Int, Seq[UO]) => Seq[UI], protected[tilelink2] val numPO: Range.Inclusive, protected[tilelink2] val numPI: Range.Inclusive) - extends RootNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] + extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] { // meta-data for printing the node graph protected[tilelink2] def outputs = oPorts.map(_._2) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 463ac2e3..71fd667e 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -149,7 +149,7 @@ case class TLManagerParameters( sinkId: IdRange = IdRange(0, 1), regionType: RegionType.T = RegionType.GET_EFFECTS, executable: Boolean = false, // processor can execute from this memory - nodePath: Seq[RootNode] = Seq(), + nodePath: Seq[BaseNode] = Seq(), // Supports both Acquire+Release+Finish of these sizes supportsAcquire: TransferSizes = TransferSizes.none, supportsArithmetic: TransferSizes = TransferSizes.none, @@ -293,7 +293,7 @@ case class TLManagerPortParameters( case class TLClientParameters( sourceId: IdRange = IdRange(0,1), - nodePath: Seq[RootNode] = Seq(), + nodePath: Seq[BaseNode] = Seq(), // Supports both Probe+Grant of these sizes supportsProbe: TransferSizes = TransferSizes.none, supportsArithmetic: TransferSizes = TransferSizes.none, From 8e4c1e567cd7073aa0a1d91a55cd2652bc7e9cab Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 15:34:21 -0700 Subject: [PATCH 5/7] tilelink2: add types for a TL clockless interface --- src/main/scala/uncore/tilelink2/Bundles.scala | 22 ++++++++++- .../scala/uncore/tilelink2/Parameters.scala | 26 ++++++++++--- src/main/scala/uncore/tilelink2/TLNodes.scala | 39 +++++++++++++++++++ 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala index 5b0893c2..c32e3f4c 100644 --- a/src/main/scala/uncore/tilelink2/Bundles.scala +++ b/src/main/scala/uncore/tilelink2/Bundles.scala @@ -190,7 +190,7 @@ object TLBundle def apply(params: TLBundleParameters) = new TLBundle(params) } -class IrrevocableSnoop[+T <: Data](gen: T) extends Bundle +final class IrrevocableSnoop[+T <: Data](gen: T) extends Bundle { val ready = Bool() val valid = Bool() @@ -232,3 +232,23 @@ object TLBundleSnoop out } } + +final class AsyncBundle[T <: Data](depth: Int, gen: T) extends Bundle +{ + require (isPow2(depth)) + val ridx = UInt(width = log2Up(depth)+1).flip + val widx = UInt(width = log2Up(depth)+1) + val mem = Vec(depth, gen) + override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type] +} + +class TLAsyncBundleBase(params: TLAsyncBundleParameters) extends GenericParameterizedBundle(params) + +class TLAsyncBundle(params: TLAsyncBundleParameters) extends TLAsyncBundleBase(params) +{ + val a = new AsyncBundle(params.depth, new TLBundleA(params.base)) + val b = new AsyncBundle(params.depth, new TLBundleB(params.base)).flip + val c = new AsyncBundle(params.depth, new TLBundleC(params.base)) + val d = new AsyncBundle(params.depth, new TLBundleD(params.base)).flip + val e = new AsyncBundle(params.depth, new TLBundleE(params.base)) +} diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 71fd667e..514e6acd 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -401,6 +401,17 @@ case class TLBundleParameters( max(sizeBits, x.sizeBits)) } +object TLBundleParameters +{ + def apply(client: TLClientPortParameters, manager: TLManagerPortParameters) = + new TLBundleParameters( + addrHiBits = log2Up(manager.maxAddress + 1) - log2Ceil(manager.beatBytes), + dataBits = manager.beatBytes * 8, + sourceBits = log2Up(client.endSourceId), + sinkBits = log2Up(manager.endSinkId), + sizeBits = log2Up(log2Ceil(max(client.maxTransfer, manager.maxTransfer))+1)) +} + case class TLEdgeParameters( client: TLClientPortParameters, manager: TLManagerPortParameters) @@ -411,10 +422,13 @@ case class TLEdgeParameters( // Sanity check the link... require (maxTransfer >= manager.beatBytes) - val bundle = TLBundleParameters( - addrHiBits = log2Up(manager.maxAddress + 1) - log2Ceil(manager.beatBytes), - dataBits = manager.beatBytes * 8, - sourceBits = log2Up(client.endSourceId), - sinkBits = log2Up(manager.endSinkId), - sizeBits = log2Up(maxLgSize+1)) + val bundle = TLBundleParameters(client, manager) +} + +case class TLAsyncManagerPortParameters(depth: Int, base: TLManagerPortParameters) { require (isPow2(depth)) } +case class TLAsyncClientPortParameters(base: TLClientPortParameters) +case class TLAsyncBundleParameters(depth: Int, base: TLBundleParameters) { require (isPow2(depth)) } +case class TLAsyncEdgeParameters(client: TLAsyncClientPortParameters, manager: TLAsyncManagerPortParameters) +{ + val bundle = TLAsyncBundleParameters(manager.depth, TLBundleParameters(client.base, manager.base)) } diff --git a/src/main/scala/uncore/tilelink2/TLNodes.scala b/src/main/scala/uncore/tilelink2/TLNodes.scala index 84c1405e..e52b275d 100644 --- a/src/main/scala/uncore/tilelink2/TLNodes.scala +++ b/src/main/scala/uncore/tilelink2/TLNodes.scala @@ -71,3 +71,42 @@ class TLInputNodeTest extends UnitTest(500000) { io.finished := Module(fuzzer.module).io.finished } + +object TLAsyncImp extends NodeImp[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncEdgeParameters, TLAsyncEdgeParameters, TLAsyncBundle] +{ + def edgeO(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu) + def edgeI(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu) + def bundleO(eo: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = { + require (eo.size == 1) + Vec(eo.size, new TLAsyncBundle(eo(0).bundle)) + } + def bundleI(ei: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = { + require (ei.size == 1) + Vec(ei.size, new TLAsyncBundle(ei(0).bundle)).flip + } + + def connect(bo: => TLAsyncBundle, bi: => TLAsyncBundle, ei: => TLAsyncEdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = { + (None, () => { bi <> bo }) + } + + override def mixO(pd: TLAsyncClientPortParameters, node: OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncClientPortParameters = + pd.copy(base = pd.base.copy(clients = pd.base.clients.map { c => c.copy (nodePath = node +: c.nodePath) })) + override def mixI(pu: TLAsyncManagerPortParameters, node: InwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncManagerPortParameters = + pu.copy(base = pu.base.copy(managers = pu.base.managers.map { m => m.copy (nodePath = node +: m.nodePath) })) +} + +case class TLAsyncIdentityNode() extends IdentityNode(TLAsyncImp) +case class TLAsyncOutputNode() extends OutputNode(TLAsyncImp) +case class TLAsyncInputNode() extends InputNode(TLAsyncImp) + +case class TLAsyncSourceNode() extends MixedNode(TLImp, TLAsyncImp)( + dFn = { case (1, s) => s.map(TLAsyncClientPortParameters(_)) }, + uFn = { case (1, s) => s.map(_.base) }, + numPO = 1 to 1, + numPI = 1 to 1) + +case class TLAsyncSinkNode(depth: Int) extends MixedNode(TLAsyncImp, TLImp)( + dFn = { case (1, s) => s.map(_.base) }, + uFn = { case (1, s) => s.map(TLAsyncManagerPortParameters(depth, _)) }, + numPO = 1 to 1, + numPI = 1 to 1) From 20f42a8762dcccefdc7a7318704fbb349d73347f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 17:12:13 -0700 Subject: [PATCH 6/7] tilelink2: reuse the halves of the AsyncQueue --- src/main/scala/uncore/tilelink2/Bundles.scala | 35 +++++++++++++++++-- src/main/scala/util/AsyncQueue.scala | 15 ++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala index c32e3f4c..27071966 100644 --- a/src/main/scala/uncore/tilelink2/Bundles.scala +++ b/src/main/scala/uncore/tilelink2/Bundles.scala @@ -3,7 +3,8 @@ package uncore.tilelink2 import Chisel._ -import chisel3.util.{Irrevocable, IrrevocableIO} +import chisel3.util.{Irrevocable, IrrevocableIO, ReadyValidIO} +import util.{AsyncQueueSource, AsyncQueueSink} abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle { @@ -233,7 +234,7 @@ object TLBundleSnoop } } -final class AsyncBundle[T <: Data](depth: Int, gen: T) extends Bundle +final class AsyncBundle[T <: Data](val depth: Int, gen: T) extends Bundle { require (isPow2(depth)) val ridx = UInt(width = log2Up(depth)+1).flip @@ -242,6 +243,36 @@ final class AsyncBundle[T <: Data](depth: Int, gen: T) extends Bundle override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type] } +object FromAsyncBundle +{ + def apply[T <: Data](x: AsyncBundle[T], sync: Int = 3): IrrevocableIO[T] = { + val sink = Module(new AsyncQueueSink(x.mem(0), x.depth, sync)) + x.ridx := sink.io.ridx + sink.io.widx := x.widx + sink.io.mem := x.mem + val out = Wire(Irrevocable(x.mem(0))) + out.valid := sink.io.deq.valid + out.bits := sink.io.deq.bits + sink.io.deq.ready := out.ready + out + } +} + +object ToAsyncBundle +{ + def apply[T <: Data](x: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): AsyncBundle[T] = { + val source = Module(new AsyncQueueSource(x.bits, depth, sync)) + source.io.enq.valid := x.valid + source.io.enq.bits := x.bits + x.ready := source.io.enq.ready + val out = Wire(new AsyncBundle(depth, x.bits)) + source.io.ridx := out.ridx + out.mem := source.io.mem + out.widx := source.io.widx + out + } +} + class TLAsyncBundleBase(params: TLAsyncBundleParameters) extends GenericParameterizedBundle(params) class TLAsyncBundle(params: TLAsyncBundleParameters) extends TLAsyncBundleBase(params) diff --git a/src/main/scala/util/AsyncQueue.scala b/src/main/scala/util/AsyncQueue.scala index 81049414..9c8732d7 100644 --- a/src/main/scala/util/AsyncQueue.scala +++ b/src/main/scala/util/AsyncQueue.scala @@ -25,8 +25,7 @@ object AsyncGrayCounter { } } -class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool) - extends Module(_clock = clockIn, _reset = resetIn) { +class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int) extends Module { val bits = log2Ceil(depth) val io = new Bundle { // These come from the source domain @@ -53,8 +52,7 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, io.mem := mem } -class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool) - extends Module(_clock = clockIn, _reset = resetIn) { +class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module { val bits = log2Ceil(depth) val io = new Bundle { // These come from the sink domain @@ -88,8 +86,13 @@ class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Cross require (depth > 0 && isPow2(depth)) val io = new CrossingIO(gen) - val source = Module(new AsyncQueueSource(gen, depth, sync, io.enq_clock, io.enq_reset)) - val sink = Module(new AsyncQueueSink (gen, depth, sync, io.deq_clock, io.deq_reset)) + val source = Module(new AsyncQueueSource(gen, depth, sync)) + val sink = Module(new AsyncQueueSink (gen, depth, sync)) + + source.clock := io.enq_clock + source.reset := io.enq_reset + sink.clock := io.deq_clock + sink.reset := io.deq_reset source.io.enq <> io.enq io.deq <> sink.io.deq From 6d8c965f045e16942abf8e8188f4f66357cf4bb0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 29 Sep 2016 17:32:18 -0700 Subject: [PATCH 7/7] tilelink2 Crossing: cut the crossing between clock domains --- .../scala/uncore/tilelink2/Crossing.scala | 102 +++++++++++++++--- src/main/scala/uncore/tilelink2/Fuzzer.scala | 4 +- 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Crossing.scala b/src/main/scala/uncore/tilelink2/Crossing.scala index 58424b9b..ac63f1a1 100644 --- a/src/main/scala/uncore/tilelink2/Crossing.scala +++ b/src/main/scala/uncore/tilelink2/Crossing.scala @@ -6,33 +6,63 @@ import Chisel._ import chisel3.internal.sourceinfo.SourceInfo import util._ -class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule +class TLAsyncCrossingSource(sync: Int = 3) extends LazyModule { - val node = TLIdentityNode() + val node = TLAsyncSourceNode() lazy val module = new LazyModuleImp(this) { val io = new Bundle { - val in = node.bundleIn - val in_clock = Clock(INPUT) - val in_reset = Bool(INPUT) - val out = node.bundleOut - val out_clock = Clock(INPUT) - val out_reset = Bool(INPUT) + val in = node.bundleIn + val out = node.bundleOut } - // Transfer all TL2 bundles from/to the same domains ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => - out.a <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.a, io.out_clock, io.out_reset, depth, sync) - in.d <> AsyncIrrevocableCrossing(io.out_clock, io.out_reset, out.d, io.in_clock, io.in_reset, depth, sync) + val bce = edgeIn.manager.anySupportAcquire && edgeIn.client.anySupportProbe + val depth = edgeOut.manager.depth - if (edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe) { - in.b <> AsyncIrrevocableCrossing(io.out_clock, io.out_reset, out.b, io.in_clock, io.in_reset, depth, sync) - out.c <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.c, io.out_clock, io.out_reset, depth, sync) - out.e <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.e, io.out_clock, io.out_reset, depth, sync) + out.a := ToAsyncBundle(in.a, depth, sync) + in.d := FromAsyncBundle(out.d, sync) + + if (bce) { + in.b := FromAsyncBundle(out.b, sync) + out.c := ToAsyncBundle(in.c, depth, sync) + out.e := ToAsyncBundle(in.e, depth, sync) } else { in.b.valid := Bool(false) in.c.ready := Bool(true) in.e.ready := Bool(true) + out.b.ridx := UInt(0) + out.c.widx := UInt(0) + out.e.widx := UInt(0) + } + } + } +} + +class TLAsyncCrossingSink(depth: Int = 8, sync: Int = 3) extends LazyModule +{ + val node = TLAsyncSinkNode(depth) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => + val bce = edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe + + out.a := FromAsyncBundle(in.a, sync) + in.d := ToAsyncBundle(out.d, depth, sync) + + if (bce) { + in.b := ToAsyncBundle(out.b, depth, sync) + out.c := FromAsyncBundle(in.c, sync) + out.e := FromAsyncBundle(in.e, sync) + } else { + in.b.widx := UInt(0) + in.c.ridx := UInt(0) + in.e.ridx := UInt(0) out.b.ready := Bool(true) out.c.valid := Bool(false) out.e.valid := Bool(false) @@ -41,6 +71,44 @@ class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule } } +class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule +{ + val nodeIn = TLInputNode() + val nodeOut = TLOutputNode() + + val source = LazyModule(new TLAsyncCrossingSource(sync)) + val sink = LazyModule(new TLAsyncCrossingSink(depth, sync)) + + val _ = (sink.node := source.node) // no monitor + val in = (source.node := nodeIn) + val out = (nodeOut := sink.node) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = nodeIn.bundleIn + val in_clock = Clock(INPUT) + val in_reset = Bool(INPUT) + val out = nodeOut.bundleOut + val out_clock = Clock(INPUT) + val out_reset = Bool(INPUT) + } + + source.module.clock := io.in_clock + source.module.reset := io.in_reset + in.foreach { lm => + lm.module.clock := io.in_clock + lm.module.reset := io.in_reset + } + + sink.module.clock := io.out_clock + sink.module.reset := io.out_reset + out.foreach { lm => + lm.module.clock := io.out_clock + lm.module.reset := io.out_reset + } + } +} + /** Synthesizeable unit tests */ import unittest._ @@ -51,8 +119,8 @@ class TLRAMCrossing extends LazyModule { val cross = LazyModule(new TLAsyncCrossing) model.node := fuzz.node - cross.node := TLFragmenter(4, 256)(model.node) - val monitor = (ram.node := cross.node) + cross.nodeIn := TLFragmenter(4, 256)(model.node) + val monitor = (ram.node := cross.nodeOut) lazy val module = new LazyModuleImp(this) with HasUnitTestIO { io.finished := fuzz.module.io.finished diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index 968f9efd..8b396f50 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -224,8 +224,8 @@ class TLFuzzRAM extends LazyModule xbar2.node := TLAtomicAutomata()(model.node) ram2.node := TLFragmenter(16, 256)(xbar2.node) xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node)) - cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node)) - val monitor = (ram.node := cross.node) + cross.nodeIn := TLFragmenter(4, 256)(TLBuffer()(xbar.node)) + val monitor = (ram.node := cross.nodeOut) gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node)) lazy val module = new LazyModuleImp(this) with HasUnitTestIO {