aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/transforms/InferResets.scala
diff options
context:
space:
mode:
authorJack Koenig2019-12-26 13:27:39 -0800
committerJack Koenig2019-12-30 21:24:20 -0800
commit1f63318b849012ba5655ac26774db383cf57f37d (patch)
tree258b18b1d36c2ac853d933caa90df9d958604a97 /src/main/scala/firrtl/transforms/InferResets.scala
parent70088cd22d842fd757d39150062e81c32e427dde (diff)
Respect last connect semantics in InferResets
InferResets will now support last connect semantics (within the same scope) when determining the concrete reset type for components of type Reset. This only includes *unconditional* last connects; it remains illegal to drive a component of type Reset with different concrete types under differing when conditions. For example, the following is now legal: input a : UInt<1> input b : AsyncReset output z : Reset z <= a z <= b The second connect will when and z will be of type AsyncReset. The following remains illegal: input a : UInt<1> input b : AsyncReset input c : UInt<1> output z : Reset z <= a when c : z <= b This commit also ensures that components of type Reset with no drivers (or only invalidation) default to type UInt<1>. This fixes a bug where the transform would crash with such input.
Diffstat (limited to 'src/main/scala/firrtl/transforms/InferResets.scala')
-rw-r--r--src/main/scala/firrtl/transforms/InferResets.scala49
1 files changed, 34 insertions, 15 deletions
diff --git a/src/main/scala/firrtl/transforms/InferResets.scala b/src/main/scala/firrtl/transforms/InferResets.scala
index 70e2b76c..ea5b3092 100644
--- a/src/main/scala/firrtl/transforms/InferResets.scala
+++ b/src/main/scala/firrtl/transforms/InferResets.scala
@@ -36,7 +36,11 @@ object InferResets {
private case class TypeDriver(tpe: Type, target: () => ReferenceTarget) extends ResetDriver {
override def toString: String = s"TypeDriver(${tpe.serialize}, $target)"
}
-
+ // When a [[ResetType]] is invalidated, we record the InvalidDrive
+ // If there are no types but invalid drivers, we default to BoolType
+ private case object InvalidDriver extends ResetDriver {
+ def defaultType: Type = Utils.BoolType
+ }
// Type hierarchy representing the path to a leaf type in an aggregate type structure
// Used by this [[InferResets]] to pinpoint instances of [[ResetType]] and their inferred type
@@ -84,7 +88,7 @@ class InferResets extends Transform {
// Collect all drivers for circuit elements of type ResetType
private def analyze(c: Circuit): Map[ReferenceTarget, List[ResetDriver]] = {
- type DriverMap = mutable.HashMap[ReferenceTarget, mutable.ListBuffer[ResetDriver]]
+ type DriverMap = mutable.HashMap[ReferenceTarget, List[ResetDriver]]
def onMod(mod: DefModule): DriverMap = {
val instMap = mutable.Map[String, String]()
// We need to convert submodule port targets into targets on the Module port itself
@@ -116,7 +120,7 @@ class InferResets extends Transform {
case ResetType => TargetDriver(makeTarget(exp))
case tpe => TypeDriver(tpe, () => makeTarget(exp))
}
- map.getOrElseUpdate(target, mutable.ListBuffer()) += driver
+ map(target) = driver :: Nil
}
}
stmt match {
@@ -136,6 +140,16 @@ class InferResets extends Transform {
for ((i, j) <- points) {
markResetDriver(locs(i), exps(j))
}
+ case IsInvalid(_, lhs) =>
+ val exprs = Utils.create_exps(lhs)
+ for (expr <- exprs) {
+ // Ignore leaves that are not of type ResetType
+ // Unlike in markResetDriver, flow is irrelevant for invalidation
+ if (expr.tpe == ResetType) {
+ val target = makeTarget(expr)
+ map(target) = InvalidDriver :: Nil
+ }
+ }
case WDefInstance(_, inst, module, _) =>
instMap += (inst -> module)
case Conditionally(_, _, con, alt) =>
@@ -143,12 +157,12 @@ class InferResets extends Transform {
val altMap = new DriverMap
onStmt(conMap)(con)
onStmt(altMap)(alt)
- // Default to outerscope if not found in alt
+ // Default to outerscope if not found on either side
+ val conLookup = conMap.orElse(map).lift
val altLookup = altMap.orElse(map).lift
for (key <- conMap.keys ++ altMap.keys) {
- val ds = map.getOrElseUpdate(key, mutable.ListBuffer())
- conMap.get(key).foreach(ds ++= _)
- altLookup(key).foreach(ds ++= _)
+ val values = conLookup(key).getOrElse(Nil) ++ altLookup(key).getOrElse(Nil)
+ map(key) = values
}
case other => other.foreach(onStmt(map))
}
@@ -167,17 +181,22 @@ class InferResets extends Transform {
val res = mutable.Map[ReferenceTarget, Type]()
val errors = new Errors
def rec(target: ReferenceTarget): Type = {
- val drivers = map(target)
+ val drivers = map.getOrElse(target, Nil)
res.getOrElseUpdate(target, {
- val tpes = drivers.map {
- case TargetDriver(t) => TypeDriver(rec(t), () => t)
- case td: TypeDriver => td
+ val tpes = drivers.flatMap {
+ case TargetDriver(t) => Some(TypeDriver(rec(t), () => t))
+ case td: TypeDriver => Some(td)
+ case InvalidDriver => None
}.groupBy(_.tpe)
- if (tpes.keys.size != 1) {
- // Multiple types of driver!
- errors.append(DifferingDriverTypesException(target, tpes.toSeq))
+ tpes.keys.size match {
+ // This can occur if something of type Reset has no driver
+ case 0 => InvalidDriver.defaultType
+ case 1 => tpes.keys.head
+ case _ =>
+ // Multiple types of driver!
+ errors.append(DifferingDriverTypesException(target, tpes.toSeq))
+ tpes.keys.head
}
- tpes.keys.head
})
}
for ((target, _) <- map) {