Materialized bridge FCCAs in BridgeExtraction (#1225)
This patch moves the materialization of FCCAs connected to bridges to the BridgeExtraction stage. Up to that point, information about channels connected to bridges is carried in the bridgeChannels field of the SerializableBridgeAnnotation. Bridges with IO towards the target must construct BridgeChannel decriptors for the channels they want materialized instead of eagerly creating FCCAs.
This commit is contained in:
parent
f9afbcceb8
commit
760411bc93
|
@ -2,8 +2,10 @@
|
|||
|
||||
package midas.passes
|
||||
|
||||
import midas.widgets.{BridgeAnnotation, ClockBridgeModule}
|
||||
import midas.passes.fame.{PromoteSubmodule, PromoteSubmoduleAnnotation, FAMEChannelConnectionAnnotation}
|
||||
import midas.widgets.{BridgeAnnotation, ClockBridgeModule, FindScaledPeriodGCD}
|
||||
import midas.widgets.{PipeBridgeChannel, ClockBridgeChannel, ReadyValidBridgeChannel}
|
||||
import midas.passes.fame.{PromoteSubmodule, PromoteSubmoduleAnnotation, FAMEChannelConnectionAnnotation, RTRenamer}
|
||||
import midas.passes.fame.{PipeChannel, TargetClockChannel, DecoupledReverseChannel, DecoupledForwardChannel}
|
||||
|
||||
import firrtl._
|
||||
import firrtl.ir._
|
||||
|
@ -84,16 +86,13 @@ private[passes] class BridgeExtraction extends firrtl.Transform {
|
|||
val topModule = c.modules.find(_.name == c.main).get
|
||||
// Collect all bridge modules
|
||||
val bridgeAnnos = mutable.ArrayBuffer[BridgeAnnotation]()
|
||||
val fcaAnnos = mutable.ArrayBuffer[FAMEChannelConnectionAnnotation]()
|
||||
|
||||
val otherAnnos = state.annotations.flatMap({
|
||||
case anno: BridgeAnnotation => bridgeAnnos += anno; None
|
||||
case fca: FAMEChannelConnectionAnnotation => fcaAnnos += fca; None
|
||||
case otherAnno => Some(otherAnno)
|
||||
})
|
||||
|
||||
val bridgeAnnoMap = bridgeAnnos.map(anno => anno.target.module -> anno ).toMap
|
||||
val fcaMap = fcaAnnos.groupBy(_.getBridgeModule).toMap
|
||||
|
||||
val portInstPairs = new mutable.ArrayBuffer[(String, String)]()
|
||||
val instList = new mutable.ArrayBuffer[(String, String)]()
|
||||
|
@ -110,9 +109,68 @@ private[passes] class BridgeExtraction extends firrtl.Transform {
|
|||
s"Multiple ClockBridge instances found: ${clockBridgeInsts.mkString("\n")} ${bridgeInstMessage}")
|
||||
|
||||
val ioAnnotations = portInstPairs.flatMap({ case (port, inst) =>
|
||||
val updatedBridgeAnno = bridgeAnnoMap(instMap(inst)).toIOAnnotation(port)
|
||||
val updatedFCAAnnos = fcaMap(instMap(inst)).map(_.moveFromBridge(port))
|
||||
Seq(updatedBridgeAnno) ++ updatedFCAAnnos
|
||||
val bridge = bridgeAnnoMap(instMap(inst))
|
||||
val updatedBridgeAnno = bridge.toIOAnnotation(port)
|
||||
|
||||
def buildRenamer(rTs: Seq[ReferenceTarget]) = {
|
||||
def updateRT(rT: ReferenceTarget): ReferenceTarget =
|
||||
ModuleTarget(rT.circuit, rT.circuit).ref(port).field(rT.ref)
|
||||
RTRenamer.exact(RenameMap(Map((rTs.map(rT => rT -> Seq(updateRT(rT)))):_*)))
|
||||
}
|
||||
|
||||
val bridgeFCCAAnnos : AnnotationSeq = bridge.bridgeChannels.flatMap({
|
||||
case PipeBridgeChannel(name, clock, sinks, sources, latency) => {
|
||||
val renamer = buildRenamer(sinks ++ sources ++ Seq(clock))
|
||||
|
||||
Seq(FAMEChannelConnectionAnnotation(
|
||||
s"${port}_${name}",
|
||||
PipeChannel(latency),
|
||||
Some(renamer(clock)),
|
||||
if (sources.isEmpty) { None } else { Some(sources.map(renamer(_))) },
|
||||
if (sinks.isEmpty) { None } else { Some(sinks.map(renamer(_))) }
|
||||
))
|
||||
}
|
||||
case ClockBridgeChannel(name, sinks, clocks, clockMFMRs) => {
|
||||
val renamer = buildRenamer(sinks)
|
||||
|
||||
Seq(FAMEChannelConnectionAnnotation(
|
||||
s"${port}_${name}",
|
||||
channelInfo = TargetClockChannel(clocks, clockMFMRs),
|
||||
clock = None,
|
||||
sinks = Some(sinks.map(renamer(_))),
|
||||
sources = None
|
||||
))
|
||||
}
|
||||
case ReadyValidBridgeChannel(fwdName, revName, clock, sinks, sources, valid, ready) => {
|
||||
val renamer = buildRenamer(sinks ++ sources ++ Seq(clock, valid, ready))
|
||||
|
||||
val clockRT = renamer(clock)
|
||||
val validRT = renamer(valid)
|
||||
val readyRT = renamer(ready)
|
||||
|
||||
Seq(
|
||||
FAMEChannelConnectionAnnotation(
|
||||
s"${port}_${fwdName}",
|
||||
if (sinks.isEmpty) {
|
||||
DecoupledForwardChannel.source(validRT, readyRT)
|
||||
} else {
|
||||
DecoupledForwardChannel.sink(validRT, readyRT)
|
||||
},
|
||||
Some(clockRT),
|
||||
if (sources.isEmpty) { None } else { Some(sources.map(renamer(_))) },
|
||||
if (sinks.isEmpty) { None } else { Some(sinks.map(renamer(_))) }
|
||||
),
|
||||
FAMEChannelConnectionAnnotation(
|
||||
s"${port}_${revName}",
|
||||
DecoupledReverseChannel,
|
||||
Some(clockRT),
|
||||
if (sources.isEmpty) { Some(Seq(readyRT)) } else { None },
|
||||
if (sinks.isEmpty) { Some(Seq(readyRT)) } else { None }
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
Seq(updatedBridgeAnno) ++ bridgeFCCAAnnos
|
||||
})
|
||||
|
||||
state.copy(annotations = otherAnnos ++ ioAnnotations)
|
||||
|
|
|
@ -65,19 +65,6 @@ case class FAMEChannelConnectionAnnotation(
|
|||
|
||||
def getBridgeModule(): String = sources.getOrElse(sinks.get).head.module
|
||||
|
||||
def moveFromBridge(portName: String): FAMEChannelConnectionAnnotation = {
|
||||
def updateRT(rT: ReferenceTarget): ReferenceTarget = ModuleTarget(rT.circuit, rT.circuit).ref(portName).field(rT.ref)
|
||||
|
||||
require(sources == None || sinks == None, "Bridge-connected channels cannot loopback")
|
||||
val rTs = sources.getOrElse(sinks.get) ++ clock ++ (channelInfo match {
|
||||
case i: DecoupledForwardChannel => Seq(i.readySink.getOrElse(i.readySource.get))
|
||||
case other => Seq()
|
||||
})
|
||||
|
||||
val localRenames = RenameMap(Map((rTs.map(rT => rT -> Seq(updateRT(rT)))):_*))
|
||||
copy(globalName = s"${portName}_${globalName}").update(localRenames).head.asInstanceOf[this.type]
|
||||
}
|
||||
|
||||
override def getTargets: Seq[ReferenceTarget] = clock ++: (sources.toSeq.flatten ++ sinks.toSeq.flatten)
|
||||
}
|
||||
|
||||
|
|
|
@ -63,27 +63,19 @@ trait Bridge[HPType <: Record with HasChannels, WidgetType <: BridgeModule[HPTyp
|
|||
annotate(new ChiselAnnotation { def toFirrtl = {
|
||||
BridgeAnnotation(
|
||||
self.toNamed.toTarget,
|
||||
bridgeIO.allChannelNames,
|
||||
bridgeIO.bridgeChannels,
|
||||
widgetClass = widgetClassSymbol.fullName,
|
||||
widgetConstructorKey = constructorArg)
|
||||
}
|
||||
})
|
||||
// Emit annotations to capture channel information
|
||||
bridgeIO.generateAnnotations()
|
||||
}
|
||||
}
|
||||
|
||||
trait HasChannels {
|
||||
/**
|
||||
* Called to emit FCCAs in the target RTL in order to assign the target
|
||||
* port's fields to channels.
|
||||
* Returns a list of channel descriptors.
|
||||
*/
|
||||
def generateAnnotations(): Unit
|
||||
|
||||
/**
|
||||
* Returns a list of channel names for which FAMEChannelConnectionAnnotations have been generated
|
||||
*/
|
||||
def allChannelNames(): Seq[String]
|
||||
def bridgeChannels(): Seq[BridgeChannel]
|
||||
|
||||
// Called in FPGATop to connect the instantiated bridge to channel ports on the wrapper
|
||||
private[midas] def connectChannels2Port(bridgeAnno: BridgeIOAnnotation, channels: TargetChannelIO): Unit
|
||||
|
|
|
@ -3,20 +3,83 @@
|
|||
package midas.widgets
|
||||
|
||||
import chisel3._
|
||||
|
||||
import firrtl.{RenameMap}
|
||||
import firrtl.annotations.{SingleTargetAnnotation} // Deprecated
|
||||
import firrtl.annotations.{ReferenceTarget, ModuleTarget, HasSerializationHints}
|
||||
import firrtl.annotations.{Annotation, ReferenceTarget, ModuleTarget, HasSerializationHints}
|
||||
import freechips.rocketchip.config.Parameters
|
||||
|
||||
import midas.passes.fame.{RTRenamer}
|
||||
import midas.targetutils.FAMEAnnotation
|
||||
|
||||
sealed trait BridgeChannel {
|
||||
def update(renames: RenameMap): BridgeChannel
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor for a pipe channel ending at the bridge.
|
||||
*/
|
||||
case class PipeBridgeChannel(
|
||||
name: String,
|
||||
clock: ReferenceTarget,
|
||||
sinks: Seq[ReferenceTarget],
|
||||
sources: Seq[ReferenceTarget],
|
||||
latency: Int
|
||||
) extends BridgeChannel {
|
||||
def update(renames: RenameMap): BridgeChannel = {
|
||||
val renamer = RTRenamer.exact(renames)
|
||||
PipeBridgeChannel(name, renamer(clock), sinks.map(renamer), sources.map(renamer), latency)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor for a clock channel originating from a clock bridge.
|
||||
*/
|
||||
case class ClockBridgeChannel(
|
||||
name: String,
|
||||
sinks: Seq[ReferenceTarget],
|
||||
clocks: Seq[RationalClock],
|
||||
clockMFMRs: Seq[Int]
|
||||
) extends BridgeChannel {
|
||||
def update(renames: RenameMap): BridgeChannel = {
|
||||
val renamer = RTRenamer.exact(renames)
|
||||
ClockBridgeChannel(name, sinks.map(renamer), clocks, clockMFMRs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor for a Ready-Valid channel originating from a bridge.
|
||||
*/
|
||||
case class ReadyValidBridgeChannel(
|
||||
fwdName: String,
|
||||
revName: String,
|
||||
clock: ReferenceTarget,
|
||||
sinks: Seq[ReferenceTarget],
|
||||
sources: Seq[ReferenceTarget],
|
||||
valid: ReferenceTarget,
|
||||
ready: ReferenceTarget,
|
||||
) extends BridgeChannel {
|
||||
def update(renames: RenameMap): BridgeChannel = {
|
||||
val renamer = RTRenamer.exact(renames)
|
||||
ReadyValidBridgeChannel(
|
||||
fwdName,
|
||||
revName,
|
||||
renamer(clock),
|
||||
sinks.map(renamer),
|
||||
sources.map(renamer),
|
||||
renamer(valid),
|
||||
renamer(ready)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A serializable annotation emitted by Chisel Modules that extend Bridge
|
||||
*
|
||||
* @param target The module representing an Bridge. Typically a black box
|
||||
*
|
||||
* @param channelNames A list of channel names that match the globalName emitted in the FCCAs
|
||||
* associated with this bridge. We use these strings to look up those annotations
|
||||
* @param bridgeChannels A list of descriptors for the channels attached to the
|
||||
* bridge. FCCAs are materialized from these descriptors.
|
||||
*
|
||||
* @param widgetClass The full class name of the BridgeModule generator
|
||||
*
|
||||
|
@ -31,7 +94,7 @@ import midas.targetutils.FAMEAnnotation
|
|||
|
||||
case class BridgeAnnotation(
|
||||
target: ModuleTarget,
|
||||
channelNames: Seq[String],
|
||||
bridgeChannels: Seq[BridgeChannel],
|
||||
widgetClass: String,
|
||||
widgetConstructorKey: Option[_ <: AnyRef])
|
||||
extends SingleTargetAnnotation[ModuleTarget] with FAMEAnnotation with HasSerializationHints {
|
||||
|
@ -41,21 +104,32 @@ case class BridgeAnnotation(
|
|||
* a ReferenceTarget based one that can be attached to newly created IO on the top-level
|
||||
*/
|
||||
def toIOAnnotation(port: String): BridgeIOAnnotation = {
|
||||
val channelNames = bridgeChannels.flatMap({
|
||||
case ch: PipeBridgeChannel => Seq(ch.name)
|
||||
case ch: ClockBridgeChannel => Seq(ch.name)
|
||||
case ch: ReadyValidBridgeChannel => Seq(ch.fwdName, ch.revName)
|
||||
})
|
||||
val channelMapping = channelNames.map(oldName => oldName -> s"${port}_$oldName")
|
||||
BridgeIOAnnotation(target.copy(module = target.circuit).ref(port),
|
||||
channelMapping.toMap,
|
||||
widgetClass = widgetClass,
|
||||
widgetConstructorKey = widgetConstructorKey)
|
||||
widgetConstructorKey = widgetConstructorKey
|
||||
)
|
||||
}
|
||||
|
||||
def typeHints() = widgetConstructorKey match {
|
||||
def typeHints() = bridgeChannels.map(_.getClass) ++ (widgetConstructorKey match {
|
||||
// If the key has extra type hints too, grab them as well
|
||||
case Some(key: HasSerializationHints) => key.getClass +: key.typeHints
|
||||
case Some(key) => Seq(key.getClass)
|
||||
case None => Seq()
|
||||
}
|
||||
})
|
||||
|
||||
def duplicate(n: ModuleTarget) = this.copy(target)
|
||||
|
||||
override def update(renames: RenameMap): Seq[Annotation] = {
|
||||
val renamer = RTRenamer.exact(renames)
|
||||
Seq(BridgeAnnotation(target, bridgeChannels.map(_.update(renames)), widgetClass, widgetConstructorKey))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,27 +20,9 @@ import scala.collection.mutable
|
|||
* This becomes more useful when there are channel types.
|
||||
*
|
||||
*/
|
||||
sealed trait ChannelMetadata {
|
||||
def clockRT(): Option[ReferenceTarget]
|
||||
def chInfo(): FAMEChannelInfo
|
||||
def fieldRTs(): Seq[ReferenceTarget]
|
||||
def bridgeSunk: Boolean
|
||||
// Channel name is passed as an argument here because it is determined reflexively after the record
|
||||
// is constructed -- it's not avaiable when the metadata instance is created
|
||||
def generateAnnotations(chName: String): Seq[ChiselAnnotation] = {
|
||||
Seq(new ChiselAnnotation { def toFirrtl =
|
||||
if (bridgeSunk) {
|
||||
FAMEChannelConnectionAnnotation.source(chName, chInfo, clockRT, fieldRTs)
|
||||
} else {
|
||||
FAMEChannelConnectionAnnotation.sink(chName, chInfo, clockRT, fieldRTs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case class PipeChannelMetadata(field: Data, clock: Clock, bridgeSunk: Boolean, latency: Int = 0) extends ChannelMetadata {
|
||||
case class PipeChannelMetadata(field: Data, clock: Clock, bridgeSunk: Boolean, latency: Int = 0) {
|
||||
def fieldRTs = Seq(field.toTarget)
|
||||
def clockRT = Some(clock.toTarget)
|
||||
def clockRT = clock.toTarget
|
||||
def chInfo = midas.passes.fame.PipeChannel(latency)
|
||||
}
|
||||
|
||||
|
@ -63,7 +45,7 @@ trait ChannelizedHostPortIO extends HasChannels { this: Record =>
|
|||
// of the target-side of the bridge)
|
||||
// _2 -> The associated host-channel (an actual element in this aggregate, unlike above)
|
||||
// _3 -> Associated metadate which will encode for the FCCA
|
||||
private val channels = mutable.ArrayBuffer[(Data, ChannelType[_ <: Data], ChannelMetadata)]()
|
||||
private val channels = mutable.ArrayBuffer[(Data, ChannelType[_ <: Data], PipeChannelMetadata)]()
|
||||
|
||||
// These will only be called after the record has been finalized.
|
||||
lazy private val fieldToChannelMap = Map((channels.map(t => t._1 -> t._2)):_*)
|
||||
|
@ -123,14 +105,6 @@ trait ChannelizedHostPortIO extends HasChannels { this: Record =>
|
|||
ch
|
||||
}
|
||||
|
||||
// Implement methods of HasChannels
|
||||
def generateAnnotations(): Unit = {
|
||||
for ((targetField, channelElement, metadata) <- channels) {
|
||||
checkFieldDirection(targetField, metadata.bridgeSunk)
|
||||
metadata.generateAnnotations(reverseElementMap(channelElement)).map(a => annotate(a))
|
||||
}
|
||||
}
|
||||
|
||||
def connectChannels2Port(bridgeAnno: BridgeIOAnnotation, targetIO: TargetChannelIO): Unit = {
|
||||
val local2globalName = bridgeAnno.channelMapping.toMap
|
||||
for ((_, channel, metadata) <- channels) {
|
||||
|
@ -143,5 +117,12 @@ trait ChannelizedHostPortIO extends HasChannels { this: Record =>
|
|||
}
|
||||
}
|
||||
|
||||
def allChannelNames() = channels.map(ch => reverseElementMap(ch._2))
|
||||
def bridgeChannels = channels.map({ case (_, ch, meta) =>
|
||||
val name = reverseElementMap(ch)
|
||||
if (meta.bridgeSunk) {
|
||||
PipeBridgeChannel(name, meta.clockRT, Seq(), meta.fieldRTs, 0)
|
||||
} else {
|
||||
PipeBridgeChannel(name, meta.clockRT, meta.fieldRTs, Seq(), 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package midas.widgets
|
|||
|
||||
import midas.core.{TargetChannelIO, SimUtils}
|
||||
import midas.core.SimUtils.{RVChTuple}
|
||||
import midas.passes.fame.{FAMEChannelConnectionAnnotation, TargetClockChannel}
|
||||
import midas.passes.fame.{FAMEChannelConnectionAnnotation, TargetClockChannel, RTRenamer}
|
||||
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.util.DensePrefixSum
|
||||
|
@ -12,7 +12,9 @@ import freechips.rocketchip.util.DensePrefixSum
|
|||
import chisel3._
|
||||
import chisel3.util._
|
||||
import chisel3.experimental.{BaseModule, Direction, ChiselAnnotation, annotate}
|
||||
import firrtl.annotations.{ModuleTarget, ReferenceTarget}
|
||||
|
||||
import firrtl.{RenameMap}
|
||||
import firrtl.annotations.{Annotation, ModuleTarget, ReferenceTarget}
|
||||
|
||||
/**
|
||||
* Defines a generated clock as a rational multiple of some reference clock. The generated
|
||||
|
@ -87,20 +89,16 @@ class RationalClockBridge(val allClocks: Seq[RationalClock]) extends BlackBox wi
|
|||
annotate(new ChiselAnnotation { def toFirrtl =
|
||||
BridgeAnnotation(
|
||||
target = outer.toTarget,
|
||||
channelNames = Seq(clockChannelName),
|
||||
bridgeChannels = Seq(
|
||||
ClockBridgeChannel(
|
||||
name = clockChannelName,
|
||||
sinks = io.clocks.map(_.toTarget),
|
||||
clocks = allClocks,
|
||||
clockMFMRs)),
|
||||
widgetClass = classOf[ClockBridgeModule].getName,
|
||||
widgetConstructorKey = Some(ClockParameters(allClocks))
|
||||
)
|
||||
})
|
||||
annotate(new ChiselAnnotation { def toFirrtl =
|
||||
FAMEChannelConnectionAnnotation(
|
||||
clockChannelName,
|
||||
channelInfo = TargetClockChannel(allClocks, clockMFMRs),
|
||||
clock = None, // Clock channels do not have a reference clock
|
||||
sinks = Some(io.clocks.map(_.toTarget)),
|
||||
sources = None
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
object RationalClockBridge {
|
||||
|
@ -127,9 +125,11 @@ object RationalClockBridge {
|
|||
class ClockTokenVector(numClocks: Int) extends Bundle with HasChannels with ClockBridgeConsts {
|
||||
val clocks = new DecoupledIO(Vec(numClocks, Bool()))
|
||||
|
||||
def allChannelNames = Seq(clockChannelName)
|
||||
def bridgeChannels = Seq()
|
||||
|
||||
def connectChannels2Port(bridgeAnno: BridgeIOAnnotation, targetIO: TargetChannelIO): Unit =
|
||||
targetIO.clockElement._2 <> clocks
|
||||
|
||||
def generateAnnotations(): Unit = {}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,66 +46,6 @@ class HostPortIO[+T <: Data](private val targetPortProto: T) extends Record with
|
|||
allTargetClocks.head
|
||||
}
|
||||
|
||||
private def getRVChannelNames(channels: Seq[SimUtils.RVChTuple]): Seq[String] =
|
||||
channels.flatMap({ channel =>
|
||||
val (fwd, rev) = SimUtils.rvChannelNamePair(channel)
|
||||
Seq(fwd, rev)
|
||||
})
|
||||
|
||||
// Create a wire channel annotation
|
||||
protected def generateWireChannelFCCAs(channels: Seq[(Data, String)], bridgeSunk: Boolean = false, latency: Int = 0): Unit = {
|
||||
for ((field, chName) <- channels) {
|
||||
annotate(new ChiselAnnotation { def toFirrtl =
|
||||
if (bridgeSunk) {
|
||||
FAMEChannelConnectionAnnotation.source(chName, PipeChannel(latency), Some(getClock.toNamed.toTarget), Seq(field.toNamed.toTarget))
|
||||
} else {
|
||||
FAMEChannelConnectionAnnotation.sink(chName, PipeChannel(latency), Some(getClock.toNamed.toTarget), Seq(field.toNamed.toTarget))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Create Ready Valid channel annotations assuming bridge-sourced directions
|
||||
protected def generateRVChannelFCCAs(channels: Seq[(ReadyValidIO[Data], String)], bridgeSunk: Boolean = false): Unit = {
|
||||
for ((field, chName) <- channels) yield {
|
||||
// Generate the forward channel annotation
|
||||
val (fwdChName, revChName) = SimUtils.rvChannelNamePair(chName)
|
||||
annotate(new ChiselAnnotation { def toFirrtl = {
|
||||
val clockTarget = Some(getClock.toNamed.toTarget)
|
||||
val validTarget = field.valid.toNamed.toTarget
|
||||
val readyTarget = field.ready.toNamed.toTarget
|
||||
val leafTargets = Seq(validTarget) ++ SimUtils.lowerAggregateIntoLeafTargets(field.bits)
|
||||
// Bridge is the sink; it applies target backpressure
|
||||
if (bridgeSunk) {
|
||||
FAMEChannelConnectionAnnotation.source(
|
||||
fwdChName,
|
||||
DecoupledForwardChannel.source(validTarget, readyTarget),
|
||||
clockTarget,
|
||||
leafTargets
|
||||
)
|
||||
} else {
|
||||
// Bridge is the source; it asserts target-valid and receives target-backpressure
|
||||
FAMEChannelConnectionAnnotation.sink(
|
||||
fwdChName,
|
||||
DecoupledForwardChannel.sink(validTarget, readyTarget),
|
||||
clockTarget,
|
||||
leafTargets
|
||||
)
|
||||
}
|
||||
}})
|
||||
|
||||
annotate(new ChiselAnnotation { def toFirrtl = {
|
||||
val clockTarget = Some(getClock.toNamed.toTarget)
|
||||
val readyTarget = Seq(field.ready.toNamed.toTarget)
|
||||
if (bridgeSunk) {
|
||||
FAMEChannelConnectionAnnotation.sink(revChName, DecoupledReverseChannel, clockTarget, readyTarget)
|
||||
} else {
|
||||
FAMEChannelConnectionAnnotation.source(revChName, DecoupledReverseChannel, clockTarget, readyTarget)
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
|
||||
// These are lazy because parsePorts needs a directioned gen; these can be called once
|
||||
// this Record has been bound to Hardware
|
||||
//private lazy val (ins, outs, rvIns, rvOuts) = SimUtils.parsePorts(targetPortProto, alsoFlattenRVPorts = false)
|
||||
|
@ -180,16 +120,53 @@ class HostPortIO[+T <: Data](private val targetPortProto: T) extends Record with
|
|||
SimUtils.findClocks(hBits).map(_ := false.B.asClock)
|
||||
}
|
||||
|
||||
def generateAnnotations(): Unit = {
|
||||
generateWireChannelFCCAs(inputWireChannels, bridgeSunk = true, latency = 1)
|
||||
generateWireChannelFCCAs(outputWireChannels, bridgeSunk = false, latency = 1)
|
||||
generateRVChannelFCCAs(inputRVChannels, bridgeSunk = true)
|
||||
generateRVChannelFCCAs(outputRVChannels, bridgeSunk = false)
|
||||
}
|
||||
def allChannelNames: Seq[String] = ins.unzip._2 ++ outs.unzip._2 ++
|
||||
(rvIns.unzip._2 ++ rvOuts.unzip._2).flatMap { ch =>
|
||||
val (fwd, rev) = SimUtils.rvChannelNamePair(ch)
|
||||
Seq(fwd, rev)
|
||||
def bridgeChannels: Seq[BridgeChannel] = {
|
||||
val clockRT = getClock.toNamed.toTarget
|
||||
|
||||
inputWireChannels.map({ case (field, chName) =>
|
||||
PipeBridgeChannel(
|
||||
chName,
|
||||
clock = clockRT,
|
||||
sinks = Seq(),
|
||||
sources = Seq(field.toNamed.toTarget),
|
||||
latency = 1
|
||||
)
|
||||
}) ++
|
||||
outputWireChannels.map({ case (field, chName) =>
|
||||
PipeBridgeChannel(
|
||||
chName,
|
||||
clock = clockRT,
|
||||
sinks = Seq(field.toNamed.toTarget),
|
||||
sources = Seq(),
|
||||
latency = 1
|
||||
)
|
||||
}) ++
|
||||
rvIns.map({ case (field, chName) =>
|
||||
val (fwdChName, revChName) = SimUtils.rvChannelNamePair(chName)
|
||||
val validTarget = field.valid.toNamed.toTarget
|
||||
ReadyValidBridgeChannel(
|
||||
fwdChName,
|
||||
revChName,
|
||||
clock = getClock.toNamed.toTarget,
|
||||
sinks = Seq(),
|
||||
sources = Seq(validTarget) ++ SimUtils.lowerAggregateIntoLeafTargets(field.bits),
|
||||
valid = validTarget,
|
||||
ready = field.ready.toNamed.toTarget
|
||||
)
|
||||
}) ++
|
||||
rvOuts.map({ case (field, chName) =>
|
||||
val (fwdChName, revChName) = SimUtils.rvChannelNamePair(chName)
|
||||
val validTarget = field.valid.toNamed.toTarget
|
||||
ReadyValidBridgeChannel(
|
||||
fwdChName,
|
||||
revChName,
|
||||
clock = getClock.toNamed.toTarget,
|
||||
sinks = Seq(validTarget) ++ SimUtils.lowerAggregateIntoLeafTargets(field.bits),
|
||||
sources = Seq(),
|
||||
valid = validTarget,
|
||||
ready = field.ready.toNamed.toTarget
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue