aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorJack Koenig2019-02-14 15:08:35 -0800
committerGitHub2019-02-14 15:08:35 -0800
commit2272044c6ab46b5148c39c124e66e1a8e9073a24 (patch)
tree83ad2141b1a3c54707dd9b33073f9217b0ae16c8 /src/test
parentd487b4cb6726e7e8d1a18f894021652594125221 (diff)
Asynchronous Reset (#1011)
Fixes #219 * Adds AsyncResetType (similar to ClockType) * Registers with reset signal of type AsyncResetType are async reset registers * Registers with async reset can only be reset to literal values * Add initialization logic for async reset registers
Diffstat (limited to 'src/test')
-rw-r--r--src/test/resources/features/AsyncResetTester.fir43
-rw-r--r--src/test/scala/firrtlTests/AsyncResetSpec.scala169
-rw-r--r--src/test/scala/firrtlTests/ConstantPropagationTests.scala26
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala13
-rw-r--r--src/test/scala/firrtlTests/ProtoBufSpec.scala8
-rw-r--r--src/test/scala/firrtlTests/RemoveWiresSpec.scala17
6 files changed, 270 insertions, 6 deletions
diff --git a/src/test/resources/features/AsyncResetTester.fir b/src/test/resources/features/AsyncResetTester.fir
new file mode 100644
index 00000000..15efbd8d
--- /dev/null
+++ b/src/test/resources/features/AsyncResetTester.fir
@@ -0,0 +1,43 @@
+
+circuit AsyncResetTester :
+ module AsyncResetTester :
+ 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 asyncResetReg : UInt<1>, clock with : (reset => (reset, UInt(0)))
+ asyncResetReg <= eq(counter, UInt(2))
+ node asyncReset = asAsyncReset(asyncResetReg)
+
+ reg r : UInt<8>, slowClk with : (reset => (asyncReset, UInt("h55")))
+ ; We always set the register on slowClk
+ when UInt(1) :
+ r <= UInt("hff")
+
+ when and(leq(counter, UInt(2)), neq(counter, UInt(0))) :
+ when neq(r, UInt("hff")) :
+ printf(clock, UInt(1), "Assertion 1 failed!\n")
+ stop(clock, UInt(1), 1)
+ ; Do the async reset
+ when eq(counter, UInt(3)) :
+ when neq(r, UInt("h55")) :
+ printf(clock, UInt(1), "Assertion 2 failed!\n")
+ stop(clock, UInt(1), 1)
+ ; Back to normal value
+ when eq(counter, UInt(5)) :
+ when neq(r, UInt("hff")) :
+ printf(clock, UInt(1), "Assertion 3 failed!\n")
+ stop(clock, UInt(1), 1)
+ ; Success!
+ when eq(counter, UInt(6)) :
+ stop(clock, UInt(1), 0)
+
diff --git a/src/test/scala/firrtlTests/AsyncResetSpec.scala b/src/test/scala/firrtlTests/AsyncResetSpec.scala
new file mode 100644
index 00000000..c1078a03
--- /dev/null
+++ b/src/test/scala/firrtlTests/AsyncResetSpec.scala
@@ -0,0 +1,169 @@
+// See LICENSE for license details.
+
+package firrtlTests
+
+import firrtl._
+import firrtl.ir._
+import FirrtlCheckers._
+
+class AsyncResetSpec extends FirrtlFlatSpec {
+ def compile(input: String): CircuitState =
+ (new VerilogCompiler).compileAndEmit(CircuitState(parse(input), ChirrtlForm), List.empty)
+ def compileBody(body: String) = {
+ val str = """
+ |circuit Test :
+ | module Test :
+ |""".stripMargin + body.split("\n").mkString(" ", "\n ", "")
+ compile(str)
+ }
+
+ "AsyncReset" should "generate async-reset always blocks" in {
+ val result = compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<8>
+ |output z : UInt<8>
+ |reg r : UInt<8>, clock with : (reset => (reset, UInt(123)))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ result should containLine ("always @(posedge clock or posedge reset) begin")
+ }
+
+ it should "support casting to other types" in {
+ val result = compileBody(s"""
+ |input a : AsyncReset
+ |output v : UInt<1>
+ |output w : SInt<1>
+ |output x : Clock
+ |output y : Fixed<1><<0>>
+ |output z : AsyncReset
+ |v <= asUInt(a)
+ |w <= asSInt(a)
+ |x <= asClock(a)
+ |y <= asFixedPoint(a, 0)
+ |z <= asAsyncReset(a)""".stripMargin
+ )
+ result should containLine ("assign v = $unsigned(a);")
+ result should containLine ("assign w = $signed(a);")
+ result should containLine ("assign x = a;")
+ result should containLine ("assign y = $signed(a);")
+ result should containLine ("assign z = a;")
+ }
+
+ "Other types" should "support casting to AsyncReset" in {
+ val result = compileBody(s"""
+ |input a : UInt<1>
+ |input b : SInt<1>
+ |input c : Clock
+ |input d : Fixed<1><<0>>
+ |input e : AsyncReset
+ |output v : AsyncReset
+ |output w : AsyncReset
+ |output x : AsyncReset
+ |output y : AsyncReset
+ |output z : AsyncReset
+ |v <= asAsyncReset(a)
+ |w <= asAsyncReset(a)
+ |x <= asAsyncReset(a)
+ |y <= asAsyncReset(a)
+ |z <= asAsyncReset(a)""".stripMargin
+ )
+ result should containLine ("assign v = a;")
+ result should containLine ("assign w = a;")
+ result should containLine ("assign x = a;")
+ result should containLine ("assign y = a;")
+ result should containLine ("assign z = a;")
+ }
+
+ "Non-literals" should "NOT be allowed as reset values for AsyncReset" in {
+ an [passes.CheckHighForm.NonLiteralAsyncResetValueException] shouldBe thrownBy {
+ compileBody(s"""
+ |input clock : Clock
+ |input reset : AsyncReset
+ |input x : UInt<8>
+ |input y : UInt<8>
+ |output z : UInt<8>
+ |reg r : UInt<8>, clock with : (reset => (reset, y))
+ |r <= x
+ |z <= r""".stripMargin
+ )
+ }
+ }
+
+
+ "Every async reset reg" should "generate its own always block" in {
+ val result = compileBody(s"""
+ |input clock0 : Clock
+ |input clock1 : Clock
+ |input syncReset : UInt<1>
+ |input asyncReset : AsyncReset
+ |input x : UInt<8>[5]
+ |output z : UInt<8>[5]
+ |reg r0 : UInt<8>, clock0 with : (reset => (syncReset, UInt(123)))
+ |reg r1 : UInt<8>, clock1 with : (reset => (syncReset, UInt(123)))
+ |reg r2 : UInt<8>, clock0 with : (reset => (asyncReset, UInt(123)))
+ |reg r3 : UInt<8>, clock0 with : (reset => (asyncReset, UInt(123)))
+ |reg r4 : UInt<8>, clock1 with : (reset => (asyncReset, UInt(123)))
+ |r0 <= x[0]
+ |r1 <= x[1]
+ |r2 <= x[2]
+ |r3 <= x[3]
+ |r4 <= x[4]
+ |z[0] <= r0
+ |z[1] <= r1
+ |z[2] <= r2
+ |z[3] <= r3
+ |z[4] <= r4""".stripMargin
+ )
+ result should containLines (
+ "always @(posedge clock0) begin",
+ "if (syncReset) begin",
+ "r0 <= 8'h7b;",
+ "end else begin",
+ "r0 <= x_0;",
+ "end",
+ "end"
+ )
+ result should containLines (
+ "always @(posedge clock1) begin",
+ "if (syncReset) begin",
+ "r1 <= 8'h7b;",
+ "end else begin",
+ "r1 <= x_1;",
+ "end",
+ "end"
+ )
+ result should containLines (
+ "always @(posedge clock0 or posedge asyncReset) begin",
+ "if (asyncReset) begin",
+ "r2 <= 8'h7b;",
+ "end else begin",
+ "r2 <= x_2;",
+ "end",
+ "end"
+ )
+ result should containLines (
+ "always @(posedge clock0 or posedge asyncReset) begin",
+ "if (asyncReset) begin",
+ "r3 <= 8'h7b;",
+ "end else begin",
+ "r3 <= x_3;",
+ "end",
+ "end"
+ )
+ result should containLines (
+ "always @(posedge clock1 or posedge asyncReset) begin",
+ "if (asyncReset) begin",
+ "r4 <= 8'h7b;",
+ "end else begin",
+ "r4 <= x_4;",
+ "end",
+ "end"
+ )
+ }
+
+}
+
+class AsyncResetExecutionTest extends ExecutionTest("AsyncResetTester", "/features")
+
diff --git a/src/test/scala/firrtlTests/ConstantPropagationTests.scala b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
index ee2540e0..6fb2ab8d 100644
--- a/src/test/scala/firrtlTests/ConstantPropagationTests.scala
+++ b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
@@ -1005,6 +1005,32 @@ class ConstantPropagationIntegrationSpec extends LowTransformSpec {
execute(input, check, Seq.empty)
}
+ "Registers async reset and a constant connection" should "NOT be removed" in {
+ val input =
+ """circuit Top :
+ | module Top :
+ | input clock : Clock
+ | input reset : AsyncReset
+ | input en : UInt<1>
+ | output z : UInt<8>
+ | reg r : UInt<8>, clock with : (reset => (reset, UInt<4>("hb")))
+ | when en :
+ | r <= UInt<4>("h0")
+ | z <= r""".stripMargin
+ val check =
+ """circuit Top :
+ | module Top :
+ | input clock : Clock
+ | input reset : AsyncReset
+ | input en : UInt<1>
+ | output z : UInt<8>
+ | reg r : UInt<8>, clock with :
+ | reset => (reset, UInt<8>("hb"))
+ | z <= r
+ | r <= mux(en, UInt<8>("h0"), r)""".stripMargin
+ execute(input, check, Seq.empty)
+ }
+
"Registers with constant reset and connection to the same constant" should "be replaced with that constant" in {
val input =
"""circuit Top :
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index 88238785..b3729f96 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -216,15 +216,18 @@ object FirrtlCheckers extends FirrtlMatchers {
}
/** Checks that the emitted circuit has the expected line, both will be normalized */
- def containLine(expectedLine: String) = new CircuitStateStringMatcher(expectedLine)
+ def containLine(expectedLine: String) = containLines(expectedLine)
- class CircuitStateStringMatcher(expectedLine: String) extends Matcher[CircuitState] {
+ /** Checks that the emitted circuit has the expected lines in order, all lines will be normalized */
+ def containLines(expectedLines: String*) = new CircuitStateStringsMatcher(expectedLines)
+
+ class CircuitStateStringsMatcher(expectedLines: Seq[String]) extends Matcher[CircuitState] {
override def apply(state: CircuitState): MatchResult = {
val emitted = state.getEmittedCircuit.value
MatchResult(
- emitted.split("\n").map(normalized).contains(normalized(expectedLine)),
- emitted + "\n did not contain \"" + expectedLine + "\"",
- s"${state.circuit.main} contained $expectedLine"
+ emitted.split("\n").map(normalized).containsSlice(expectedLines.map(normalized)),
+ emitted + "\n did not contain \"" + expectedLines + "\"",
+ s"${state.circuit.main} contained $expectedLines"
)
}
}
diff --git a/src/test/scala/firrtlTests/ProtoBufSpec.scala b/src/test/scala/firrtlTests/ProtoBufSpec.scala
index ff266f1f..090a7fea 100644
--- a/src/test/scala/firrtlTests/ProtoBufSpec.scala
+++ b/src/test/scala/firrtlTests/ProtoBufSpec.scala
@@ -24,7 +24,8 @@ class ProtoBufSpec extends FirrtlFlatSpec {
FirrtlResourceTest("Rob", "/regress"),
FirrtlResourceTest("RocketCore", "/regress"),
FirrtlResourceTest("ICache", "/regress"),
- FirrtlResourceTest("FPU", "/regress")
+ FirrtlResourceTest("FPU", "/regress"),
+ FirrtlResourceTest("AsyncResetTester", "/features")
)
for (FirrtlResourceTest(name, dir) <- firrtlResourceTests) {
@@ -136,4 +137,9 @@ class ProtoBufSpec extends FirrtlFlatSpec {
val slit = ir.SIntLiteral(-123)
FromProto.convert(ToProto.convert(slit).build) should equal (slit)
}
+
+ it should "support AsyncResetTypes" in {
+ val port = ir.Port(ir.NoInfo, "reset", ir.Input, ir.AsyncResetType)
+ FromProto.convert(ToProto.convert(port).build) should equal (port)
+ }
}
diff --git a/src/test/scala/firrtlTests/RemoveWiresSpec.scala b/src/test/scala/firrtlTests/RemoveWiresSpec.scala
index d15e6908..e40a770b 100644
--- a/src/test/scala/firrtlTests/RemoveWiresSpec.scala
+++ b/src/test/scala/firrtlTests/RemoveWiresSpec.scala
@@ -165,4 +165,21 @@ class RemoveWiresSpec extends FirrtlFlatSpec {
// Check declaration before use is maintained
passes.CheckHighForm.execute(result)
}
+
+ it should "order registers with async reset correctly" in {
+ val result = compileBody(s"""
+ |input clock : Clock
+ |input reset : UInt<1>
+ |input in : UInt<8>
+ |output out : UInt<8>
+ |wire areset : AsyncReset
+ |reg r : UInt<8>, clock with : (reset => (areset, UInt(0)))
+ |areset <= asAsyncReset(reset)
+ |r <= in
+ |out <= r
+ |""".stripMargin
+ )
+ // Check declaration before use is maintained
+ passes.CheckHighForm.execute(result)
+ }
}