aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorJack Koenig2019-08-13 12:09:27 +0530
committerGitHub2019-08-13 12:09:27 +0530
commitf08f8dbb3c480220f92923a7f3242fcbb644b65e (patch)
tree45cdb7543f6252ad2feb5aaf4e0e0580d3d27565 /src/test
parent63e88b6e1696e2c8d6da91f6f5eb128a9d0395ae (diff)
Infer reset (#1068)
* Add abstract "Reset" which can be inferred to AsyncReset or UInt<1> * Enhance async reset initial value literal check to support aggregates
Diffstat (limited to 'src/test')
-rw-r--r--src/test/scala/firrtlTests/AsyncResetSpec.scala137
-rw-r--r--src/test/scala/firrtlTests/InferResetsSpec.scala355
-rw-r--r--src/test/scala/firrtlTests/ProtoBufSpec.scala5
3 files changed, 495 insertions, 2 deletions
diff --git a/src/test/scala/firrtlTests/AsyncResetSpec.scala b/src/test/scala/firrtlTests/AsyncResetSpec.scala
index c1078a03..6fcb647a 100644
--- a/src/test/scala/firrtlTests/AsyncResetSpec.scala
+++ b/src/test/scala/firrtlTests/AsyncResetSpec.scala
@@ -3,7 +3,6 @@
package firrtlTests
import firrtl._
-import firrtl.ir._
import FirrtlCheckers._
class AsyncResetSpec extends FirrtlFlatSpec {
@@ -30,6 +29,25 @@ class AsyncResetSpec extends FirrtlFlatSpec {
result should containLine ("always @(posedge clock or posedge reset) begin")
}
+ it should "work in nested and flipped aggregates with regular and partial connect" in {
+ val result = compileBody(s"""
+ |output fizz : { flip foo : { a : AsyncReset, flip b: AsyncReset }[2], bar : { a : AsyncReset, flip b: AsyncReset }[2] }
+ |output buzz : { flip foo : { a : AsyncReset, flip b: AsyncReset }[2], bar : { a : AsyncReset, flip b: AsyncReset }[2] }
+ |fizz.bar <= fizz.foo
+ |buzz.bar <- buzz.foo
+ |""".stripMargin
+ )
+
+ result should containLine ("assign fizz_foo_0_b = fizz_bar_0_b;")
+ result should containLine ("assign fizz_foo_1_b = fizz_bar_1_b;")
+ result should containLine ("assign fizz_bar_0_a = fizz_foo_0_a;")
+ result should containLine ("assign fizz_bar_1_a = fizz_foo_1_a;")
+ result should containLine ("assign buzz_foo_0_b = buzz_bar_0_b;")
+ result should containLine ("assign buzz_foo_1_b = buzz_bar_1_b;")
+ result should containLine ("assign buzz_bar_0_a = buzz_foo_0_a;")
+ result should containLine ("assign buzz_bar_1_a = buzz_foo_1_a;")
+ }
+
it should "support casting to other types" in {
val result = compileBody(s"""
|input a : AsyncReset
@@ -77,7 +95,7 @@ class AsyncResetSpec extends FirrtlFlatSpec {
}
"Non-literals" should "NOT be allowed as reset values for AsyncReset" in {
- an [passes.CheckHighForm.NonLiteralAsyncResetValueException] shouldBe thrownBy {
+ an [checks.CheckResets.NonLiteralAsyncResetValueException] shouldBe thrownBy {
compileBody(s"""
|input clock : Clock
|input reset : AsyncReset
@@ -91,6 +109,121 @@ class AsyncResetSpec extends FirrtlFlatSpec {
}
}
+ "Late non-literals connections" should "NOT be allowed as reset values for AsyncReset" in {
+ an [checks.CheckResets.NonLiteralAsyncResetValueException] shouldBe thrownBy {
+ compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<8>
+ |input y : UInt<8>
+ |output z : UInt<8>
+ |wire a : UInt<8>
+ |reg r : UInt<8>, clock with : (reset => (reset, a))
+ |a <= y
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ }
+ }
+
+ "Hidden Non-literals" should "NOT be allowed as reset values for AsyncReset" in {
+ an [checks.CheckResets.NonLiteralAsyncResetValueException] shouldBe thrownBy {
+ compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>[4]
+ |input y : UInt<1>
+ |output z : UInt<1>[4]
+ |wire literal : UInt<1>[4]
+ |literal[0] <= UInt<1>("h00")
+ |literal[1] <= y
+ |literal[2] <= UInt<1>("h00")
+ |literal[3] <= UInt<1>("h00")
+ |reg r : UInt<1>[4], clock with : (reset => (reset, literal))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ }
+ }
+ "Wire connected to non-literal" should "NOT be allowed as reset values for AsyncReset" in {
+ an [checks.CheckResets.NonLiteralAsyncResetValueException] shouldBe thrownBy {
+ compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |input y : UInt<1>
+ |input cond : UInt<1>
+ |output z : UInt<1>
+ |wire w : UInt<1>
+ |w <= UInt(1)
+ |when cond :
+ | w <= y
+ |reg r : UInt<1>, clock with : (reset => (reset, w))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ }
+ }
+
+ "Complex literals" should "be allowed as reset values for AsyncReset" in {
+ val result = compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>[4]
+ |output z : UInt<1>[4]
+ |wire literal : UInt<1>[4]
+ |literal[0] <= UInt<1>("h00")
+ |literal[1] <= UInt<1>("h00")
+ |literal[2] <= UInt<1>("h00")
+ |literal[3] <= UInt<1>("h00")
+ |reg r : UInt<1>[4], clock with : (reset => (reset, literal))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ result should containLine ("always @(posedge clock or posedge reset) begin")
+ }
+
+ "Complex literals of complex literals" should "be allowed as reset values for AsyncReset" in {
+ val result = compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>[4]
+ |output z : UInt<1>[4]
+ |wire literal : UInt<1>[2]
+ |literal[0] <= UInt<1>("h01")
+ |literal[1] <= UInt<1>("h01")
+ |wire complex_literal : UInt<1>[4]
+ |complex_literal[0] <= literal[0]
+ |complex_literal[1] <= literal[1]
+ |complex_literal[2] <= UInt<1>("h00")
+ |complex_literal[3] <= UInt<1>("h00")
+ |reg r : UInt<1>[4], clock with : (reset => (reset, complex_literal))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ result should containLine ("always @(posedge clock or posedge reset) begin")
+ }
+ "Literals of bundle literals" should "be allowed as reset values for AsyncReset" in {
+ val result = compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>[4]
+ |output z : UInt<1>[4]
+ |wire bundle : {a: UInt<1>, b: UInt<1>}
+ |bundle.a <= UInt<1>("h01")
+ |bundle.b <= UInt<1>("h01")
+ |wire complex_literal : UInt<1>[4]
+ |complex_literal[0] <= bundle.a
+ |complex_literal[1] <= bundle.b
+ |complex_literal[2] <= UInt<1>("h00")
+ |complex_literal[3] <= UInt<1>("h00")
+ |reg r : UInt<1>[4], clock with : (reset => (reset, complex_literal))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ result should containLine ("always @(posedge clock or posedge reset) begin")
+ }
+
"Every async reset reg" should "generate its own always block" in {
val result = compileBody(s"""
diff --git a/src/test/scala/firrtlTests/InferResetsSpec.scala b/src/test/scala/firrtlTests/InferResetsSpec.scala
new file mode 100644
index 00000000..ac13033a
--- /dev/null
+++ b/src/test/scala/firrtlTests/InferResetsSpec.scala
@@ -0,0 +1,355 @@
+// See LICENSE for license details.
+
+package firrtlTests
+
+import firrtl._
+import firrtl.ir._
+import firrtl.passes.{CheckHighForm, CheckTypes}
+import firrtl.transforms.InferResets
+import FirrtlCheckers._
+
+// TODO
+// - Test nodes in the connection
+// - Test with whens (is this allowed?)
+class InferResetsSpec extends FirrtlFlatSpec {
+ def compile(input: String, compiler: Compiler = new MiddleFirrtlCompiler): CircuitState =
+ compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm), List.empty)
+
+ 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
+ )
+ println(result.getEmittedCircuit)
+ 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
+ )
+ 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
+ )
+ 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,
+ new LowFirrtlCompiler
+ )
+ result should containTree { case Port(_, "fizz_foo_0_a", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_foo_0_b", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_foo_1_a", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_foo_1_b", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_bar_0_a", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_bar_0_b", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_bar_1_a", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "fizz_bar_1_b", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_foo_0_a", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_foo_0_b", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_foo_1_a", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_foo_1_b", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_bar_0_a", Output, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_bar_0_b", Input, AsyncResetType) => true }
+ result should containTree { case Port(_, "buzz_bar_1_a", Output, AsyncResetType) => true }
+ 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 {
+ compile(s"""
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : UInt<1>
+ | output out : Reset
+ | wire w1 : Reset
+ | wire w2 : Reset
+ | w1 <= reset0
+ | w2 <= reset1
+ | out <= w1
+ | out <= w2
+ |""".stripMargin
+ )
+ }
+ }
+
+ it should "NOT support last connect semantics across whens" in {
+ an [InferResets.DifferingDriverTypesException] shouldBe thrownBy {
+ compile(s"""
+ |circuit top :
+ | module top :
+ | input reset0 : AsyncReset
+ | input reset1 : UInt<1>
+ | input en0 : UInt<1>
+ | output out : Reset
+ | wire w1 : Reset
+ | wire w2 : Reset
+ | w1 <= reset0
+ | w2 <= reset1
+ | out <= w1
+ | when en0 :
+ | out <= w2
+ |""".stripMargin
+ )
+ }
+ }
+
+ it should "not allow different Reset Types to drive a single Reset" in {
+ an [InferResets.DifferingDriverTypesException] 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
+ )
+ }
+ }
+
+ 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
+ )
+ 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
+ )
+ 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
+ )
+ 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 {
+ compile(s"""
+ |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 {
+ compile(s"""
+ |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 {
+ val result = compile(s"""
+ |circuit top :
+ | module top :
+ | input in : { foo : Reset }
+ | output out : Reset
+ | out <= in.foo
+ |""".stripMargin
+ )
+ }
+ 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
+ )
+ }
+ }
+
+ it should "not allow Vecs to infer different Reset Types" in {
+ 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
+ )
+ }
+ }
+
+ // 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 {
+ val result = compile(s"""
+ |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
+ )
+ result should containTree { case Port(_, "childReset", Input, BoolType) => true }
+ result should containTree { case Port(_, "childReset", Input, AsyncResetType) => true }
+ }
+}
+
diff --git a/src/test/scala/firrtlTests/ProtoBufSpec.scala b/src/test/scala/firrtlTests/ProtoBufSpec.scala
index 526a194c..2f347c6d 100644
--- a/src/test/scala/firrtlTests/ProtoBufSpec.scala
+++ b/src/test/scala/firrtlTests/ProtoBufSpec.scala
@@ -180,4 +180,9 @@ class ProtoBufSpec extends FirrtlFlatSpec {
val port = ir.Port(ir.NoInfo, "reset", ir.Input, ir.AsyncResetType)
FromProto.convert(ToProto.convert(port).build) should equal (port)
}
+
+ it should "support ResetTypes" in {
+ val port = ir.Port(ir.NoInfo, "reset", ir.Input, ir.ResetType)
+ FromProto.convert(ToProto.convert(port).build) should equal (port)
+ }
}