aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Driver.scala6
-rw-r--r--src/main/scala/firrtl/Utils.scala8
-rw-r--r--src/main/scala/midas/Fame.scala220
-rw-r--r--src/main/scala/midas/Utils.scala303
4 files changed, 362 insertions, 175 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index ce8d2b1d..e8ad8d56 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -83,9 +83,9 @@ object Driver
writer.write(ast3.serialize())
writer.close()
- //val postCmd = Seq("firrtl-stanza", "-i", temp2, "-o", output, "-b", "firrtl") ++ stanzaPostTransform.flatMap(Seq("-x", _))
- //println(postCmd.mkString(" "))
- //postCmd.!
+ val postCmd = Seq("firrtl-stanza", "-i", temp2, "-o", output, "-X", "verilog")
+ println(postCmd.mkString(" "))
+ postCmd.!
}
private def verilog(input: String, output: String)(implicit logger: Logger)
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index 73799765..d767f027 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -196,6 +196,13 @@ object Utils {
}
s + debug(dir)
}
+ def flip(): FieldDir = {
+ dir match {
+ case Reverse => Default
+ case Default => Reverse
+ }
+ }
+
def toPortDir(): PortDir = {
dir match {
case Default => Output
@@ -207,6 +214,7 @@ object Utils {
implicit class FieldUtils(field: Field) {
def serialize(implicit flags: FlagMap = FlagMap): String =
s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + debug(field)
+ def flip(): Field = Field(field.name, field.dir.flip, field.tpe)
def getType(): Type = field.tpe
def toPort(): Port = Port(NoInfo, field.name, field.dir.toPortDir, field.tpe)
diff --git a/src/main/scala/midas/Fame.scala b/src/main/scala/midas/Fame.scala
index f53ab56d..49cdb613 100644
--- a/src/main/scala/midas/Fame.scala
+++ b/src/main/scala/midas/Fame.scala
@@ -30,16 +30,22 @@ import firrtl.Utils._
* - All and only instances in NewTop are sim tagged
* - No black boxes in design
* 2. Simulation Transformation
- * a. Iteratively transform each inst in Top (see example firrtl in dram_midas top dir)
+ * a. Perform Decoupled Transformation on every RTL Module
+ * i. Add targetFire signal input
+ * ii. Find all DefInst nodes and propogate targetFire to the instances
+ * iii. Find all registers and add when statement connecting regIn to regOut when !targetFire
+ * b. Iteratively transform each inst in Top (see example firrtl in dram_midas top dir)
* i. Create wrapper class
* ii. Create input and output (ready, valid) pairs for every other sim module this module connects to
* * Note that TopIO counts as a "sim module"
- * iii. Create simFire as AND of inputs.valid and outputs.ready
- * iv. Create [target] simClock as AND of simFire and [host] clock
+ * iii. Create targetFire as AND of inputs.valid and outputs.ready
+ * iv. Connect targetFire to targetFire input of target rtl inst
* v. Connect target IO to wrapper IO, except connect target clock to simClock
*
* TODO
+ * - Change from clock gating to reg enable, dont' forget to change sequential memory read enable
* - Implement Flatten RTL
+ * - Refactor important strings/naming to API (eg. "topIO" needs to be a constant defined somewhere or something)
* - Check that circuit is in LowFIRRTL?
*
* NOTES
@@ -61,49 +67,35 @@ import firrtl.Utils._
*/
object Fame1 {
- private def getDefInsts(s: Stmt): Seq[DefInst] = {
- s match {
- case i: DefInst => Seq(i)
- case b: Block => b.stmts.map(getDefInsts).flatten
- case _ => Seq()
- }
- }
- private def getDefInsts(m: Module): Seq[DefInst] = getDefInsts(m.stmt)
+ // Constants, common nodes, and common types used throughout
+ private type PortMap = Map[String, Seq[String]]
+ private val PortMap = Map[String, Seq[String]]()
+ private type ConnMap = Map[String, PortMap]
+ private val ConnMap = Map[String, PortMap]()
+ private type SimQMap = Map[(String, String), Module]
+ private val SimQMap = Map[(String, String), Module]()
- private def getDefInstRef(inst: DefInst): Ref = {
- inst.module match {
- case ref: Ref => ref
- case _ => throw new Exception("Invalid module expression for DefInst: " + inst.serialize)
- }
- }
+ private val hostReady = Field("hostReady", Reverse, UIntType(IntWidth(1)))
+ private val hostValid = Field("hostValid", Default, UIntType(IntWidth(1)))
+ private val hostClock = Port(NoInfo, "hostClock", Input, ClockType)
+ private val hostReset = Port(NoInfo, "hostReset", Input, UIntType(IntWidth(1)))
+ private val targetFire = Port(NoInfo, "targetFire", Input, UIntType(IntWidth(1)))
- // DefInsts have an Expression for the module, this expression should be a reference this
- // reference has a tpe that should be a bundle representing the IO of that module class
- private def getDefInstType(inst: DefInst): BundleType = {
- val ref = getDefInstRef(inst)
- ref.tpe match {
- case b: BundleType => b
- case _ => throw new Exception("Invalid reference type for DefInst: " + inst.serialize)
- }
- }
+ private def wrapName(name: String): String = s"SimWrap_${name}"
+ private def unwrapName(name: String): String = name.stripPrefix("SimWrap_")
+ private def queueName(src: String, dst: String): String = s"SimQueue_${src}_${dst}"
+ private def instName(name: String): String = s"inst_${name}"
+ private def unInstName(name: String): String = name.stripPrefix("inst_")
- private def getModuleFromDefInst(nameToModule: Map[String, Module], inst: DefInst): Module = {
- val instModule = getDefInstRef(inst)
- if(!nameToModule.contains(instModule.name))
- throw new Exception(s"Module ${instModule.name} not found in circuit!")
- else
- nameToModule(instModule.name)
+ private def genHostDecoupled(fields: Seq[Field]): BundleType = {
+ BundleType(Seq(hostReady, hostValid) :+ Field("hostBits", Default, BundleType(fields)))
}
- // ***** findPortConn *****
+ // ********** findPortConn **********
// This takes lowFIRRTL top module that follows invariants described above and returns a connection Map
// of instanceName -> (instanctPorts -> portEndpoint)
// It honestly feels kind of brittle given it assumes there will be no intermediate nodes or anything in
// the way of direct connections between IO of module instances
- private type PortMap = Map[String, Seq[String]]
- private val PortMap = Map[String, Seq[String]]()
- private type ConnMap = Map[String, PortMap]
- private val ConnMap = Map[String, PortMap]()
private def processConnectExp(exp: Exp): (String, String) = {
val unsupportedExp = new Exception("Unsupported Exp for finding port connections: " + exp)
exp match {
@@ -143,27 +135,33 @@ object Fame1 {
findPortConn(initConnMap, topStmts)
}
- // ***** Name Translation functions to help make naming consistent and easy to change *****
- private def wrapName(name: String): String = s"SimWrap_${name}"
- private def unwrapName(name: String): String = name.stripPrefix("SimWrap_")
- private def queueName(src: String, dst: String): String = s"SimQueue_${src}_${dst}"
- private def instName(name: String): String = s"inst_${name}"
- private def unInstName(name: String): String = name.stripPrefix("inst_")
-
- // ***** genWrapperModule *****
- // Generates FAME-1 Decoupled wrappers for simulation module instances
- private val hostReady = Field("hostReady", Reverse, UIntType(IntWidth(1)))
- private val hostValid = Field("hostValid", Default, UIntType(IntWidth(1)))
- private val hostClock = Port(NoInfo, "hostClock", Input, ClockType)
- private val hostReset = Port(NoInfo, "hostReset", Input, UIntType(IntWidth(1)))
+ // Removes clocks from a portmap
+ private def scrubClocks(ports: Seq[Port], portMap: PortMap): PortMap = {
+ val clocks = ports filter (_.tpe == ClockType) map (_.name)
+ portMap filter { case (portName, _) => !clocks.contains(portName) }
+ }
- private def genHostDecoupled(fields: Seq[Field]): BundleType = {
- BundleType(Seq(hostReady, hostValid) :+ Field("hostBits", Default, BundleType(fields)))
+ // ********** transformRTL **********
+ // Takes an RTL module and give it targetFire input, propogates targetFire to all child instances,
+ // puts targetFire on regEnable for all registers
+ // TODO
+ // - Add smem support
+ private def transformRTL(m: Module): Module = {
+ val ports = m.ports :+ targetFire
+ val instProp = getDefInsts(m) map { inst =>
+ Connect(NoInfo, buildExp(Seq(inst.name, targetFire.name)), buildExp(targetFire.name))
+ }
+ val regEn = getDefRegs(m) map { reg =>
+ When(NoInfo, DoPrimop(Not, Seq(buildExp(targetFire.name)), Seq(), UnknownType),
+ Connect(NoInfo, buildExp(reg.name), buildExp(reg.name)), EmptyStmt)
+ }
+ Module(m.info, m.name, ports, Block(m.stmt +: (instProp ++ regEn)))
}
+ // ********** genWrapperModule **********
+ // Generates FAME-1 Decoupled wrappers for simulation module instances
private def genWrapperModule(inst: DefInst, portMap: PortMap): Module = {
- println(s"Wrapping ${inst.name}")
- println(portMap)
+
val instIO = getDefInstType(inst)
val nameToField = (instIO.fields map (f => f.name -> f)).toMap
@@ -181,7 +179,7 @@ object Fame1 {
else Seq(Field("hostIn", Reverse, genHostDecoupled(inputSet)))
) ++
(if (outputSet.isEmpty) Seq()
- else Seq(Field("hostOut", Default, genHostDecoupled(inputSet)))
+ else Seq(Field("hostOut", Default, genHostDecoupled(outputSet)))
)
))
}
@@ -198,11 +196,8 @@ object Fame1 {
}
}).flatten
- val targetFire = DefNode(inst.info, "targetFire", genPrimopReduce(And, targetFireInputs))
- // targetClock is the simple AND of targetFire and the hostClock so that the rtl module only executes when data
- // is available and outputs are ready
- val targetClock = DefNode(inst.info, "targetClock", DoPrimop(And,
- Seq(buildExp(targetFire.name), buildExp(hostClock.name)), Seq(), UnknownType))
+ val defTargetFire = DefNode(inst.info, targetFire.name, genPrimopReduce(And, targetFireInputs))
+ val connectTargetFire = Connect(NoInfo, buildExp(Seq(inst.name, targetFire.name)), buildExp(targetFire.name))
// As a simple RTL module, we're always ready
val inputsReady = (connPorts map { port =>
@@ -224,37 +219,33 @@ object Fame1 {
val instIOConnect = (connectedInstIOFields map { field =>
field.tpe match {
case ClockType => Seq(Connect(inst.info, buildExp(Seq(inst.name, field.name)),
- Ref(targetClock.name, ClockType)))
+ Ref(hostClock.name, ClockType)))
case _ => field.dir match {
case Default => portMap(field.name) map { endpoint =>
- Connect(inst.info, buildExp(Seq(endpoint, "hostOut", field.name)),
+ Connect(inst.info, buildExp(Seq(endpoint, "hostOut", "hostBits", field.name)),
buildExp(Seq(inst.name, field.name)))
}
case Reverse => {
if (portMap(field.name).length > 1)
throw new Exception("It is illegal to have more than 1 connection to a single input" + field)
Seq(Connect(inst.info, buildExp(Seq(inst.name, field.name)),
- buildExp(Seq(portMap(field.name).head, "hostIn", field.name))))
+ buildExp(Seq(portMap(field.name).head, "hostIn", "hostBits", field.name))))
}
}
}
}).flatten
- //val stmts = Block(Seq(simFire, simClock, inst) ++ inputsReady ++ outputsValid ++ instIOConnect)
- val stmts = Block(Seq(targetFire, targetClock) ++ inputsReady ++ outputsValid ++ Seq(inst) ++ instIOConnect)
+ val stmts = Block(Seq(defTargetFire) ++ inputsReady ++ outputsValid ++ Seq(inst) ++
+ Seq(connectTargetFire) ++ instIOConnect)
Module(inst.info, wrapName(inst.name), ports, stmts)
}
-
-
- // ***** generateSimQueues *****
+ // ********** generateSimQueues **********
// Takes Seq of SimWrapper modules
// Returns Map of (src, dest) -> SimQueue
// To prevent duplicates, instead of creating a map with (src, dest) as the key, we could instead
// only one direction of the queue for each simport of each module. The only problem with this is
// it won't create queues for TopIO since that isn't a real module
- private type SimQMap = Map[(String, String), Module]
- private val SimQMap = Map[(String, String), Module]()
private def generateSimQueues(wrappers: Seq[Module]): SimQMap = {
def rec(wrappers: Seq[Module], map: SimQMap): SimQMap = {
if (wrappers.isEmpty) map
@@ -274,58 +265,101 @@ object Fame1 {
rec(wrappers, SimQMap)
}
- // ***** generateSimTop *****
+ // ********** generateSimTop **********
// Creates the Simulation Top module where all sim modules and sim queues are instantiated and connected
- private def generateSimTop(wrappers: Seq[Module], simQueues: SimQMap, rtlTop: Module): Module = {
+ private def transformTopIO(ports: Seq[Port]): Seq[Port] = {
+ val noClock = ports filter (_.tpe != ClockType)
+ val inputs = noClock filter (_.dir == Input) map (_.toField.flip) // Flip because wrapping port is input
+ val outputs = noClock filter (_.dir == Output) map (_.toField)
+
+ Seq(Port(NoInfo, "io", Output, BundleType(Seq(Field("hostIn", Reverse, genHostDecoupled(inputs)),
+ Field("hostOut", Default, genHostDecoupled(outputs))))))
+ }
+ private def generateSimTop(wrappers: Seq[Module], simQueues: SimQMap, portMap: PortMap, rtlTop: Module): Module = {
val insts = (wrappers map { m => DefInst(NoInfo, instName(m.name), buildExp(m.name)) }) ++
(simQueues.values map { m => DefInst(NoInfo, instName(m.name), buildExp(m.name)) })
val connectClocks = (wrappers ++ simQueues.values) map { m =>
- Connect(NoInfo, buildExp(Seq(m.name, hostClock.name)), buildExp(hostClock.name))
+ Connect(NoInfo, buildExp(Seq(instName(m.name), hostClock.name)), buildExp(hostClock.name))
}
val connectResets = (wrappers ++ simQueues.values) map { m =>
- Connect(NoInfo, buildExp(Seq(m.name, hostReset.name)), buildExp(hostReset.name))
- }
- val connectQueues = simQueues map { case (key, queue) =>
- (key._1, key._2) match {
- //case (src, "topIO") => EmptyStmt
- //case ("topIO", dst) => EmptyStmt
- case (src, dst) => Block(Seq(BulkConnect(NoInfo, buildExp(Seq(queue.name, "io", "enq")),
- buildExp(Seq(instName(wrapName(src)), dst, "hostOut"))),
- BulkConnect(NoInfo, buildExp(Seq(queue.name, "io", "deq")),
- buildExp(Seq(instName(wrapName(dst)), src, "hostIn")))))
- }
+ Connect(NoInfo, buildExp(Seq(instName(m.name), hostReset.name)), buildExp(hostReset.name))
}
- val stmts = Block(insts ++ connectClocks ++ connectResets ++ connectQueues)
- val ports = Seq(hostClock, hostReset) ++ rtlTop.ports
+ // Connect queues to simulation modules (excludes IO)
+ val connectQueues = (simQueues map { case ((src, dst), queue) =>
+ (if (src == "topIO") Seq()
+ else Seq(BulkConnect(NoInfo, buildExp(Seq(instName(queue.name), "io", "enq")),
+ buildExp(Seq(instName(wrapName(src)), dst, "hostOut"))))
+ ) ++
+ (if (dst == "topIO") Seq()
+ else Seq(BulkConnect(NoInfo, buildExp(Seq(instName(wrapName(dst)), src, "hostIn")),
+ buildExp(Seq(instName(queue.name), "io", "deq"))))
+ )
+ }).flatten
+ // Connect IO queues, Src means input, Dst means output (ie. the outside word is the Src or Dst)
+ val ioSrcQueues = (simQueues filter {case ((src, dst), _) => src == "topIO"} map {case (_, queue) => queue}).toSeq
+ val ioDstQueues = (simQueues filter {case ((src, dst), _) => dst == "topIO"} map {case (_, queue) => queue}).toSeq
+ val ioSrcSignals = rtlTop.ports filter (sig => sig.tpe != ClockType && sig.dir == Input) map (_.name)
+ val ioDstSignals = rtlTop.ports filter (sig => sig.tpe != ClockType && sig.dir == Output) map (_.name)
+
+ val ioSrcQueueConnect = if (ioSrcQueues.length > 0) {
+ val readySignals = ioSrcQueues map (queue => buildExp(Seq(instName(queue.name), "io", "enq", hostReady.name)))
+ val validSignals = ioSrcQueues map (queue => buildExp(Seq(instName(queue.name), "io", "enq", hostValid.name)))
+
+ (ioSrcSignals map { sig =>
+ (portMap(sig) map { dst =>
+ Connect(NoInfo, buildExp(Seq(instName(queueName("topIO", dst)), "io", "enq", "hostBits", sig)),
+ buildExp(Seq("io", "hostIn", "hostBits", sig)))
+ })
+ }).flatten ++
+ (validSignals map (sig => Connect(NoInfo, buildExp(sig), buildExp(Seq("io", "hostIn", hostValid.name))))) :+
+ Connect(NoInfo, buildExp(Seq("io", "hostIn", hostReady.name)), genPrimopReduce(And, readySignals))
+ } else Seq(EmptyStmt)
+
+ val ioDstQueueConnect = if (ioDstQueues.length > 0) {
+ val readySignals = ioDstQueues map (queue => buildExp(Seq(instName(queue.name), "io", "deq", hostReady.name)))
+ val validSignals = ioDstQueues map (queue => buildExp(Seq(instName(queue.name), "io", "deq", hostValid.name)))
+
+ (ioDstSignals map { sig =>
+ (portMap(sig) map { src =>
+ Connect(NoInfo, buildExp(Seq("io", "hostOut", "hostBits", sig)),
+ buildExp(Seq(instName(queueName(src, "topIO")), "io", "deq", "hostBits", sig)))
+ })
+ }).flatten ++
+ (readySignals map (sig => Connect(NoInfo, buildExp(sig), buildExp(Seq("io", "hostOut", hostReady.name))))) :+
+ Connect(NoInfo, buildExp(Seq("io", "hostOut", hostValid.name)), genPrimopReduce(And, validSignals))
+ } else Seq(EmptyStmt)
+
+ val stmts = Block(insts ++ connectClocks ++ connectResets ++ connectQueues ++ ioSrcQueueConnect ++ ioDstQueueConnect)
+ val ports = Seq(hostClock, hostReset) ++ transformTopIO(rtlTop.ports)
Module(NoInfo, "SimTop", ports, stmts)
}
- // ***** transform *****
+ // ********** transform **********
// Perform FAME-1 Transformation for MIDAS
def transform(c: Circuit): Circuit = {
// We should check that the invariants mentioned above are true
val nameToModule = (c.modules map (m => m.name -> m))(collection.breakOut): Map[String, Module]
val top = nameToModule(c.name)
+ val rtlModules = c.modules filter (_.name != top.name) map (transformRTL)
+
val insts = getDefInsts(top)
val portConn = findPortConn(top, insts)
+
// Check that port Connections include all ports for each instance?
- println(portConn)
val simWrappers = insts map (inst => genWrapperModule(inst, portConn(inst.name)))
val simQueues = generateSimQueues(simWrappers)
- // Remove duplicate simWrapper and simQueue modules
+ // Remove duplicate simWrapper and simQueue modules?
- val simTop = generateSimTop(simWrappers, simQueues, top)
+ val simTop = generateSimTop(simWrappers, simQueues, portConn("topIO"), top)
- val modules = (c.modules filter (_.name != top.name)) ++ simWrappers ++ simQueues.values.toSeq ++ Seq(simTop)
+ val modules = rtlModules ++ simWrappers ++ simQueues.values.toSeq ++ Seq(simTop)
- println(simTop.serialize)
Circuit(c.info, simTop.name, modules)
- //c
}
}
diff --git a/src/main/scala/midas/Utils.scala b/src/main/scala/midas/Utils.scala
index b9006b59..003f22bb 100644
--- a/src/main/scala/midas/Utils.scala
+++ b/src/main/scala/midas/Utils.scala
@@ -19,6 +19,58 @@ object Utils {
}
}
+ // This doesn't work because of Type Erasure >.<
+ //private def getStmts[A <: Stmt](s: Stmt): Seq[A] = {
+ // s match {
+ // case a: A => Seq(a)
+ // case b: Block => b.stmts.map(getStmts[A]).flatten
+ // case _ => Seq()
+ // }
+ //}
+ //private def getStmts[A <: Stmt](m: Module): Seq[A] = getStmts[A](m.stmt)
+
+ def getDefRegs(s: Stmt): Seq[DefReg] = {
+ s match {
+ case r: DefReg => Seq(r)
+ case b: Block => b.stmts.map(getDefRegs).flatten
+ case _ => Seq()
+ }
+ }
+ def getDefRegs(m: Module): Seq[DefReg] = getDefRegs(m.stmt)
+
+ def getDefInsts(s: Stmt): Seq[DefInst] = {
+ s match {
+ case i: DefInst => Seq(i)
+ case b: Block => b.stmts.map(getDefInsts).flatten
+ case _ => Seq()
+ }
+ }
+ def getDefInsts(m: Module): Seq[DefInst] = getDefInsts(m.stmt)
+
+ def getDefInstRef(inst: DefInst): Ref = {
+ inst.module match {
+ case ref: Ref => ref
+ case _ => throw new Exception("Invalid module expression for DefInst: " + inst.serialize)
+ }
+ }
+
+ // DefInsts have an Expression for the module, this expression should be a reference this
+ // reference has a tpe that should be a bundle representing the IO of that module class
+ def getDefInstType(inst: DefInst): BundleType = {
+ val ref = getDefInstRef(inst)
+ ref.tpe match {
+ case b: BundleType => b
+ case _ => throw new Exception("Invalid reference type for DefInst: " + inst.serialize)
+ }
+ }
+
+ def getModuleFromDefInst(nameToModule: Map[String, Module], inst: DefInst): Module = {
+ val instModule = getDefInstRef(inst)
+ if(!nameToModule.contains(instModule.name))
+ throw new Exception(s"Module ${instModule.name} not found in circuit!")
+ else
+ nameToModule(instModule.name)
+ }
// Takes a set of strings or ints and returns equivalent expression node
// Strings correspond to subfields/references, ints correspond to indexes
@@ -46,8 +98,10 @@ object Utils {
}
def buildExp(name: Any): Exp = buildExp(Seq(name))
- def genPrimopReduce(op: Primop, args: Seq[Exp]): DoPrimop = {
- if( args.length == 2 ) DoPrimop(op, Seq(args.head, args.last), Seq(), UnknownType)
+ def genPrimopReduce(op: Primop, args: Seq[Exp]): Exp = {
+ if( args.length == 0 ) throw new Exception("genPrimopReduce called on empty sequence!")
+ else if( args.length == 1 ) args.head
+ else if( args.length == 2 ) DoPrimop(op, Seq(args.head, args.last), Seq(), UnknownType)
else DoPrimop(op, Seq(args.head, genPrimopReduce(op, args.tail)), Seq(), UnknownType)
}
@@ -95,88 +149,179 @@ object Utils {
}
}
+ // Recursively iterates through firrtl.Type returning sequence of names to address signals
+ // * Intended for use with recursive bundle types
+ def enumerateMembers(tpe: Type): Seq[Seq[Any]] = {
+ def rec(tpe: Type, path: Seq[Any], members: Seq[Seq[Any]]): Seq[Seq[Any]] = {
+ tpe match {
+ case b: BundleType => (b.fields map ( f => rec(f.tpe, path :+ f.name, members) )).flatten
+ case v: VectorType => (Seq.tabulate(v.size.toInt) ( i => rec(v.tpe, path :+ i, members) )).flatten
+ case _ => members :+ path
+ }
+ }
+ rec(tpe, Seq[Any](), Seq[Seq[Any]]())
+ }
+
// Queue
+ // TODO
+ // - Insert null tokens upon hostReset (or should this be elsewhere?)
def buildSimQueue(name: String, tpe: Type): Module = {
- val templatedQueue =
+ val scopeSpaces = " " * 4 // Spaces before lines in module scope, for default assignments
+ val templatedQueue =
+// """
+// circuit `NAME:
+// module `NAME :
+// input hostClock : Clock
+// input hostReset : UInt<1>
+// output io : {flip enq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, deq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, count : UInt<3>}
+//
+// io.count := UInt<1>("h00")
+// `DEFAULT_ASSIGN
+// io.deq.hostValid := UInt<1>("h00")
+// io.enq.hostReady := UInt<1>("h00")
+// cmem ram : `TYPE[4], hostClock
+// reg T_80 : UInt<2>, hostClock, hostReset
+// onreset T_80 := UInt<2>("h00")
+// reg T_82 : UInt<2>, hostClock, hostReset
+// onreset T_82 := UInt<2>("h00")
+// reg maybe_full : UInt<1>, hostClock, hostReset
+// onreset maybe_full := UInt<1>("h00")
+// node ptr_match = eq(T_80, T_82)
+// node T_87 = eq(maybe_full, UInt<1>("h00"))
+// node empty = and(ptr_match, T_87)
+// node full = and(ptr_match, maybe_full)
+// node maybe_flow = and(UInt<1>("h00"), empty)
+// node do_flow = and(maybe_flow, io.deq.hostReady)
+// node T_93 = and(io.enq.hostReady, io.enq.hostValid)
+// node T_95 = eq(do_flow, UInt<1>("h00"))
+// node do_enq = and(T_93, T_95)
+// node T_97 = and(io.deq.hostReady, io.deq.hostValid)
+// node T_99 = eq(do_flow, UInt<1>("h00"))
+// node do_deq = and(T_97, T_99)
+// when do_enq :
+// infer accessor T_101 = ram[T_80]
+// T_101 <> io.enq.hostBits
+// node T_109 = eq(T_80, UInt<2>("h03"))
+// node T_111 = and(UInt<1>("h00"), T_109)
+// node T_114 = addw(T_80, UInt<1>("h01"))
+// node T_115 = mux(T_111, UInt<1>("h00"), T_114)
+// T_80 := T_115
+// skip
+// when do_deq :
+// node T_117 = eq(T_82, UInt<2>("h03"))
+// node T_119 = and(UInt<1>("h00"), T_117)
+// node T_122 = addw(T_82, UInt<1>("h01"))
+// node T_123 = mux(T_119, UInt<1>("h00"), T_122)
+// T_82 := T_123
+// skip
+// node T_124 = neq(do_enq, do_deq)
+// when T_124 :
+// maybe_full := do_enq
+// skip
+// node T_126 = eq(empty, UInt<1>("h00"))
+// node T_128 = and(UInt<1>("h00"), io.enq.hostValid)
+// node T_129 = or(T_126, T_128)
+// io.deq.hostValid := T_129
+// node T_131 = eq(full, UInt<1>("h00"))
+// node T_133 = and(UInt<1>("h00"), io.deq.hostReady)
+// node T_134 = or(T_131, T_133)
+// io.enq.hostReady := T_134
+// infer accessor T_135 = ram[T_82]
+// wire T_149 : `TYPE
+// T_149 <> T_135
+// when maybe_flow :
+// T_149 <> io.enq.hostBits
+// skip
+// io.deq.hostBits <> T_149
+// node ptr_diff = subw(T_80, T_82)
+// node T_157 = and(maybe_full, ptr_match)
+// node T_158 = cat(T_157, ptr_diff)
+// io.count := T_158
+// """
"""
- circuit `NAME:
- module `NAME :
- input hostClock : Clock
- input hostReset : UInt<1>
- output io : {flip enq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, deq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, count : UInt<3>}
-
- io.count := UInt<1>("h00")
- //io.deq.hostBits.surprise.no := UInt<1>("h00")
- //io.deq.hostBits.surprise.yes := UInt<1>("h00")
- //io.deq.hostBits.store := UInt<1>("h00")
- //io.deq.hostBits.data := UInt<1>("h00")
- //io.deq.hostBits.addr := UInt<1>("h00")
- io.deq.hostValid := UInt<1>("h00")
- io.enq.hostReady := UInt<1>("h00")
- cmem ram : `TYPE[4], hostClock
- reg T_80 : UInt<2>, hostClock, hostReset
- onreset T_80 := UInt<2>("h00")
- reg T_82 : UInt<2>, hostClock, hostReset
- onreset T_82 := UInt<2>("h00")
- reg maybe_full : UInt<1>, hostClock, hostReset
- onreset maybe_full := UInt<1>("h00")
- node ptr_match = eq(T_80, T_82)
- node T_87 = eq(maybe_full, UInt<1>("h00"))
- node empty = and(ptr_match, T_87)
- node full = and(ptr_match, maybe_full)
- node maybe_flow = and(UInt<1>("h00"), empty)
- node do_flow = and(maybe_flow, io.deq.hostReady)
- node T_93 = and(io.enq.hostReady, io.enq.hostValid)
- node T_95 = eq(do_flow, UInt<1>("h00"))
- node do_enq = and(T_93, T_95)
- node T_97 = and(io.deq.hostReady, io.deq.hostValid)
- node T_99 = eq(do_flow, UInt<1>("h00"))
- node do_deq = and(T_97, T_99)
- when do_enq :
- infer accessor T_101 = ram[T_80]
- T_101 <> io.enq.hostBits
- node T_109 = eq(T_80, UInt<2>("h03"))
- node T_111 = and(UInt<1>("h00"), T_109)
- node T_114 = addw(T_80, UInt<1>("h01"))
- node T_115 = mux(T_111, UInt<1>("h00"), T_114)
- T_80 := T_115
- skip
- when do_deq :
- node T_117 = eq(T_82, UInt<2>("h03"))
- node T_119 = and(UInt<1>("h00"), T_117)
- node T_122 = addw(T_82, UInt<1>("h01"))
- node T_123 = mux(T_119, UInt<1>("h00"), T_122)
- T_82 := T_123
- skip
- node T_124 = neq(do_enq, do_deq)
- when T_124 :
- maybe_full := do_enq
- skip
- node T_126 = eq(empty, UInt<1>("h00"))
- node T_128 = and(UInt<1>("h00"), io.enq.hostValid)
- node T_129 = or(T_126, T_128)
- io.deq.hostValid := T_129
- node T_131 = eq(full, UInt<1>("h00"))
- node T_133 = and(UInt<1>("h00"), io.deq.hostReady)
- node T_134 = or(T_131, T_133)
- io.enq.hostReady := T_134
- infer accessor T_135 = ram[T_82]
- wire T_149 : `TYPE
- T_149 <> T_135
- when maybe_flow :
- T_149 <> io.enq.hostBits
- skip
- io.deq.hostBits <> T_149
- node ptr_diff = subw(T_80, T_82)
- node T_157 = and(maybe_full, ptr_match)
- node T_158 = cat(T_157, ptr_diff)
- io.count := T_158
+circuit `NAME:
+ module `NAME :
+ input hostClock : Clock
+ input hostReset : UInt<1>
+ output io : {flip enq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, deq : {flip hostReady : UInt<1>, hostValid : UInt<1>, hostBits : `TYPE}, count : UInt<3>}
+
+ io.count := UInt<1>("h00")
+ `DEFAULT_ASSIGN
+ io.deq.hostValid := UInt<1>("h00")
+ io.enq.hostReady := UInt<1>("h00")
+ cmem ram : `TYPE[4], hostClock
+ reg T_404 : UInt<2>, hostClock, hostReset
+ onreset T_404 := UInt<2>("h00")
+ reg T_406 : UInt<2>, hostClock, hostReset
+ onreset T_406 := UInt<2>("h00")
+ reg maybe_full : UInt<1>, hostClock, hostReset
+ onreset maybe_full := UInt<1>("h00")
+ reg add_token_on_reset : UInt<1>, hostClock, hostReset
+ onreset add_token_on_reset := UInt<1>("h01")
+ add_token_on_reset := UInt<1>("h00")
+ node ptr_match = eq(T_404, T_406)
+ node T_414 = eq(maybe_full, UInt<1>("h00"))
+ node empty = and(ptr_match, T_414)
+ node full = and(ptr_match, maybe_full)
+ node maybe_flow = and(UInt<1>("h00"), empty)
+ node do_flow = and(maybe_flow, io.deq.hostReady)
+ node T_420 = and(io.enq.hostReady, io.enq.hostValid)
+ node T_422 = eq(do_flow, UInt<1>("h00"))
+ node do_enq = and(T_420, T_422)
+ node T_424 = and(io.deq.hostReady, io.deq.hostValid)
+ node T_426 = eq(do_flow, UInt<1>("h00"))
+ node do_deq = and(T_424, T_426)
+ node T_428 = or(do_enq, add_token_on_reset)
+ when T_428 :
+ infer accessor T_443 = ram[T_404]
+ T_443 := io.enq.hostBits
+ node T_473 = eq(T_404, UInt<2>("h03"))
+ node T_475 = and(UInt<1>("h00"), T_473)
+ node T_478 = addw(T_404, UInt<1>("h01"))
+ node T_479 = mux(T_475, UInt<1>("h00"), T_478)
+ T_404 := T_479
+ skip
+ when do_deq :
+ node T_481 = eq(T_406, UInt<2>("h03"))
+ node T_483 = and(UInt<1>("h00"), T_481)
+ node T_486 = addw(T_406, UInt<1>("h01"))
+ node T_487 = mux(T_483, UInt<1>("h00"), T_486)
+ T_406 := T_487
+ skip
+ node T_488 = neq(do_enq, do_deq)
+ when T_488 :
+ maybe_full := do_enq
+ skip
+ node T_490 = eq(empty, UInt<1>("h00"))
+ node T_492 = and(UInt<1>("h00"), io.enq.hostValid)
+ node T_493 = or(T_490, T_492)
+ io.deq.hostValid := T_493
+ node T_495 = eq(full, UInt<1>("h00"))
+ node T_497 = and(UInt<1>("h00"), io.deq.hostReady)
+ node T_498 = or(T_495, T_497)
+ io.enq.hostReady := T_498
+ infer accessor T_513 = ram[T_406]
+ wire T_599 : `TYPE
+ T_599 := T_513
+ when maybe_flow :
+ T_599 := io.enq.hostBits
+ skip
+ io.deq.hostBits := T_599
+ node ptr_diff = subw(T_404, T_406)
+ node T_629 = and(maybe_full, ptr_match)
+ node T_630 = cat(T_629, ptr_diff)
+ io.count := T_630
"""
- //def buildQueue(name: String, tpe: Type): Module = {
- val concreteQueue = templatedQueue.replaceAllLiterally("`NAME", name).
- replaceAllLiterally("`TYPE", tpe.serialize)
// Generate initial values
- //val bitsField = Field("bits", Default, tpe)
+ val signals = enumerateMembers(tpe) map ( Seq("io", "deq", "hostBits") ++ _ )
+ val defaultAssign = signals map { sig =>
+ scopeSpaces + Connect(NoInfo, buildExp(sig), UIntValue(0, UnknownWidth)).serialize
+ }
+
+ val concreteQueue = templatedQueue.replaceAllLiterally("`NAME", name).
+ replaceAllLiterally("`TYPE", tpe.serialize).
+ replaceAllLiterally(scopeSpaces+"`DEFAULT_ASSIGN", defaultAssign.mkString("\n"))
+
val ast = firrtl.Parser.parse(concreteQueue.split("\n"))
ast.modules.head
}