Makes it to SimWrapper generator
This commit is contained in:
parent
dbbe9d657c
commit
83ab93c7d9
|
@ -51,14 +51,11 @@ private[midas] class MidasTransforms(
|
|||
new ResolveAndCheck,
|
||||
new HighFirrtlToMiddleFirrtl,
|
||||
new MiddleFirrtlToLowFirrtl,
|
||||
new EmitFirrtl("pre-bridge-extraction.fir"),
|
||||
new fame.EmitFAMEAnnotations("pre-bridge-extraction.json"),
|
||||
new BridgeExtraction,
|
||||
new fame.EmitFAMEAnnotations("post-bridge-extraction.json"),
|
||||
new EmitFirrtl("post-bridge-extraction.fir"),
|
||||
new ResolveAndCheck,
|
||||
new EmitFirrtl("post-bridge-extraction.fir"),
|
||||
new MiddleFirrtlToLowFirrtl,
|
||||
new fame.WrapTop,
|
||||
fame.WrapTop,
|
||||
new ResolveAndCheck,
|
||||
new EmitFirrtl("post-wrap-top.fir")) ++
|
||||
optionalTargetTransforms ++
|
||||
|
@ -69,15 +66,13 @@ private[midas] class MidasTransforms(
|
|||
new HighFirrtlToMiddleFirrtl,
|
||||
new MiddleFirrtlToLowFirrtl,
|
||||
new fame.FAMEDefaults,
|
||||
new EmitFirrtl("pre-channel-excision.fir"),
|
||||
new fame.ChannelExcision,
|
||||
new EmitFirrtl("post-channel-excision.fir"),
|
||||
new fame.EmitFAMEAnnotations("post-channel-excision.json"),
|
||||
new fame.InferModelPorts,
|
||||
new fame.EmitFAMEAnnotations("post-infer-model-ports.json"),
|
||||
new EmitFirrtl("post-channel-excision.fir"),
|
||||
new fame.FAMETransform,
|
||||
DefineAbstractClockGate,
|
||||
new EmitFirrtl("post-fame-transform.fir"),
|
||||
new fame.EmitFAMEAnnotations("post-fame-transform.json"),
|
||||
new ResolveAndCheck,
|
||||
new fame.EmitAndWrapRAMModels,
|
||||
new EmitFirrtl("post-gen-sram-models.fir"),
|
||||
|
|
|
@ -47,18 +47,18 @@ case class FAME1ClockChannel(name: String, ports: Seq[Port]) extends FAME1Channe
|
|||
}
|
||||
|
||||
trait FAME1DataChannel extends FAME1Channel {
|
||||
def clockDomainEnable: Port
|
||||
def clockDomainEnable: Expression
|
||||
def firedReg: DefRegister
|
||||
def isFired = WRef(firedReg)
|
||||
def isFiredOrFiring = Or(isFired, isFiring)
|
||||
def updateFiredReg(finishing: WRef): Statement = {
|
||||
Connect(NoInfo, isFired, Mux(finishing, Negate(WRef(clockDomainEnable)), isFiredOrFiring, BoolType))
|
||||
Connect(NoInfo, isFired, Mux(finishing, Negate(clockDomainEnable), isFiredOrFiring, BoolType))
|
||||
}
|
||||
}
|
||||
|
||||
case class FAME1InputChannel(
|
||||
name: String,
|
||||
clockDomainEnable: Port,
|
||||
clockDomainEnable: Expression,
|
||||
ports: Seq[Port],
|
||||
firedReg: DefRegister) extends FAME1DataChannel {
|
||||
val direction = Input
|
||||
|
@ -70,13 +70,13 @@ case class FAME1InputChannel(
|
|||
|
||||
case class FAME1OutputChannel(
|
||||
name: String,
|
||||
clockDomainEnable: Port,
|
||||
clockDomainEnable: Expression,
|
||||
ports: Seq[Port],
|
||||
firedReg: DefRegister) extends FAME1DataChannel {
|
||||
val direction = Output
|
||||
val portName = s"${name}_source"
|
||||
def setValid(finishing: WRef, ccDeps: Iterable[FAME1InputChannel]): Statement = {
|
||||
Connect(NoInfo, isValid, And(And.reduce(ccDeps.map(_.isValid)), Negate(isFired)))
|
||||
Connect(NoInfo, isValid, And.reduce(ccDeps.map(_.isValid).toSeq :+ Negate(isFired)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,9 @@ object FAMEModuleTransformer {
|
|||
// Multi-clock management step 1: Add host clock + reset ports, finishing wire
|
||||
// TODO: Should finishing be a WrappedComponent?
|
||||
// TODO: Avoid static naming convention.
|
||||
val hostReset = Port(NoInfo, "hostReset", Input, BoolType)
|
||||
val hostClock = Port(NoInfo, "hostClock", Input, ClockType)
|
||||
val finishing = DefWire(NoInfo, "targetCyclefinishing", BoolType)
|
||||
val hostReset = Port(NoInfo, WrapTop.hostResetName, Input, BoolType)
|
||||
val hostClock = Port(NoInfo, WrapTop.hostClockName, Input, ClockType)
|
||||
val finishing = DefWire(NoInfo, "targetCycleFinishing", BoolType)
|
||||
assert(ns.tryName(hostReset.name) && ns.tryName(hostClock.name) && ns.tryName(finishing.name))
|
||||
def hostFlagReg(suggestName: String, resetVal: UIntLiteral = UIntLiteral(0)): DefRegister = {
|
||||
DefRegister(NoInfo, ns.newName(suggestName), BoolType, WRef(hostClock), WRef(hostReset), resetVal)
|
||||
|
@ -110,17 +110,22 @@ object FAMEModuleTransformer {
|
|||
}
|
||||
|
||||
val clockChannel = analysis.modelInputChannelPortMap(mTarget).find(isClockChannel) match {
|
||||
case Some((name, (None, ports))) => FAME1ClockChannel(name, ports.map(_.copy(tpe = BoolType)))
|
||||
case Some((name, (None, ports))) => FAME1ClockChannel(name, ports)
|
||||
case Some(_) => ??? // Clock channel cannot have
|
||||
case None => ??? // Clock channel is mandatory for now
|
||||
}
|
||||
|
||||
def tokenizeClockRef(wr: WRef): Expression = wr match {
|
||||
case WRef(name, ClockType, PortKind, _) => DoPrim(PrimOps.AsUInt, Seq(clockChannel.replacePortRef(wr)), Nil, BoolType)
|
||||
}
|
||||
|
||||
// Multi-clock management step 4: Generate clock buffers for all target clocks
|
||||
val targetClockBufs: Seq[SignalInfo] = clockChannel.ports.map { en =>
|
||||
val enableReg = hostFlagReg(s"${en.name}_enabled", resetVal = UIntLiteral(1))
|
||||
val buf = WDefInstance(DefineAbstractClockGate.blackbox.name, ns.newName(s"${en.name}_buffer"))
|
||||
val buf = WDefInstance(ns.newName(s"${en.name}_buffer"), DefineAbstractClockGate.blackbox.name)
|
||||
val clockFlag = tokenizeClockRef(WRef(en))
|
||||
val connects = Block(Seq(
|
||||
Connect(NoInfo, WRef(enableReg), Mux(WRef(finishing), WRef(en), WRef(enableReg), BoolType)),
|
||||
Connect(NoInfo, WRef(enableReg), Mux(WRef(finishing), clockFlag, WRef(enableReg), BoolType)),
|
||||
Connect(NoInfo, WSubField(WRef(buf), "I"), WRef(hostClock)),
|
||||
Connect(NoInfo, WSubField(WRef(buf), "CE"), And(WRef(enableReg), WRef(finishing)))))
|
||||
SignalInfo(Block(Seq(enableReg, buf)), connects, WSubField(WRef(buf), "O", ClockType, MALE))
|
||||
|
@ -136,15 +141,15 @@ object FAMEModuleTransformer {
|
|||
|
||||
def genMetadata(info: (String, (Option[Port], Seq[Port]))) = info match {
|
||||
case (cName, (Some(clock), ports)) =>
|
||||
val sourceClocks = portDeps.getEdges(clock.name)
|
||||
assert(sourceClocks.size == 1) // must be driven by one clock input
|
||||
val clkFlag = portsByName(sourceClocks.head).copy(tpe = BoolType)
|
||||
// must be driven by one clock input port
|
||||
// TODO: this should not include muxes in connectivity!
|
||||
val srcClockPorts = portDeps.getEdges(clock.name).map(portsByName(_))
|
||||
assert(srcClockPorts.size == 1)
|
||||
val clockRef = WRef(srcClockPorts.head)
|
||||
val clockFlag = tokenizeClockRef(clockRef)
|
||||
val firedReg = hostFlagReg(suggestName = ns.newName(s"${cName}_fired"))
|
||||
(cName, clkFlag, ports, firedReg)
|
||||
case (cName, (None, ports)) =>
|
||||
println(s"Channel ${cName} has no clock")
|
||||
ports.foreach { p => println(s" ${p}") }
|
||||
??? // clock is mandatory for now
|
||||
(cName, clockFlag, ports, firedReg)
|
||||
case (cName, (None, ports)) => ??? // clock is mandatory for now
|
||||
}
|
||||
|
||||
// LinkedHashMap.from is 2.13-only :(
|
||||
|
@ -184,7 +189,10 @@ object FAMEModuleTransformer {
|
|||
case e => e map onExpr
|
||||
}
|
||||
|
||||
def onStmt(stmt: Statement): Statement = stmt map onStmt map onExpr
|
||||
def onStmt(stmt: Statement): Statement = stmt match {
|
||||
case Connect(_, WRef(_, ClockType, PortKind, _), _) => EmptyStmt // don't drive clock outputs
|
||||
case s => s map onStmt map onExpr
|
||||
}
|
||||
|
||||
val updatedBody = onStmt(m.body)
|
||||
|
||||
|
@ -212,8 +220,9 @@ class FAMETransform extends Transform {
|
|||
|
||||
def updateNonChannelConnects(analysis: FAMEChannelAnalysis)(stmt: Statement): Statement = stmt.map(updateNonChannelConnects(analysis)) match {
|
||||
case wi: WDefInstance if (analysis.transformedModules.contains(analysis.moduleTarget(wi))) =>
|
||||
val resetConn = Connect(NoInfo, WSubField(WRef(wi), "hostReset"), WRef(analysis.hostReset.ref, BoolType))
|
||||
Block(Seq(wi, resetConn))
|
||||
val clockConn = Connect(NoInfo, WSubField(WRef(wi), WrapTop.hostClockName), WRef(analysis.hostClock.ref, ClockType))
|
||||
val resetConn = Connect(NoInfo, WSubField(WRef(wi), WrapTop.hostResetName), WRef(analysis.hostReset.ref, BoolType))
|
||||
Block(Seq(wi, clockConn, resetConn))
|
||||
case Connect(_, WRef(name, _, _, _), _) if (analysis.staleTopPorts.contains(analysis.topTarget.ref(name))) => EmptyStmt
|
||||
case Connect(_, _, WRef(name, _, _, _)) if (analysis.staleTopPorts.contains(analysis.topTarget.ref(name))) => EmptyStmt
|
||||
case s => s
|
||||
|
@ -277,8 +286,7 @@ class FAMETransform extends Transform {
|
|||
val transformedModules = c.modules.map {
|
||||
case m: Module if (m.name == c.main) => transformTop(m, analysis)
|
||||
case m: Module if (analysis.transformedModules.contains(ModuleTarget(c.main,m.name))) => FAMEModuleTransformer(m, analysis)
|
||||
case m: Module if (analysis.syncNativeModules.contains(ModuleTarget(c.main, m.name))) => PatientSSMTransformer(m, analysis)
|
||||
case m => m
|
||||
case m => m // TODO (Albert): revisit this; currently, not transforming nested modules
|
||||
}
|
||||
state.copy(circuit = c.copy(modules = transformedModules), renames = Some(hostDecouplingRenames(analysis)))
|
||||
}
|
||||
|
|
|
@ -51,11 +51,6 @@ private[fame] object FAMEChannelAnalysis {
|
|||
def getHostDecoupledChannelType(name: String, ports: Seq[Port]): Type = Decouple(getHostDecoupledChannelPayloadType(name, ports))
|
||||
}
|
||||
|
||||
private [fame] object HostReset {
|
||||
def makePort(ns: Namespace): Port =
|
||||
new Port(NoInfo, ns.newName("hostReset"), Input, Utils.BoolType)
|
||||
}
|
||||
|
||||
private[fame] class FAMEChannelAnalysis(val state: CircuitState, val fameType: FAMETransformType) {
|
||||
// TODO: only transform submodules of model modules
|
||||
// TODO: add renames!
|
||||
|
@ -176,18 +171,10 @@ private[fame] class FAMEChannelAnalysis(val state: CircuitState, val fameType: F
|
|||
})
|
||||
})
|
||||
|
||||
val hostClock = state.annotations.collect({ case FAMEHostClock(rt) => rt }).head
|
||||
val hostReset = state.annotations.collect({ case FAMEHostReset(rt) => rt }).head
|
||||
|
||||
private def irPortFromGlobalTarget(rt: ReferenceTarget): Port = {
|
||||
println(s"Resolving port node from global ref ${rt}")
|
||||
if (topConnects.contains(rt)) {
|
||||
println(s"${rt} is connected to ${topConnects(rt)} (in some direction)")
|
||||
} else {
|
||||
println(s"Key ${rt} not found, dumping topConnects:")
|
||||
topConnects.foreach {
|
||||
case (k, v) => println(s" ${k} <> ${v}")
|
||||
}
|
||||
}
|
||||
portNodes(topConnects(rt).pathlessTarget)
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ sealed trait BinaryBooleanOp {
|
|||
def op: PrimOp
|
||||
def apply(l: Expression, r: Expression): DoPrim = DoPrim(op, Seq(l, r), Nil, UnknownType)
|
||||
def reduce(args: Iterable[Expression]): Expression = {
|
||||
require(args.nonEmpty)
|
||||
args.tail.foldLeft(args.head){ (l, r) => apply(l, r) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,33 +7,48 @@ import ir._
|
|||
import annotations._
|
||||
|
||||
// Wrap the top module of a circuit with another module
|
||||
class WrapTop extends Transform {
|
||||
object WrapTop extends Transform {
|
||||
def inputForm = HighForm
|
||||
def outputForm = HighForm
|
||||
|
||||
// TODO: Make these names flexible
|
||||
// Previously, it looked like they were in the code, but they weren't
|
||||
// This refactors them to reflect that fact
|
||||
val topWrapperName = "FAMETop"
|
||||
val hostClockName = "clock"
|
||||
val hostResetName = "hostReset"
|
||||
|
||||
def checkNames(c: Circuit, top: DefModule) = {
|
||||
val ns = Namespace(top.ports.map(_.name))
|
||||
val portsOK = ns.tryName(hostClockName) && ns.tryName(hostResetName)
|
||||
portsOK && ns.tryName(top.name) && Namespace(c).tryName(topWrapperName)
|
||||
}
|
||||
|
||||
override def execute(state: CircuitState): CircuitState = {
|
||||
val topName = state.circuit.main
|
||||
val topModule = state.circuit.modules.find(_.name == topName).get
|
||||
val circuitNS = Namespace(state.circuit)
|
||||
val topWrapperName = circuitNS.newName("FAMETop")
|
||||
val topWrapperNS = Namespace(topModule.ports.map(_.name))
|
||||
val topInstance = WDefInstance(topWrapperNS.newName(topName), topName)
|
||||
assert(checkNames(state.circuit, topModule))
|
||||
|
||||
val topInstance = WDefInstance(topName, topName)
|
||||
val portConnections = topModule.ports.map({
|
||||
case ip @ Port(_, name, Input, _) => Connect(NoInfo, WSubField(WRef(topInstance), name), WRef(ip))
|
||||
case op @ Port(_, name, Output, _) => Connect(NoInfo, WRef(op), WSubField(WRef(topInstance), name))
|
||||
})
|
||||
val clocks = topModule.ports.filter(_.tpe == ClockType)
|
||||
val hostClock = clocks.find(_.name == "clock").getOrElse(clocks.head)
|
||||
val hostReset = HostReset.makePort(topWrapperNS)
|
||||
|
||||
val hostClock = Port(NoInfo, hostClockName, Input, ClockType)
|
||||
val hostReset = Port(NoInfo, hostResetName, Input, Utils.BoolType)
|
||||
|
||||
val oldCircuitTarget = CircuitTarget(topName)
|
||||
val topWrapperTarget = ModuleTarget(topWrapperName, topWrapperName)
|
||||
val topWrapper = Module(NoInfo, topWrapperName, topModule.ports :+ hostReset, Block(topInstance +: portConnections))
|
||||
val topWrapper = Module(NoInfo, topWrapperName, hostClock +: hostReset +: topModule.ports, Block(topInstance +: portConnections))
|
||||
val specialPortAnnotations = Seq(FAMEHostClock(topWrapperTarget.ref(hostClock.name)), FAMEHostReset(topWrapperTarget.ref(hostReset.name)))
|
||||
|
||||
val renames = RenameMap()
|
||||
val newCircuit = Circuit(state.circuit.info, topWrapper +: state.circuit.modules, topWrapperName)
|
||||
// Make channel annotations point at top-level ports
|
||||
val fccaRenames = RenameMap()
|
||||
fccaRenames.record(oldCircuitTarget.module(topName), oldCircuitTarget.module(topWrapperName))
|
||||
|
||||
val updatedAnnotations = state.annotations.map({
|
||||
case fcca: FAMEChannelConnectionAnnotation =>
|
||||
val renamedInfo = fcca.channelInfo match {
|
||||
|
|
|
@ -14,9 +14,9 @@ class NoConfig extends Config(Parameters.empty)
|
|||
// This is incomplete and must be mixed into a complete platform config
|
||||
class DefaultF1Config extends Config(new Config((site, here, up) => {
|
||||
case DesiredHostFrequency => 75
|
||||
case SynthAsserts => true
|
||||
case SynthAsserts => false
|
||||
case midas.GenerateMultiCycleRamModels => true
|
||||
case SynthPrints => true
|
||||
case SynthPrints => false
|
||||
}) ++ new Config(new firesim.configs.WithEC2F1Artefacts ++ new WithDefaultMemModel ++ new midas.F1Config))
|
||||
|
||||
class PointerChaserConfig extends Config((site, here, up) => {
|
||||
|
|
Loading…
Reference in New Issue