aboutsummaryrefslogtreecommitdiff
path: root/src/test/scala/firrtlTests/InferResetsSpec.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/scala/firrtlTests/InferResetsSpec.scala')
-rw-r--r--src/test/scala/firrtlTests/InferResetsSpec.scala668
1 files changed, 325 insertions, 343 deletions
diff --git a/src/test/scala/firrtlTests/InferResetsSpec.scala b/src/test/scala/firrtlTests/InferResetsSpec.scala
index b607fb46..057fb3b0 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, CheckInitialization}
+import firrtl.passes.{CheckHighForm, CheckInitialization, CheckTypes}
import firrtl.transforms.{CheckCombLoops, InferResets}
import firrtl.testutils._
import firrtl.testutils.FirrtlCheckers._
@@ -16,95 +16,93 @@ class InferResetsSpec extends FirrtlFlatSpec {
def compile(input: String, compiler: Compiler = new MiddleFirrtlCompiler): CircuitState =
compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm), List.empty)
- behavior of "ResetType"
+ behavior.of("ResetType")
val BoolType = UIntType(IntWidth(1))
it should "support casting to other types" in {
val result = compile(s"""
- |circuit top:
- | module top:
- | input a : UInt<1>
- | output v : UInt<1>
- | output w : SInt<1>
- | output x : Clock
- | output y : Fixed<1><<0>>
- | output z : AsyncReset
- | wire r : Reset
- | r <= a
- | v <= asUInt(r)
- | w <= asSInt(r)
- | x <= asClock(r)
- | y <= asFixedPoint(r, 0)
- | z <= asAsyncReset(r)""".stripMargin
- )
- result should containLine ("wire r : UInt<1>")
- result should containLine ("r <= a")
- result should containLine ("v <= asUInt(r)")
- result should containLine ("w <= asSInt(r)")
- result should containLine ("x <= asClock(r)")
- result should containLine ("y <= asSInt(r)")
- result should containLine ("z <= asAsyncReset(r)")
+ |circuit top:
+ | module top:
+ | input a : UInt<1>
+ | output v : UInt<1>
+ | output w : SInt<1>
+ | output x : Clock
+ | output y : Fixed<1><<0>>
+ | output z : AsyncReset
+ | wire r : Reset
+ | r <= a
+ | v <= asUInt(r)
+ | w <= asSInt(r)
+ | x <= asClock(r)
+ | y <= asFixedPoint(r, 0)
+ | z <= asAsyncReset(r)""".stripMargin)
+ result should containLine("wire r : UInt<1>")
+ result should containLine("r <= a")
+ result should containLine("v <= asUInt(r)")
+ result should containLine("w <= asSInt(r)")
+ result should containLine("x <= asClock(r)")
+ result should containLine("y <= asSInt(r)")
+ result should containLine("z <= asAsyncReset(r)")
}
it should "work across Module boundaries" in {
val result = compile(s"""
- |circuit top :
- | module child :
- | input clock : Clock
- | input childReset : Reset
- | input x : UInt<8>
- | output z : UInt<8>
- | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
- | r <= x
- | z <= r
- | module top :
- | input clock : Clock
- | input reset : UInt<1>
- | input x : UInt<8>
- | output z : UInt<8>
- | inst c of child
- | c.clock <= clock
- | c.childReset <= reset
- | c.x <= x
- | z <= c.z
- |""".stripMargin
- )
+ |circuit top :
+ | module child :
+ | input clock : Clock
+ | input childReset : Reset
+ | input x : UInt<8>
+ | output z : UInt<8>
+ | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
+ | r <= x
+ | z <= r
+ | module top :
+ | input clock : Clock
+ | input reset : UInt<1>
+ | input x : UInt<8>
+ | output z : UInt<8>
+ | inst c of child
+ | c.clock <= clock
+ | c.childReset <= reset
+ | c.x <= x
+ | z <= c.z
+ |""".stripMargin)
result should containTree { case Port(_, "childReset", Input, BoolType) => true }
}
it should "work across multiple Module boundaries" in {
val result = compile(s"""
- |circuit top :
- | module child :
- | input resetIn : Reset
- | output resetOut : Reset
- | resetOut <= resetIn
- | module top :
- | input clock : Clock
- | input reset : UInt<1>
- | input x : UInt<8>
- | output z : UInt<8>
- | inst c of child
- | c.resetIn <= reset
- | reg r : UInt<8>, clock with : (reset => (c.resetOut, UInt(123)))
- | r <= x
- | z <= r
- |""".stripMargin
- )
+ |circuit top :
+ | module child :
+ | input resetIn : Reset
+ | output resetOut : Reset
+ | resetOut <= resetIn
+ | module top :
+ | input clock : Clock
+ | input reset : UInt<1>
+ | input x : UInt<8>
+ | output z : UInt<8>
+ | inst c of child
+ | c.resetIn <= reset
+ | reg r : UInt<8>, clock with : (reset => (c.resetOut, UInt(123)))
+ | r <= x
+ | z <= r
+ |""".stripMargin)
result should containTree { case Port(_, "resetIn", Input, BoolType) => true }
result should containTree { case Port(_, "resetOut", Output, BoolType) => true }
}
it should "work in nested and flipped aggregates with regular and partial connect" in {
- val result = compile(s"""
- |circuit top :
- | module top :
- | output fizz : { flip foo : { a : AsyncReset, flip b: Reset }[2], bar : { a : Reset, flip b: AsyncReset }[2] }
- | output buzz : { flip foo : { a : AsyncReset, c: UInt<1>, flip b: Reset }[2], bar : { a : Reset, flip b: AsyncReset, c: UInt<8> }[2] }
- | fizz.bar <= fizz.foo
- | buzz.bar <- buzz.foo
- |""".stripMargin,
+ val result = compile(
+ s"""
+ |circuit top :
+ | module top :
+ | output fizz : { flip foo : { a : AsyncReset, flip b: Reset }[2], bar : { a : Reset, flip b: AsyncReset }[2] }
+ | output buzz : { flip foo : { a : AsyncReset, c: UInt<1>, flip b: Reset }[2], bar : { a : Reset, flip b: AsyncReset, c: UInt<8> }[2] }
+ | fizz.bar <= fizz.foo
+ | buzz.bar <- buzz.foo
+ |""".stripMargin,
new LowFirrtlCompiler
)
result should containTree { case Port(_, "fizz_foo_0_a", Input, AsyncResetType) => true }
@@ -126,386 +124,370 @@ class InferResetsSpec extends FirrtlFlatSpec {
}
it should "not crash if a ResetType has no drivers" in {
- a [CheckInitialization.RefNotInitializedException] shouldBe thrownBy {
+ a[CheckInitialization.RefNotInitializedException] shouldBe thrownBy {
compile(s"""
- |circuit test :
- | module test :
- | output out : Reset
- | wire w : Reset
- | out <= w
- | out <= UInt(1)
- |""".stripMargin
- )
+ |circuit test :
+ | module test :
+ | output out : Reset
+ | wire w : Reset
+ | out <= w
+ | out <= UInt(1)
+ |""".stripMargin)
}
}
it should "NOT allow last connect semantics to pick the right type for Reset" in {
- an [InferResets.InferResetsException] shouldBe thrownBy {
+ an[InferResets.InferResetsException] shouldBe thrownBy {
compile(s"""
- |circuit top :
- | module top :
- | input reset0 : AsyncReset
- | input reset1 : UInt<1>
- | output out : Reset
- | wire w0 : Reset
- | wire w1 : Reset
- | w0 <= reset0
- | w1 <= reset1
- | out <= w0
- | out <= w1
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : UInt<1>
+ | output out : Reset
+ | wire w0 : Reset
+ | wire w1 : Reset
+ | w0 <= reset0
+ | w1 <= reset1
+ | out <= w0
+ | out <= w1
+ |""".stripMargin)
}
}
it should "NOT support last connect semantics across whens" in {
- an [InferResets.InferResetsException] shouldBe thrownBy {
+ an[InferResets.InferResetsException] shouldBe thrownBy {
compile(s"""
- |circuit top :
- | module top :
- | input reset0 : AsyncReset
- | input reset1 : AsyncReset
- | input reset2 : UInt<1>
- | input en : UInt<1>
- | output out : Reset
- | wire w0 : Reset
- | wire w1 : Reset
- | wire w2 : Reset
- | w0 <= reset0
- | w1 <= reset1
- | w2 <= reset2
- | out <= w2
- | when en :
- | out <= w0
- | else :
- | out <= w1
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : AsyncReset
+ | input reset2 : UInt<1>
+ | input en : UInt<1>
+ | output out : Reset
+ | wire w0 : Reset
+ | wire w1 : Reset
+ | wire w2 : Reset
+ | w0 <= reset0
+ | w1 <= reset1
+ | w2 <= reset2
+ | out <= w2
+ | when en :
+ | out <= w0
+ | else :
+ | out <= w1
+ |""".stripMargin)
}
}
it should "not allow different Reset Types to drive a single Reset" in {
- an [InferResets.InferResetsException] shouldBe thrownBy {
+ an[InferResets.InferResetsException] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | module top :
- | input reset0 : AsyncReset
- | input reset1 : UInt<1>
- | input en : UInt<1>
- | output out : Reset
- | wire w1 : Reset
- | wire w2 : Reset
- | w1 <= reset0
- | w2 <= reset1
- | out <= w1
- | when en :
- | out <= w2
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : UInt<1>
+ | input en : UInt<1>
+ | output out : Reset
+ | wire w1 : Reset
+ | wire w2 : Reset
+ | w1 <= reset0
+ | w2 <= reset1
+ | out <= w1
+ | when en :
+ | out <= w2
+ |""".stripMargin)
}
}
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)
+ |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)
+ |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)
+ |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 :
- | module top :
- | input in : UInt<1>
- | output out : UInt<1>
- | wire w : Reset
- | w <= in
- | out <= w
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in : UInt<1>
+ | output out : UInt<1>
+ | wire w : Reset
+ | w <= in
+ | out <= w
+ |""".stripMargin)
result1 should containTree { case DefWire(_, "w", BoolType) => true }
val result2 = compile(s"""
- |circuit top :
- | module top :
- | output foo : { flip a : UInt<1> }
- | input bar : { flip a : UInt<1> }
- | wire w : { flip a : Reset }
- | foo <= w
- | w <= bar
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | output foo : { flip a : UInt<1> }
+ | input bar : { flip a : UInt<1> }
+ | wire w : { flip a : Reset }
+ | foo <= w
+ | w <= bar
+ |""".stripMargin)
val AggType = BundleType(Seq(Field("a", Flip, BoolType)))
result2 should containTree { case DefWire(_, "w", AggType) => true }
val result3 = compile(s"""
- |circuit top :
- | module top :
- | input in : UInt<1>
- | output out : UInt<1>
- | wire w : Reset
- | w <- in
- | out <- w
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in : UInt<1>
+ | output out : UInt<1>
+ | wire w : Reset
+ | w <- in
+ | out <- w
+ |""".stripMargin)
result3 should containTree { case DefWire(_, "w", BoolType) => true }
}
it should "error if a ResetType driving UInt<1> infers to AsyncReset" in {
- an [Exception] shouldBe thrownBy {
+ an[Exception] shouldBe thrownBy {
compile(s"""
- |circuit top :
- | module top :
- | input in : AsyncReset
- | output out : UInt<1>
- | wire w : Reset
- | w <= in
- | out <= w
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in : AsyncReset
+ | output out : UInt<1>
+ | wire w : Reset
+ | w <= in
+ | out <= w
+ |""".stripMargin)
}
}
it should "error if a ResetType driving AsyncReset infers to UInt<1>" in {
- an [Exception] shouldBe thrownBy {
+ an[Exception] shouldBe thrownBy {
compile(s"""
- |circuit top :
- | module top :
- | input in : UInt<1>
- | output out : AsyncReset
- | wire w : Reset
- | w <= in
- | out <= w
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in : UInt<1>
+ | output out : AsyncReset
+ | wire w : Reset
+ | w <= in
+ | out <= w
+ |""".stripMargin)
}
}
it should "not allow ResetType as an Input or ExtModule output" in {
// TODO what exception should be thrown here?
- an [CheckHighForm.ResetInputException] shouldBe thrownBy {
+ an[CheckHighForm.ResetInputException] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | module top :
- | input in : { foo : Reset }
- | output out : Reset
- | out <= in.foo
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in : { foo : Reset }
+ | output out : Reset
+ | out <= in.foo
+ |""".stripMargin)
}
- an [CheckHighForm.ResetExtModuleOutputException] shouldBe thrownBy {
+ an[CheckHighForm.ResetExtModuleOutputException] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | extmodule ext :
- | output out : { foo : Reset }
- | module top :
- | output out : Reset
- | inst e of ext
- | out <= e.out.foo
- |""".stripMargin
- )
+ |circuit top :
+ | extmodule ext :
+ | output out : { foo : Reset }
+ | module top :
+ | output out : Reset
+ | inst e of ext
+ | out <= e.out.foo
+ |""".stripMargin)
}
}
it should "not allow Vecs to infer different Reset Types" in {
- an [CheckTypes.InvalidConnect] shouldBe thrownBy {
+ an[CheckTypes.InvalidConnect] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | module top :
- | input reset0 : AsyncReset
- | input reset1 : UInt<1>
- | output out : Reset[2]
- | out[0] <= reset0
- | out[1] <= reset1
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : UInt<1>
+ | output out : Reset[2]
+ | out[0] <= reset0
+ | out[1] <= reset1
+ |""".stripMargin)
}
}
// Or is this actually an error? The behavior is that out is inferred as AsyncReset[2]
ignore should "not allow Vecs only be partially inferred" in {
// Some exception should be thrown, TODO figure out which one
- an [Exception] shouldBe thrownBy {
+ an[Exception] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | module top :
- | input reset : AsyncReset
- | output out : Reset[2]
- | out is invalid
- | out[0] <= reset
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input reset : AsyncReset
+ | output out : Reset[2]
+ | out is invalid
+ | out[0] <= reset
+ |""".stripMargin)
}
}
-
it should "support inferring modules that would dedup differently" in {
val result = compile(s"""
- |circuit top :
- | module child :
- | input clock : Clock
- | input childReset : Reset
- | input x : UInt<8>
- | output z : UInt<8>
- | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
- | r <= x
- | z <= r
- | module child_1 :
- | input clock : Clock
- | input childReset : Reset
- | input x : UInt<8>
- | output z : UInt<8>
- | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
- | r <= x
- | z <= r
- | module top :
- | input clock : Clock
- | input reset1 : UInt<1>
- | input reset2 : AsyncReset
- | input x : UInt<8>[2]
- | output z : UInt<8>[2]
- | inst c of child
- | c.clock <= clock
- | c.childReset <= reset1
- | c.x <= x[0]
- | z[0] <= c.z
- | inst c2 of child_1
- | c2.clock <= clock
- | c2.childReset <= reset2
- | c2.x <= x[1]
- | z[1] <= c2.z
- |""".stripMargin
- )
+ |circuit top :
+ | module child :
+ | input clock : Clock
+ | input childReset : Reset
+ | input x : UInt<8>
+ | output z : UInt<8>
+ | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
+ | r <= x
+ | z <= r
+ | module child_1 :
+ | input clock : Clock
+ | input childReset : Reset
+ | input x : UInt<8>
+ | output z : UInt<8>
+ | reg r : UInt<8>, clock with : (reset => (childReset, UInt(123)))
+ | r <= x
+ | z <= r
+ | module top :
+ | input clock : Clock
+ | input reset1 : UInt<1>
+ | input reset2 : AsyncReset
+ | input x : UInt<8>[2]
+ | output z : UInt<8>[2]
+ | inst c of child
+ | c.clock <= clock
+ | c.childReset <= reset1
+ | c.x <= x[0]
+ | z[0] <= c.z
+ | inst c2 of child_1
+ | c2.clock <= clock
+ | c2.childReset <= reset2
+ | c2.x <= x[1]
+ | z[1] <= c2.z
+ |""".stripMargin)
result should containTree { case Port(_, "childReset", Input, BoolType) => true }
result should containTree { case Port(_, "childReset", Input, AsyncResetType) => true }
}
it should "infer based on what a component *drives* not just what drives it" in {
val result = compile(s"""
- |circuit top :
- | module top :
- | input in : AsyncReset
- | output out : Reset
- | wire w : Reset
- | w is invalid
- | out <= w
- | out <= in
- |""".stripMargin)
+ |circuit top :
+ | module top :
+ | input in : AsyncReset
+ | output out : Reset
+ | wire w : Reset
+ | w is invalid
+ | out <= w
+ | out <= in
+ |""".stripMargin)
result should containTree { case DefWire(_, "w", AsyncResetType) => true }
}
it should "infer from connections, ignoring the fact that the invalidation wins" in {
val result = compile(s"""
- |circuit top :
- | module top :
- | input in : AsyncReset
- | output out : Reset
- | out <= in
- | out is invalid
- |""".stripMargin)
+ |circuit top :
+ | module top :
+ | input in : AsyncReset
+ | output out : Reset
+ | out <= in
+ | out is invalid
+ |""".stripMargin)
result should containTree { case Port(_, "out", Output, AsyncResetType) => true }
}
// The backwards type propagation constrains `w` to be the same as both `out0` and `out1`
it should "not allow an invalidated Wire to drive both a UInt<1> and an AsyncReset" in {
- an [InferResets.InferResetsException] shouldBe thrownBy {
+ an[InferResets.InferResetsException] shouldBe thrownBy {
val result = compile(s"""
- |circuit top :
- | module top :
- | input in0 : AsyncReset
- | input in1 : UInt<1>
- | output out0 : Reset
- | output out1 : Reset
- | wire w : Reset
- | w is invalid
- | out0 <= w
- | out1 <= w
- | out0 <= in0
- | out1 <= in1
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in0 : AsyncReset
+ | input in1 : UInt<1>
+ | output out0 : Reset
+ | output out1 : Reset
+ | wire w : Reset
+ | w is invalid
+ | out0 <= w
+ | out1 <= w
+ | out0 <= in0
+ | out1 <= in1
+ |""".stripMargin)
}
}
it should "not propagate type info from downstream across a cast" in {
val result = compile(s"""
- |circuit top :
- | module top :
- | input in0 : AsyncReset
- | input in1 : UInt<1>
- | output out0 : Reset
- | output out1 : Reset
- | wire w : Reset
- | w is invalid
- | out0 <= asAsyncReset(w)
- | out1 <= w
- | out0 <= in0
- | out1 <= in1
- |""".stripMargin
- )
+ |circuit top :
+ | module top :
+ | input in0 : AsyncReset
+ | input in1 : UInt<1>
+ | output out0 : Reset
+ | output out1 : Reset
+ | wire w : Reset
+ | w is invalid
+ | out0 <= asAsyncReset(w)
+ | out1 <= w
+ | out0 <= in0
+ | out1 <= in1
+ |""".stripMargin)
result should containTree { case Port(_, "out0", Output, AsyncResetType) => true }
}
// This tests for a bug unrelated to support or lackthereof for last connect in inference
it should "take into account both internal and external constraints on Module port types" in {
val result = compile(s"""
- |circuit top :
- | module child :
- | input i : AsyncReset
- | output o : Reset
- | o <= i
- | module top :
- | input in : AsyncReset
- | output out : AsyncReset
- | inst c of child
- | c.o is invalid
- | c.i <= in
- | out <= c.o
- |""".stripMargin)
+ |circuit top :
+ | module child :
+ | input i : AsyncReset
+ | output o : Reset
+ | o <= i
+ | module top :
+ | input in : AsyncReset
+ | output out : AsyncReset
+ | inst c of child
+ | c.o is invalid
+ | c.i <= in
+ | out <= c.o
+ |""".stripMargin)
result should containTree { case Port(_, "o", Output, AsyncResetType) => true }
}
it should "not crash on combinational loops" in {
- a [CheckCombLoops.CombLoopException] shouldBe thrownBy {
- val result = compile(s"""
- |circuit top :
- | module top :
- | input in : AsyncReset
- | output out : Reset
- | wire w0 : Reset
- | wire w1 : Reset
- | w0 <= in
- | w0 <= w1
- | w1 <= w0
- | out <= in
- |""".stripMargin,
+ a[CheckCombLoops.CombLoopException] shouldBe thrownBy {
+ val result = compile(
+ s"""
+ |circuit top :
+ | module top :
+ | input in : AsyncReset
+ | output out : Reset
+ | wire w0 : Reset
+ | wire w1 : Reset
+ | w0 <= in
+ | w0 <= w1
+ | w1 <= w0
+ | out <= in
+ |""".stripMargin,
compiler = new LowFirrtlCompiler
)
}