Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for asynchronous reset #1011

Merged
merged 16 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion chiselFrontend/src/main/scala/chisel3/Bits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,106 @@ trait SIntFactory {

object SInt extends SIntFactory

sealed trait Reset extends Element with ToBoolable
sealed trait Reset extends Element with ToBoolable {
/** Casts this $coll to an [[AsyncReset]] */
final def asAsyncReset(): AsyncReset = macro SourceInfoWhiteboxTransform.noArg

/** @group SourceInfoTransformMacro */
def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset
}

object Reset {
def apply(): Reset = new ResetType
}

/** "Abstract" Reset Type inferred in FIRRTL to either [[AsyncReset]] or [[Bool]]
*
* @note This shares a common interface with [[AsyncReset]] and [[Bool]] but is not their actual
* super type due to Bool inheriting from abstract class UInt
*/
final class ResetType(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
override def toString: String = s"Reset$bindingToString"

def cloneType: this.type = Reset().asInstanceOf[this.type]

private[chisel3] def typeEquivalent(that: Data): Boolean =
this.getClass == that.getClass

override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
case _: Reset => super.connect(that)(sourceInfo, connectCompileOptions)
case _ => super.badConnect(that)(sourceInfo)
}

override def litOption = None

/** Not really supported */
def toPrintable: Printable = PString("Reset")

override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))

private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Unit = {
this := that
}

/** @group SourceInfoTransformMacro */
def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset =
pushOp(DefPrim(sourceInfo, AsyncReset(), AsAsyncResetOp, ref))

/** @group SourceInfoTransformMacro */
def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
pushOp(DefPrim(sourceInfo, Bool(), AsUIntOp, ref))

/** @group SourceInfoTransformMacro */
def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = do_asBool
}

object AsyncReset {
def apply(): AsyncReset = new AsyncReset
}

/** Data type representing asynchronous reset signals
*
* These signals are similar to [[Clock]]s in that they must be glitch-free for proper circuit
* operation. [[Reg]]s defined with the implicit reset being an [[AsyncReset]] will be
* asychronously reset registers.
*/
sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
override def toString: String = s"AsyncReset$bindingToString"

def cloneType: this.type = AsyncReset().asInstanceOf[this.type]

private[chisel3] def typeEquivalent(that: Data): Boolean =
this.getClass == that.getClass

override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
case _: AsyncReset => super.connect(that)(sourceInfo, connectCompileOptions)
case _ => super.badConnect(that)(sourceInfo)
}

override def litOption = None

/** Not really supported */
def toPrintable: Printable = PString("AsyncReset")

override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))

// TODO Is this right?
private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Unit = {
this := that.asBool.asAsyncReset
}

/** @group SourceInfoTransformMacro */
def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset = this

/** @group SourceInfoTransformMacro */
def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
pushOp(DefPrim(sourceInfo, Bool(), AsUIntOp, ref))

/** @group SourceInfoTransformMacro */
def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = do_asBool
}

// REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth
// operations on a Bool make sense?
Expand Down Expand Up @@ -1286,6 +1385,10 @@ sealed class Bool() extends UInt(1.W) with Reset {

/** @group SourceInfoTransformMacro */
def do_asClock(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Clock = pushOp(DefPrim(sourceInfo, Clock(), AsClockOp, ref))

/** @group SourceInfoTransformMacro */
def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset =
pushOp(DefPrim(sourceInfo, AsyncReset(), AsAsyncResetOp, ref))
}

trait BoolFactory {
Expand Down
12 changes: 9 additions & 3 deletions chiselFrontend/src/main/scala/chisel3/CompileOptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ trait CompileOptions {
val checkSynthesizable: Boolean
// Require explicit assignment of DontCare to generate "x is invalid"
val explicitInvalidate: Boolean
// Should the reset type of Module be a Bool or a Reset
val inferModuleReset: Boolean
}

object CompileOptions {
Expand Down Expand Up @@ -48,7 +50,9 @@ object ExplicitCompileOptions {
// Check that referenced Data have actually been declared.
val checkSynthesizable: Boolean,
// Require an explicit DontCare assignment to generate a firrtl DefInvalid
val explicitInvalidate: Boolean
val explicitInvalidate: Boolean,
// Should the reset type of Module be a Bool or a Reset
val inferModuleReset: Boolean
) extends CompileOptions

// Collection of "not strict" connection compile options.
Expand All @@ -59,7 +63,8 @@ object ExplicitCompileOptions {
dontTryConnectionsSwapped = false,
dontAssumeDirectionality = false,
checkSynthesizable = false,
explicitInvalidate = false
explicitInvalidate = false,
inferModuleReset = false
)

// Collection of "strict" connection compile options, preferred for new code.
Expand All @@ -69,6 +74,7 @@ object ExplicitCompileOptions {
dontTryConnectionsSwapped = true,
dontAssumeDirectionality = true,
checkSynthesizable = true,
explicitInvalidate = true
explicitInvalidate = true,
inferModuleReset = true
)
}
17 changes: 7 additions & 10 deletions chiselFrontend/src/main/scala/chisel3/RawModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions)
extends RawModule {
// Implicit clock and reset pins
val clock: Clock = IO(Input(Clock()))
val reset: Reset = IO(Input(Bool()))
val reset: Reset = {
// Top module and compatibility mode use Bool for reset
val inferReset = _parent.isDefined && moduleCompileOptions.inferModuleReset
IO(Input(if (inferReset) Reset() else Bool()))
}

// Setup ClockAndReset
Builder.currentClock = Some(clock)
Expand Down Expand Up @@ -219,14 +223,7 @@ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions)
pushCommand(DefInvalid(sourceInfo, io.ref))
}

override_clock match {
case Some(override_clock) => clock := override_clock
case _ => clock := Builder.forcedClock
}

override_reset match {
case Some(override_reset) => reset := override_reset
case _ => reset := Builder.forcedReset
}
clock := override_clock.getOrElse(Builder.forcedClock)
reset := override_reset.getOrElse(Builder.forcedReset)
}
}
6 changes: 3 additions & 3 deletions chiselFrontend/src/main/scala/chisel3/Reg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,12 @@ object RegInit {
requireIsChiselType(t, "reg type")
}
val reg = t.cloneTypeFull
val clock = Builder.forcedClock.ref
val reset = Builder.forcedReset.ref
val clock = Builder.forcedClock
val reset = Builder.forcedReset

reg.bind(RegBinding(Builder.forcedUserModule))
requireIsHardware(init, "reg initializer")
pushCommand(DefRegInit(sourceInfo, reg, clock, reset, init.ref))
pushCommand(DefRegInit(sourceInfo, reg, clock.ref, reset.ref, init.ref))
reg
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ private[chisel3] object MonoConnect {
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: Clock, source_e: Clock) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: AsyncReset, source_e: AsyncReset) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: ResetType, source_e: Reset) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: EnumType, source_e: UnsafeEnum) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: EnumType, source_e: EnumType) if sink_e.typeEquivalent(source_e) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ private[chisel3] object Converter {

def extractType(data: Data, clearDir: Boolean = false): fir.Type = data match { // scalastyle:ignore cyclomatic.complexity line.size.limit
case _: Clock => fir.ClockType
case _: AsyncReset => fir.AsyncResetType
case _: ResetType => fir.ResetType
case d: EnumType => fir.UIntType(convert(d.width))
case d: UInt => fir.UIntType(convert(d.width))
case d: SInt => fir.SIntType(convert(d.width))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ object PrimOp {
val AsFixedPointOp = PrimOp("asFixedPoint")
val SetBinaryPoint = PrimOp("bpset")
val AsClockOp = PrimOp("asClock")
val AsAsyncResetOp = PrimOp("asAsyncReset")
}

abstract class Arg {
Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/chisel3/internal/firrtl/Emitter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ private class Emitter(circuit: Circuit) {

private def emitType(d: Data, clearDir: Boolean = false): String = d match { // scalastyle:ignore cyclomatic.complexity line.size.limit
case d: Clock => "Clock"
case d: EnumType => s"UInt${d.width}"
case _: AsyncReset => "AsyncReset"
case _: ResetType => "Reset"
case d: chisel3.core.EnumType => s"UInt${d.width}"
case d: UInt => s"UInt${d.width}"
case d: SInt => s"SInt${d.width}"
case d: FixedPoint => s"Fixed${d.width}${d.binaryPoint}"
Expand Down
Loading