aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjackkoenig2015-12-03 18:03:31 -0800
committerjackkoenig2015-12-03 18:03:31 -0800
commitbff84efaa56ca8f21e58557a50d2c496d3c1bec0 (patch)
treeb206e7be3af8009f3dffe28b8f8dca16536f8e9b /src
parent8e050ba48063d7f33551abcbb5c924b5d484aab7 (diff)
Changing simwrapper to group ports that go to different places, not quite there yet. Will allow simple bulk connecting at top-level
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/IR.scala36
-rw-r--r--src/main/scala/firrtl/Utils.scala14
-rw-r--r--src/main/scala/firrtl/Visitor.scala10
-rw-r--r--src/main/scala/midas/Fame.scala252
-rw-r--r--src/main/scala/midas/Utils.scala46
5 files changed, 205 insertions, 153 deletions
diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala
index 5eb4e9e6..1e7c4ced 100644
--- a/src/main/scala/firrtl/IR.scala
+++ b/src/main/scala/firrtl/IR.scala
@@ -1,6 +1,6 @@
/* TODO
- * - Should FileInfo be a FIRRTL node?
+ * - Should Info be a FIRRTL node?
*
*/
@@ -9,7 +9,9 @@ package firrtl
import scala.collection.Seq
// Should this be defined elsewhere?
-case class FileInfo(file: String, line: Int, column: Int) {
+trait Info
+case object NoInfo extends Info
+case class FileInfo(file: String, line: Int, column: Int) extends Info {
override def toString(): String = s"$file@$line.$column"
}
@@ -72,18 +74,18 @@ case object Write extends AccessorDir
case object RdWr extends AccessorDir
trait Stmt extends AST
-case class DefWire(info: FileInfo, name: String, tpe: Type) extends Stmt
-case class DefReg(info: FileInfo, name: String, tpe: Type, clock: Exp, reset: Exp) extends Stmt
-case class DefMemory(info: FileInfo, name: String, seq: Boolean, tpe: Type, clock: Exp) extends Stmt
-case class DefInst(info: FileInfo, name: String, module: Exp) extends Stmt
-case class DefNode(info: FileInfo, name: String, value: Exp) extends Stmt
-case class DefPoison(info: FileInfo, name: String, tpe: Type) extends Stmt
-case class DefAccessor(info: FileInfo, name: String, dir: AccessorDir, source: Exp, index: Exp) extends Stmt
-case class OnReset(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt
-case class Connect(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt
-case class BulkConnect(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt
-case class When(info: FileInfo, pred: Exp, conseq: Stmt, alt: Stmt) extends Stmt
-case class Assert(info: FileInfo, pred: Exp) extends Stmt
+case class DefWire(info: Info, name: String, tpe: Type) extends Stmt
+case class DefReg(info: Info, name: String, tpe: Type, clock: Exp, reset: Exp) extends Stmt
+case class DefMemory(info: Info, name: String, seq: Boolean, tpe: Type, clock: Exp) extends Stmt
+case class DefInst(info: Info, name: String, module: Exp) extends Stmt
+case class DefNode(info: Info, name: String, value: Exp) extends Stmt
+case class DefPoison(info: Info, name: String, tpe: Type) extends Stmt
+case class DefAccessor(info: Info, name: String, dir: AccessorDir, source: Exp, index: Exp) extends Stmt
+case class OnReset(info: Info, lhs: Exp, rhs: Exp) extends Stmt
+case class Connect(info: Info, lhs: Exp, rhs: Exp) extends Stmt
+case class BulkConnect(info: Info, lhs: Exp, rhs: Exp) extends Stmt
+case class When(info: Info, pred: Exp, conseq: Stmt, alt: Stmt) extends Stmt
+case class Assert(info: Info, pred: Exp) extends Stmt
case class Block(stmts: Seq[Stmt]) extends Stmt
case object EmptyStmt extends Stmt
@@ -109,10 +111,10 @@ trait PortDir extends AST
case object Input extends PortDir
case object Output extends PortDir
-case class Port(info: FileInfo, name: String, dir: PortDir, tpe: Type) extends AST
+case class Port(info: Info, name: String, dir: PortDir, tpe: Type) extends AST
-case class Module(info: FileInfo, name: String, ports: Seq[Port], stmt: Stmt) extends AST
+case class Module(info: Info, name: String, ports: Seq[Port], stmt: Stmt) extends AST
-case class Circuit(info: FileInfo, name: String, modules: Seq[Module]) extends AST
+case class Circuit(info: Info, name: String, modules: Seq[Module]) extends AST
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index 4220e07f..73799765 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -196,6 +196,12 @@ object Utils {
}
s + debug(dir)
}
+ def toPortDir(): PortDir = {
+ dir match {
+ case Default => Output
+ case Reverse => Input
+ }
+ }
}
implicit class FieldUtils(field: Field) {
@@ -203,6 +209,7 @@ object Utils {
s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + debug(field)
def getType(): Type = field.tpe
+ def toPort(): Port = Port(NoInfo, field.name, field.dir.toPortDir, field.tpe)
}
implicit class TypeUtils(t: Type) {
@@ -242,12 +249,19 @@ object Utils {
}
s + debug(p)
}
+ def toFieldDir(): FieldDir = {
+ p match {
+ case Input => Reverse
+ case Output => Default
+ }
+ }
}
implicit class PortUtils(p: Port) {
def serialize(implicit flags: FlagMap = FlagMap): String =
s"${p.dir.serialize} ${p.name} : ${p.tpe.serialize}" + debug(p)
def getType(): Type = p.tpe
+ def toField(): Field = Field(p.name, p.dir.toFieldDir, p.tpe)
}
implicit class ModuleUtils(m: Module) {
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index 7d54ca1a..d5220206 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -39,17 +39,17 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
case _ => throw new Exception("Invalid String for conversion to BigInt " + s)
}
}
- private def getFileInfo(ctx: ParserRuleContext): FileInfo =
+ private def getInfo(ctx: ParserRuleContext): Info =
FileInfo(filename, ctx.getStart().getLine(), ctx.getStart().getCharPositionInLine())
private def visitCircuit[AST](ctx: FIRRTLParser.CircuitContext): Circuit =
- Circuit(getFileInfo(ctx), ctx.id.getText, ctx.module.map(visitModule))
+ Circuit(getInfo(ctx), ctx.id.getText, ctx.module.map(visitModule))
private def visitModule[AST](ctx: FIRRTLParser.ModuleContext): Module =
- Module(getFileInfo(ctx), ctx.id.getText, ctx.port.map(visitPort), visitBlockStmt(ctx.blockStmt))
+ Module(getInfo(ctx), ctx.id.getText, ctx.port.map(visitPort), visitBlockStmt(ctx.blockStmt))
private def visitPort[AST](ctx: FIRRTLParser.PortContext): Port =
- Port(getFileInfo(ctx), ctx.id.getText, visitPortKind(ctx.portKind), visitType(ctx.`type`))
+ Port(getInfo(ctx), ctx.id.getText, visitPortKind(ctx.portKind), visitType(ctx.`type`))
private def visitPortKind[AST](ctx: FIRRTLParser.PortKindContext): PortDir =
ctx.getText match {
@@ -91,7 +91,7 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
Block(ctx.stmt.map(visitStmt))
private def visitStmt[AST](ctx: FIRRTLParser.StmtContext): Stmt = {
- val info = getFileInfo(ctx)
+ val info = getInfo(ctx)
ctx.getChild(0).getText match {
case "wire" => DefWire(info, ctx.id(0).getText, visitType(ctx.`type`))
diff --git a/src/main/scala/midas/Fame.scala b/src/main/scala/midas/Fame.scala
index c2a7ff22..27a93413 100644
--- a/src/main/scala/midas/Fame.scala
+++ b/src/main/scala/midas/Fame.scala
@@ -1,6 +1,7 @@
package midas
+import Utils._
import firrtl._
import firrtl.Utils._
@@ -29,17 +30,17 @@ import firrtl.Utils._
* - 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
+ * a. 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
+ * v. Connect target IO to wrapper IO, except connect target clock to simClock
*
* TODO
* - Implement Flatten RTL
+ * - Check that circuit is in LowFIRRTL?
*
* NOTES
* - How do we only transform the necessary modules? Should there be a MIDAS list of modules
@@ -60,74 +61,6 @@ import firrtl.Utils._
*/
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)
@@ -137,7 +70,7 @@ object Fame1 {
}
private def getDefInsts(m: Module): Seq[DefInst] = getDefInsts(m.stmt)
- private def getInstRef(inst: DefInst): Ref = {
+ private def getDefInstRef(inst: DefInst): Ref = {
inst.module match {
case ref: Ref => ref
case _ => throw new Exception("Invalid module expression for DefInst: " + inst.serialize)
@@ -147,7 +80,7 @@ object Fame1 {
// 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 = getInstRef(inst)
+ val ref = getDefInstRef(inst)
ref.tpe match {
case b: BundleType => b
case _ => throw new Exception("Invalid reference type for DefInst: " + inst.serialize)
@@ -155,70 +88,133 @@ object Fame1 {
}
private def getModuleFromDefInst(nameToModule: Map[String, Module], inst: DefInst): Module = {
- val instModule = getInstRef(inst)
+ 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 genWrapperModuleName(name: String): String = s"SimWrap_${name}"
- private val readyValidPair = BundleType(Seq(Field("ready", Reverse, UIntType(IntWidth(1))),
- Field("valid", Default, UIntType(IntWidth(1)))))
- private def getPortDir(dir: FieldDir): PortDir = {
- dir match {
- case Default => Output
- case Reverse => Input
+ // ***** 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, String]
+ private val PortMap = Map[String, 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 {
+ case ref: Ref => ("topIO", ref.name)
+ case sub: Subfield =>
+ sub.exp match {
+ case ref: Ref => (ref.name, sub.name)
+ case _ => throw unsupportedExp
+ }
+ case exp: Exp => throw unsupportedExp
}
}
- // Takes a set of strings and returns equivalent subfield node
- // eg. Seq(io, port, ready) corresponds to io.port.ready
- private def namesToSubfield(names: Seq[String]): Subfield = {
- def rec(names: Seq[String]): Exp = {
- if( names.length == 1 ) Ref(names.head, UnknownType)
- else Subfield(rec(names.tail), names.head, UnknownType)
- }
- rec(names.reverse) match {
- case s: Subfield => s
- case _ => throw new Exception("Subfield requires more than 1 name!")
+ private def processConnect(conn: Connect): ConnMap = {
+ val lhs = processConnectExp(conn.lhs)
+ val rhs = processConnectExp(conn.rhs)
+ Map(lhs._1 -> Map(lhs._2 -> rhs._1), rhs._1 -> Map(rhs._2 -> lhs._1)).withDefaultValue(PortMap)
+ }
+ private def findPortConn(connMap: ConnMap, stmts: Seq[Stmt]): ConnMap = {
+ if (stmts.isEmpty) connMap
+ else {
+ stmts.head match {
+ case conn: Connect => {
+ val newConnMap = processConnect(conn)
+ findPortConn(connMap.map{case (k,v) => k -> (v ++ newConnMap(k)) }, stmts.tail)
+ }
+ case _ => findPortConn(connMap, stmts.tail)
+ }
}
}
- private def genAndReduce(args: Seq[Seq[String]]): DoPrimop = {
- if( args.length == 2 )
- DoPrimop(And, Seq(namesToSubfield(args.head), namesToSubfield(args.last)), Seq(), UnknownType)
- else
- DoPrimop(And, Seq(namesToSubfield(args.head), genAndReduce(args.tail)), Seq(), UnknownType)
+ private def findPortConn(top: Module, insts: Seq[DefInst]): ConnMap = {
+ val initConnMap = insts.map( _.name -> PortMap ).toMap ++ Map("topIO" -> PortMap)
+ val topStmts = top.stmt match {
+ case b: Block => b.stmts
+ case s: Stmt => Seq(s) // This honestly shouldn't happen but let's be safe
+ }
+ findPortConn(initConnMap, topStmts)
}
- private def genWrapperModule(inst: DefInst, connections: Seq[String]): Module = {
+
+ // ***** genWrapperModule *****
+ // Generates FAME-1 Decoupled wrappers for simulation module instances
+ private val readyField = Field("ready", Reverse, UIntType(IntWidth(1)))
+ private val validField = Field("valid", Default, UIntType(IntWidth(1)))
+
+ private def genWrapperModule(inst: DefInst, portMap: PortMap): Module = {
val instIO = getDefInstType(inst)
- // Add ports for each connection
- val simInputPorts = connections.map(s => Port(inst.info, s"simInput_${s}", Input, readyValidPair))
- val simOutputPorts = connections.map(s => Port(inst.info, s"simOutput_${s}", Output, readyValidPair))
- val rtlPorts = instIO.fields.map(f => Port(inst.info, f.name, getPortDir(f.dir), f.tpe))
- val ports = rtlPorts ++ simInputPorts ++ simOutputPorts
-
- val simFireInputs = simInputPorts.map(p => Seq(p.name, "valid")) ++ simOutputPorts.map(p => Seq(p.name, "ready"))
- val simFire = DefNode(inst.info, "simFire", genAndReduce(simFireInputs))
+ val nameToField = instIO.fields.map(f => f.name -> f).toMap
+
+ val connections = portMap.map(_._2).toSeq.distinct // modules we connect to
+ // Build simPort for each connecting module
+ val connPorts = connections.map{ c =>
+ // Get ports that connect to this particular module as fields
+ val fields = portMap.filter(_._2 == c).keySet.toSeq.sorted.map(nameToField(_))
+ val noClock = fields.filter(_.tpe != ClockType) // Remove clock
+ val inputSet = noClock.filter(_.dir == Reverse).map(f => Field(f.name, Default, f.tpe))
+ val outputSet = noClock.filter(_.dir == Default)
+ Port(inst.info, c + "Port", Output, BundleType(Seq(
+ Field("input", Reverse, BundleType(Seq(readyField, validField) ++ inputSet)),
+ Field("output", Default, BundleType(Seq(readyField, validField) ++ outputSet))
+ )))
+ }
+ val ports = connPorts ++ instIO.fields.filter(_.tpe == ClockType).map(_.toPort) // Add clock back
+
+ // simFire is signal to indicate when a simulation module can execute, this is indicated by all of its inputs
+ // being valid and all of its outputs being ready
+ val simFireInputs = connPorts.map { port =>
+ getFields(port).map { field =>
+ field.dir match {
+ case Reverse => buildExp(Seq(port.name, field.name, validField.name))
+ case Default => buildExp(Seq(port.name, field.name, readyField.name))
+ }
+ }
+ }.flatten
+ val simFire = DefNode(inst.info, "simFire", genPrimopReduce(And, simFireInputs))
+ // simClock is the simple AND of simFire and the real clock so that the rtl module only executes when data is
+ // available and outputs are ready
val simClock = DefNode(inst.info, "simClock", DoPrimop(And,
Seq(Ref(simFire.name, UnknownType), Ref("clock", UnknownType)), Seq(), UnknownType))
- val inputsReady = simInputPorts.map(p =>
- Connect(inst.info, namesToSubfield(Seq(p.name, "ready")), UIntValue(1, IntWidth(1))))
- val outputsValid = simOutputPorts.map(p =>
- Connect(inst.info, namesToSubfield(Seq(p.name, "valid")), Ref(simFire.name, UnknownType)))
- val instIOConnect = instIO.fields.map{ io =>
- io.tpe match {
- case ClockType => Connect(inst.info, Ref(io.name, io.tpe), Ref(simClock.name, UnknownType))
- case _ =>
- io.dir match {
- case Default => Connect(inst.info, Ref(io.name, io.tpe), namesToSubfield(Seq(inst.name, io.name)))
- case Reverse => Connect(inst.info, namesToSubfield(Seq(inst.name, io.name)), Ref(io.name, io.tpe))
- } } }
- val stmts = Block(Seq(simFire, simClock, inst) ++ inputsReady ++ outputsValid ++ instIOConnect)
+ // As a simple RTL module, we're always ready
+ val inputsReady = connPorts.map { port =>
+ getFields(port).filter(_.dir == Reverse).map { field =>
+ Connect(inst.info, buildExp(Seq(port.name, field.name, readyField.name)), UIntValue(1, IntWidth(1)))
+ }
+ }.flatten
+ // Outputs are valid on cycles where we fire
+ val outputsValid = connPorts.map { port =>
+ getFields(port).filter(_.dir == Default).map { field =>
+ Connect(inst.info, buildExp(Seq(port.name, field.name, validField.name)), Ref(simFire.name, UnknownType))
+ }
+ }.flatten
+ //val outputsValid = simOutputPorts.map(p =>
+ // Connect(inst.info, buildExp(Seq(p.name, "valid")), Ref(simFire.name, UnknownType)))
+ //// Connect up all of the IO of the RTL module to sim module IO, except clock which should be connected
+ //// to simClock
+ //val instIOConnect = instIO.fields.map{ io =>
+ // io.tpe match {
+ // case ClockType => Connect(inst.info, Ref(io.name, io.tpe), Ref(simClock.name, UnknownType))
+ // case _ =>
+ // io.dir match {
+ // case Default => Connect(inst.info, Ref(io.name, io.tpe), buildExp(Seq(inst.name, io.name)))
+ // case Reverse => Connect(inst.info, buildExp(Seq(inst.name, io.name)), Ref(io.name, io.tpe))
+ // } } }
+ //val stmts = Block(Seq(simFire, simClock, inst) ++ inputsReady ++ outputsValid ++ instIOConnect)
+ val stmts = Block(Seq(simFire, simClock) ++ inputsReady ++ outputsValid)
Module(inst.info, s"SimWrap_${inst.name}", ports, stmts)
}
+ // ***** transform *****
+ // Perform FAME-1 Transformation for MIDAS
def transform(c: Circuit): Circuit = {
+ // We should do a check low firrtl
val nameToModule = c.modules.map(m => m.name -> m)(collection.breakOut): Map[String, Module]
val top = nameToModule(c.name)
@@ -226,21 +222,15 @@ object Fame1 {
println(top.serialize)
val insts = getDefInsts(top)
- println(s"In top module ${top.name}, we have instances: ")
- insts.foreach(i => println(" " + i.name))
- val connections = Seq("topIO") ++ insts.map(_.name)
- println(connections)
+ val portConn = findPortConn(top, insts)
val wrappers = insts.map { inst =>
- genWrapperModule(inst, connections.filter(_ != inst.name))
+ genWrapperModule(inst, portConn(inst.name))
}
wrappers.foreach { w => println(w.serialize) }
- //val wrappers = insts.map(genWrapperModule(_, connections))
- //wrappers.foreach(println(_.serialize))
-
c
}
diff --git a/src/main/scala/midas/Utils.scala b/src/main/scala/midas/Utils.scala
new file mode 100644
index 00000000..06cf6902
--- /dev/null
+++ b/src/main/scala/midas/Utils.scala
@@ -0,0 +1,46 @@
+
+package midas
+
+import firrtl._
+
+object Utils {
+
+ // Takes a set of strings or ints and returns equivalent expression node
+ // Strings correspond to subfields/references, ints correspond to indexes
+ // eg. Seq(io, port, ready) => io.port.ready
+ // Seq(io, port, 5, valid) => io.port[5].valid
+ // Seq(3) => UInt("h3")
+ def buildExp(names: Seq[Any]): Exp = {
+ def rec(names: Seq[Any]): Exp = {
+ names.head match {
+ // Useful for adding on indexes or subfields
+ case head: Exp => head
+ // Int -> UInt/SInt/Index
+ case head: Int =>
+ if( names.tail.isEmpty ) // Is the UInt/SInt inference good enough?
+ if( head > 0 ) UIntValue(head, UnknownWidth) else SIntValue(head, UnknownWidth)
+ else Index(rec(names.tail), head, UnknownType)
+ // String -> Ref/Subfield
+ case head: String =>
+ if( names.tail.isEmpty ) Ref(head, UnknownType)
+ else Subfield(rec(names.tail), head, UnknownType)
+ case _ => throw new Exception("Invalid argument type to buildExp! " + names)
+ }
+ }
+ rec(names.reverse) // Let user specify in more natural format
+ }
+
+ def genPrimopReduce(op: Primop, args: Seq[Exp]): DoPrimop = {
+ 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)
+ }
+
+ // For a port that is known to be of type BundleType, return the fields of that bundle
+ def getFields(port: Port): Seq[Field] = {
+ port.tpe match {
+ case b: BundleType => b.fields
+ case _ => throw new Exception("getFields called on invalid port " + port)
+ }
+ }
+
+}