Reset
As of Chisel 3.2.0, Chisel 3 supports both synchronous and asynchronous reset, meaning that it can natively emit both synchronous and asynchronously reset registers.
The type of register that is emitted is based on the type of the reset signal associated with the register.
There are three types of reset that implement a common trait Reset:
Bool- constructed withBool(). Also known as "synchronous reset".AsyncReset- constructed withAsyncReset(). Also known as "asynchronous reset".Reset- constructed withReset(). Also known as "abstract reset".
For implementation reasons, the concrete Scala type is ResetType. Stylistically we avoid ResetType, instead using the common trait Reset.
Registers with reset signals of type Bool are emitted as synchronous reset flops.
Registers with reset signals of type AsyncReset are emitted as asynchronouly reset flops.
Registers with reset signals of type Reset will have their reset type inferred during FIRRTL compilation.
Reset Inference
FIRRTL will infer a concrete type for any signals of type abstract Reset.
The rules are as follows:
- An abstract
Resetwith only signals of typeAsyncReset, abstractReset, andDontCarein both its fan-in and fan-out will infer to be of typeAsyncReset - An abstract
Resetwith signals of both typesBoolandAsyncResetin its fan-in and fan-out is an error. - Otherwise, an abstract
Resetwill infer to typeBool.
You can think about (3) as the mirror of (1) replacing AsyncReset with Bool with the additional
rule that abstract Resets with neither AsyncReset nor Bool in their fan-in and fan-out will
default to type Bool.
This "default" case is uncommon and implies that reset signal is ultimately driven by a DontCare.
Implicit Reset
A Module's reset is of type abstract Reset.
Prior to Chisel 3.2.0, the type of this field was Bool.
For backwards compatability, if the top-level module has an implicit reset, its type will default to Bool.
Setting Implicit Reset Type
New in Chisel 3.3.0
If you would like to set the reset type from within a Module (including the top-level Module),
rather than relying on Reset Inference, you can mixin one of the following traits:
RequireSyncReset- sets the type ofresettoBoolRequireAsyncReset- sets the type ofresettoAsyncReset
For example:
class MyAlwaysSyncResetModule extends Module with RequireSyncReset {
val mySyncResetReg = RegInit(false.B) // reset is of type Bool
}
class MyAlwaysAsyncResetModule extends Module with RequireAsyncReset {
val myAsyncResetReg = RegInit(false.B) // reset is of type AsyncReset
}
Note: This sets the concrete type, but the Scala type will remain Reset, so casting may still be necessary.
This comes up most often when using a reset of type Bool in logic.
Reset-Agnostic Code
The purpose of abstract Reset is to make it possible to design hardware that is agnostic to the
reset discipline used.
This enables code reuse for utilities and designs where the reset discipline does not matter to
the functionality of the block.
Consider the two example modules below which are agnostic to the type of reset used within them:
class ResetAgnosticModule extends Module {
val io = IO(new Bundle {
val out = UInt(4.W)
})
val resetAgnosticReg = RegInit(0.U(4.W))
resetAgnosticReg := resetAgnosticReg + 1.U
io.out := resetAgnosticReg
}
class ResetAgnosticRawModule extends RawModule {
val clk = IO(Input(Clock()))
val rst = IO(Input(Reset()))
val out = IO(Output(UInt(8.W)))
val resetAgnosticReg = withClockAndReset(clk, rst)(RegInit(0.U(8.W)))
resetAgnosticReg := resetAgnosticReg + 1.U
out := resetAgnosticReg
}
These modules can be used in both synchronous and asynchronous reset domains. Their reset types will be inferred based on the context within which they are used.
Forcing Reset Type
You can set the type of a Module's implicit reset as described above.
You can also cast to force the concrete type of reset.
.asBoolwill reinterpret aResetasBool.asAsyncResetwill reinterpret aResetasAsyncReset.
You can then use withReset to use a cast reset as the implicit reset.
See "Multiple Clock Domains" for more information about withReset.
The following will make myReg as well as both resetAgnosticRegs synchronously reset:
class ForcedSyncReset extends Module {
// withReset's argument becomes the implicit reset in its scope
withReset (reset.asBool) {
val myReg = RegInit(0.U)
val myModule = Module(new ResetAgnosticModule)
// RawModules do not have implicit resets so withReset has no effect
val myRawModule = Module(new ResetAgnosticRawModule)
// We must drive the reset port manually
myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset
}
}
The following will make myReg as well as both resetAgnosticRegs asynchronously reset:
class ForcedAysncReset extends Module {
// withReset's argument becomes the implicit reset in its scope
withReset (reset.asAsyncReset){
val myReg = RegInit(0.U)
val myModule = Module(new ResetAgnosticModule) // myModule.reset is connected implicitly
// RawModules do not have implicit resets so withReset has no effect
val myRawModule = Module(new ResetAgnosticRawModule)
// We must drive the reset port manually
myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset
}
}
Note: such casts (asBool and asAsyncReset) are not checked by FIRRTL.
In doing such a cast, you as the designer are effectively telling the compiler
that you know what you are doing and to force the type as cast.
Last-Connect Semantics
It is not legal to override the reset type using last-connect semantics
unless you are overriding a DontCare:
class MyModule extends Module {
val resetBool = Wire(Reset())
resetBool := DontCare
resetBool := false.B // this is fine
withReset(resetBool) {
val mySubmodule = Module(new Submodule())
}
resetBool := true.B // this is fine
resetBool := false.B.asAsyncReset // this will error in FIRRTL
}