diff options
| author | Jack Koenig | 2019-08-13 15:06:58 +0530 |
|---|---|---|
| committer | GitHub | 2019-08-13 15:06:58 +0530 |
| commit | 24dddea6dccea5a570cece78324a5db624c7303a (patch) | |
| tree | b03fa616d0b8796548604a3d2b564fd17cf4e2d8 /src/test/scala/chiselTests/AsyncResetSpec.scala | |
| parent | fddb5943b1d36925a5435d327c3312572e98ca58 (diff) | |
Add support for asynchronous reset (#1011)
Adds new AsyncReset and "abstract" Reset types. Reset is inferred
in FIRRTL to be either AsyncReset or Bool. The "reset type" of a
register is set by the type of its reset signal:
val asyncReset: AsyncReset = IO(Input(AsyncReset()))
val syncReset: Bool = IO(Input(Bool()))
val abstractReset: Reset = IO(Input(Reset()))
val asyncReg = withReset(asyncReset) { RegInit(0.U) }
val syncReg = withReset(syncReset) { RegInit(0.U) }
val inferredReg = withReset(abstractReset) { RegInit(0.U) }
AsyncReset can be cast to and from Bool. Whereas synchronous reset is
equivalent to a mux in front of a flip-flop and thus can be driven by
logic, asynchronous reset requires that the reset value is a constant.
This is checked in FIRRTL.
Inference of the concrete type of a Reset occurs based on the type the
Reset's drivers. This inference is very simple, it is simple forward propagation
of the type, but it allows for writing blocks and modules that are agnostic
to the reset type. In particular, the implicit `reset` value in MultiIOModule
and thus Module is now concretely an instance of Reset and thus will be
inferred in FIRRTL.
Diffstat (limited to 'src/test/scala/chiselTests/AsyncResetSpec.scala')
| -rw-r--r-- | src/test/scala/chiselTests/AsyncResetSpec.scala | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/test/scala/chiselTests/AsyncResetSpec.scala b/src/test/scala/chiselTests/AsyncResetSpec.scala new file mode 100644 index 00000000..78a29e99 --- /dev/null +++ b/src/test/scala/chiselTests/AsyncResetSpec.scala @@ -0,0 +1,172 @@ +// See LICENSE for license details. + +package chiselTests + +import chisel3._ +import chisel3.util.{Counter, Queue} +import chisel3.testers.BasicTester +import firrtl.checks.CheckResets.NonLiteralAsyncResetValueException + +class AsyncResetTester extends BasicTester { + val (_, cDiv) = Counter(true.B, 4) + // First rising edge when count === 3 + val slowClk = cDiv.asClock + + val (count, done) = Counter(true.B, 16) + + val asyncResetNext = RegInit(false.B) + asyncResetNext := count === 4.U + val asyncReset = asyncResetNext.asAsyncReset + + val reg = withClockAndReset(slowClk, asyncReset) { + RegInit(123.U(8.W)) + } + reg := 5.U // Normal connection + + when (count === 3.U) { + assert(reg === 5.U) + } + when (count >= 5.U && count < 7.U) { + assert(reg === 123.U) + } .elsewhen (count >= 7.U) { + assert(reg === 5.U) + } + + when (done) { + stop() + } +} + +class AsyncResetAggregateTester extends BasicTester { + class MyBundle extends Bundle { + val x = UInt(8.W) + val y = UInt(8.W) + } + val (_, cDiv) = Counter(true.B, 4) + // First rising edge when count === 3 + val slowClk = cDiv.asClock + + val (count, done) = Counter(true.B, 16) + + val asyncResetNext = RegInit(false.B) + asyncResetNext := count === 4.U + val asyncReset = asyncResetNext.asAsyncReset + + val reg = withClockAndReset(slowClk, asyncReset) { + val init = Wire(Vec(2, new MyBundle)) + init(0).x := 0.U + init(0).y := 0.U + init(1).x := 0.U + init(1).y := 0.U + RegInit(init) + } + reg(0).x := 5.U // Normal connections + reg(0).y := 6.U + reg(1).x := 7.U + reg(1).y := 8.U + + when (count === 3.U) { + assert(reg(0).x === 5.U) + assert(reg(0).y === 6.U) + assert(reg(1).x === 7.U) + assert(reg(1).y === 8.U) + } + when (count >= 5.U && count < 7.U) { + assert(reg(0).x === 0.U) + assert(reg(0).y === 0.U) + assert(reg(1).x === 0.U) + assert(reg(1).y === 0.U) + } .elsewhen (count >= 7.U) { + assert(reg(0).x === 5.U) + assert(reg(0).y === 6.U) + assert(reg(1).x === 7.U) + assert(reg(1).y === 8.U) + } + + when (done) { + stop() + } +} + +class AsyncResetQueueTester extends BasicTester { + val (_, cDiv) = Counter(true.B, 4) + val slowClk = cDiv.asClock + + val (count, done) = Counter(true.B, 16) + + val asyncResetNext = RegNext(false.B, false.B) + val asyncReset = asyncResetNext.asAsyncReset + + val queue = withClockAndReset (slowClk, asyncReset) { + Module(new Queue(UInt(8.W), 4)) + } + queue.io.enq.valid := true.B + queue.io.enq.bits := count + + queue.io.deq.ready := false.B + + val doCheck = RegNext(false.B, false.B) + when (queue.io.count === 3.U) { + asyncResetNext := true.B + doCheck := true.B + } + when (doCheck) { + assert(queue.io.count === 0.U) + } + + when (done) { + stop() + } +} + +class AsyncResetSpec extends ChiselFlatSpec { + + behavior of "AsyncReset" + + it should "be allowed with literal reset values" in { + elaborate(new BasicTester { + withReset(reset.asAsyncReset)(RegInit(123.U)) + }) + } + + it should "NOT be allowed with non-literal reset values" in { + a [NonLiteralAsyncResetValueException] shouldBe thrownBy { + compile(new BasicTester { + val x = WireInit(123.U + 456.U) + withReset(reset.asAsyncReset)(RegInit(x)) + }) + } + } + + it should "NOT be allowed to connect directly to a Bool" in { + a [ChiselException] shouldBe thrownBy { + elaborate(new BasicTester { + val bool = Wire(Bool()) + val areset = reset.asAsyncReset + bool := areset + }) + } + } + + it should "simulate correctly" in { + assertTesterPasses(new AsyncResetTester) + } + + it should "simulate correctly with aggregates" in { + assertTesterPasses(new AsyncResetAggregateTester) + } + + it should "allow casting to and from Bool" in { + elaborate(new BasicTester { + val r: Reset = reset + val a: AsyncReset = WireInit(r.asAsyncReset) + val b: Bool = a.asBool + val c: AsyncReset = b.asAsyncReset + }) + } + + it should "allow changing the reset type of whole modules like Queue" in { + assertTesterPasses(new AsyncResetQueueTester) + } + +} |
