From 294ad95458fbdf8a1fc2904e65973f8f931070d4 Mon Sep 17 00:00:00 2001 From: Trevor McKay Date: Fri, 30 Jan 2026 13:49:30 -0800 Subject: [PATCH 1/3] use reifySingleTarget to get data underlying Settings signals --- src/main/scala/chisel3/simulator/Settings.scala | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/scala/chisel3/simulator/Settings.scala b/src/main/scala/chisel3/simulator/Settings.scala index 885b9b1fb4e..212fa9dc91d 100644 --- a/src/main/scala/chisel3/simulator/Settings.scala +++ b/src/main/scala/chisel3/simulator/Settings.scala @@ -3,6 +3,7 @@ package chisel3.simulator import chisel3.{Data, Module, RawModule} +import chisel3.experimental.dataview.reifySingleTarget import svsim.CommonCompilationSettings.VerilogPreprocessorDefine import svsim.Workspace @@ -27,6 +28,16 @@ object MacroText { } + /** Given a [[Data]] and its parent [[ElaboratedModule]], lookup the underlying hardware. */ + private def lookupSignal[A <: RawModule](data: Data, elaboratedModule: ElaboratedModule[A]): String = { + val reified = reifySingleTarget(data).getOrElse { + throw new IllegalArgumentException( + s"Cannot use $data as a macro signal because it does not map to a single Data." + ) + } + elaboratedModule.portMap(reified).name + } + /** A macro that will return macro text with the name of a signal in the design * under test * @@ -38,7 +49,7 @@ object MacroText { macroName: String, elaboratedModule: ElaboratedModule[A] ) = { - val port = elaboratedModule.portMap(get(elaboratedModule.wrapped)).name + val port = lookupSignal(get(elaboratedModule.wrapped), elaboratedModule) VerilogPreprocessorDefine(macroName, s"${Workspace.testbenchModuleName}.$port") } @@ -55,7 +66,7 @@ object MacroText { macroName: String, elaboratedModule: ElaboratedModule[A] ) = { - val port = elaboratedModule.portMap(get(elaboratedModule.wrapped)).name + val port = lookupSignal(get(elaboratedModule.wrapped), elaboratedModule) VerilogPreprocessorDefine(macroName, s"!${Workspace.testbenchModuleName}.$port") } From 438893f0d4a0468c5c891c74668ece17eb66cd85 Mon Sep 17 00:00:00 2001 From: Trevor McKay Date: Fri, 30 Jan 2026 13:50:08 -0800 Subject: [PATCH 2/3] add Settings.defaultTest --- .../scala/chisel3/simulator/Settings.scala | 29 +++- .../simulator/scalatest/ChiselSimSpec.scala | 160 ++++++++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) diff --git a/src/main/scala/chisel3/simulator/Settings.scala b/src/main/scala/chisel3/simulator/Settings.scala index 212fa9dc91d..f16ad0d673d 100644 --- a/src/main/scala/chisel3/simulator/Settings.scala +++ b/src/main/scala/chisel3/simulator/Settings.scala @@ -2,7 +2,7 @@ package chisel3.simulator -import chisel3.{Data, Module, RawModule} +import chisel3.{Data, Module, RawModule, SimulationTestHarnessInterface} import chisel3.experimental.dataview.reifySingleTarget import svsim.CommonCompilationSettings.VerilogPreprocessorDefine import svsim.Workspace @@ -193,6 +193,33 @@ object Settings { randomization = Randomization.random ) + /** Return a default [[Settings]] for a [[SimulationTestHarnessInterface]]. Macros will be set to + * disable [[chisel3.assert]]-style assertions using the [[SimulationTestHarnessInterface]]'s init + * port. + * + * Note: this _requires_ that an explicit type parameter is provided. You + * must invoke this method like: + * + * {{{ + * Settings.default[Foo] + * }}} + * + * If you invoke this method like the following, you will get an error: + * + * {{{ + * Settings.default + * }}} + */ + final def defaultTest[A <: RawModule with SimulationTestHarnessInterface]: Settings[A] = new Settings[A]( + verilogLayers = LayerControl.EnableAll, + assertVerboseCond = Some(MacroText.NotSignal(get = _.init)), + printfCond = Some(MacroText.NotSignal(get = _.init)), + stopCond = Some(MacroText.NotSignal(get = _.init)), + plusArgs = Seq.empty, + enableWavesAtTimeZero = false, + randomization = Randomization.random + ) + /** Simple factory for construcing a [[Settings]] from arguments. * * This method primarily exists as a way to make future refactors that add diff --git a/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala b/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala index 29bef657c47..59a395c65f1 100644 --- a/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala +++ b/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala @@ -147,6 +147,166 @@ class ChiselSimSpec extends AnyFunSpec with Matchers with ChiselSim with FileChe ) } + it("should set macros to use init for Settings.defaultTest") { + class Foo extends SimulationTestHarness { + val (_, wrap) = Counter(true.B, 4) + done :<= wrap + success :<= true.B + } + simulateTest(new Foo, timeout = 100, settings = Settings.defaultTest[Foo]) + io.Source + .fromFile( + FileSystems + .getDefault() + .getPath(implicitly[HasTestingDirectory].getDirectory.toString, "workdir-verilator", "Makefile") + .toFile + ) + .mkString + .fileCheck()( + """|CHECK: '+define+ASSERT_VERBOSE_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+PRINTF_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+STOP_COND=!svsimTestbench.init' + |""".stripMargin + ) + } + + it("should set macros for SimulationTestHarnessInterface with separate IO") { + class SeparateIOHarness extends RawModule with SimulationTestHarnessInterface { + val clock = IO(Input(Clock())) + val init = IO(Input(Bool())) + val done = IO(Output(Bool())) + val success = IO(Output(Bool())) + + withClockAndReset(clock, init) { + val (_, wrap) = Counter(true.B, 4) + done := wrap + success := true.B + } + } + simulateTest(new SeparateIOHarness, timeout = 100, settings = Settings.defaultTest[SeparateIOHarness]) + io.Source + .fromFile( + FileSystems + .getDefault() + .getPath(implicitly[HasTestingDirectory].getDirectory.toString, "workdir-verilator", "Makefile") + .toFile + ) + .mkString + .fileCheck()( + """|CHECK: '+define+ASSERT_VERBOSE_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+PRINTF_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+STOP_COND=!svsimTestbench.init' + |""".stripMargin + ) + } + + it("should set macros for SimulationTestHarnessInterface with FlatIO") { + class FlatIOHarness extends RawModule with SimulationTestHarnessInterface { + private val io = FlatIO(new Bundle { + val clock = Input(Clock()) + val init = Input(Bool()) + val done = Output(Bool()) + val success = Output(Bool()) + }) + def clock = io.clock + def init = io.init + def done = io.done + def success = io.success + + withClockAndReset(clock, init) { + val (_, wrap) = Counter(true.B, 4) + io.done := wrap + io.success := true.B + } + } + simulateTest(new FlatIOHarness, timeout = 100, settings = Settings.defaultTest[FlatIOHarness]) + io.Source + .fromFile( + FileSystems + .getDefault() + .getPath(implicitly[HasTestingDirectory].getDirectory.toString, "workdir-verilator", "Makefile") + .toFile + ) + .mkString + .fileCheck()( + """|CHECK: '+define+ASSERT_VERBOSE_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+PRINTF_COND=!svsimTestbench.init' + |CHECK-NEXT: '+define+STOP_COND=!svsimTestbench.init' + |""".stripMargin + ) + } + + it("should set macros for SimulationTestHarnessInterface with IO of a bundle") { + class BundleIOHarness extends RawModule with SimulationTestHarnessInterface { + private val io = IO(new Bundle { + val clock = Input(Clock()) + val init = Input(Bool()) + val done = Output(Bool()) + val success = Output(Bool()) + }) + def clock = io.clock + def init = io.init + def done = io.done + def success = io.success + + withClockAndReset(clock, init) { + val (_, wrap) = Counter(true.B, 4) + io.done := wrap + io.success := true.B + } + } + simulateTest(new BundleIOHarness, timeout = 100, settings = Settings.defaultTest[BundleIOHarness]) + io.Source + .fromFile( + FileSystems + .getDefault() + .getPath(implicitly[HasTestingDirectory].getDirectory.toString, "workdir-verilator", "Makefile") + .toFile + ) + .mkString + .fileCheck()( + """|CHECK: '+define+ASSERT_VERBOSE_COND=!svsimTestbench.io_init' + |CHECK-NEXT: '+define+PRINTF_COND=!svsimTestbench.io_init' + |CHECK-NEXT: '+define+STOP_COND=!svsimTestbench.io_init' + |""".stripMargin + ) + } + + it("should set macros for SimulationTestHarnessInterface with renamed ports") { + class RenamedPortHarness extends RawModule with SimulationTestHarnessInterface { + val clk = IO(Input(Clock())) + val reset_n = IO(Input(Bool())) + val finished = IO(Output(Bool())) + val passed = IO(Output(Bool())) + + def clock = clk + def init = reset_n + def done = finished + def success = passed + + withClockAndReset(clk, reset_n) { + val (_, wrap) = Counter(true.B, 4) + finished := wrap + passed := true.B + } + } + simulateTest(new RenamedPortHarness, timeout = 100, settings = Settings.defaultTest[RenamedPortHarness]) + io.Source + .fromFile( + FileSystems + .getDefault() + .getPath(implicitly[HasTestingDirectory].getDirectory.toString, "workdir-verilator", "Makefile") + .toFile + ) + .mkString + .fileCheck()( + """|CHECK: '+define+ASSERT_VERBOSE_COND=!svsimTestbench.reset_n' + |CHECK-NEXT: '+define+PRINTF_COND=!svsimTestbench.reset_n' + |CHECK-NEXT: '+define+STOP_COND=!svsimTestbench.reset_n' + |""".stripMargin + ) + } + it("should allow for a user to customize the build directory") { class Foo extends Module { stop() From ab4e1301b6746be34dac47710f416459e6e4ca05 Mon Sep 17 00:00:00 2001 From: Trevor McKay Date: Fri, 30 Jan 2026 13:58:31 -0800 Subject: [PATCH 3/3] use Settings.defaultTest in simulateTest --- src/main/scala/chisel3/simulator/SimulatorAPI.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/chisel3/simulator/SimulatorAPI.scala b/src/main/scala/chisel3/simulator/SimulatorAPI.scala index 1982108fa11..afcdf80a7b7 100644 --- a/src/main/scala/chisel3/simulator/SimulatorAPI.scala +++ b/src/main/scala/chisel3/simulator/SimulatorAPI.scala @@ -127,7 +127,7 @@ trait SimulatorAPI { timeout: Int, chiselOpts: Array[String] = Array.empty, firtoolOpts: Array[String] = Array.empty, - settings: Settings[T] = Settings.defaultRaw[T], + settings: Settings[T] = Settings.defaultTest[T], additionalResetCycles: Int = 0, subdirectory: Option[String] = None )(