diff options
| author | Jack Koenig | 2019-12-26 13:27:39 -0800 |
|---|---|---|
| committer | Jack Koenig | 2019-12-30 21:24:20 -0800 |
| commit | 1f63318b849012ba5655ac26774db383cf57f37d (patch) | |
| tree | 258b18b1d36c2ac853d933caa90df9d958604a97 /src/main/scala/firrtl/transforms/InferResets.scala | |
| parent | 70088cd22d842fd757d39150062e81c32e427dde (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.scala | 49 |
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) { |
