2024-01-01 08:19:59 +00:00
|
|
|
.. Copyright 2003-2024 by Wilson Snyder.
|
2021-04-11 22:55:06 +00:00
|
|
|
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
|
|
|
|
.. _Connecting:
|
|
|
|
|
|
|
|
******************************
|
|
|
|
Connecting to Verilated Models
|
|
|
|
******************************
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
Structure of the Verilated Model
|
|
|
|
================================
|
|
|
|
|
|
|
|
Verilator outputs a :file:`{prefix}.h` header file which defines a class
|
|
|
|
named :code:`{prefix}` which represents the generated model the user is
|
|
|
|
supposed to instantiate. This model class defines the interface of the
|
|
|
|
Verilated model.
|
|
|
|
|
|
|
|
Verilator will additionally create a :file:`{prefix}.cpp` file, together
|
|
|
|
with additional .h and .cpp files for internals. See the :file:`examples`
|
|
|
|
directory in the kit for examples. See :ref:`Files Read/Written` for
|
|
|
|
information on all the files Verilator might output.
|
|
|
|
|
|
|
|
The output of Verilator will contain a :file:`{prefix}.mk` file that may be
|
|
|
|
used with Make to build a :file:`{prefix}__ALL.a` library with all required
|
|
|
|
objects in it.
|
|
|
|
|
|
|
|
The generated model class file manages all internal state required by the
|
|
|
|
model, and exposes the following interface that allows interaction with the
|
|
|
|
model:
|
|
|
|
|
|
|
|
* Top level IO ports are exposed as references to the appropriate internal
|
|
|
|
equivalents.
|
|
|
|
|
|
|
|
* Public top level module instances are exposed as pointers to allow access
|
|
|
|
to :code:`/* verilator public */` items.
|
|
|
|
|
|
|
|
* The root of the design hierarchy (as in SystemVerilog :code:`$root`) is
|
|
|
|
exposed via the :code:`rootp` member pointer to allow access to model
|
|
|
|
internals, including :code:`/* verilator public_flat */` items.
|
|
|
|
|
|
|
|
|
2021-07-08 00:43:07 +00:00
|
|
|
.. _Porting from pre 4.210:
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
|
2021-07-08 00:43:07 +00:00
|
|
|
Model interface changes in version 4.210
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
------------------------------------------
|
|
|
|
|
2021-07-08 00:43:07 +00:00
|
|
|
Starting from version 4.210, the model class is an interface object.
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
|
|
|
|
Up until Verilator version 4.204 inclusive, the generated model class was
|
|
|
|
also the instance of the top level instance in the design hierarchy (what
|
|
|
|
you would refer to with :code:`$root` in SystemVerilog). This meant that
|
|
|
|
all internal variables that were implemented by Verilator in the root scope
|
|
|
|
were accessible as members of the model class itself. Note there were often
|
2022-12-10 02:01:33 +00:00
|
|
|
many such variable due to module inlining, including
|
|
|
|
:code:`/* verilator public_flat */` items.
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
|
|
|
|
This means that user code that accesses internal signals in the model
|
|
|
|
(likely including :code:`/* verilator public_flat */` signals, as they are
|
|
|
|
often inlined into the root scope) will need to be updated as follows:
|
|
|
|
|
|
|
|
* No change required for accessing top level IO signals. These are directly
|
|
|
|
accessible in the model class via references.
|
|
|
|
|
|
|
|
* No change required for accessing :code:`/* verilator public */` items.
|
|
|
|
These are directly accessible via sub-module pointers in the model class.
|
|
|
|
|
|
|
|
* Accessing any other internal members, including
|
|
|
|
:code:`/* verilator public_flat */` items requires the following changes:
|
|
|
|
|
|
|
|
* Additionally include :file:`{prefix}___024root.h`. This header defines
|
|
|
|
type of the :code:`rootp` pointer within the model class. Note the
|
|
|
|
:code:`__024` substring is the Verilator escape sequence for the
|
|
|
|
:code:`$` character, i.e.: :code:`rootp` points to the Verilated
|
|
|
|
SystemVerilog :code:`$root` scope.
|
|
|
|
|
|
|
|
* Replace :code:`modelp->internal->member->lookup` references with
|
|
|
|
:code:`modelp->rootp->internal->member->lookup` references, which
|
|
|
|
contain one additional indirection via the :code:`rootp` pointer.
|
|
|
|
|
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
.. _Connecting to C++:
|
|
|
|
|
|
|
|
Connecting to C++
|
|
|
|
=================
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
In C++ output mode (:vlopt:`--cc`), the Verilator generated model class is a
|
|
|
|
simple C++ class. The user must write a C++ wrapper and main loop for the
|
|
|
|
simulation, which instantiates the model class, and link with the Verilated
|
2022-07-09 13:50:50 +00:00
|
|
|
model.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
2022-07-09 13:50:50 +00:00
|
|
|
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
|
|
|
commented example.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
2022-07-09 13:50:50 +00:00
|
|
|
Top level IO signals are read and written as members of the model. You
|
|
|
|
call the model's :code:`eval()` method to evaluate the model. When the
|
|
|
|
simulation is complete call the model's :code:`final()` method to execute
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
any SystemVerilog final blocks, and complete any assertions. If using
|
|
|
|
:vlopt:`--timing`, there are two additional functions for checking if
|
|
|
|
there are any events pending in the simulation due to delays, and for
|
|
|
|
retrieving the simulation time of the next delayed event. See
|
2022-07-09 13:50:50 +00:00
|
|
|
:ref:`Evaluation Loop`.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Connecting to SystemC
|
|
|
|
=====================
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
In SystemC output mode (:vlopt:`--sc`), the Verilator generated model class
|
|
|
|
is a SystemC SC_MODULE. This module will attach directly into a SystemC
|
|
|
|
netlist as an instantiation.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
The SC_MODULE gets the same pinout as the Verilog module, with the
|
|
|
|
following type conversions: Pins of a single bit become bool. Pins 2-32
|
|
|
|
bits wide become uint32_t's. Pins 33-64 bits wide become sc_bv's or
|
2022-03-27 19:27:40 +00:00
|
|
|
uint64_t's depending on the :vlopt:`--no-pins64` option. Wider pins
|
2021-04-11 22:55:06 +00:00
|
|
|
become sc_bv's. (Uints simulate the fastest so are used where possible.)
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 14:30:20 +00:00
|
|
|
Model internals, including lower level sub-modules are not pure SystemC
|
|
|
|
code. This is a feature, as using the SystemC pin interconnect scheme
|
|
|
|
everywhere would reduce performance by an order of magnitude.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
|
2023-03-14 12:29:39 +00:00
|
|
|
Verilated API
|
|
|
|
=============
|
|
|
|
|
|
|
|
The API to a Verilated model is the C++ headers in the include/ directory
|
|
|
|
in the distribution. These headers use Doxygen comments, `///` and `//<`,
|
|
|
|
to indicate and document those functions that are part of the Verilated
|
|
|
|
public API.
|
|
|
|
|
2023-08-30 11:02:55 +00:00
|
|
|
Process-Level Clone APIs
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
Modern operating systems support process-level clone (a.k.a copying, forking)
|
|
|
|
with system call interfaces in C/C++, e.g., :code:`fork()` in Linux.
|
|
|
|
|
|
|
|
However, after cloning a parent process, some resources cannot be inherited
|
|
|
|
in the child process. For example, in POSIX systems, when you fork a process,
|
|
|
|
the child process inherits all the memory of the parent process. However,
|
|
|
|
only the thread that called fork is replicated in the child process. Other
|
|
|
|
threads are not.
|
|
|
|
|
|
|
|
Therefore, to support the process-level clone mechanisms, Verilator supports
|
|
|
|
:code:`prepareClone()` and :code:`atClone()` APIs to allow the user to manually
|
|
|
|
re-construct the model in the child process. The two APIs handle all necessary
|
|
|
|
resources required for releasing and re-initializing before and after cloning.
|
|
|
|
|
|
|
|
The two APIs are supported in the verilated models. Here is an example of usage
|
|
|
|
with Linux :code:`fork()` and :code:`pthread_atfork` APIs:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
// static function pointers to fit pthread_atfork
|
|
|
|
static auto prepareClone = [](){ topp->prepareClone(); };
|
|
|
|
static auto atClone = [](){ topp->atClone(); };
|
|
|
|
|
|
|
|
// in main function, register the handlers:
|
|
|
|
pthread_atfork(prepareClone, atClone, atClone);
|
|
|
|
|
|
|
|
For better flexibility, you can also manually call the handlers before and
|
|
|
|
after :code:`fork()`.
|
|
|
|
|
|
|
|
With the process-level clone APIs, users can create process-level snapshots
|
|
|
|
for the verilated models. While the Verilator save/restore option provides
|
2023-08-30 11:46:39 +00:00
|
|
|
persistent and circuit-dependent snapshots, the process-level clone APIs
|
2023-08-30 11:02:55 +00:00
|
|
|
enable in-memory, circuit-transparent, and highly efficient snapshots.
|
|
|
|
|
2023-03-14 12:29:39 +00:00
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
Direct Programming Interface (DPI)
|
|
|
|
==================================
|
|
|
|
|
|
|
|
Verilator supports SystemVerilog Direct Programming Interface import and
|
|
|
|
export statements. Only the SystemVerilog form ("DPI-C") is supported, not
|
|
|
|
the original Synopsys-only DPI.
|
|
|
|
|
|
|
|
DPI Example
|
|
|
|
-----------
|
|
|
|
|
|
|
|
In the SYSTEMC example above, if you wanted to import C++ functions into
|
|
|
|
Verilog, put in our.v:
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
|
|
|
import "DPI-C" function int add (input int a, input int b);
|
|
|
|
|
|
|
|
initial begin
|
|
|
|
$display("%x + %x = %x", 1, 2, add(1,2));
|
|
|
|
endtask
|
|
|
|
|
|
|
|
Then after Verilating, Verilator will create a file Vour__Dpi.h with the
|
|
|
|
prototype to call this function:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
extern int add(int a, int b);
|
|
|
|
|
|
|
|
From the sc_main.cpp file (or another .cpp file passed to the Verilator
|
|
|
|
command line, or the link), you'd then:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
#include "svdpi.h"
|
|
|
|
#include "Vour__Dpi.h"
|
|
|
|
int add(int a, int b) { return a+b; }
|
|
|
|
|
|
|
|
|
|
|
|
DPI System Task/Functions
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
Verilator extends the DPI format to allow using the same scheme to
|
2022-03-31 00:17:59 +00:00
|
|
|
efficiently add system functions. Use a dollar-sign prefixed system
|
2021-04-11 22:55:06 +00:00
|
|
|
function name for the import, but note it must be escaped.
|
|
|
|
|
|
|
|
.. code-block:: sv
|
|
|
|
|
|
|
|
export "DPI-C" function integer \$myRand;
|
|
|
|
|
|
|
|
initial $display("myRand=%d", $myRand());
|
|
|
|
|
|
|
|
Going the other direction, you can export Verilog tasks so they can be
|
|
|
|
called from C++:
|
|
|
|
|
|
|
|
.. code-block:: sv
|
|
|
|
|
|
|
|
export "DPI-C" task publicSetBool;
|
|
|
|
|
|
|
|
task publicSetBool;
|
|
|
|
input bit in_bool;
|
|
|
|
var_bool = in_bool;
|
|
|
|
endtask
|
|
|
|
|
|
|
|
Then after Verilating, Verilator will create a file Vour__Dpi.h with the
|
|
|
|
prototype to call this function:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
extern void publicSetBool(svBit in_bool);
|
|
|
|
|
|
|
|
From the sc_main.cpp file, you'd then:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
#include "Vour__Dpi.h"
|
|
|
|
publicSetBool(value);
|
|
|
|
|
|
|
|
Or, alternatively, call the function under the design class. This isn't
|
|
|
|
DPI compatible but is easier to read and better supports multiple designs.
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
#include "Vour__Dpi.h"
|
|
|
|
Vour::publicSetBool(value);
|
|
|
|
// or top->publicSetBool(value);
|
|
|
|
|
|
|
|
Note that if the DPI task or function accesses any register or net within
|
|
|
|
the RTL, it will require a scope to be set. This can be done using the
|
|
|
|
standard functions within svdpi.h, after the module is instantiated, but
|
|
|
|
before the task(s) and/or function(s) are called.
|
|
|
|
|
|
|
|
For example, if the top level module is instantiated with the name "dut"
|
|
|
|
and the name references within tasks are all hierarchical (dotted) names
|
|
|
|
with respect to that top level module, then the scope could be set with
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
#include "svdpi.h"
|
|
|
|
...
|
2022-03-14 13:10:03 +00:00
|
|
|
const svScope scope = svGetScopeFromName("TOP.dut");
|
|
|
|
assert(scope); // Check for nullptr if scope not found
|
|
|
|
svSetScope(scope);
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
(Remember that Verilator adds a "TOP" to the top of the module hierarchy.)
|
|
|
|
|
|
|
|
Scope can also be set from within a DPI imported C function that has been
|
|
|
|
called from Verilog by querying the scope of that function. See the
|
|
|
|
sections on DPI Context Functions and DPI Header Isolation below and the
|
|
|
|
comments within the svdpi.h header for more information.
|
|
|
|
|
|
|
|
|
|
|
|
DPI Imports that access signals
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
If a DPI import accesses a signal through the VPI Verilator will not be
|
|
|
|
able to know what variables are accessed and may schedule the code
|
|
|
|
inappropriately. Ideally pass the values as inputs/outputs so the VPI is
|
|
|
|
not required. Alternatively a workaround is to use a non-inlined task as a
|
|
|
|
wrapper:
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
|
|
|
logic din;
|
|
|
|
|
|
|
|
// This DPI function will read "din"
|
|
|
|
import "DPI-C" context function void dpi_that_accesses_din();
|
|
|
|
|
|
|
|
always @(...)
|
|
|
|
dpi_din_args(din);
|
|
|
|
|
|
|
|
task dpi_din_args(input din);
|
|
|
|
/* verilator no_inline_task */
|
|
|
|
dpi_that_accesses_din();
|
|
|
|
endtask
|
|
|
|
|
|
|
|
|
|
|
|
DPI Display Functions
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
Verilator allows writing $display like functions using this syntax:
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
|
|
|
import "DPI-C" function void
|
|
|
|
\$my_display(input string formatted /*verilator sformat*/ );
|
|
|
|
|
|
|
|
The :option:`/*verilator&32;sformat*/` metacomment indicates that this
|
|
|
|
function accepts a $display like format specifier followed by any number of
|
|
|
|
arguments to satisfy the format.
|
|
|
|
|
|
|
|
|
|
|
|
DPI Context Functions
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
Verilator supports IEEE DPI Context Functions. Context imports pass the
|
|
|
|
simulator context, including calling scope name, and filename and line
|
|
|
|
number to the C code. For example, in Verilog:
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
|
|
|
import "DPI-C" context function int dpic_line();
|
|
|
|
initial $display("This is line %d, again, line %d\n", `line, dpic_line());
|
|
|
|
|
|
|
|
This will call C++ code which may then use the svGet\* functions to read
|
|
|
|
information, in this case the line number of the Verilog statement that
|
|
|
|
invoked the dpic_line function:
|
|
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
|
|
|
|
int dpic_line() {
|
|
|
|
// Get a scope: svScope scope = svGetScope();
|
|
|
|
|
|
|
|
const char* scopenamep = svGetNameFromScope(scope);
|
|
|
|
assert(scopenamep);
|
|
|
|
|
|
|
|
const char* filenamep = "";
|
|
|
|
int lineno = 0;
|
|
|
|
if (svGetCallerInfo(&filenamep, &lineno)) {
|
|
|
|
printf("dpic_line called from scope %s on line %d\n",
|
|
|
|
scopenamep, lineno);
|
|
|
|
return lineno;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
See the IEEE Standard for more information.
|
|
|
|
|
|
|
|
|
|
|
|
DPI Header Isolation
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
Verilator places the IEEE standard header files such as svdpi.h into a
|
|
|
|
separate include directory, vltstd (VeriLaTor STandarD). When compiling
|
|
|
|
most applications $VERILATOR_ROOT/include/vltstd would be in the include
|
|
|
|
path along with the normal $VERILATOR_ROOT/include. However, when
|
|
|
|
compiling Verilated models into other simulators which have their own
|
|
|
|
svdpi.h and similar standard files with different contents, the vltstd
|
|
|
|
directory should not be included to prevent picking up incompatible
|
|
|
|
definitions.
|
|
|
|
|
|
|
|
|
|
|
|
Public Functions
|
|
|
|
----------------
|
|
|
|
|
|
|
|
Instead of DPI exporting, there's also Verilator public functions, which
|
|
|
|
are slightly faster, but less compatible.
|
|
|
|
|
|
|
|
|
|
|
|
Verification Procedural Interface (VPI)
|
|
|
|
=======================================
|
|
|
|
|
|
|
|
Verilator supports a limited subset of the VPI. This subset allows
|
|
|
|
inspection, examination, value change callbacks, and depositing of values
|
|
|
|
to public signals only.
|
|
|
|
|
|
|
|
VPI is enabled with the Verilator :vlopt:`--vpi` option.
|
|
|
|
|
|
|
|
To access signals via the VPI, Verilator must be told exactly which signals
|
|
|
|
are to be accessed. This is done using the Verilator public pragmas
|
|
|
|
documented below.
|
|
|
|
|
|
|
|
Verilator has an important difference from an event based simulator; signal
|
|
|
|
values that are changed by the VPI will not immediately propagate their
|
|
|
|
values, instead the top level header file's :code:`eval()` method must be
|
|
|
|
called. Normally this would be part of the normal evaluation (i.e. the
|
|
|
|
next clock edge), not as part of the value change. This makes the
|
|
|
|
performance of VPI routines extremely fast compared to event based
|
|
|
|
simulators, but can confuse some test-benches that expect immediate
|
|
|
|
propagation.
|
|
|
|
|
|
|
|
Note the VPI by its specified implementation will always be much slower
|
|
|
|
than accessing the Verilator values by direct reference
|
|
|
|
(structure->module->signame), as the VPI accessors perform lookup in
|
|
|
|
functions at simulation runtime requiring at best hundreds of instructions,
|
|
|
|
while the direct references are evaluated by the compiler and result in
|
|
|
|
only a couple of instructions.
|
|
|
|
|
|
|
|
For signal callbacks to work the main loop of the program must call
|
|
|
|
:code:`VerilatedVpi::callValueCbs()`.
|
|
|
|
|
2024-04-25 13:07:31 +00:00
|
|
|
Verilator also tracks when the model state has been modified via the VPI with
|
|
|
|
an :code:`evalNeeded` flag. This flag can be checked with :code:`VerilatedVpi::evalNeeded()`
|
|
|
|
and it can be cleared with :code:`VerilatedVpi::clearEvalNeeded()`. Used together
|
|
|
|
it is possible to skip :code:`eval()` calls if no model state has been changed
|
|
|
|
since the last :code:`eval()`.
|
|
|
|
|
2024-05-01 22:56:50 +00:00
|
|
|
Any data written via :code:`vpi_put_value` with :code:`vpiInertialDelay` will
|
|
|
|
be deferred for later. These delayed values can be flushed to the model with
|
|
|
|
:code:`VerilatedVpi::doInertialPuts()`.
|
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
.. _VPI Example:
|
|
|
|
|
|
|
|
VPI Example
|
|
|
|
-----------
|
|
|
|
|
|
|
|
In the below example, we have readme marked read-only, and writeme which if
|
|
|
|
written from outside the model will have the same semantics as if it
|
|
|
|
changed on the specified clock edge.
|
|
|
|
|
|
|
|
.. code-block:: bash
|
|
|
|
|
|
|
|
cat >our.v <<'EOF'
|
2023-02-03 02:51:23 +00:00
|
|
|
module our #(
|
|
|
|
parameter WIDTH /*verilator public_flat_rd*/ = 32
|
|
|
|
) (input clk);
|
|
|
|
reg [WIDTH-1:0] readme /*verilator public_flat_rd*/;
|
|
|
|
reg [WIDTH-1:0] writeme /*verilator public_flat_rw @(posedge clk) */;
|
2021-04-11 22:55:06 +00:00
|
|
|
initial $finish;
|
|
|
|
endmodule
|
|
|
|
EOF
|
|
|
|
|
|
|
|
There are many online tutorials and books on the VPI, but an example that
|
|
|
|
accesses the above signal "readme" would be:
|
|
|
|
|
|
|
|
.. code-block:: bash
|
|
|
|
|
2022-03-09 08:57:55 +00:00
|
|
|
cat >sim_main.cpp <<'EOF'
|
2021-04-11 22:55:06 +00:00
|
|
|
#include "Vour.h"
|
|
|
|
#include "verilated.h"
|
|
|
|
#include "verilated_vpi.h" // Required to get definitions
|
|
|
|
|
2022-03-27 19:27:40 +00:00
|
|
|
uint64_t main_time = 0; // See comments in first example
|
2021-04-11 22:55:06 +00:00
|
|
|
double sc_time_stamp() { return main_time; }
|
|
|
|
|
|
|
|
void read_and_check() {
|
|
|
|
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
|
|
|
if (!vh1) vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found");
|
|
|
|
const char* name = vpi_get_str(vpiName, vh1);
|
2023-02-23 10:47:56 +00:00
|
|
|
const char* type = vpi_get_str(vpiType, vh1);
|
|
|
|
const int size = vpi_get(vpiSize, vh1);
|
2023-02-03 02:51:23 +00:00
|
|
|
printf("register name: %s, type: %s, size: %d\n", name, type, size); // Prints "register name: readme, type: vpiReg, size: 32"
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
s_vpi_value v;
|
|
|
|
v.format = vpiIntVal;
|
|
|
|
vpi_get_value(vh1, &v);
|
2023-02-03 02:51:23 +00:00
|
|
|
printf("Value of %s: %d\n", name, v.value.integer); // Prints "Value of readme: 0"
|
2021-04-11 22:55:06 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 23:50:31 +00:00
|
|
|
int main(int argc, char** argv) {
|
2021-04-11 22:55:06 +00:00
|
|
|
Verilated::commandArgs(argc, argv);
|
2022-07-09 13:50:50 +00:00
|
|
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
|
|
|
const std::unique_ptr<Vour> top{new Vour{contextp.get()}};
|
|
|
|
|
|
|
|
contextp->internalsDump(); // See scopes to help debug
|
|
|
|
while (!contextp->gotFinish()) {
|
2021-04-11 22:55:06 +00:00
|
|
|
top->eval();
|
|
|
|
VerilatedVpi::callValueCbs(); // For signal callbacks
|
|
|
|
read_and_check();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
|
|
|
|
.. _Evaluation Loop:
|
|
|
|
|
|
|
|
Wrappers and Model Evaluation Loop
|
|
|
|
==================================
|
|
|
|
|
|
|
|
When using SystemC, evaluation of the Verilated model is managed by the
|
|
|
|
SystemC kernel, and for the most part can be ignored. When using C++, the
|
|
|
|
user must call :code:`eval()`, or :code:`eval_step()` and
|
|
|
|
:code:`eval_end_step()`.
|
|
|
|
|
|
|
|
1. When there is a single design instantiated at the C++ level that needs
|
|
|
|
to evaluate within a given context, call :code:`designp->eval()`.
|
|
|
|
|
|
|
|
2. When there are multiple designs instantiated at the C++ level that need
|
|
|
|
to evaluate within a context, call :code:`first_designp->eval_step()` then
|
|
|
|
:code:`->eval_step()` on all other designs. Then call
|
|
|
|
:code:`->eval_end_step()` on the first design then all other designs. If
|
|
|
|
there is only a single design, you would call :code:`eval_step()` then
|
|
|
|
:code:`eval_end_step()`; in fact :code:`eval()` described above is just a
|
|
|
|
wrapper which calls these two functions.
|
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
3. If using delays and :vlopt:`--timing`, there are two additional methods
|
|
|
|
the user should call:
|
|
|
|
|
|
|
|
* :code:`designp->eventsPending()`, which returns :code:`true` if there are
|
2022-10-16 15:10:41 +00:00
|
|
|
any delayed events pending,
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
* :code:`designp->nextTimeSlot()`, which returns the simulation time of the
|
|
|
|
next delayed event. This method can only be called if
|
2024-02-21 15:15:29 +00:00
|
|
|
:code:`designp->eventsPending()` returned :code:`true`.
|
2022-10-02 20:47:32 +00:00
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
Call :code:`eventsPending()` to check if you should continue with the
|
|
|
|
simulation, and then :code:`nextTimeSlot()` to move simulation time forward.
|
|
|
|
:vlopt:`--main` can be used with :vlopt:`--timing` to generate a basic example
|
|
|
|
of a timing-enabled eval loop.
|
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
When :code:`eval()` (or :code:`eval_step()`) is called Verilator looks for
|
|
|
|
changes in clock signals and evaluates related sequential always blocks,
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
such as computing always_ff @ (posedge...) outputs. With :vlopt:`--timing`, it
|
|
|
|
resumes any delayed processes awaiting the current simulation time. Then
|
|
|
|
Verilator evaluates combinational logic.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
Note combinatorial logic is not computed before sequential always blocks
|
|
|
|
are computed (for speed reasons). Therefore it is best to set any non-clock
|
|
|
|
inputs up with a separate :code:`eval()` call before changing clocks.
|
|
|
|
|
|
|
|
Alternatively, if all always_ff statements use only the posedge of clocks,
|
|
|
|
or all inputs go directly to always_ff statements, as is typical, then you
|
|
|
|
can change non-clock inputs on the negative edge of the input clock, which
|
|
|
|
will be faster as there will be fewer :code:`eval()` calls.
|
|
|
|
|
|
|
|
For more information on evaluation, see :file:`docs/internals.rst` in the
|
|
|
|
distribution.
|
|
|
|
|
|
|
|
|
|
|
|
Verilated and VerilatedContext
|
|
|
|
==============================
|
|
|
|
|
2023-01-26 23:27:00 +00:00
|
|
|
Multiple C++ Verilated models may be part of the same simulation context,
|
|
|
|
that is share a VPI interface, sense of time, and common settings. This
|
|
|
|
common simulation context information is stored in a ``VerilatedContext``
|
2021-04-11 22:55:06 +00:00
|
|
|
structure. If a ``VerilatedContext`` is not created prior to creating a
|
2023-01-26 23:27:00 +00:00
|
|
|
model, a default global one is created automatically. SystemC requires
|
|
|
|
using only the single, default VerilatedContext.
|
2021-04-11 22:55:06 +00:00
|
|
|
|
|
|
|
The ``Verilated::`` methods, including the ``Verilated::commandArgs`` call
|
2022-03-31 00:17:59 +00:00
|
|
|
shown above, call VerilatedContext methods using the default global
|
2021-04-11 22:55:06 +00:00
|
|
|
VerilatedContext. (Technically they operate on the last one used by a
|
|
|
|
given thread.) If you are using multiple simulation contexts you should
|
|
|
|
not use the Verilated:: methods, and instead always use VerilatedContext
|
|
|
|
methods called on the appropriate VerilatedContext object.
|
|
|
|
|
|
|
|
For methods available under Verilated and VerilatedContext see
|
|
|
|
:file:`include/verilated.h` in the distribution.
|