Makes it to SimWrapper generator

This commit is contained in:
Albert Magyar 2019-11-14 00:55:14 -08:00
parent dbbe9d657c
commit 83ab93c7d9
6 changed files with 64 additions and 58 deletions

View File

@ -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"),

View File

@ -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)))
}

View File

@ -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)
}

View File

@ -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) }
}
}

View File

@ -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 {

View File

@ -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) => {