From 0326988258c7d0304893336d5e7545406d1124ef Mon Sep 17 00:00:00 2001 From: Qiming Chu Date: Wed, 5 Mar 2025 00:42:07 +0800 Subject: [PATCH] feat: add waveform tracing support for Chisel Module and RawModule simulations This commit introduces a new `enableTrace` parameter to the `simulate` and `simulateRaw` methods in `SimulatorAPI.scala`, allowing users to enable waveform tracing during simulations. Additionally, corresponding test cases have been added to `ChiselSimSpec.scala` to verify that waveform files are correctly generated for both `Module` and `RawModule` simulations. Signed-off-by: Qiming Chu --- .../chisel3/simulator/SimulatorAPI.scala | 10 ++- .../simulator/scalatest/ChiselSimSpec.scala | 70 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/main/scala/chisel3/simulator/SimulatorAPI.scala b/src/main/scala/chisel3/simulator/SimulatorAPI.scala index d6853a49ea..afa7e6d777 100644 --- a/src/main/scala/chisel3/simulator/SimulatorAPI.scala +++ b/src/main/scala/chisel3/simulator/SimulatorAPI.scala @@ -24,11 +24,13 @@ trait SimulatorAPI { */ def simulateRaw[T <: RawModule]( module: => T, - chiselSettings: ChiselSettings[T] = ChiselSettings.defaultRaw[T] + chiselSettings: ChiselSettings[T] = ChiselSettings.defaultRaw[T], + enableTrace: Boolean = false )(stimulus: (T) => Unit)(implicit hasSimulator: HasSimulator, testingDirectory: HasTestingDirectory): Unit = { hasSimulator.getSimulator .simulate(module, chiselSettings) { module => + module.controller.setTraceEnabled(enableTrace) stimulus(module.wrapped) } .result @@ -76,7 +78,8 @@ trait SimulatorAPI { def simulate[T <: Module]( module: => T, chiselSettings: ChiselSettings[T] = ChiselSettings.default[T], - additionalResetCycles: Int = 0 + additionalResetCycles: Int = 0, + enableTrace: Boolean = false )(stimulus: (T) => Unit)(implicit hasSimulator: HasSimulator, testingDirectory: HasTestingDirectory): Unit = { hasSimulator.getSimulator @@ -86,6 +89,9 @@ trait SimulatorAPI { val clock = module.port(dut.clock) val controller = module.controller + // Set the trace enable flag. + controller.setTraceEnabled(enableTrace) + // Run the initialization procedure. controller.run(1) reset.set(0) diff --git a/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala b/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala index 8a236dfce0..68340335f0 100644 --- a/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala +++ b/src/test/scala-2/chiselTests/simulator/scalatest/ChiselSimSpec.scala @@ -175,4 +175,74 @@ class ChiselSimSpec extends AnyFunSpec with Matchers with ChiselSim with FileChe } } + it("should dump waveform with Chisel Module") { + class Foo extends Module { + val a = IO(Input(Bool())) + val b = IO(Output(Bool())) + + b :<= !a + } + import chisel3.simulator.HasSimulator.simulators + import chisel3.simulator.stimulus.RunUntilFinished + implicit val verilator = simulators + .verilator(verilatorSettings = + svsim.verilator.Backend.CompilationSettings( + traceStyle = + Some(svsim.verilator.Backend.CompilationSettings.TraceStyle.Vcd(traceUnderscore = true, "trace.vcd")) + ) + ) + val workSpacePath = "dump_wave_module" + val directory = Directory(FileSystems.getDefault().getPath("test_run_dir", workSpacePath).toFile()) + directory.deleteRecursively() + implicit val waveDirectory = new HasTestingDirectory { + override def getDirectory = + FileSystems.getDefault().getPath("test_run_dir", workSpacePath) + } + simulate(new Foo, enableTrace = true) { foo => + foo.a.poke(true.B) + foo.b.expect(false.B) + foo.a.poke(false.B) + foo.b.expect(true.B) + }(hasSimulator = verilator, testingDirectory = waveDirectory) + val allFiles = directory.deepFiles.toSeq.map(_.toString).toSet + val file = s"test_run_dir/$workSpacePath/workdir-verilator/trace.vcd" + info(s"found expected file: '$file'") + allFiles should contain(file) + } + + it("should dump waveform with RawModule") { + class Foo extends RawModule { + val a = IO(Input(Bool())) + val b = IO(Output(Bool())) + + b :<= !a + } + import chisel3.simulator.HasSimulator.simulators + import chisel3.simulator.stimulus.RunUntilFinished + implicit val verilator = simulators + .verilator(verilatorSettings = + svsim.verilator.Backend.CompilationSettings( + traceStyle = + Some(svsim.verilator.Backend.CompilationSettings.TraceStyle.Vcd(traceUnderscore = true, "trace.vcd")) + ) + ) + val workSpacePath = "dump_wave_raw_module" + val directory = Directory(FileSystems.getDefault().getPath("test_run_dir", workSpacePath).toFile()) + directory.deleteRecursively() + implicit val waveDirectory = new HasTestingDirectory { + override def getDirectory = + FileSystems.getDefault().getPath("test_run_dir", workSpacePath) + } + simulateRaw(new Foo, enableTrace = true) { foo => + foo.a.poke(true.B) + foo.b.expect(false.B) + foo.a.poke(false.B) + foo.b.expect(true.B) + }(hasSimulator = verilator, testingDirectory = waveDirectory) + val allFiles = directory.deepFiles.toSeq.map(_.toString).toSet + val file = s"test_run_dir/$workSpacePath/workdir-verilator/trace.vcd" + info(s"found expected file: '$file'") + allFiles should contain(file) + } + }