-
Notifications
You must be signed in to change notification settings - Fork 592
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Disable, a new API for disabling simulation constructs
- Loading branch information
1 parent
468cc3a
commit 9a213d1
Showing
6 changed files
with
245 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package chisel3 | ||
|
||
import chisel3.internal._ | ||
import chisel3.experimental.{IntrinsicModule, OpaqueType, SourceInfo} | ||
import chisel3.internal.sourceinfo.SourceInfoTransform | ||
|
||
import scala.language.experimental.macros | ||
import scala.collection.immutable.ListMap | ||
|
||
/** API for handling disabling of simulation constructs | ||
* | ||
* Disables may be non-synthesizable so they can only be used for disabling simulation constructs | ||
* | ||
* The default disable is the "hasBeenReset" of the currently in scope reset. | ||
* It can be set by the user via the [[withDisable]] API | ||
* | ||
* Users can access the current `Disable` with [[Module.disable]] | ||
*/ | ||
// We could just an OpaqueType, but since OpaqueTypes have some API holes, this non-Data type | ||
class Disable private[chisel3] (private[chisel3] val value: Bool) { | ||
|
||
/** Logical not | ||
* | ||
* @return invert the logical value of this `Disable` | ||
* @group Bitwise | ||
*/ | ||
final def unary_! : Disable = macro SourceInfoTransform.noArg | ||
|
||
/** @group SourceInfoTransformMacro */ | ||
def do_unary_!(implicit sourceInfo: SourceInfo): Disable = new Disable(!this.value) | ||
} | ||
|
||
object Disable { | ||
|
||
sealed trait Option | ||
case object None extends Option | ||
case object NotHasBeenReset extends Option | ||
|
||
private[chisel3] def withDisable[T](option: Option)(block: => T): T = { | ||
// Save parentScope | ||
val parentDisable = Builder.currentDisable | ||
|
||
Builder.currentDisable = option | ||
|
||
val res = block // execute block | ||
|
||
// Return to old scope | ||
Builder.currentDisable = parentDisable | ||
res | ||
} | ||
} | ||
|
||
/** Creates a new [[Disable]] scope */ | ||
object withDisable { | ||
|
||
/** Creates a new Disable scope | ||
* | ||
* @param disable an Optional new implicit Disable, None means no disable | ||
* @param block the block of code to run with new implicit Disable | ||
* @return the result of the block | ||
*/ | ||
def apply[T](disable: Disable.Option)(block: => T): T = Disable.withDisable(disable)(block) | ||
} | ||
|
||
/** | ||
*/ | ||
// Note because this uses abstract reset, it cannot be instantiable until we have the ability to | ||
// create both sync and sync reset instances from the same Definition | ||
private[chisel3] class HasBeenResetIntrinsic(implicit sourceInfo: SourceInfo) | ||
extends IntrinsicModule(f"circt_has_been_reset") { | ||
// Compiler plugin does not run on core so we have to suggest names | ||
val clock = IO(Input(Clock())).suggestName("clock") | ||
val reset = IO(Input(Reset())).suggestName("reset") | ||
val out = IO(Output(Bool())).suggestName("out") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package chiselTests | ||
|
||
import chisel3._ | ||
import chisel3.testers.BasicTester | ||
import _root_.circt.stage.ChiselStage | ||
|
||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
import chisel3.experimental.prefix | ||
|
||
class DisableSpec extends AnyFlatSpec with Matchers { | ||
|
||
behavior.of("Disable") | ||
|
||
it should "should be None by default in a RawModule" in { | ||
ChiselStage.emitCHIRRTL(new RawModule { | ||
Module.disable should be(None) | ||
}) | ||
} | ||
|
||
it should "default to hasBeenReset in a Module" in { | ||
val chirrtl = ChiselStage.emitCHIRRTL(new Module { | ||
override def desiredName = "Top" | ||
val doDisable = Module.disable | ||
}) | ||
chirrtl should include("intmodule HasBeenResetIntrinsic :") | ||
chirrtl should include("input clock : Clock") | ||
chirrtl should include("input reset : Reset") | ||
chirrtl should include("output out : UInt<1>") | ||
chirrtl should include("intrinsic = circt_has_been_reset") | ||
chirrtl should include("module Top :") | ||
chirrtl should include("inst HasBeenResetIntrinsic of HasBeenResetIntrinsic") | ||
chirrtl should include("connect HasBeenResetIntrinsic.clock, clock") | ||
chirrtl should include("connect HasBeenResetIntrinsic.reset, reset") | ||
chirrtl should include("node doDisable = eq(HasBeenResetIntrinsic.out, UInt<1>(0h0))") | ||
} | ||
|
||
it should "be None when there is a clock but no reset" in { | ||
ChiselStage.emitCHIRRTL(new RawModule { | ||
val clk = IO(Input(Clock())) | ||
withClock(clk) { | ||
Module.disable should be(None) | ||
} | ||
}) | ||
} | ||
|
||
it should "be None when there is a reset but no clock" in { | ||
ChiselStage.emitCHIRRTL(new RawModule { | ||
val rst = IO(Input(AsyncReset())) | ||
withReset(rst) { | ||
Module.disable should be(None) | ||
} | ||
}) | ||
} | ||
|
||
it should "be defined when there is a clock and a reset" in { | ||
ChiselStage.emitCHIRRTL(new RawModule { | ||
val clk = IO(Input(Clock())) | ||
val rst = IO(Input(AsyncReset())) | ||
withClockAndReset(clk, rst) { | ||
assert(Module.disable.isDefined) | ||
} | ||
}) | ||
} | ||
|
||
it should "be possible to set it to None" in { | ||
ChiselStage.emitCHIRRTL(new Module { | ||
assert(Module.disable.isDefined) | ||
withDisable(Disable.None) { | ||
Module.disable should be(None) | ||
} | ||
assert(Module.disable.isDefined) | ||
}) | ||
} | ||
|
||
it should "setting should propagate across module boundaries" in { | ||
ChiselStage.emitCHIRRTL(new Module { | ||
assert(Module.disable.isDefined) | ||
withDisable(Disable.None) { | ||
Module.disable should be(None) | ||
val inst = Module(new Module { | ||
Module.disable should be(None) | ||
}) | ||
} | ||
assert(Module.disable.isDefined) | ||
}) | ||
} | ||
|
||
it should "be setable back to notHasBeenReset" in { | ||
ChiselStage.emitCHIRRTL(new Module { | ||
assert(Module.disable.isDefined) | ||
withDisable(Disable.None) { | ||
Module.disable should be(None) | ||
val inst = Module(new Module { | ||
Module.disable should be(None) | ||
withDisable(Disable.NotHasBeenReset) { | ||
assert(Module.disable.isDefined) | ||
} | ||
}) | ||
} | ||
assert(Module.disable.isDefined) | ||
}) | ||
} | ||
|
||
it should "default the node name to disable" in { | ||
val chirrtl = ChiselStage.emitCHIRRTL(new Module { | ||
Module.disable // No name given | ||
}) | ||
chirrtl should include("node disable = eq(HasBeenResetIntrinsic.out, UInt<1>(0h0))") | ||
} | ||
|
||
it should "be impacted by prefix" in { | ||
val chirrtl = ChiselStage.emitCHIRRTL(new Module { | ||
prefix("foo") { | ||
Module.disable // No name given | ||
} | ||
}) | ||
chirrtl should include("node foo_disable = eq(HasBeenResetIntrinsic.out, UInt<1>(0h0))") | ||
} | ||
} |