diff options
| author | jackkoenig | 2016-04-28 16:44:22 -0700 |
|---|---|---|
| committer | jackkoenig | 2016-05-03 16:56:52 -0700 |
| commit | b0ce2fa1b15708ab90753a0d70cbaac7f25729d0 (patch) | |
| tree | 21924c356efbfc60a24c43775a28e5322e209e73 /src | |
| parent | c32b1d4a13bb0f1c35f1f4e074f4740a32755258 (diff) | |
Refactor Check Initialization to trace voids through temporary nodes
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/firrtl/passes/CheckInitialization.scala | 79 |
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 } } |
