Skip to content

Commit

Permalink
Merge pull request #2497 from chipsalliance/bundle-broadcast-enhancem…
Browse files Browse the repository at this point in the history
…ents

BundleBridge enhancements
  • Loading branch information
hcook authored Jun 4, 2020
2 parents 03cccb4 + 0b28265 commit ab3dcdc
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 36 deletions.
132 changes: 105 additions & 27 deletions src/main/scala/diplomacy/BundleBridge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) = {
Expand All @@ -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)
}
}
6 changes: 3 additions & 3 deletions src/main/scala/diplomacy/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
2 changes: 1 addition & 1 deletion src/main/scala/subsystem/RocketSubsystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 1 addition & 5 deletions src/main/scala/tile/BaseTile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit ab3dcdc

Please sign in to comment.