Skip to content

Commit

Permalink
Support Optionality of implicit clock and reset (chipsalliance#3496)
Browse files Browse the repository at this point in the history
* withClock, withReset, and withClockAndReset now have forms that take
  Option[Clock] and Option[Reset]
* Module.clockOption and Module.resetOption return Option[Clock] and
  Option[Reset]
  • Loading branch information
jackkoenig authored Aug 18, 2023
1 parent 4c8b6c0 commit 468cc3a
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 9 deletions.
6 changes: 6 additions & 0 deletions core/src/main/scala/chisel3/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,15 @@ object Module extends SourceInfoDoc {
/** Returns the implicit Clock */
def clock: Clock = Builder.forcedClock

/** Returns the implicit Clock, if it is defined */
def clockOption: Option[Clock] = Builder.currentClock

/** Returns the implicit Reset */
def reset: Reset = Builder.forcedReset

/** Returns the implicit Reset, if it is defined */
def resetOption: Option[Reset] = Builder.currentReset

/** Returns the current Module */
def currentModule: Option[BaseModule] = Builder.currentModule

Expand Down
39 changes: 32 additions & 7 deletions core/src/main/scala/chisel3/MultiClock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@ object withClockAndReset {
* @param block the block of code to run with new implicit Clock and Reset
* @return the result of the block
*/
def apply[T](clock: Clock, reset: Reset)(block: => T): T = {
def apply[T](clock: Clock, reset: Reset)(block: => T): T = apply(Some(clock), Some(reset))(block)

/** Creates a new Clock and Reset scope
*
* @param clock the new implicit Clock, None will set no implicit clock
* @param reset the new implicit Reset, None will set no implicit reset
* @param block the block of code to run with new implicit Clock and Reset
* @return the result of the block
*/
def apply[T](clock: Option[Clock], reset: Option[Reset])(block: => T): T = {
// Save parentScope
val parentClock = Builder.currentClock
val parentReset = Builder.currentReset

Builder.currentClock = Some(clock)
Builder.currentReset = Some(reset)
Builder.currentClock = clock
Builder.currentReset = reset

val res = block // execute block

Expand All @@ -40,10 +49,18 @@ object withClock {
* @param block the block of code to run with new implicit Clock
* @return the result of the block
*/
def apply[T](clock: Clock)(block: => T): T = {
def apply[T](clock: Clock)(block: => T): T = apply(Some(clock))(block)

/** Creates a new Clock scope
*
* @param clock the new implicit Clock, None will set no implicit clock
* @param block the block of code to run with new implicit Clock
* @return the result of the block
*/
def apply[T](clock: Option[Clock])(block: => T): T = {
// Save parentScope
val parentClock = Builder.currentClock
Builder.currentClock = Some(clock)
Builder.currentClock = clock
val res = block // execute block
// Return to old scope
Builder.currentClock = parentClock
Expand All @@ -59,10 +76,18 @@ object withReset {
* @param block the block of code to run with new implicit Reset
* @return the result of the block
*/
def apply[T](reset: Reset)(block: => T): T = {
def apply[T](reset: Reset)(block: => T): T = apply(Some(reset))(block)

/** Creates a new Reset scope
*
* @param reset the new implicit Reset, None will set no implicit reset
* @param block the block of code to run with new implicit Reset
* @return the result of the block
*/
def apply[T](reset: Option[Reset])(block: => T): T = {
// Save parentScope
val parentReset = Builder.currentReset
Builder.currentReset = Some(reset)
Builder.currentReset = reset
val res = block // execute block
// Return to old scope
Builder.currentReset = parentReset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class ModuleSpec extends ChiselPropSpec with Utils {
}).getMessage should include("Module() cannot be called on a Class")
}

property("object Module.clock should return a reference to the currently in scope clock") {
property("Module.clock should return a reference to the currently in scope clock") {
ChiselStage.emitCHIRRTL(new Module {
val io = IO(new Bundle {
val clock2 = Input(Clock())
Expand All @@ -138,7 +138,27 @@ class ModuleSpec extends ChiselPropSpec with Utils {
withClock(io.clock2) { assert(Module.clock eq io.clock2) }
})
}
property("object Module.reset should return a reference to the currently in scope reset") {

property("Module.clockOption should return a reference to the currently in scope clock") {
ChiselStage.emitCHIRRTL(new Module {
val clock2 = IO(Input(Clock()))
Module.clockOption should be(Some(this.clock))
withClock(clock2) {
Module.clockOption should be(Some(clock2))
}
withClock(None) {
Module.clockOption should be(None)
}
})
}

property("Module.clockOption should be None for a RawModule") {
ChiselStage.emitCHIRRTL(new RawModule {
Module.clockOption should be(None)
})
}

property("Module.reset should return a reference to the currently in scope reset") {
ChiselStage.emitCHIRRTL(new Module {
val io = IO(new Bundle {
val reset2 = Input(Bool())
Expand All @@ -147,6 +167,26 @@ class ModuleSpec extends ChiselPropSpec with Utils {
withReset(io.reset2) { assert(Module.reset eq io.reset2) }
})
}

property("Module.resetOption should return a reference to the currently in scope reset") {
ChiselStage.emitCHIRRTL(new Module {
val reset2 = IO(Input(AsyncReset()))
Module.resetOption should be(Some(this.reset))
withReset(reset2) {
Module.resetOption should be(Some(reset2))
}
withReset(None) {
Module.resetOption should be(None)
}
})
}

property("Module.resetOption should be None for a RawModule") {
ChiselStage.emitCHIRRTL(new RawModule {
Module.resetOption should be(None)
})
}

property("object Module.currentModule should return an Option reference to the current Module") {
def checkModule(mod: Module): Boolean = Module.currentModule.map(_ eq mod).getOrElse(false)
ChiselStage.emitCHIRRTL(new Module {
Expand Down
20 changes: 20 additions & 0 deletions src/test/scala/chiselTests/MultiClockSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,24 @@ class MultiClockSpec extends ChiselFlatSpec with Utils {
when(done) { stop() }
})
}

it should "support setting Clock and Reset to None" in {
val e1 = the[ChiselException] thrownBy {
ChiselStage.emitCHIRRTL(new Module {
withClockAndReset(None, Some(this.reset)) {
Reg(UInt(8.W))
}
})
}
e1.getMessage should include("No implicit clock.")

val e2 = the[ChiselException] thrownBy {
ChiselStage.emitCHIRRTL(new Module {
withClockAndReset(Some(this.clock), None) {
RegInit(0.U(8.W))
}
})
}
e2.getMessage should include("No implicit reset.")
}
}

0 comments on commit 468cc3a

Please sign in to comment.