diff --git a/src/main/scala/diplomacy/BundleBridge.scala b/src/main/scala/diplomacy/BundleBridge.scala index 33977df732..054a5e1e86 100644 --- a/src/main/scala/diplomacy/BundleBridge.scala +++ b/src/main/scala/diplomacy/BundleBridge.scala @@ -7,28 +7,51 @@ import chisel3.internal.sourceinfo.SourceInfo import chisel3.experimental.{DataMirror,IO} import freechips.rocketchip.config.{Parameters,Field} -case class BundleBridgeParams[T <: Data](gen: () => T) -case class BundleBridgeNull() +case class BundleBridgeParams[T <: Data](genOpt: Option[() => T]) -class BundleBridgeImp[T <: Data]() extends SimpleNodeImp[BundleBridgeParams[T], BundleBridgeNull, BundleBridgeParams[T], T] +case object BundleBridgeParams { + def apply[T <: Data](gen: () => T): BundleBridgeParams[T] = BundleBridgeParams(Some(gen)) +} + +case class BundleBridgeEdgeParams[T <: Data](source: BundleBridgeParams[T], sink: BundleBridgeParams[T]) + +class BundleBridgeImp[T <: Data]() extends SimpleNodeImp[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] { - def edge(pd: BundleBridgeParams[T], pu: BundleBridgeNull, p: Parameters, sourceInfo: SourceInfo) = pd - def bundle(e: BundleBridgeParams[T]) = e.gen() - def render(e: BundleBridgeParams[T]) = RenderedEdge(colour = "#cccc00" /* yellow */) + def edge(pd: BundleBridgeParams[T], pu: BundleBridgeParams[T], p: Parameters, sourceInfo: SourceInfo) = BundleBridgeEdgeParams(pd, pu) + def bundle(e: BundleBridgeEdgeParams[T]): T = { + val sourceOpt = e.source.genOpt.map(_()) + val sinkOpt = e.sink.genOpt.map(_()) + (sourceOpt, sinkOpt) match { + case (None, None) => + throw new Exception("BundleBridge needs source or sink to provide bundle generator function") + case (Some(a), None) => a + case (None, Some(b)) => b + case (Some(a), Some(b)) => { + require(DataMirror.checkTypeEquivalence(a, b), + s"BundleBridge requires doubly-specified source and sink generators to have equivalent Chisel Data types, but got \n$a\n vs\n$b") + a + } + } + } + def render(e: BundleBridgeEdgeParams[T]) = RenderedEdge(colour = "#cccc00" /* yellow */) } -case class BundleBridgeSink[T <: Data]()(implicit valName: ValName) extends SinkNode(new BundleBridgeImp[T])(Seq(BundleBridgeNull())) +case class BundleBridgeSink[T <: Data](genOpt: Option[() => T] = None) + (implicit valName: ValName) + extends SinkNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt))) { def bundle: T = in(0)._1 def makeIO()(implicit valName: ValName): T = makeIOs()(valName).head + def makeIO(name: String): T = makeIOs()(ValName(name)).head } -case class BundleBridgeSource[T <: Data](gen: () => T)(implicit valName: ValName) extends SourceNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(gen))) +case class BundleBridgeSource[T <: Data](genOpt: Option[() => T] = None)(implicit valName: ValName) extends SourceNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt))) { def bundle: T = out(0)._1 def makeIO()(implicit valName: ValName): T = makeIOs()(valName).head + def makeIO(name: String): T = makeIOs()(ValName(name)).head private var doneSink = false def makeSink()(implicit p: Parameters) = { @@ -40,43 +63,98 @@ case class BundleBridgeSource[T <: Data](gen: () => T)(implicit valName: ValName } } +case object BundleBridgeSource { + def apply[T <: Data](gen: () => T)(implicit valName: ValName): BundleBridgeSource[T] = { + BundleBridgeSource(Some(gen)) + } +} + case class BundleBridgeIdentityNode[T <: Data]()(implicit valName: ValName) extends IdentityNode(new BundleBridgeImp[T])() case class BundleBridgeEphemeralNode[T <: Data]()(implicit valName: ValName) extends EphemeralNode(new BundleBridgeImp[T])() -case class BundleBridgeNexus[T <: Data]()(implicit valName: ValName) extends NexusNode(new BundleBridgeImp[T])( - dFn = seq => seq.head, - uFn = _ => BundleBridgeNull(), - inputRequiresOutput = false) - -class BundleBroadcast[T <: Data](registered: Boolean = false)(implicit p: Parameters) extends LazyModule +case class BundleBridgeNexusNode[T <: Data](default: Option[() => T] = None) + (implicit valName: ValName) + extends NexusNode(new BundleBridgeImp[T])( + dFn = seq => seq.headOption.getOrElse(BundleBridgeParams(default)), + uFn = seq => seq.headOption.getOrElse(BundleBridgeParams(default)), + inputRequiresOutput = false, // enables publishers with no subscribers + outputRequiresInput = !default.isDefined) + +class BundleBridgeNexus[T <: Data]( + inputFn: Seq[T] => T, + outputFn: (T, Int) => Seq[T], + default: Option[() => T] = None +) (implicit p: Parameters) extends LazyModule { - val node = BundleBridgeNexus[T]() + val node = BundleBridgeNexusNode[T](default) lazy val module = new LazyModuleImp(this) { - require (node.in.size == 1) - val (in, _) = node.in.head + val defaultWireOpt = default.map(_()) + val inputs: Seq[T] = defaultWireOpt.toList ++ node.in.map(_._1) + require(inputs.size >= 1 || node.out.size == 0, s"${node.context} requires at least one input or default.") + inputs.foreach { i => require(DataMirror.checkTypeEquivalence(i, inputs.head), + s"${node.context} requires all inputs have equivalent Chisel Data types, but got\n$i\nvs\n${inputs.head}") + } def getElements(x: Data): Seq[Element] = x match { case e: Element => Seq(e) case a: Aggregate => a.getElements.flatMap(getElements) } - getElements(in).foreach { elt => DataMirror.directionOf(elt) match { + inputs.flatMap(getElements).foreach { elt => DataMirror.directionOf(elt) match { case ActualDirection.Output => () case ActualDirection.Unspecified => () - case _ => require(false, "BundleBroadcast can only be used with Output-directed Bundles") + case _ => require(false, s"${node.context} can only be used with Output-directed Bundles") } } - def reg[T <: Data](x: T) = { if (registered) RegNext(x) else x } + val outputs: Seq[T] = if (node.out.size > 0) { + val broadcast: T = inputFn(inputs) + outputFn(broadcast, node.out.size) + } else { Nil } + + node.out.map(_._1).foreach { o => require(DataMirror.checkTypeEquivalence(o, outputs.head), + s"${node.context} requires all outputs have equivalent Chisel Data types, but got\n$o\nvs\n${outputs.head}") + } - val ireg = reg(in) - node.out.foreach { case (out, _) => out := reg(ireg) } + require(outputs.size == node.out.size, + s"${node.context} outputFn must generate one output wire per edgeOut, but got ${outputs.size} vs ${node.out.size}") + + node.out.zip(outputs).foreach { case ((out, _), bcast) => out := bcast } } } -object BundleBroadcast -{ - def apply[T <: Data](name: Option[String] = None, registered: Boolean = false)(implicit p: Parameters): BundleBridgeNexus[T] = { - val broadcast = LazyModule(new BundleBroadcast[T](registered)) - name.map(broadcast.suggestName) +object BundleBridgeNexus { + def requireOne[T <: Data](registered: Boolean)(seq: Seq[T]): T = { + require(seq.size == 1, "BundleBroadcast default requires one input") + if (registered) RegNext(seq.head) else seq.head + } + + def orReduction[T <: Data](registered: Boolean)(seq: Seq[T]): T = { + val x = seq.reduce((a,b) => (a.asUInt | b.asUInt).asTypeOf(seq.head)) + if (registered) RegNext(x) else x + } + + def fillN[T <: Data](registered: Boolean)(x: T, n: Int): Seq[T] = Seq.fill(n) { + if (registered) RegNext(x) else x + } + + def apply[T <: Data]( + inputFn: Seq[T] => T = orReduction[T](false) _, + outputFn: (T, Int) => Seq[T] = fillN[T](false) _, + default: Option[() => T] = None + )(implicit p: Parameters, valName: ValName): BundleBridgeNexusNode[T] = { + val broadcast = LazyModule(new BundleBridgeNexus[T](inputFn, outputFn, default)) broadcast.node } } + +object BundleBroadcast { + def apply[T <: Data]( + name: Option[String] = None, + registered: Boolean = false + )(implicit p: Parameters, valName: ValName): BundleBridgeNexusNode[T] = { + val finalName = name.map(ValName(_)).getOrElse(valName) + BundleBridgeNexus.apply[T]( + inputFn = BundleBridgeNexus.requireOne[T](registered) _, + outputFn = BundleBridgeNexus.fillN[T](registered) _)( + p, finalName) + } +} diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala index 65be5db8b8..9d88e80ca9 100644 --- a/src/main/scala/diplomacy/package.scala +++ b/src/main/scala/diplomacy/package.scala @@ -66,7 +66,7 @@ package object diplomacy implicit def noCrossing(value: NoCrossing.type): ClockCrossingType = SynchronousCrossing(BufferParams.none) - type BundleBridgeInwardNode[T <: Data] = InwardNodeHandle[BundleBridgeParams[T], BundleBridgeNull, BundleBridgeParams[T], T] - type BundleBridgeOutwardNode[T <: Data] = OutwardNodeHandle[BundleBridgeParams[T], BundleBridgeNull, BundleBridgeParams[T], T] - type BundleBridgeNode[T <: Data] = NodeHandle[BundleBridgeParams[T], BundleBridgeNull, BundleBridgeParams[T], T, BundleBridgeParams[T], BundleBridgeNull, BundleBridgeParams[T], T] + type BundleBridgeInwardNode[T <: Data] = InwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] + type BundleBridgeOutwardNode[T <: Data] = OutwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] + type BundleBridgeNode[T <: Data] = NodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T, BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T] } diff --git a/src/main/scala/subsystem/RocketSubsystem.scala b/src/main/scala/subsystem/RocketSubsystem.scala index 49b45a3c5c..789a883ae7 100644 --- a/src/main/scala/subsystem/RocketSubsystem.scala +++ b/src/main/scala/subsystem/RocketSubsystem.scala @@ -89,7 +89,7 @@ class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem } val hartPrefixes = hartPrefixNode.map { hpn => Seq.fill(tiles.size) { - val hps = BundleBridgeSink[UInt] + val hps = BundleBridgeSink[UInt]() hps := hpn hps } }.getOrElse(Nil) diff --git a/src/main/scala/tile/BaseTile.scala b/src/main/scala/tile/BaseTile.scala index dd6aae8cf0..df658ddcd8 100644 --- a/src/main/scala/tile/BaseTile.scala +++ b/src/main/scala/tile/BaseTile.scala @@ -187,7 +187,7 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) val traceCoreSourceNode = BundleBridgeSource(() => new TraceCoreInterface(new TraceCoreParams())) val traceCoreBroadcastNode = BundleBroadcast[TraceCoreInterface](Some("tracecore")) traceCoreBroadcastNode := traceCoreSourceNode - def traceCoreNode: BundleBridgeNexus[TraceCoreInterface] = traceCoreBroadcastNode + def traceCoreNode: BundleBridgeNexusNode[TraceCoreInterface] = traceCoreBroadcastNode // Node for watchpoints to control trace def getBpwatchParams: (Int, Int) = { (tileParams.core.nBreakpoints, tileParams.core.retireWidth) } @@ -264,10 +264,6 @@ abstract class BaseTileModuleImp[+L <: BaseTile](val outer: L) extends LazyModul outer.traceAuxDefaultNode.bundle.stall := false.B outer.traceAuxDefaultNode.bundle.enable := false.B - val aux = Wire(new TraceAux) - aux.stall := outer.traceAuxNode.in.map(in => in._1.stall).orR - aux.enable := outer.traceAuxNode.in.map(in => in._1.enable).orR - outer.traceAuxNode.out.foreach { case (out, _) => out := aux } val constants = IO(new TileInputConstants) }