From 1f63318b849012ba5655ac26774db383cf57f37d Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 26 Dec 2019 13:27:39 -0800 Subject: 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. --- src/test/scala/firrtlTests/InferResetsSpec.scala | 97 +++++++++++++++++++----- 1 file changed, 78 insertions(+), 19 deletions(-) (limited to 'src/test') diff --git a/src/test/scala/firrtlTests/InferResetsSpec.scala b/src/test/scala/firrtlTests/InferResetsSpec.scala index ac13033a..501dce20 100644 --- a/src/test/scala/firrtlTests/InferResetsSpec.scala +++ b/src/test/scala/firrtlTests/InferResetsSpec.scala @@ -4,7 +4,7 @@ package firrtlTests import firrtl._ import firrtl.ir._ -import firrtl.passes.{CheckHighForm, CheckTypes} +import firrtl.passes.{CheckHighForm, CheckTypes, CheckInitialization} import firrtl.transforms.InferResets import FirrtlCheckers._ @@ -37,7 +37,6 @@ class InferResetsSpec extends FirrtlFlatSpec { | y <= asFixedPoint(r, 0) | z <= asAsyncReset(r)""".stripMargin ) - println(result.getEmittedCircuit) result should containLine ("wire r : UInt<1>") result should containLine ("r <= a") result should containLine ("v <= asUInt(r)") @@ -125,44 +124,68 @@ class InferResetsSpec extends FirrtlFlatSpec { result should containTree { case Port(_, "buzz_bar_1_b", Input, AsyncResetType) => true } } - it should "NOT allow last connect semantics to pick the right type for Reset" in { - an [InferResets.DifferingDriverTypesException] shouldBe thrownBy { + it should "not crash if a ResetType has no drivers" in { + a [CheckInitialization.RefNotInitializedException] shouldBe thrownBy { + compile(s""" + |circuit test : + | module test : + | output out : Reset + | wire w : Reset + | out <= w + | out <= UInt(1) + |""".stripMargin + ) + } + } + + it should "allow last connect semantics to pick the right type for Reset" in { + val result = compile(s""" |circuit top : | module top : | input reset0 : AsyncReset | input reset1 : UInt<1> | output out : Reset + | wire w0 : Reset | wire w1 : Reset - | wire w2 : Reset - | w1 <= reset0 - | w2 <= reset1 + | w0 <= reset0 + | w1 <= reset1 + | out <= w0 | out <= w1 - | out <= w2 |""".stripMargin ) - } + result should containTree { case DefWire(_, "w0", AsyncResetType) => true } + result should containTree { case DefWire(_, "w1", BoolType) => true } + result should containTree { case Port(_, "out", Output, BoolType) => true } } - it should "NOT support last connect semantics across whens" in { - an [InferResets.DifferingDriverTypesException] shouldBe thrownBy { + it should "support last connect semantics across whens" in { + val result = compile(s""" |circuit top : | module top : | input reset0 : AsyncReset - | input reset1 : UInt<1> - | input en0 : UInt<1> + | input reset1 : AsyncReset + | input reset2 : UInt<1> + | input en : UInt<1> | output out : Reset + | wire w0 : Reset | wire w1 : Reset | wire w2 : Reset - | w1 <= reset0 - | w2 <= reset1 - | out <= w1 - | when en0 : - | out <= w2 + | w0 <= reset0 + | w1 <= reset1 + | w2 <= reset2 + | out <= w2 + | when en : + | out <= w0 + | else : + | out <= w1 |""".stripMargin ) - } + result should containTree { case DefWire(_, "w0", AsyncResetType) => true } + result should containTree { case DefWire(_, "w1", AsyncResetType) => true } + result should containTree { case DefWire(_, "w2", BoolType) => true } + result should containTree { case Port(_, "out", Output, AsyncResetType) => true } } it should "not allow different Reset Types to drive a single Reset" in { @@ -186,6 +209,42 @@ class InferResetsSpec extends FirrtlFlatSpec { } } + it should "allow concrete reset types to overrule invalidation" in { + val result = compile(s""" + |circuit test : + | module test : + | input in : AsyncReset + | output out : Reset + | out is invalid + | out <= in + |""".stripMargin) + result should containTree { case Port(_, "out", Output, AsyncResetType) => true } + } + + it should "default to BoolType for Resets that are only invalidated" in { + val result = compile(s""" + |circuit test : + | module test : + | output out : Reset + | out is invalid + |""".stripMargin) + result should containTree { case Port(_, "out", Output, BoolType) => true } + } + + it should "not error if component of ResetType is invalidated and connected to an AsyncResetType" in { + val result = compile(s""" + |circuit test : + | module test : + | input cond : UInt<1> + | input in : AsyncReset + | output out : Reset + | out is invalid + | when cond : + | out <= in + |""".stripMargin) + result should containTree { case Port(_, "out", Output, AsyncResetType) => true } + } + it should "allow ResetType to drive AsyncResets or UInt<1>" in { val result1 = compile(s""" |circuit top : -- cgit v1.2.3