aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorJohn's Brew2020-03-13 02:35:10 +0100
committerGitHub2020-03-12 18:35:10 -0700
commit5c0c0018d812d57270035a9d3bd82e2289acf4ec (patch)
tree3e9c319c0e98566b42540a5f31d043d5d0287c17 /src/test
parent7e8d21e7f5fe3469eada53e6a6c60e38c134c403 (diff)
Add Support for FPGA Bitstream Preset-registers (#1050)
Introduce Preset Register Specialized Emission - Introduce EmissionOption trait - Introduce PresetAnnotation & PresetRegAnnotation - Enable the collection of Annotations in the Emitter - Introduce collection mechanism for EmissionOptions in the Emitter - Add PropagatePresetAnnotation transform to annotate register for emission and clean-up the useless reset tree (no DCE involved) - Add corresponding tests spec and tester Co-authored-by: Jack Koenig <koenig@sifive.com>
Diffstat (limited to 'src/test')
-rw-r--r--src/test/resources/features/PresetTester.fir51
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala4
-rw-r--r--src/test/scala/firrtlTests/LoweringCompilersSpec.scala2
-rw-r--r--src/test/scala/firrtlTests/PresetSpec.scala239
4 files changed, 294 insertions, 2 deletions
diff --git a/src/test/resources/features/PresetTester.fir b/src/test/resources/features/PresetTester.fir
new file mode 100644
index 00000000..a2395c99
--- /dev/null
+++ b/src/test/resources/features/PresetTester.fir
@@ -0,0 +1,51 @@
+
+circuit PresetTester :
+
+ module Test :
+ input clock : Clock
+ input reset : AsyncReset
+ input x : UInt<4>
+ output z : UInt<4>
+ reg r : UInt<4>, clock with : (reset => (reset, UInt(12)))
+ r <= x
+ z <= r
+
+ module PresetTester :
+ input clock : Clock
+ input reset : UInt<1>
+
+ reg div : UInt<2>, clock with : (reset => (reset, UInt(0)))
+ div <= tail(add(div, UInt(1)), 1)
+
+ reg slowClkReg : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ slowClkReg <= eq(div, UInt(0))
+ node slowClk = asClock(slowClkReg)
+
+ reg counter : UInt<4>, clock with : (reset => (reset, UInt(0)))
+ counter <= tail(add(counter, UInt(1)), 1)
+
+ reg x : UInt<5>, slowClk with : (reset => (reset, UInt(9)))
+ wire z : UInt<5>
+
+ wire preset : AsyncReset
+ preset <= asAsyncReset(UInt(0)) ; should be annotated as Preset
+
+ inst i of Test
+ i.clock <= slowClk
+ i.reset <= preset
+ i.x <= x
+ z <= i.z
+
+ when eq(counter, UInt(0)) :
+ when neq(z, UInt(12)) :
+ printf(clock, UInt(1), "Assertion 1 failed! z=%d \n",z)
+ stop(clock, UInt(1), 1)
+ ; Do the async reset
+ when eq(counter, UInt(1)) :
+ when neq(z, UInt(9)) :
+ printf(clock, UInt(1), "Assertion 2 failed! z=%d \n",z)
+ stop(clock, UInt(1), 1)
+ ; Success!
+ when eq(counter, UInt(3)) :
+ stop(clock, UInt(1), 0)
+
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index fe94a643..1eea3671 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -310,9 +310,9 @@ class TestFirrtlFlatSpec extends FirrtlFlatSpec {
}
/** Super class for execution driven Firrtl tests */
-abstract class ExecutionTest(name: String, dir: String, vFiles: Seq[String] = Seq.empty) extends FirrtlPropSpec {
+abstract class ExecutionTest(name: String, dir: String, vFiles: Seq[String] = Seq.empty, annotations: AnnotationSeq = Seq.empty) extends FirrtlPropSpec {
property(s"$name should execute correctly") {
- runFirrtlTest(name, dir, vFiles)
+ runFirrtlTest(name, dir, vFiles, annotations = annotations)
}
}
/** Super class for compilation driven Firrtl tests */
diff --git a/src/test/scala/firrtlTests/LoweringCompilersSpec.scala b/src/test/scala/firrtlTests/LoweringCompilersSpec.scala
index f3183599..dcc4e48d 100644
--- a/src/test/scala/firrtlTests/LoweringCompilersSpec.scala
+++ b/src/test/scala/firrtlTests/LoweringCompilersSpec.scala
@@ -203,6 +203,7 @@ class LoweringCompilersSpec extends FlatSpec with Matchers {
new firrtl.transforms.FixAddingNegativeLiterals,
new firrtl.transforms.ReplaceTruncatingArithmetic,
new firrtl.transforms.InlineBitExtractionsTransform,
+ new firrtl.transforms.PropagatePresetAnnotations,
new firrtl.transforms.InlineCastsTransform,
new firrtl.transforms.LegalizeClocksTransform,
new firrtl.transforms.FlattenRegUpdate,
@@ -222,6 +223,7 @@ class LoweringCompilersSpec extends FlatSpec with Matchers {
new firrtl.transforms.FixAddingNegativeLiterals,
new firrtl.transforms.ReplaceTruncatingArithmetic,
new firrtl.transforms.InlineBitExtractionsTransform,
+ new firrtl.transforms.PropagatePresetAnnotations,
new firrtl.transforms.InlineCastsTransform,
new firrtl.transforms.LegalizeClocksTransform,
new firrtl.transforms.FlattenRegUpdate,
diff --git a/src/test/scala/firrtlTests/PresetSpec.scala b/src/test/scala/firrtlTests/PresetSpec.scala
new file mode 100644
index 00000000..d35aa69f
--- /dev/null
+++ b/src/test/scala/firrtlTests/PresetSpec.scala
@@ -0,0 +1,239 @@
+// See LICENSE for license details.
+
+package firrtlTests
+
+import firrtl._
+import FirrtlCheckers._
+import firrtl.annotations._
+
+class PresetSpec extends FirrtlFlatSpec {
+ type Mod = Seq[String]
+ type ModuleSeq = Seq[Mod]
+ def compile(input: String, annos: AnnotationSeq): CircuitState =
+ (new VerilogCompiler).compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos), List.empty)
+ def compileBody(modules: ModuleSeq) = {
+ val annos = Seq(new PresetAnnotation(CircuitTarget("Test").module("Test").ref("reset")), firrtl.transforms.NoDCEAnnotation)
+ var str = """
+ |circuit Test :
+ |""".stripMargin
+ modules foreach ((m: Mod) => {
+ val header = "|module " + m(0) + " :"
+ str += header.stripMargin.stripMargin.split("\n").mkString(" ", "\n ", "")
+ str += m(1).split("\n").mkString(" ", "\n ", "")
+ str += """
+ |""".stripMargin
+ })
+ compile(str,annos)
+ }
+
+ "Preset" should """behave properly given a `Preset` annotated `AsyncReset` INPUT reset:
+ - replace AsyncReset specific blocks by standard Register blocks
+ - add inline declaration of all registers connected to reset
+ - remove the useless input port""" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |reg r : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result shouldNot containLine ("input reset,")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+
+ it should """behave properly given a `Preset` annotated `AsyncReset` WIRE reset:
+ - replace AsyncReset specific blocks by standard Register blocks
+ - add inline declaration of all registers connected to reset
+ - remove the useless wire declaration and assignation""" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire reset : AsyncReset
+ |reset <= asAsyncReset(UInt(0))
+ |reg r : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ // it should also remove useless asyncReset signal, all along the path down to registers
+ result shouldNot containLine ("wire reset;")
+ result shouldNot containLine ("assign reset = 1'h0;")
+ }
+ it should "raise TreeCleanUpOrphantException on cast of annotated AsyncReset" in {
+ an [firrtl.transforms.PropagatePresetAnnotations.TreeCleanUpOrphanException] shouldBe thrownBy {
+ compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |output sz : UInt<1>
+ |wire reset : AsyncReset
+ |reset <= asAsyncReset(UInt(0))
+ |reg r : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ |wire sreset : UInt<1>
+ |sreset <= asUInt(reset) ; this is FORBIDDEN
+ |reg s : UInt<1>, clock with : (reset => (sreset, UInt(0)))
+ |r <= x
+ |s <= x
+ |z <= r
+ |sz <= s""".stripMargin))
+ )
+ }
+ }
+
+ it should "propagate through bundles" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire bundle : {in_rst: AsyncReset, out_rst:AsyncReset}
+ |bundle.in_rst <= reset
+ |bundle.out_rst <= bundle.in_rst
+ |reg r : UInt<1>, clock with : (reset => (bundle.out_rst, UInt(0)))
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("input reset,")
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+ it should "propagate through vectors" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire vector : AsyncReset[2]
+ |vector[0] <= reset
+ |vector[1] <= vector[0]
+ |reg r : UInt<1>, clock with : (reset => (vector[1], UInt(0)))
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("input reset,")
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+
+ it should "propagate through bundles of vectors" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire bundle : {in_rst: AsyncReset[2], out_rst:AsyncReset}
+ |bundle.in_rst[0] <= reset
+ |bundle.in_rst[1] <= bundle.in_rst[0]
+ |bundle.out_rst <= bundle.in_rst[1]
+ |reg r : UInt<1>, clock with : (reset => (bundle.out_rst, UInt(0)))
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("input reset,")
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+ it should """propagate properly accross modules:
+ - replace AsyncReset specific blocks by standard Register blocks
+ - add inline declaration of all registers connected to reset
+ - remove the useless input port of instanciated module
+ - remove the useless instance connections
+ - remove wires and assignations used in instance connections
+ """ in {
+ val result = compileBody(Seq(
+ Seq("TestA",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |reg r : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ |r <= x
+ |z <= r
+ |""".stripMargin),
+ Seq("Test",s"""
+ |input clock : Clock
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire reset : AsyncReset
+ |reset <= asAsyncReset(UInt(0))
+ |inst i of TestA
+ |i.clock <= clock
+ |i.reset <= reset
+ |i.x <= x
+ |z <= i.z""".stripMargin)
+ ))
+ // assess that all useless connections are not emitted
+ result shouldNot containLine ("wire i_reset;")
+ result shouldNot containLine (".reset(i_reset),")
+ result shouldNot containLine ("assign i_reset = reset;")
+ result shouldNot containLine ("input reset,")
+
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+
+ it should "propagate even through disordonned statements" in {
+ val result = compileBody(Seq(Seq("Test",s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<1>
+ |output z : UInt<1>
+ |wire bundle : {in_rst: AsyncReset, out_rst:AsyncReset}
+ |reg r : UInt<1>, clock with : (reset => (bundle.out_rst, UInt(0)))
+ |bundle.out_rst <= bundle.in_rst
+ |bundle.in_rst <= reset
+ |r <= x
+ |z <= r""".stripMargin))
+ )
+ result shouldNot containLine ("input reset,")
+ result shouldNot containLine ("always @(posedge clock or posedge reset) begin")
+ result shouldNot containLines (
+ "if (reset) begin",
+ "r = 1'h0;",
+ "end")
+ result should containLine ("always @(posedge clock) begin")
+ result should containLine ("reg r = 1'h0;")
+ }
+
+}
+
+class PresetExecutionTest extends ExecutionTest(
+ "PresetTester",
+ "/features",
+ annotations = Seq(new PresetAnnotation(CircuitTarget("PresetTester").module("PresetTester").ref("preset")))
+)