From 36b925f13d2bc2ce05319585e68bcc95801a16c3 Mon Sep 17 00:00:00 2001 From: Raffaele Meloni Date: Thu, 11 Jul 2024 22:50:28 +0200 Subject: [PATCH 1/3] Add test for issue #27 --- README.md | 2 +- example/gcd.test.scala | 2 +- .../ImportSimulatorReverseOrder.scala | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/test/scala/tywaves/simulator/ImportSimulatorReverseOrder.scala diff --git a/README.md b/README.md index d516197..421e970 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,7 @@ The following list shows a summary of the features added by the Tywaves project - [x] Selectable signal value rendering (with type information attached) - [ ] Automatic/custom signal value rendering - [ ] For loops code generation - - [ ] Temporary values (also inside `when` and `otherwise` blocks) + - [x] Temporary values (also inside `when` and `otherwise` blocks) # Versioning and tools ([ref](https://github.com/rameloni/tywaves-chisel-demo/wiki/Tywaves-internals#tywaves-software-architecture)) diff --git a/example/gcd.test.scala b/example/gcd.test.scala index d35ff3d..c583bc9 100644 --- a/example/gcd.test.scala +++ b/example/gcd.test.scala @@ -6,10 +6,10 @@ //> using dep "org.scalatest::scalatest:3.2.18" // DO NOT EDIT THE ORTHER OF THESE IMPORTS (it will be solved in future versions) +import chisel3._ import tywaves.simulator._ import tywaves.simulator.ParametricSimulator._ import tywaves.simulator.simulatorSettings._ -import chisel3._ import circt.stage.ChiselStage // _root_ disambiguates from package chisel3.util.circt if user imports chisel3.util._ //import _root_.circt.stage.ChiselStage diff --git a/src/test/scala/tywaves/simulator/ImportSimulatorReverseOrder.scala b/src/test/scala/tywaves/simulator/ImportSimulatorReverseOrder.scala new file mode 100644 index 0000000..e9004ab --- /dev/null +++ b/src/test/scala/tywaves/simulator/ImportSimulatorReverseOrder.scala @@ -0,0 +1,29 @@ +package tywaves.simulator + +import gcd.GCD +import org.scalatest.funspec.AnyFunSpec +import org.scalatest.matchers.must.Matchers + +class ImportSimulatorReverseOrder extends AnyFunSpec with Matchers { + describe("Issue 27") { + it("Should import chisel before tywaves") { + import chisel3._ + import tywaves.simulator.TywavesSimulator._ + simulate(new GCD()) { + gcd => + gcd.clock.step() + gcd.io.loadValues.poke(true.B) + } + } + it("Should import chisel after tywaves") { + import tywaves.simulator.TywavesSimulator._ + import chisel3._ + simulate(new GCD()) { + gcd => + gcd.clock.step() + gcd.io.loadValues.poke(true.B) + } + } + } + +} From 1d2463c94af9704e9627ed2a226b05787acd14bc Mon Sep 17 00:00:00 2001 From: Raffaele Meloni Date: Thu, 11 Jul 2024 22:53:33 +0200 Subject: [PATCH 2/3] Reset ParametricSimulator for every simulation run by default Fix #22 --- .../simulator/ParametricSimulator.scala | 22 ++----------------- .../simulator/ParametricSimulatorSpec.scala | 4 +--- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/main/scala/tywaves/simulator/ParametricSimulator.scala b/src/main/scala/tywaves/simulator/ParametricSimulator.scala index 9e06139..fa2f997 100644 --- a/src/main/scala/tywaves/simulator/ParametricSimulator.scala +++ b/src/main/scala/tywaves/simulator/ParametricSimulator.scala @@ -15,31 +15,13 @@ import java.time.{LocalDateTime, format} */ object ParametricSimulator extends PeekPokeAPI { - private var simulator = new ParametricSimulator - - /** If true, the simulator will be reset before running each simulation */ - private var _resetSimulationBeforeRun = false - /** Use this method to run a simulations */ def simulate[T <: RawModule]( module: => T, settings: Seq[SimulatorSettings] = Seq(), simName: String = "defaultSimulation", - )(body: T => Unit): Unit = { - if (_resetSimulationBeforeRun) - reset() - simulator.simulate(module, settings, simName)(body) - } - - /** - * Use this method to manually reset the simulator and run multiple - * independent simulations - */ - def reset(): Unit = - simulator = new ParametricSimulator - - def resetBeforeEachRun(): Unit = - _resetSimulationBeforeRun = true + )(body: T => Unit): Unit = + (new ParametricSimulator).simulate(module, settings, simName)(body) } /** diff --git a/src/test/scala/tywaves/simulator/ParametricSimulatorSpec.scala b/src/test/scala/tywaves/simulator/ParametricSimulatorSpec.scala index ea60b29..b4ce484 100644 --- a/src/test/scala/tywaves/simulator/ParametricSimulatorSpec.scala +++ b/src/test/scala/tywaves/simulator/ParametricSimulatorSpec.scala @@ -25,8 +25,6 @@ class ParametricSimulatorSpec extends AnyFunSpec with Matchers { describe("ParametricSimulator Runs") { - resetBeforeEachRun() - it("runs GCD correctly without settings") { simulate(new GCD())(gcd => gcdTb(gcd)) } @@ -90,7 +88,7 @@ class ParametricSimulatorSpec extends AnyFunSpec with Matchers { } describe("ParametricSimulator Exceptions") { - resetBeforeEachRun() + it("throws an exception when NameTrace is used without VcdTrace or VcdTraceWithUnderscore") { intercept[Exception] { simulate(new GCD(), Seq(NameTrace("")))(_ => gcdTb _) From f6fa33885c5fef54c0e087fc06d69a8f38a46019 Mon Sep 17 00:00:00 2001 From: Raffaele Meloni Date: Thu, 11 Jul 2024 23:13:42 +0200 Subject: [PATCH 3/3] Improve TywavesSimulator Add option to wait for the waveform viewer or not" --- README.md | 19 ++++++------ example/myfsm.test.scala | 6 ++++ .../tywaves/simulator/TywavesInterface.scala | 3 ++ .../tywaves/simulator/TywavesSimulator.scala | 30 ++++++++----------- .../simulator/TywavesSimulatorSpec.scala | 4 --- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 421e970..01bc6f6 100644 --- a/README.md +++ b/README.md @@ -145,15 +145,16 @@ simulate( A simulation can be customized by passing some settings to the simulator. The following options can be specified for `ParametricSimulator` and / or `TywavesSimulator` classes using the following syntax: -| Setting | Description | Simulator | -|:------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------| -| `VcdTrace` | Enable the VCD output optimizing out signals starting with an underscore (_) in the final verilog | `ParametricSimulator` and `TywavesSimulator` | -| `VcdTraceWithUnderscore` | Enable the VCD output (including "underscored" signals) | `ParametricSimulator` and `TywavesSimulator` | -| `SaveWorkdir` | Save the workdir of `svsim` | `ParametricSimulator` and `TywavesSimulator` | -| `SaveWorkdirFile(name: String)` | Save the workdir with a specific name | `ParametricSimulator` and `TywavesSimulator` | -| `NameTrace(name: String)` | Give a name to the VCD trace | `ParametricSimulator` and `TywavesSimulator` | -| `WithFirtoolArgs(args: Seq[String])` | Pass arguments to `firtool` under the simulation | `ParametricSimulator` and `TywavesSimulator` | -| `WithTywavesWaveforms(runWaves: Boolean)` | Enable the generation of extra debug information (to fully exploit the tywaves project) and (optionally `runWaves=true`) launch the waveform viewer directly once the simulation has been completed | `ParametricSimulator` and `TywavesSimulator` | +| Setting | Description | Simulator | +|:--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------| +| `VcdTrace` | Enable the VCD output optimizing out signals starting with an underscore (_) in the final verilog | `ParametricSimulator` and `TywavesSimulator` | +| `VcdTraceWithUnderscore` | Enable the VCD output (including "underscored" signals) | `ParametricSimulator` and `TywavesSimulator` | +| `SaveWorkdir` | Save the workdir of `svsim` | `ParametricSimulator` and `TywavesSimulator` | +| `SaveWorkdirFile(name: String)` | Save the workdir with a specific name | `ParametricSimulator` and `TywavesSimulator` | +| `NameTrace(name: String)` | Give a name to the VCD trace | `ParametricSimulator` and `TywavesSimulator` | +| `WithFirtoolArgs(args: Seq[String])` | Pass arguments to `firtool` under the simulation | `ParametricSimulator` and `TywavesSimulator` | +| `WithTywavesWaveforms(runWaves: Boolean)` | Enable the generation of extra debug information (to fully exploit the tywaves project) and (optionally `runWaves=true`) launch the waveform viewer directly once the simulation has been completed | `ParametricSimulator` and `TywavesSimulator` | +| `WithTywavesWaveformsGo(runWaves: Boolean)` | Same as `WithTywavesWaveforms` but without blocking sbt if `runWaves` is `true` | `ParametricSimulator` and `TywavesSimulator` | > **Note**: open an issue/PR to request new settings. diff --git a/example/myfsm.test.scala b/example/myfsm.test.scala index 7fc89b3..7368b28 100644 --- a/example/myfsm.test.scala +++ b/example/myfsm.test.scala @@ -80,9 +80,15 @@ class MyFSMTest extends AnyFunSpec with Matchers { circt.stage.FirtoolOption("--emit-hgldd"), ), ) + simulate(new MyFSM(), Seq(VcdTrace, WithTywavesWaveformsGo(true)), simName = "runs_MYFSM_correctly_launch_tywaves_and_go") { + fsm => + fsm.clock.step(10) + fsm.clock.step(10) + } simulate(new MyFSM(), Seq(VcdTrace, WithTywavesWaveforms(true)), simName = "runs_MYFSM_correctly_launch_tywaves") { fsm => fsm.clock.step(10) + fsm.io.inputState.poke(MyFSMStates.StateA) fsm.clock.step(10) } } diff --git a/src/main/scala/tywaves/simulator/TywavesInterface.scala b/src/main/scala/tywaves/simulator/TywavesInterface.scala index ee776f4..040e8e6 100644 --- a/src/main/scala/tywaves/simulator/TywavesInterface.scala +++ b/src/main/scala/tywaves/simulator/TywavesInterface.scala @@ -11,6 +11,7 @@ private[tywaves] object TywavesInterface { hglddDirPath: Option[String], extraScopes: Seq[String], topModuleName: Option[String], + waitFor: Boolean = true, ): Unit = { { import scala.sys.process._ @@ -36,6 +37,8 @@ private[tywaves] object TywavesInterface { // Execute and return to the caller @unused val process = new ProcessBuilder(cmd: _*).inheritIO().start() + if (waitFor) + process.waitFor() // No wait for the process to finish } } diff --git a/src/main/scala/tywaves/simulator/TywavesSimulator.scala b/src/main/scala/tywaves/simulator/TywavesSimulator.scala index 4cf6394..38a5551 100644 --- a/src/main/scala/tywaves/simulator/TywavesSimulator.scala +++ b/src/main/scala/tywaves/simulator/TywavesSimulator.scala @@ -7,13 +7,15 @@ import tywaves.circuitmapper.TypedConverter object TywavesSimulator extends PeekPokeAPI { - private[simulator] case class Tywaves(runWaves: Boolean) extends SimulatorSettings - val WithTywavesWaveforms: Boolean => Tywaves = (runWaves: Boolean) => Tywaves(runWaves) + private[simulator] case class Tywaves(runWaves: Boolean, waitFor: Boolean) extends SimulatorSettings - private var simulator = new TywavesSimulator + /** Generate tywaves info and optionally run the waveform */ + val WithTywavesWaveforms: Boolean => Tywaves = (runWaves: Boolean) => Tywaves(runWaves, waitFor = true) - /** If true, the simulator will be reset before running each simulation */ - private var _resetSimulationBeforeRun = false + /** + * Generate tywaves info and optionally run the waveform without blocking sbt + */ + val WithTywavesWaveformsGo: Boolean => Tywaves = (runWaves: Boolean) => Tywaves(runWaves, waitFor = false) /** Use this method to run a simulation */ def simulate[T <: RawModule]( @@ -44,28 +46,22 @@ object TywavesSimulator extends PeekPokeAPI { TypedConverter.createDebugInfoHgldd(() => module, simulator.wantedWorkspacePath) // Run tywaves viewer if the Tywaves waveform generation is enabled by Tywaves(true) - if (finalSettings.contains(Tywaves(true))) + val (runWaves, waitFor) = + if (finalSettings.contains(Tywaves(runWaves = true, waitFor = true))) { (true, true) } + else if (finalSettings.contains(Tywaves(runWaves = true, waitFor = false))) { (true, false) } + else { (false, false) } + if (runWaves) TywavesInterface.run( vcdPath = simulator.finalTracePath.get, hglddDirPath = Some(TypedConverter.getDebugInfoDir(gOpt = true)), extraScopes = extraScopes, topModuleName = TypedConverter.getTopModuleName, + waitFor = waitFor, ) } else if (containTywaves) throw new Exception("Tywaves waveform generation requires a trace file. Please enable VcdTrace.") } - /** - * Use this method to manually reset the simulator and run multiple - * independent simulations - */ - @deprecated - def reset(): Unit = - simulator = new TywavesSimulator - - @deprecated - def resetBeforeEachRun(): Unit = - _resetSimulationBeforeRun = true } class TywavesSimulator extends ParametricSimulator diff --git a/src/test/scala/tywaves/simulator/TywavesSimulatorSpec.scala b/src/test/scala/tywaves/simulator/TywavesSimulatorSpec.scala index a5eabae..40c7deb 100644 --- a/src/test/scala/tywaves/simulator/TywavesSimulatorSpec.scala +++ b/src/test/scala/tywaves/simulator/TywavesSimulatorSpec.scala @@ -23,7 +23,6 @@ class TywavesSimulatorSpec extends AnyFunSpec with Matchers { } describe("New TywavesFunctionalities") { - resetBeforeEachRun() it("runs GCD with waveform generation") { simulate(new GCD(), Seq(VcdTrace, WithTywavesWaveforms(false)), simName = "runs_gcd_with_waveform_generation") { @@ -66,8 +65,6 @@ class TywavesSimulatorSpec extends AnyFunSpec with Matchers { describe("Tywaves with ParametricSimulator Functionalities") { - resetBeforeEachRun() - it("runs GCD correctly without settings") { simulate(new GCD())(gcd => gcdTb(gcd)) } @@ -131,7 +128,6 @@ class TywavesSimulatorSpec extends AnyFunSpec with Matchers { } describe("TywavesSimulator Exceptions") { - resetBeforeEachRun() it("throws an exception when NameTrace is used without VcdTrace or VcdTraceWithUnderscore") { intercept[Exception] { simulate(new GCD(), Seq(NameTrace("")))(_ => gcdTb _)