aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjackkoenig2016-04-28 16:44:22 -0700
committerjackkoenig2016-05-03 16:56:52 -0700
commitb0ce2fa1b15708ab90753a0d70cbaac7f25729d0 (patch)
tree21924c356efbfc60a24c43775a28e5322e209e73 /src
parentc32b1d4a13bb0f1c35f1f4e074f4740a32755258 (diff)
Refactor Check Initialization to trace voids through temporary nodes
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/passes/CheckInitialization.scala79
1 files changed, 60 insertions, 19 deletions
diff --git a/src/main/scala/firrtl/passes/CheckInitialization.scala b/src/main/scala/firrtl/passes/CheckInitialization.scala
index 0982fdb6..27857768 100644
--- a/src/main/scala/firrtl/passes/CheckInitialization.scala
+++ b/src/main/scala/firrtl/passes/CheckInitialization.scala
@@ -31,52 +31,93 @@ import firrtl._
import firrtl.Utils._
import firrtl.Mappers._
+import annotation.tailrec
+
+/** Reports errors for any references that are not fully initialized
+ *
+ * @note This pass looks for [[firrtl.WVoid]]s left behind by [[ExpandWhens]]
+ * @note Assumes single connection (ie. no last connect semantics)
+ */
object CheckInitialization extends Pass {
def name = "Check Initialization"
- var mname = ""
- class RefNotInitialized(info: Info, name: String) extends PassException(s"$info : [module $mname] Reference $name is not fully initialized.")
+
+ private case class VoidExpr(stmt: Stmt, voidDeps: Seq[Expression])
+
+ class RefNotInitializedException(info: Info, mname: String, name: String, trace: Seq[Stmt]) extends PassException(
+ s"$info : [module $mname] Reference $name is not fully initialized.\n" +
+ trace.map(s => s" ${get_info(s)} : ${s.serialize}").mkString("\n")
+ )
+
+ private def getTrace(expr: WrappedExpression, voidExprs: Map[WrappedExpression, VoidExpr]): Seq[Stmt] = {
+ @tailrec
+ def rec(e: WrappedExpression, map: Map[WrappedExpression, VoidExpr], trace: Seq[Stmt]): Seq[Stmt] = {
+ val voidExpr = map(e)
+ val newTrace = voidExpr.stmt +: trace
+ if (voidExpr.voidDeps.nonEmpty) rec(voidExpr.voidDeps.head, map, newTrace) else newTrace
+ }
+ rec(expr, voidExprs, Seq())
+ }
+
def run(c: Circuit): Circuit = {
val errors = collection.mutable.ArrayBuffer[PassException]()
+
+
def checkInitM(m: InModule): Unit = {
- def getName(e: Expression): String = {
- e match {
- case e: WRef => e.name
- case e: WSubField => getName(e.exp) + "." + e.name
- case e: WSubIndex => getName(e.exp) + "[" + e.value + "]"
- case e =>
- error("Shouldn't be here")
- ""
- }
- }
- def hasVoidQ(e: Expression): Boolean = {
+ val voidExprs = collection.mutable.HashMap[WrappedExpression, VoidExpr]()
+
+ def hasVoidExpr(e: Expression): (Boolean, Seq[Expression]) = {
var void = false
+ val voidDeps = collection.mutable.ArrayBuffer[Expression]()
def hasVoid(e: Expression): Expression = {
e match {
case e: WVoid =>
void = true
e
+ case (_: WRef | _: WSubField) =>
+ if (voidExprs.contains(e)) {
+ void = true
+ voidDeps += e
+ }
+ e
case e => e map hasVoid
}
}
hasVoid(e)
- void
+ (void, voidDeps)
}
def checkInitS(s: Stmt): Stmt = {
s match {
- case s: Connect =>
- if (hasVoidQ(s.exp)) errors += new RefNotInitialized(s.info, getName(s.loc))
- s
+ case con: Connect =>
+ val (hasVoid, voidDeps) = hasVoidExpr(con.exp)
+ if (hasVoid) voidExprs(con.loc) = VoidExpr(con, voidDeps)
+ con
+ case node: DefNode =>
+ val (hasVoid, voidDeps) = hasVoidExpr(node.value)
+ if (hasVoid) {
+ val nodeRef = WRef(node.name, node.value.tpe, NodeKind(), MALE)
+ voidExprs(nodeRef) = VoidExpr(node, voidDeps)
+ }
+ node
case s => s map checkInitS
}
}
checkInitS(m.body)
+
+ // Build Up Errors
+ for ((expr, _) <- voidExprs) {
+ getDeclaration(m, expr.e1) match {
+ case node: DefNode => // Ignore nodes
+ case decl: IsDeclaration =>
+ val trace = getTrace(expr, voidExprs.toMap)
+ errors += new RefNotInitializedException(decl.info, m.name, decl.name, trace)
+ }
+ }
}
c.modules foreach { m =>
- mname = m.name
m match {
case m: InModule => checkInitM(m)
- case m => false
+ case m => // Do nothing
}
}