SystemVerilog Meets C++
SystemVerilog Meets C++
SystemVerilog Meets C++
John Aynsley
Doulos
[email protected]
Abstract- The OVM and VMM methodologies each provide relatively simple coding guidelines tried-and-tested with current
powerful, flexible and intuitive frameworks for the construction simulator releases. As a consequence, we are forced down the line of
of SystemVerilog verification environments. However, many addressing practical issues of simulator support for the DPI and the
SystemVerilog users also have models written in C, C++, or procedural interface between SystemVerilog and SystemC.
sometimes SystemC. Furthermore, the emergence of the
SystemC TLM-1 and TLM-2.0 transaction-level modeling The DPI supports simple function calls between SystemVerilog and
standards is having an impact on communication styles within C. Simulation tool vendors also offer the facility of mixed-language
SystemVerlog verification environments. This paper offers simulation, such as the ability to instantiate a SystemC module from
practical guidance on using the SystemVerilog Direct a top-level SystemVerilog module. But mixed-language instantiation
Programming Interface (DPI) to integrate existing C, C++ and alone is insufficient to address the issue of building procedural
SystemC code into an OVM- or VMM-based SystemVerilog interfaces between the languages. Tool vendors offer proprietary
testbench without jeopardizing portability from one simulator to (non-standard) solutions to the problem of making object-oriented
another. This is achieved by presenting a set of simple, robust method calls (that is, calling class member functions as opposed to
guidelines for creating portable DPI code. global functions) between SystemVerilog and C++ and of passing
transactions between SystemVerilog and SystemC. Anyone wishing
to use these facilities is force to chose between “selling their soul” to
1. Introduction the EDA vendor in the sense of getting locked into a proprietary
solution, or of investigating and using a restricted set of features that
The requirement to call a C/C++ reference model from a form the “lowest common denominator” between tools. We take the
SystemVerilog test bench is not uncommon. A contemporary latter approach in this paper.
SystemVerilog test bench would typically be based on either the
OVM or the VMM functional verification methodology or 1.2 Transaction-Level Modeling
sometimes on a homebrew variant of these. One of the tasks
performed by such a test bench is to compare the actual behavior of The SystemC community has developed the TLM-1.0 and TLM-2.0
the design-under-test (DUT) against the behavior of a functional standards for Transaction Level Modeling in the context of
reference model, which might originally have been coded in C, C++, architectural exploration and creating so-called virtual platform
or SystemC. A C/C++ algorithm or reference model would models of a hardware platform for early software execution.
necessarily be untimed, but a SystemC model could include timing Meanwhile, for functional verification, SystemVerilog test benches
information. written to the OVM or VMM standards also make use of transaction-
level modeling (TLM) for internal communication. This means using
Against this backdrop, the question of how to call a C/C++ or function calls to pass around objects that encapsulate the attributes of
SystemC reference model from a SystemVerilog test bench is a transaction. The transactions themselves are specific to the
frequently raised. Unfortunately, although each of the above- interfaces or protocols being modeled. In order to exploit this
mentioned languages is defined by a formal standard, the interface commonality between the domains of modeling and verification
between the languages is not standardized with the same precision as OVM has adopted the TLM-1.0 standard for communication and the
the languages themselves. In principle, the SystemVerilog Direct latest version of VMM has added internal communication features
Programming Interface (DPI) permits procedural function calls inspired by TLM-2.0. In this paper, we look to develop an approach
between SystemVerilog and C. In practice, differences between to communication between SystemVerilog and C/SystemC that is
implementations and the lack of any standard support for calls consistent and interoperable with these TLM standards.
between SystemVerilog and SystemC mean that any solution needs
to be tool-dependent. OVM and VMM test benches are transaction-oriented. On the other
hand, although C/C++ reference models can also be transaction-
1.1 Portability oriented, they will sometimes be completely untimed or may perform
some transformation on an entire dataset without having any regard
The goal of this paper is to present a very practical answer to the for how and when that data is presented in the hardware
question of how to use the SystemVerilog DPI to communicate implementation or the test bench. For example, a reference model for
between an OVM or VMM SystemVerilog test bench and a C/C++, an FFT may transform a dataset from the time domain to the
or SystemC reference model in a way that is, as far as possible, frequency domain. Integrating such a reference model into a test
portable between simulators. The intent is to provide a solution that bench requires that the mismatch between transaction-by-transaction
actually works, today! To this end, we endeavor to offer a set of processing and batch processing be addressed. There may also be
In principle, the DPI offers the ability to pass so-called open array 5.4 DPI Guidelines: SystemVerilog-to-C++
argument in which the size of the array is left unspecified on the
SystemVerilog side, and provides a C programming interface to The standard SystemVerilog DPI, i.e. “DPI-C”, only supports
manipulate such open arrays on the C side. Again, we found that not function calls between SystemVerilog and C. However it is very
all current simulators provide robust support for this facility. straightforward to make C++ calls simply by forcing the C++
compiler to use C linkage for both imported and exported functions
Aside from current tool limitations, the DPI also has some inherent as follows:
limitations in the sense that it does not permit SystemVerilog class
objects to be passed as DPI arguments, and does not permit
SystemVerilog class methods or C++ class member functions to be // C++
called directly through the DPI in either direction. #include "svdpi.h"
i. Pass only small types as DPI arguments, that is, do not pass The only caveat is that the DPI does not permit C++ member
user-defined structs, open arrays, or multi-dimensional functions (methods) to be called.
arrays
DPI code such as this can be made portable across all current
ii. Logic vectors, i.e. packed arrays of type logic, may be simulators. All simulators provide the standard DPI header
passed as DPI arguments and accessed using the standard “svdpi.h”.
C API with the proviso that conditional compilation may
be necessary to pick out the appropriate class properties in
a portable way. Some simulators refer to the two words of 6. Calling an Untimed C/C++ Reference Model
the canonical representation using class properties .a and .b
while others use .aval and .bval. For example: In this section we explore the issues involved in calling an untimed
reference model from an OVM or VMM SystemVerilog test bench
using a Fast Fourier Transform (FFT) algorithm as an example. The
// SystemVerilog test bench passes around transactions that each represent a single 16-
#include "svdpi.h" bit sample in the time domain. The intent is to use the FFT reference
model to convert a set of samples from the time domain to the
int print ( svLogicVecVal* v ) { frequency domain for analysis. The samples are collected by the
int i; scoreboard as the test bench executes, a batch of samples is sent to
for (i = 0; i < 8; i++) { the FFT reference algorithm, and the scoreboard logs the results of
#ifdef CADENCE the analysis. The transaction stream in the test bench actually
printf("%d%d", v->a % 2, v->b % 2);
consists of multiple interleaved sample streams, where each
v->a = v->a >> 1;
v->b = v->b >> 1; individual sample is tagged with a stream number.
#else
printf("%d%d", v->aval % 2, v->bval % 2); The FFT algorithm is primarily coded in C but makes occasional use
v->aval = v->aval >> 1; of C++ features such as stream I/O, so it was necessary to use a C++
v->bval = v->bval >> 1; compiler and to force the compiler to use C linkage for the DPI
#endif functions as described above.
}
printf("\n");
In the original C++ program, the main() function initialized the
}
dataset to be transformed by reading the data from an external text
file. We replaced this with two DPI functions, one to initialize the
state of the arrays used during the FFT transform, and another to pass
iii. In order to pass structs across the DPI, break them down
individual samples from the SystemVerilog test bench to the C++
into small arguments and re-assemble the struct on the C
model:
side if desired.
Using this approach, it was possible to use precisely the same DPI 7.2 DPI Guidelines: SV-to-SC, untimed, one instance
calls and C++ code with an OVM test bench and simulators from
Cadence and Mentor, and with a VMM test bench and the Synopsys We were able to create simple, robust, portable DPI code to
simulator. While this study was limited to the methodology/vendor communicate between SystemVerilog and a single instance of an
combinations as stated, this same approach should work successfully untimed SystemC module by adhering to the following guidelines (in
with other combinations. addition to those given above):
All current simulators support mixed-language designs, and ii. Use “DPI-C” imports only, not exports.
specifically permit SystemC modules to be instantiated directly from
SystemVerilog. All simulators support the ability to make pin-level iii. Cadence, and only Cadence, requires a dummy
connections across languages, but unfortunately there is no standard SystemVerilog module stub corresponding to the SystemC
for procedural communication between SystemVerilog and SystemC module:
aside from the DPI.
// SystemVerilog
The native SystemVerilog DPI does not explicitly support SystemC. `ifdef NCSC
However, it is possible to use the standard DPI with SystemC in the module scwrap ()
sense that SystemC is just another C++ application. (* integer foreign = "SystemC"; *);
endmodule
`endif
SystemC modules typically provide a procedural interface either by
implementing a SystemC interface or by offering a SystemC export.
Using this procedural interface requires the ability to make C++
method calls, which is not possible using the standard DPI. Two
// SystemVerilog
import "DPI-C" function void entry(
input int id, input byte cmd, input int addr, inout int data);
7.3 DPI Guidelines: SV-to-SC, multiple instances import "DPI-C" function string get_path(input int id);
The above approach can easily be extended to handle multiple int path_to_id[string];
instances of the same SystemC module. Instead of having a single …
instance pointer in the wrapper pointing to the module itself, have a virtual function void end_of_elaboration;
vector of pointers: path_to_id[get_path(1)] = 1;
path_to_id[get_path(2)] = 2;
endfunction
// SystemC
class scwrap: public sc_module
{ Unfortunately, differences between simulator implementations cause
public: portability issues again. The SystemC name() method returns the
scwrap(sc_module_name n); hierarchical path in a different format in each case! Conditional
compilation can be used to patch up the differences:
scmod* m_scmod;
To handle a timed SystemC model, because the DPI call itself must // DPI import
not be blocked by the SystemC scheduler (as discussed above), the extern "C"
response may need to be returned at a later time using a separate DPI void entry(int id, char cmd, int addr, int* data) {
call from SystemC to SystemVerilog. Hence we require both DPI …
calling_scope = svGetScope();
imports and DPI exports between SystemVerilog and SystemC.
}
The approach we have adopted is to use two DPI calls, a DPI import …
function that sends a request to the SystemC model (by passing small {
types as function arguments), and a DPI export function that sends a svSetScope(calling_scope);
response back to the SystemVerilog test bench at a later time (again
by passing small types as function arguments). Both can be simple // Call to DPI export
non-blocking function calls. This mechanism has similarities with tx_done(id, tx->cmd, tx->addr, tx->data);
}
the TLM-2.0 non-blocking interface, and like that interface, is able to
support multiple simultaneous pipelined transactions. However, our
approach does not require that either the SystemVerilog or the
SystemC model be TLM-2.0-compliant. In order to deal with multiple outstanding transactions, the SystemC
wrapper module maintains a pool of SystemC threads. Incoming
As a purely practical matter, linking SystemVerilog and SystemC transactions are allocated to the next free thread, and a thread
applications with function calls in both directions seems best handled remains tied to a transaction instance until the response has been
by switching to “DPI-SC” for Cadence and Mentor, while “DPI-C” returned to the SystemVerilog test bench and the transaction
is sufficient for Synopsys. As mentioned above, currently there are completed. The thread can then be returned to the pool and reused.
portability issues when making SystemC method calls using “DPI- Each thread has an associated event which, when notified, causes the
SC”, but the implementation of global C++ function calls through the thread to resume and process a new incoming transaction.
“DPI-SC” interface (or “DPI-C” for Synopsys) seem to be robust for
all simulators. Synopsys users also have the option of using the TLI, Each incoming transaction is handled by the SystemC wrapper as
but a premise of this paper is the desire to create portable code and to follows:
minimize reliance on vendor-specific features.
i. Assemble a new transaction object from the DPI arguments
To call global C++ functions at “DPI-SC” imports requires the use of ii. Associate the transaction object with the next free thread
vendor-specific function registration macros as follows: iii. Notify an event to cause the thread to resume
On the SystemVerilog side, the lifetime of each transaction will v. For timed SystemC models, use “DPI-SC” (Cadence and
extend beyond the call to the DPI import. Hence it is essential that Mentor) or “DPI-C” (Synopsys)
the test bench creates a new transaction object per transaction rather
than reusing the same object, which may still be “alive”. (This is vi. For timed SystemC models, have the SystemC wrapper
considered good practice anyway in both OVM and VMM.) The DPI maintain a pool of SystemC threads to call any blocking
export call that indicates the completion of the transaction is SystemC method
necessarily a global function call, rather than being a class method
call to the OVM component or VMM transactor that initiated the vii. For timed SystemC models, have the SystemC wrapper
transaction, so the programmer must contrive some mechanism to call a DPI export on completion of the transaction
communicate between the incoming DPI call and the initiator, based
on the id argument that is common to the outgoing and incoming viii. Have all DPI calls in either direction be non-blocking
DPI calls. From the SystemVerilog side, the incoming DPI export
call is effectively asynchronous with respect to the operation of the ix. Use conditional compilation as necessary to handle
test bench. The initiating component/transactor can either suspend differences in directives, headers, macro names, and
until it is notified of the completion of the transaction, or can hierarchical path names between simulators
continue to generate new transactions.
8. Conclusions [2] IEEE Std 1666-2005 “IEEE Standard SystemC Language Reference
Manual”
We set out to find a way of using the SystemVerilog DPI to call [3] OSCI TLM-2.0 Language Reference Manual, version JA32, 2009
C/C++ and SystemC reference models in a way that was simple,
robust, and portable between simulators. On the whole, the results [4] Bergeron, Cerny, Hunter and Nightingale. 2005 Verification Methodology
were very positive. We found an approach by which we were able to Manual for SystemVerilog. Springer ISBN-10: 0-387-25538-9
create a single body of C/C++ or SystemC code that is portable
between all current simulators, albeit by imposing some restrictions [5] VMM Standard Library User Guide, Version 1.2, November 2009
on the DPI features used.
[6] OVM Class Reference, Version 2.0.2, June 2009