aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjackkoenig2015-12-02 18:03:35 -0800
committerjackkoenig2015-12-02 18:03:35 -0800
commit9509036a2dbbe48af168762b634d96c4289eefe6 (patch)
tree2f53689270fbf61e02cf73eafb107683f311dfd3 /src
parent71f0319e8d27d1f175b4747c0367843a6ceab986 (diff)
Added fame transformation and new package, making progress
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Driver.scala25
-rw-r--r--src/main/scala/firrtl/Passes.scala57
-rw-r--r--src/main/scala/midas/Fame.scala183
3 files changed, 204 insertions, 61 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 067ad4f4..c748f92e 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -6,6 +6,7 @@ import java.nio.file.{Paths, Files}
import Utils._
import DebugUtils._
import Passes._
+import midas.Fame1
object Driver
{
@@ -39,10 +40,15 @@ object Driver
def toVerilogWithFame(input: String, output: String)
{
+ val logger = Logger(new PrintWriter(System.err, true))
+
val stanzaPreTransform = List("rem-spec-chars", "high-form-check",
"temp-elim", "to-working-ir", "resolve-kinds", "infer-types",
"resolve-genders", "check-genders", "check-kinds", "check-types",
- "expand-accessors", "lower-to-ground", "inline-indexers")
+ "expand-accessors", "lower-to-ground", "inline-indexers", "infer-types",
+ "check-genders", "expand-whens", "infer-widths", "real-ir", "width-check",
+ "pad-widths", "const-prop", "split-expressions", "width-check",
+ "high-form-check", "low-form-check", "check-init")
val stanzaPostTransform = List("rem-spec-chars", "high-form-check",
"temp-elim", "to-working-ir", "resolve-kinds", "infer-types",
"resolve-genders", "check-genders", "check-kinds", "check-types",
@@ -51,18 +57,29 @@ object Driver
"pad-widths", "const-prop", "split-expressions", "width-check",
"high-form-check", "low-form-check", "check-init")
+ //// Don't lower
+ //val temp1 = genTempFilename(input)
+ //val ast = Parser.parse(input)
+ //val writer = new PrintWriter(new File(temp1))
+ //val ast2 = fame1Transform(ast)
+ //writer.write(ast2.serialize())
+ //writer.close()
+
// Lower-to-Ground with Stanza FIRRTL
val temp1 = genTempFilename(input)
val preCmd = Seq("firrtl-stanza", "-i", input, "-o", temp1, "-b", "firrtl") ++ stanzaPreTransform.flatMap(Seq("-x", _))
println(preCmd.mkString(" "))
preCmd.!
+
+ // Read in and execute infer-types
+ val ast = Parser.parse(temp1)
+ val ast2 = inferTypes(ast)(logger)
// FAME-1 Transformation
val temp2 = genTempFilename(input)
- val ast = Parser.parse(temp1)
val writer = new PrintWriter(new File(temp2))
- val ast2 = fame1Transform(ast)
- writer.write(ast2.serialize())
+ val ast3 = Fame1.transform(ast2)
+ writer.write(ast3.serialize())
writer.close()
//val postCmd = Seq("firrtl-stanza", "-i", temp2, "-o", output, "-b", "firrtl") ++ stanzaPostTransform.flatMap(Seq("-x", _))
diff --git a/src/main/scala/firrtl/Passes.scala b/src/main/scala/firrtl/Passes.scala
index a76c3103..39e6b64e 100644
--- a/src/main/scala/firrtl/Passes.scala
+++ b/src/main/scala/firrtl/Passes.scala
@@ -99,61 +99,4 @@ object Passes {
Circuit(c.info, c.name, c.modules.map(inferTypes(typeMap, _)))
}
- /** FAME-1
- *
- * This pass takes a lowered-to-ground circuit and performs a
- * FAME-1 (Decoupled) transformation to the circuit
- *
- * TODO
- * - SWITCH TO USING HIGH-LEVEL FIRRTL SO WE CAN MAINTAIN STRUCTURE OF BUNDLES
- * - Add midas$fire : indicates when the module can operate
- * - Add transform on each assignment to inputs/outputs to assign to data part of bundle
- * - Add enable logic for each register
- * * This should just be a when not(midas$fire) : reg := reg
- * At bottom of module
- * - QUESTIONS
- * * Should we have Reset be a special Type?
- *
- * NOTES
- * - How do output consumes tie in to MIDAS fire? If all of our outputs are not consumed
- * in a given cycle, do we block midas$fire on the next cycle? Perhaps there should be
- * a register for not having consumed all outputs last cycle
- * - If our outputs are not consumed we also need to be sure not to consume out inputs,
- * so the logic for this must depend on the previous cycle being consumed as well
- * - We also need a way to determine the difference between the MIDAS modules and their
- * connecting Queues, perhaps they should be MIDAS queues, which then perhaps prints
- * out a listing of all queues so that they can be properly transformed
- * * What do these MIDAS queues look like since we're enforcing true decoupled
- * interfaces?
- */
- private type PortMap = Map[String, Port]
- //private val PortMap = Map[String, Type]().withDefaultValue(UnknownType)
- private val f1TAvail = Field("avail", Default, UIntType(IntWidth(1)))
- private val f1TConsume = Field("consume", Reverse, UIntType(IntWidth(1)))
- private def fame1Transform(p: Port): Port = {
- if( p.name == "reset" ) p // omit reset
- else {
- p.tpe match {
- case ClockType => p // Omit clocktype
- case t: BundleType => throw new Exception("Bundle Types not supported in FAME-1 Transformation!")
- case t: VectorType => throw new Exception("Vector Types not supported in FAME-1 Transformation!")
- case t: Type => {
- Port(p.info, p.name, p.dir, BundleType(
- Seq(f1TAvail, f1TConsume, Field("data", Default, t)))
- )
- }
- }
- }
- }
- private def fame1Transform(m: Module): Module = {
- println("fame1Transform called on module " + m.name)
- val ports = m.ports.map(fame1Transform)
- val portMap = Map(ports.map(p => (p.name, p)))
- println(portMap)
- Module(m.info, m.name, ports, m.stmt)
- }
- def fame1Transform(c: Circuit): Circuit = {
- Circuit(c.info, c.name, c.modules.map(fame1Transform))
- }
-
}
diff --git a/src/main/scala/midas/Fame.scala b/src/main/scala/midas/Fame.scala
new file mode 100644
index 00000000..2d32f220
--- /dev/null
+++ b/src/main/scala/midas/Fame.scala
@@ -0,0 +1,183 @@
+
+package midas
+
+import firrtl._
+import firrtl.Utils._
+
+/** FAME-1 Transformation
+ *
+ * This pass takes a lowered-to-ground circuit and performs a FAME-1 (Decoupled) transformation
+ * to the circuit
+ * It does this by creating a simulation module wrapper around the circuit, if we can gate the
+ * clock, then there need be no modification to the target RTL, if we can't, then the target
+ * RTL will have to be modified (by adding a midasFire input and use this signal to gate
+ * register enable
+ *
+ * ALGORITHM
+ * 1. Flatten RTL
+ * a. Create NewTop
+ * b. Instantiate Top in NewTop
+ * c. Iteratively pull all sim tagged instances out of hierarchy to NewTop
+ * i. Move instance declaration from child module to parent module
+ * ii. Create io in child module corresponding to io of instance
+ * iii. Connect original instance io in child to new child io
+ * iv. Connect child io in parent to instance io
+ * v. Repeate until instance is in SimTop
+ * (if black box, repeat until completely removed from design)
+ * * Post-flattening invariants
+ * - No combinational logic on NewTop
+ * - All and only instances in NewTop are sim tagged
+ * - No black boxes in design
+ * 2. Simulation Transformation
+ * //a. Transform Top to SimTop NO THIS STEP IS WRONG AND SHOULDN'T HAPPEN
+ * // i. Create ready and valid signals for input and output data
+ * // ii. Create simFire as and of input.valid and output.ready
+ * // iii. Create simClock as and of clock and simFire
+ * // iv. Replace clock inputs to sim modules with simClock
+ * 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
+ *
+ * TODO
+ * - Implement Flatten RTL
+ *
+ * NOTES
+ * - How do we only transform the necessary modules? Should there be a MIDAS list of modules
+ * or something?
+ * * YES, this will be done by requiring the user to instantiate modules that should be split
+ * with something like: val module = new MIDASModule(class... etc.)
+ * - There cannot be nested DecoupledIO or ValidIO
+ * - How do output consumes tie in to MIDAS fire? If all of our outputs are not consumed
+ * in a given cycle, do we block midas$fire on the next cycle? Perhaps there should be
+ * a register for not having consumed all outputs last cycle
+ * - If our outputs are not consumed we also need to be sure not to consume out inputs,
+ * so the logic for this must depend on the previous cycle being consumed as well
+ * - We also need a way to determine the difference between the MIDAS modules and their
+ * connecting Queues, perhaps they should be MIDAS queues, which then perhaps prints
+ * out a listing of all queues so that they can be properly transformed
+ * * What do these MIDAS queues look like since we're enforcing true decoupled
+ * interfaces?
+ */
+object Fame1 {
+
+ //private type PortMap = Map[String, Port]
+ //private val PortMap = Map[String, Type]().withDefaultValue(UnknownType)
+ private val f1TReady = Field("Ready", Reverse, UIntType(IntWidth(1)))
+ private val f1TValid = Field("Valid", Default, UIntType(IntWidth(1)))
+ private val f1THostReady = Field("hostReady", Reverse, UIntType(IntWidth(1)))
+ private val f1THostValid = Field("hostValid", Default, UIntType(IntWidth(1)))
+ private def fame1Transform(t: Type): Type = {
+ t match {
+ case ClockType => t // Omit clocktype
+ case t: BundleType => {
+ val names = t.fields.map(_.name)
+ if (names.length == 3 && names.contains("ready") && names.contains("valid") &&
+ names.contains("bits")) {
+ // Decoupled (group valid and bits)
+ println("DecoupledIO Detected!")
+ t
+ //} else if (names.length == 2 && names.contains("valid") && names.contains("bits")) {
+ // //Valid (group valid and bits)
+ } else {
+ // Default (transform each individually)
+ BundleType(t.fields.map(f => Field(f.name, f.dir, fame1Transform(f.tpe))))
+ }
+ }
+ case t: VectorType =>
+ VectorType(fame1Transform(t.tpe), t.size)
+ case t: Type =>
+ BundleType(Seq(f1THostReady, f1THostValid, Field("hostBits", Default, t)))
+ }
+ }
+ private def fame1Transform(p: Port): Port = {
+ if( p.name == "reset" ) p // omit reset
+ else Port(p.info, p.name, p.dir, fame1Transform(p.tpe))
+ }
+ private def fame1Transform(m: Module, topName: String): Module = {
+ if ( m.name == topName ) m // Skip the top module
+ else {
+ // Return new wrapper module
+ println("fame1Transform called on module " + m.name)
+ val ports = m.ports.map(fame1Transform)
+ //val portMap = ports.map(p => p.name -> p).toMap
+ //val portMap = ports.map(p => p.name -> p)(collection.breakOut): Map[String, Port]
+ //println(portMap)
+ Module(m.info, m.name, ports, m.stmt)
+ }
+ }
+
+ private trait SimInstT // TODO Is this name okay?
+ private case object UnknownSimInst extends SimInstT
+ private case object SimTopIO extends SimInstT
+ private case class SimInst(name: String, module: Module, ports: Seq[SimPort]) extends SimInstT
+ private case class SimPort(port: Port, endpoint: SimInstT)
+
+ //private def findPortEndpoint(simInsts: Seq[String], port: SimPort): Option[SimInst] = {
+ // SimPort(port, UnknownSimInst)
+ //
+ //}
+
+ // Convert firrtl.DefInst to augmented type SimInst
+ private def convertInst(c: Circuit, inst: DefInst): SimInst = {
+ val moduleName = inst.module match {
+ case r: Ref => r.name
+ case _ => throw new Exception("Module child of DefInst is not a Ref Exp!")
+ }
+ val module = c.modules.find(_.name == moduleName)
+ if (module.isEmpty) throw new Exception("No module found with name " + moduleName)
+ SimInst(inst.name, module.get, module.get.ports.map(SimPort(_, UnknownSimInst)))
+ }
+
+ 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)
+
+ // Find the top module of a firrtl.Circuit
+ private def findTop(c: Circuit): Module = {
+ val moduleMap = c.modules.map(m => m.name -> m)(collection.breakOut): Map[String, Module]
+ moduleMap(c.name)
+ }
+
+ private def genWrapperModuleName(m: Module): String = s"SimWrap_${m.name}"
+ private def genWrapperModule(m: Module, connections: Seq[String]): Module = {
+ Module(m.info, genWrapperModuleName(m), m.ports, m.stmt)
+ }
+
+ def transform(c: Circuit): Circuit = {
+ //Circuit(c.info, c.name, c.modules.map(fame1Transform(_, c.name)))
+ //println(s"In circuit ${c.name}, we have instances: ")
+ //println(insts)
+ val top = findTop(c)
+ println("Top Module:")
+ println(top.serialize)
+
+ val insts = getDefInsts(top)
+ println(s"In top module ${top.name}, we have instances: ")
+ insts.foreach(i => println(" " + i.name))
+
+ //val
+
+ //val simInsts = insts.map(convertInst(c, _))
+ //println("Simulation instances: ")
+ //simInsts.foreach{i =>
+ // println(s"${i.name} : ${i.module.name}")
+ // i.ports.foreach{p =>
+ // val endpoint = p.endpoint match {
+ // case UnknownSimInst => "?"
+ // case SimTopIO => "TopIO"
+ // case inst: SimInst => inst.name
+ // }
+ // println(s" ${p.port.name} : ${p.port.dir.serialize} : ${endpoint}")
+ // }
+ //}
+ //println(simInsts)
+
+ c
+ }
+
+}