1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
// SPDX-License-Identifier: Apache-2.0
package firrtl.passes
import firrtl._
import firrtl.ir._
import firrtl.Utils._
import firrtl.traversals.Foreachers._
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 {
override def prerequisites = firrtl.stage.Forms.Resolved
override def invalidates(a: Transform) = false
private case class VoidExpr(stmt: Statement, voidDeps: Seq[Expression])
class RefNotInitializedException(info: Info, mname: String, name: String, trace: Seq[Statement])
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[Statement] = {
@tailrec
def rec(e: WrappedExpression, map: Map[WrappedExpression, VoidExpr], trace: Seq[Statement]): Seq[Statement] = {
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 = new Errors()
def checkInitM(m: Module): Unit = {
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): Unit = e match {
case WVoid =>
void = true
case (_: WRef | _: WSubField) =>
if (voidExprs.contains(e)) {
void = true
voidDeps += e
}
case _ => e.foreach(hasVoid)
}
hasVoid(e)
(void, voidDeps.toSeq)
}
def checkInitS(s: Statement): Unit = {
s match {
case con: Connect =>
val (hasVoid, voidDeps) = hasVoidExpr(con.expr)
if (hasVoid) voidExprs(con.loc) = VoidExpr(con, voidDeps)
case node: DefNode =>
val (hasVoid, voidDeps) = hasVoidExpr(node.value)
if (hasVoid) {
val nodeRef = WRef(node.name, node.value.tpe, NodeKind, SourceFlow)
voidExprs(nodeRef) = VoidExpr(node, voidDeps)
}
case sx => sx.foreach(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.append(new RefNotInitializedException(decl.info, m.name, decl.name, trace))
}
}
}
c.modules.foreach {
case m: Module => checkInitM(m)
case m => // Do nothing
}
errors.trigger()
c
}
}
|