Skip to content

Latest commit

 

History

History

svsim

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

svsim

svsim is a low-level library for compiling and controlling SystemVerilog simulations, currently targeting Verilator and VCS as backends.

Design

In no particular order, here are some of the design considerations of svsim:

  • svsim does not know about Chisel. The inputs to svsim are SystemVerilog files and the ModuleInfo class, which encodes all the information svsim needs to generate a test harness for the supplied SystemVerilog.
  • svsim is not a testing framework, and is not opinionated about how a higher-level testing framework should be built. svsim should enable SystemVerilog simulation for any testing framework and should not be tied to any particular technology (i.e. Scalatest).
  • svsim provides a backend-independent test harness. This means that svsim's generated sources are not impacted by the choice of backend and indeed can be shared between multiple backends. If backend-specific behavior is required, it is provided via a compile-time flag (such as SVSIM_BACKEND_SUPPORTS_DELAY_IN_PUBLIC_FUNCTIONS).
  • svsim simulations are also backend-independent, meaning that the same code launches and controls a simulation regardless of what backend it was compiled using.
  • svsim backends are declarative. This means a backend only controls which executable is invoked for compilation, and what arguments are provided to that executable (either via command line or environment variables). Backends may also provide arguments to the simulation, but may not have any other specialized logic.
  • Simulations are controlled using an ad-hoc protocol where commands are read from stdin and messages are written to stdout. This protocol is not meant to be an ABI, and can change freely between Chisel verisons.
  • Communication with the simulation is pipelined, so the Scala driver can send multiple commands before processing responses from the simulation. This allows svsim to effectively eliminate the overhead of communicating with the simulation without resorting to JNA or Scala-side caching. This optimization can, of course, be defeated if the driver code waits on every command, but we consider this an antipattern.
  • svsim strives to have the minimum amount of dependencies possible, so that it may be maximally portable.
  • svsim does not provide syntactic sugar, and expects that higher level frameworks will implement whatever sugar they thing is appropriate. For example, if a framework like chiseltest were to use svsim under the hood, it might choose to store the Simulation.Controller in a DynamicValue to enable calling peek and poke directly on a Chisel Data, or pass information via annotations. Such specialization should stay in the higher-level framework and all svsim APIs should stay explicit.

Architecture

We consider it a top priority to keep svsim's architecture and implementation as simple as possible. In support of this effort, there are really only three components to svsim:

Workspace

The Workspace manages all interaction with the filesystem. Its API is mutable, because the underlying representation (files on disk) is mutable. A Workspace is represented on the filesystem as a folder. The reset() method will delete any previous state and create the necessary folders. The elaborate() method takes a ModuleInfo which describes the SystemVerilog module to be simulated. The idea is that a higher-level framework will provide specialized elaborate methods which emit SystemVerilog to primarySourcesPath, similar to what we do with elaborateGCD() in src/test/scala/Resources.scala. For example, Chisel can provide an elaborate[T <: RawModule](module: => T) method. generateAdditionalSources() uses the ModuleInfo from elaborate and generates the test harness. Finally, compile() uses a Backend to compile the simulation. Because svsim's test harness is backend-independent, compile may be called multiple times with different settings or different backends to create multiple Simulations (a workingDirectoryTag is provided so that mutliple simulations are output to separate directories).

Simulation

The Workspace's compile method returns a Simulation instance. A Simulation is launched using the run method, which passes a Simulation.Controller instance to the provided closure. The Simulation.Controller is used to explicitly control the Simulation, and should not escape the body of the closure. Like most of svsim, Simulation.Controller aims to be a low level API on which higher level APIs can be built. For example, Simulation.Controller's get method does not implicitly run the simulation to make the effects of previous set calls visible, the way you would expect for a peek/poke test. To evaluate the simulation state, the user must explicitly call controller.run(0). This, of course, does not prevent a peek/poke style API from being built using these building blocks in a higher-level framework.

Backend

svsim currently provides two Backends: verilator.Backend and vcs.Backend. Settings which all svsim Backends must support (like SystemVerilog preprocessor defines) live in CommonCompilationSettings, and each backend has its own backend-specific CompilationSettings.

Advanced Usage

make simulation

Because Backends are declarative, svsim is able to output a Makefile for compiling the simulation. This Makefile can be re-invoked after the fact to rebuild the simulation without re-running the Scala driver (make simulation). Users are free to modify either the harness generated by svsim (generated-sources), the SystemVerilog provided to svsim (primary-sources), or even the arguments passed to the compiler (workdir-$tag/Makefile) and these changes will be picked up when running make simulation.

make replay

svsim by default emits an execution-script.txt when running a Simulation. This script captures all commands sent to the simulation, which enables svsim to add a second target to the Makefile: make replay. make replay rebuilds the simulation, picking up any changes as mentioned above, and then replays the commands that were sent by Simulation.Controller verbatim. This allows replaying most tests without having to re-run the Scala code, potentially with manual modifications to either the SystemVerilog or the test harness (though tests which modify their behavior based on values read from the Simulation may not be replayed faithfully).