Support direct programming interface (DPI) "import".
This commit is contained in:
parent
f8cb6979d7
commit
a40fae04ce
2
Changes
2
Changes
|
|
@ -12,6 +12,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
** Support typedef. [Donal Casey]
|
||||
|
||||
** Support direct programming interface (DPI) "import".
|
||||
|
||||
*** Support "reg [1:0][1:0][1:0]" and "reg x [3][2]", bug176. [Byron Bradley]
|
||||
|
||||
*** Support declarations in loop initializers, bug172. [by Byron Bradley]
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
|||
MANIFEST.SKIP \
|
||||
bin/* \
|
||||
install-sh configure mkinstalldirs *.pod \
|
||||
include/verilated*.[chv]* \
|
||||
include/*.[chv]* \
|
||||
include/*.in \
|
||||
include/.*ignore \
|
||||
.*attributes */.*attributes */*/.*attributes \
|
||||
|
|
|
|||
|
|
@ -969,6 +969,7 @@ For -sp mode, instead of .cpp and .h it creates:
|
|||
|
||||
In certain optimization modes, it also creates:
|
||||
|
||||
{prefix}__Dpi.h // DPI import and export declarations
|
||||
{prefix}__Inlines.h // Inline support functions
|
||||
{prefix}__Slow.cpp // Constructors and infrequent routines
|
||||
{prefix}__Syms.cpp // Global symbol table C++
|
||||
|
|
@ -1121,6 +1122,32 @@ Lower 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.
|
||||
|
||||
=head1 DPI (DIRECT PROGRAMMING INTERFACE)
|
||||
|
||||
Verilator supports SystemVerilog Direct Programming Interface import
|
||||
statements. Only the SystemVerilog form ("DPI-C") is supported, not the
|
||||
original Synopsys-only DPI.
|
||||
|
||||
In the SYSTEMC example above, if you had in our.v:
|
||||
|
||||
import "DPI-C" function integer add (input integer a, input integer 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:
|
||||
|
||||
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:
|
||||
|
||||
#include "svdpi.h"
|
||||
#include "Vour__Dpi.h"
|
||||
int add (int a, int b) { return a+b; }
|
||||
|
||||
=head1 CROSS COMPILATION
|
||||
|
||||
Verilator supports cross-compiling Verilated code. This is generally used
|
||||
|
|
@ -2459,13 +2486,15 @@ file found in the include directory of the Verilator kit.
|
|||
|
||||
=item Is the PLI supported?
|
||||
|
||||
No.
|
||||
No, but the DPI is.
|
||||
|
||||
More specifically, the common PLI-ish calls $display, $finish, $stop,
|
||||
$time, $write are converted to C++ equivalents. If you want something more
|
||||
complex, since Verilator emits standard C++ code, you can simply write your
|
||||
own C++ routines that can access and modify signal values without needing
|
||||
any PLI interface code, and call it with $c("{any_c++_statement}").
|
||||
$time, $write are converted to C++ equivalents. You can also use the
|
||||
"import DPI" SystemVerilog feature to call C code (see the chapter above).
|
||||
If you want something more complex, since Verilator emits standard C++
|
||||
code, you can simply write your own C++ routines that can access and modify
|
||||
signal values without needing any PLI interface code, and call it with
|
||||
$c("{any_c++_statement}").
|
||||
|
||||
=item How do I make a Verilog module that contain a C++ object?
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,367 @@
|
|||
/* -*- C -*-
|
||||
*
|
||||
* svdpi.h
|
||||
*
|
||||
* SystemVerilog Direct Programming Interface (DPI).
|
||||
*
|
||||
* This file contains the constant definitions, structure definitions,
|
||||
* and routine declarations used by SystemVerilog DPI.
|
||||
*
|
||||
* This file is from the SystemVerilog IEEE 1800-2005 Annex G,
|
||||
* with modifications to support Verilator.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_SVDPI
|
||||
#define INCLUDED_SVDPI
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Ensure that size-critical types are defined on all OS platforms. */
|
||||
#if defined (_MSC_VER)
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int8 int8_t;
|
||||
#elif defined(__MINGW32__)
|
||||
#include <stdint.h>
|
||||
#elif defined(__linux)
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/* Use to export a symbol from application */
|
||||
#if defined (_MSC_VER)
|
||||
#define DPI_DLLISPEC __declspec(dllimport)
|
||||
#else
|
||||
#define DPI_DLLISPEC
|
||||
#endif
|
||||
|
||||
/* Use to import a symbol into application */
|
||||
#if defined (_MSC_VER)
|
||||
#define DPI_DLLESPEC __declspec(dllexport)
|
||||
#else
|
||||
#define DPI_DLLESPEC
|
||||
|
||||
#endif
|
||||
|
||||
/* Use to mark a function as external */
|
||||
#ifndef DPI_EXTERN
|
||||
#define DPI_EXTERN
|
||||
#endif
|
||||
|
||||
#ifndef DPI_PROTOTYPES
|
||||
#define DPI_PROTOTYPES
|
||||
/* object is defined imported by the application */
|
||||
#define XXTERN DPI_EXTERN DPI_DLLISPEC
|
||||
/* object is exported by the application */
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
#endif
|
||||
|
||||
/* canonical representation */
|
||||
#define sv_0 0
|
||||
#define sv_1 1
|
||||
#define sv_z 2
|
||||
#define sv_x 3
|
||||
|
||||
/* common type for 'bit' and 'logic' scalars. */
|
||||
typedef uint8_t svScalar;
|
||||
typedef svScalar svBit; /* scalar */
|
||||
typedef svScalar svLogic; /* scalar */
|
||||
|
||||
/*
|
||||
* DPI representation of packed arrays.
|
||||
* 2-state and 4-state vectors, exactly the same as PLI's avalue/bvalue.
|
||||
*/
|
||||
#ifndef VPI_VECVAL
|
||||
#define VPI_VECVAL
|
||||
typedef struct vpi_vecval {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
} s_vpi_vecval, *p_vpi_vecval;
|
||||
#endif
|
||||
|
||||
/* (a chunk of) packed logic array */
|
||||
typedef s_vpi_vecval svLogicVecVal;
|
||||
|
||||
/* (a chunk of) packed bit array */
|
||||
typedef uint32_t svBitVecVal;
|
||||
|
||||
/* Number of chunks required to represent the given width packed array */
|
||||
#define SV_PACKED_DATA_NELEMS(WIDTH) (((WIDTH) + 31) >> 5)
|
||||
|
||||
/*
|
||||
* Because the contents of the unused bits is undetermined,
|
||||
* the following macros can be handy.
|
||||
*/
|
||||
#define SV_MASK(N) (~(-1 << (N)))
|
||||
|
||||
#define SV_GET_UNSIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : ((VALUE) & SV_MASK(N)))
|
||||
|
||||
#define SV_GET_SIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : \
|
||||
(((VALUE) & (1 << (N))) ? ((VALUE) | ~SV_MASK(N)) : ((VALUE) & SV_MASK(N))))
|
||||
|
||||
/*
|
||||
* Implementation-dependent representation.
|
||||
*/
|
||||
/*
|
||||
* Return implementation version information string ("P1800-2005" or "SV3.1a").
|
||||
*/
|
||||
XXTERN const char* svDpiVersion();
|
||||
|
||||
/* a handle to a scope (an instance of a module or interface) */
|
||||
XXTERN typedef void* svScope;
|
||||
|
||||
/* a handle to a generic object (actually, unsized array) */
|
||||
XXTERN typedef void* svOpenArrayHandle;
|
||||
|
||||
/*
|
||||
* Bit-select utility functions.
|
||||
*
|
||||
* Packed arrays are assumed to be indexed n-1:0,
|
||||
* where 0 is the index of LSB
|
||||
*/
|
||||
|
||||
/* s=source, i=bit-index */
|
||||
XXTERN svBit svGetBitselBit(const svBitVecVal* s, int i);
|
||||
XXTERN svLogic svGetBitselLogic(const svLogicVecVal* s, int i);
|
||||
|
||||
/* d=destination, i=bit-index, s=scalar */
|
||||
XXTERN void svPutBitselBit(svBitVecVal* d, int i, svBit s);
|
||||
XXTERN void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s);
|
||||
|
||||
/*
|
||||
* Part-select utility functions.
|
||||
*
|
||||
* A narrow (<=32 bits) part-select is extracted from the
|
||||
* source representation and written into the destination word.
|
||||
*
|
||||
* Normalized ranges and indexing [n-1:0] are used for both arrays.
|
||||
*
|
||||
* s=source, d=destination, i=starting bit index, w=width
|
||||
* like for variable part-selects; limitations: w <= 32
|
||||
*/
|
||||
XXTERN void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w);
|
||||
XXTERN void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w);
|
||||
|
||||
XXTERN void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w);
|
||||
XXTERN void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal s, int i, int w);
|
||||
|
||||
/*
|
||||
* Open array querying functions
|
||||
* These functions are modeled upon the SystemVerilog array
|
||||
* querying functions and use the same semantics.
|
||||
*
|
||||
* If the dimension is 0, then the query refers to the
|
||||
* packed part of an array (which is one-dimensional).
|
||||
* Dimensions > 0 refer to the unpacked part of an array.
|
||||
*/
|
||||
|
||||
/* h= handle to open array, d=dimension */
|
||||
XXTERN int svLeft(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svRight(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svLow(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svHigh(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svIncrement(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svLength(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svDimensions(const svOpenArrayHandle h);
|
||||
|
||||
/*
|
||||
* Pointer to the actual representation of the whole array of any type
|
||||
* NULL if not in C layout
|
||||
*/
|
||||
XXTERN void *svGetArrayPtr(const svOpenArrayHandle);
|
||||
|
||||
/* total size in bytes or 0 if not in C layout */
|
||||
XXTERN int svSizeOfArray(const svOpenArrayHandle);
|
||||
|
||||
/*
|
||||
* Return a pointer to an element of the array
|
||||
* or NULL if index outside the range or null pointer
|
||||
*/
|
||||
XXTERN void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...);
|
||||
|
||||
/* specialized versions for 1-, 2- and 3-dimensional arrays: */
|
||||
XXTERN void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1);
|
||||
XXTERN void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2);
|
||||
XXTERN void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2,
|
||||
int indx3);
|
||||
|
||||
/*
|
||||
* Functions for copying between simulator storage and user space.
|
||||
* These functions copy the whole packed array in either direction.
|
||||
* The user is responsible for allocating an array to hold the
|
||||
* canonical representation.
|
||||
*/
|
||||
|
||||
/* s=source, d=destination */
|
||||
/* From user space into simulator storage */
|
||||
XXTERN void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/* From simulator storage into user space */
|
||||
XXTERN void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
|
||||
int indx1);
|
||||
XXTERN void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
...);
|
||||
XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
|
||||
XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2, int indx3);
|
||||
XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
|
||||
XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2, int indx3);
|
||||
|
||||
/* Functions for working with DPI context */
|
||||
|
||||
/*
|
||||
* Retrieve the active instance scope currently associated with the executing
|
||||
* imported function. Unless a prior call to svSetScope has occurred, this
|
||||
* is the scope of the function's declaration site, not call site.
|
||||
* Returns NULL if called from C code that is *not* an imported function.
|
||||
*/
|
||||
XXTERN svScope svGetScope();
|
||||
|
||||
/*
|
||||
* Set context for subsequent export function execution.
|
||||
* This function must be called before calling an export function, unless
|
||||
* the export function is called while executing an extern function. In that
|
||||
* case the export function shall inherit the scope of the surrounding extern
|
||||
* function. This is known as the "default scope".
|
||||
* The return is the previous active scope (per svGetScope)
|
||||
*/
|
||||
XXTERN svScope svSetScope(const svScope scope);
|
||||
|
||||
/* Gets the fully qualified name of a scope handle */
|
||||
XXTERN const char* svGetNameFromScope(const svScope);
|
||||
|
||||
/*
|
||||
* Retrieve svScope to instance scope of an arbitrary function declaration.
|
||||
* (can be either module, program, interface, or generate scope)
|
||||
* The return value shall be NULL for unrecognized scope names.
|
||||
*/
|
||||
XXTERN svScope svGetScopeFromName(const char* scopeName);
|
||||
|
||||
/*
|
||||
* Store an arbitrary user data pointer for later retrieval by svGetUserData()
|
||||
* The userKey is generated by the user. It must be guaranteed by the user to
|
||||
* be unique from all other userKey's for all unique data storage requirements
|
||||
* It is recommended that the address of static functions or variables in the
|
||||
* user's C code be used as the userKey.
|
||||
* It is illegal to pass in NULL values for either the scope or userData
|
||||
* arguments. It is also an error to call svPutUserData() with an invalid
|
||||
* svScope. This function returns -1 for all error cases, 0 upon success. It is
|
||||
* suggested that userData values of 0 (NULL) not be used as otherwise it can
|
||||
* be impossible to discern error status returns when calling svGetUserData()
|
||||
*/
|
||||
XXTERN int svPutUserData(const svScope scope, void *userKey, void* userData);
|
||||
|
||||
/*
|
||||
* Retrieve an arbitrary user data pointer that was previously
|
||||
* stored by a call to svPutUserData(). See the comment above
|
||||
* svPutUserData() for an explanation of userKey, as well as
|
||||
* restrictions on NULL and illegal svScope and userKey values.
|
||||
* This function returns NULL for all error cases, 0 upon success.
|
||||
* This function also returns NULL in the event that a prior call
|
||||
* to svPutUserData() was never made.
|
||||
*/
|
||||
XXTERN void* svGetUserData(const svScope scope, void* userKey);
|
||||
|
||||
/*
|
||||
* Returns the file and line number in the SV code from which the extern call
|
||||
* was made. If this information available, returns TRUE and updates fileName
|
||||
* and lineNumber to the appropriate values. Behavior is unpredictable if
|
||||
* fileName or lineNumber are not appropriate pointers. If this information is
|
||||
* not available return FALSE and contents of fileName and lineNumber not
|
||||
* modified. Whether this information is available or not is implementation-
|
||||
* specific. Note that the string provided (if any) is owned by the SV
|
||||
* implementation and is valid only until the next call to any SV function.
|
||||
* Applications must not modify this string or free it
|
||||
*/
|
||||
XXTERN int svGetCallerInfo(const char** fileName, int *lineNumber);
|
||||
|
||||
/*
|
||||
* Returns 1 if the current execution thread is in the disabled state.
|
||||
* Disable protocol must be adhered to if in the disabled state.
|
||||
*/
|
||||
XXTERN int svIsDisabledState();
|
||||
|
||||
/*
|
||||
* Imported functions call this API function during disable processing to
|
||||
* acknowledge that they are correctly participating in the DPI disable protocol.
|
||||
* This function must be called before returning from an imported function that is
|
||||
* in the disabled state.
|
||||
*/
|
||||
XXTERN void svAckDisabledState();
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* DEPRECATED PORTION OF FILE REMOVED.
|
||||
* DEPRECATED PORTION OF FILE ENDS HERE.
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
#undef DPI_EXTERN
|
||||
|
||||
#ifdef DPI_PROTOTYPES
|
||||
#undef DPI_PROTOTYPES
|
||||
#undef XXTERN
|
||||
#undef EETERN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: DPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the DPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
#define _VL_SVDPI_UNIMP()
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN()
|
||||
|
||||
//======================================================================
|
||||
// Version
|
||||
|
||||
const char* svDpiVersion() {
|
||||
return "P1800-2005";
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Bit-select utility functions.
|
||||
|
||||
svBit svGetBitselBit(const svBitVecVal* s, int i) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svLogic svGetBitselLogic(const svLogicVecVal* s, int i) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void svPutBitselBit(svBitVecVal* d, int i, svBit s) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Open array querying functions
|
||||
|
||||
int svLeft(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svRight(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svLow(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svHigh(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svIncrement(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svLength(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svDimensions(const svOpenArrayHandle h) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrayPtr(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
int svSizeOfArray(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// s=source, d=destination
|
||||
// From user space into simulator storage
|
||||
|
||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// From simulator storage into user space
|
||||
|
||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Functions for working with DPI context
|
||||
|
||||
svScope svGetScope() {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
svScope svSetScope(const svScope scope) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
const char* svGetNameFromScope(const svScope) {
|
||||
_VL_SVDPI_UNIMP(); return "";
|
||||
}
|
||||
|
||||
svScope svGetScopeFromName(const char* scopeName) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
int svPutUserData(const svScope scope, void *userKey, void* userData) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
return -1; // -1 == error
|
||||
}
|
||||
|
||||
void* svGetUserData(const svScope scope, void* userKey) {
|
||||
return NULL; // NULL == error
|
||||
}
|
||||
|
||||
int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) {
|
||||
_VL_SVDPI_UNIMP(); return false;
|
||||
//UNSUP if (!Verilated::dpiInContext) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
||||
//UNSUP if (fileNamep) *fileNamepp = Verilated::dpiFilenamep; // thread local
|
||||
//UNSUP if (lineNumberp) *lineNumberp = Verilated::dpiLineno; // thread local
|
||||
//UNSUP return true;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Disables
|
||||
|
||||
int svIsDisabledState() {
|
||||
return 0; // Disables not implemented
|
||||
}
|
||||
|
||||
void svAckDisabledState() {
|
||||
// Disables not implemented
|
||||
}
|
||||
42
src/V3Ast.h
42
src/V3Ast.h
|
|
@ -218,6 +218,14 @@ public:
|
|||
};
|
||||
return names[m_e];
|
||||
};
|
||||
const char* dpiType() const {
|
||||
static const char* names[] = {
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
""
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstBasicDTypeKwd () {}
|
||||
inline AstBasicDTypeKwd (en _e) : m_e(_e) {}
|
||||
explicit inline AstBasicDTypeKwd (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
|
|
@ -251,6 +259,9 @@ public:
|
|||
int isBitLogic() const { // Don't be as anal about width warnings
|
||||
return (m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
int isDpiUnsupported() const {
|
||||
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME);
|
||||
}
|
||||
};
|
||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
|
||||
|
|
@ -735,6 +746,7 @@ public:
|
|||
// CONSTANT ACCESSORS
|
||||
static int instrCountBranch() { return 4; } ///< Instruction cycles to branch
|
||||
static int instrCountDiv() { return 10; } ///< Instruction cycles to divide
|
||||
static int instrCountDpi() { return 1000; } ///< Instruction cycles to call user function
|
||||
static int instrCountLd() { return 2; } ///< Instruction cycles to load memory
|
||||
static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers
|
||||
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
|
||||
|
|
@ -1228,25 +1240,39 @@ struct AstNodeSel : public AstNodeBiop {
|
|||
struct AstNodeFTask : public AstNode {
|
||||
private:
|
||||
string m_name; // Name of task
|
||||
string m_cname; // Name of task if DPI import
|
||||
bool m_taskPublic:1; // Public task
|
||||
bool m_didSigning:1; // V3Signed completed; can skip iteration
|
||||
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
||||
bool m_prototype:1; // Just a prototype
|
||||
bool m_dpiImport:1; // DPI imported
|
||||
bool m_dpiContext:1; // DPI import context
|
||||
bool m_dpiTask:1; // DPI import task (vs. void function)
|
||||
bool m_pure:1; // DPI import pure
|
||||
public:
|
||||
// Node that simply puts name into the output stream
|
||||
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
|
||||
: AstNode(fileline)
|
||||
, m_name(name), m_taskPublic(false), m_didSigning(false)
|
||||
, m_attrIsolateAssign(false) {
|
||||
, m_attrIsolateAssign(false), m_prototype(false)
|
||||
, m_dpiImport(false), m_dpiContext(false), m_dpiTask(false), m_pure(false) {
|
||||
addNOp3p(stmtsp);
|
||||
cname(name); // Might be overridden by dpi import/export
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFTask)
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
// {AstFunc only} op1 = Range output variable
|
||||
// op3 = Statements/Ports/Vars
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* stmtsp() const { return op3p()->castNode(); } // op1 = List of statements
|
||||
string cname() const { return m_cname; }
|
||||
void cname(const string& cname) { m_cname = cname; }
|
||||
// op1 = Output variable (functions only, NULL for tasks)
|
||||
AstNode* fvarp() const { return op1p()->castNode(); }
|
||||
void addFvarp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool isFunction() const { return fvarp(); }
|
||||
// op3 = Statements/Ports/Vars
|
||||
AstNode* stmtsp() const { return op3p()->castNode(); } // op3 = List of statements
|
||||
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
|
||||
void taskPublic(bool flag) { m_taskPublic=flag; }
|
||||
bool taskPublic() const { return m_taskPublic; }
|
||||
|
|
@ -1254,6 +1280,16 @@ public:
|
|||
bool didSigning() const { return m_didSigning; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
void prototype(bool flag) { m_prototype = flag; }
|
||||
bool prototype() const { return m_prototype; }
|
||||
void dpiImport(bool flag) { m_dpiImport = flag; }
|
||||
bool dpiImport() const { return m_dpiImport; }
|
||||
void dpiContext(bool flag) { m_dpiContext = flag; }
|
||||
bool dpiContext() const { return m_dpiContext; }
|
||||
void dpiTask(bool flag) { m_dpiTask = flag; }
|
||||
bool dpiTask() const { return m_dpiTask; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
bool pure() const { return m_pure; }
|
||||
};
|
||||
|
||||
struct AstNodeFTaskRef : public AstNode {
|
||||
|
|
|
|||
|
|
@ -102,16 +102,80 @@ string AstVar::verilogKwd() const {
|
|||
}
|
||||
}
|
||||
|
||||
string AstVar::cType() const {
|
||||
if (widthMin() == 1) {
|
||||
return "bool";
|
||||
string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (widthMin() <= 8) {
|
||||
arg += "CData";
|
||||
} else if (widthMin() <= 16) {
|
||||
arg += "SData";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
return "uint32_t";
|
||||
arg += "IData";
|
||||
} else if (isQuad()) {
|
||||
arg += "QData";
|
||||
} else if (isWide()) {
|
||||
return "uint32_t"; // []'s added later
|
||||
} else {
|
||||
return "uint64_t";
|
||||
arg += "WData"; // []'s added later
|
||||
}
|
||||
if (isWide()) {
|
||||
arg += " (& "+name();
|
||||
arg += ")["+cvtToStr(widthWords())+"]";
|
||||
} else {
|
||||
if (isOutput()) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::cpubArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (widthMin() == 1) {
|
||||
arg += "bool";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
arg += "uint32_t";
|
||||
} else if (isWide()) {
|
||||
arg += "uint32_t"; // []'s added later
|
||||
} else {
|
||||
arg += "uint64_t";
|
||||
}
|
||||
if (isWide()) {
|
||||
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
|
||||
arg += " (& "+name();
|
||||
arg += ")["+cvtToStr(widthWords())+"]";
|
||||
} else {
|
||||
if (isOutput() && !forReturn) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (!basicp()) arg = "UNKNOWN";
|
||||
if (isWide()) v3error("Unsupported: DPI functions with vectored outputs > 32-bits");
|
||||
if (basicp()->isBitLogic()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isInOnly()) {
|
||||
arg = "const svBitVecVal*";
|
||||
} else {
|
||||
arg = "svBitVecVal*";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
arg = basicp()->keyword().dpiType();
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
}
|
||||
if (named) arg += " "+name();
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::scType() const {
|
||||
|
|
@ -467,6 +531,9 @@ void AstNodeFTaskRef::dump(ostream& str) {
|
|||
void AstNodeFTask::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (taskPublic()) str<<" [PUBLIC]";
|
||||
if (prototype()) str<<" [PROTOTYPE]";
|
||||
if (dpiImport()) str<<" [DPII]";
|
||||
if (dpiImport() && cname()!=name()) str<<" [c="<<cname()<<"]";
|
||||
}
|
||||
void AstBegin::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
|
|
@ -508,4 +575,6 @@ void AstCCall::dump(ostream& str) {
|
|||
void AstCFunc::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (slow()) str<<" [SLOW]";
|
||||
if (pure()) str<<" [PURE]";
|
||||
if (dpiImport()) str<<" [DPII]";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@ private:
|
|||
}
|
||||
setNOp1p(rangep);
|
||||
}
|
||||
AstBasicDTypeKwd keyword() const { return m_keyword; } // private - use isSomething accessors instead
|
||||
public:
|
||||
ASTNODE_NODE_FUNCS(BasicDType, BASICDTYPE)
|
||||
virtual void dump(ostream& str);
|
||||
|
|
@ -229,6 +228,7 @@ public:
|
|||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
AstBasicDTypeKwd keyword() const { return m_keyword; } // Avoid using - use isSomething accessors instead
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isSloppy() const { return keyword().isSloppy(); }
|
||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||
|
|
@ -381,9 +381,9 @@ struct AstSel : public AstNodeTriop {
|
|||
:AstNodeTriop(fl, fromp, lsbp, widthp) {
|
||||
if (widthp->castConst()) width(widthp->castConst()->toUInt(), widthp->castConst()->toUInt());
|
||||
}
|
||||
AstSel(FileLine* fl, AstNode* fromp, int lsbp, int bitwidth)
|
||||
AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth)
|
||||
:AstNodeTriop(fl, fromp,
|
||||
new AstConst(fl,lsbp), new AstConst(fl,bitwidth)) {
|
||||
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
|
||||
width(bitwidth,bitwidth);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Sel, SEL)
|
||||
|
|
@ -482,8 +482,10 @@ public:
|
|||
AstVarType varType() const { return m_varType; } // * = Type of variable
|
||||
void varType2Out() { m_tristate=0; m_input=0; m_output=1; }
|
||||
void varType2In() { m_tristate=0; m_input=1; m_output=0; }
|
||||
string cType() const; // Return C type for declaration: bool, uint32_t, uint64_t, etc.
|
||||
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
||||
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
||||
string cpubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
void combineType(AstVarType type);
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
|
|
@ -965,9 +967,6 @@ struct AstFunc : public AstNodeFTask {
|
|||
addNOp1p(fvarsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Func, FUNC)
|
||||
// op1 = Range output variable (functions only)
|
||||
AstNode* fvarp() const { return op1p()->castNode(); }
|
||||
void addFvarp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
};
|
||||
|
||||
struct AstTaskRef : public AstNodeFTaskRef {
|
||||
|
|
@ -984,6 +983,23 @@ struct AstFuncRef : public AstNodeFTaskRef {
|
|||
ASTNODE_NODE_FUNCS(FuncRef, FUNCREF)
|
||||
};
|
||||
|
||||
struct AstDpiExport : public AstNode {
|
||||
// We could put a AstNodeFTaskRef instead of the verilog function name,
|
||||
// however we're not *calling* it, so that seems somehow wrong.
|
||||
// (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef)
|
||||
private:
|
||||
string m_name; // Name of function
|
||||
string m_cname; // Name of function on c side
|
||||
public:
|
||||
AstDpiExport(FileLine* fl, const string& vname, const string& cname)
|
||||
:AstNode(fl), m_name(vname), m_cname(cname) { }
|
||||
ASTNODE_NODE_FUNCS(DpiExport, DPIEXPORT)
|
||||
virtual string name() const { return m_name; }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
string cname() const { return m_cname; }
|
||||
void cname(const string& cname) { m_cname = cname; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
struct AstSenItem : public AstNodeSenItem {
|
||||
|
|
@ -3065,6 +3081,8 @@ private:
|
|||
bool m_isStatic:1; // Function is declared static (no this)
|
||||
bool m_symProlog:1; // Setup symbol table for later instructions
|
||||
bool m_entryPoint:1; // User may call into this top level function
|
||||
bool m_pure:1; // Pure function
|
||||
bool m_dpiImport:1; // From dpi import
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="")
|
||||
: AstNode(fl) {
|
||||
|
|
@ -3081,6 +3099,8 @@ public:
|
|||
m_isStatic = true; // Note defaults to static, later we see where thisp is needed
|
||||
m_symProlog = false;
|
||||
m_entryPoint = false;
|
||||
m_pure = false;
|
||||
m_dpiImport = false;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(CFunc, CFUNC)
|
||||
virtual string name() const { return m_name; }
|
||||
|
|
@ -3090,9 +3110,11 @@ public:
|
|||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType())
|
||||
&& (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid())
|
||||
&& (argTypes()==samep->castCFunc()->argTypes())); }
|
||||
&& (argTypes()==samep->castCFunc()->argTypes())
|
||||
&& (!dpiImport() || name()==samep->castCFunc()->name())); }
|
||||
//
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual int instrCount() const { return dpiImport() ? instrCountDpi() : 0; }
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
void scopep(AstScope* nodep) { m_scopep = nodep; }
|
||||
string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); }
|
||||
|
|
@ -3118,8 +3140,12 @@ public:
|
|||
void symProlog(bool flag) { m_symProlog = flag; }
|
||||
bool entryPoint() const { return m_entryPoint; }
|
||||
void entryPoint(bool flag) { m_entryPoint = flag; }
|
||||
bool pure() const { return m_pure; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
bool dpiImport() const { return m_dpiImport; }
|
||||
void dpiImport(bool flag) { m_dpiImport = flag; }
|
||||
//
|
||||
// If adding node accessors, see below
|
||||
// If adding node accessors, see below emptyBody
|
||||
AstNode* argsp() const { return op1p()->castNode(); }
|
||||
void addArgsp(AstNode* nodep) { addOp1p(nodep); }
|
||||
AstNode* initsp() const { return op2p()->castNode(); }
|
||||
|
|
@ -3165,8 +3191,8 @@ public:
|
|||
AstNode* exprsp() const { return op1p()->castNode(); } // op1= expressions to print
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isSplittable() const { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isSplittable() const { return funcp()->pure(); }
|
||||
virtual bool isOutputter() const { return !(funcp()->pure()); }
|
||||
AstCFunc* funcp() const { return m_funcp; }
|
||||
string hiername() const { return m_hiername; }
|
||||
void hiername(const string& hn) { m_hiername = hn; }
|
||||
|
|
|
|||
104
src/V3EmitC.cpp
104
src/V3EmitC.cpp
|
|
@ -90,16 +90,9 @@ public:
|
|||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args+= ", ";
|
||||
if (portp->isWide()) {
|
||||
if (portp->isInOnly()) args += "const ";
|
||||
args += portp->cType();
|
||||
args += " (& "+portp->name();
|
||||
args += ")["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
args += portp->cType();
|
||||
if (portp->isOutput()) args += "&";
|
||||
args += " "+portp->name();
|
||||
}
|
||||
if (nodep->dpiImport()) args += portp->dpiArgType(true,false);
|
||||
else if (nodep->funcPublic()) args += portp->cpubArgType(true,false);
|
||||
else args += portp->vlArgType(true,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -709,9 +702,9 @@ class EmitCImp : EmitCStmts {
|
|||
//---------------------------------------
|
||||
// VISITORS
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
if (nodep->funcType().isTrace()) {
|
||||
return; // TRACE_* handled specially
|
||||
}
|
||||
// TRACE_* and DPI handled elsewhere
|
||||
if (nodep->funcType().isTrace()) return;
|
||||
if (nodep->dpiImport()) return;
|
||||
if (!(nodep->slow() ? m_slow : m_fast)) return;
|
||||
|
||||
m_blkChangeDetVec.clear();
|
||||
|
|
@ -1557,10 +1550,12 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
|
|||
|
||||
for (vector<AstCFunc*>::iterator it = funcsp.begin(); it != funcsp.end(); ++it) {
|
||||
AstCFunc* funcp = *it;
|
||||
ofp()->putsPrivate(funcp->declPrivate());
|
||||
if (funcp->isStatic()) puts("static ");
|
||||
puts(funcp->rtnTypeVoid()); puts("\t");
|
||||
puts(funcp->name()); puts("("+cFuncArgs(funcp)+");\n");
|
||||
if (!funcp->dpiImport()) { // DPI is prototyped in __Dpi.h
|
||||
ofp()->putsPrivate(funcp->declPrivate());
|
||||
if (funcp->isStatic()) puts("static ");
|
||||
puts(funcp->rtnTypeVoid()); puts("\t");
|
||||
puts(funcp->name()); puts("("+cFuncArgs(funcp)+");\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1580,6 +1575,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
|||
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
|
||||
puts("#include \""+topClassName()+"__Inlines.h\"\n");
|
||||
}
|
||||
// No __Dpi.h needed, we've shimmed it all into the interface
|
||||
|
||||
// Declare foreign instances up front to make C++ happy
|
||||
puts("class "+symClassName()+";\n");
|
||||
|
|
@ -1757,6 +1753,9 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
|
|||
|
||||
// Us
|
||||
puts("#include \""+ symClassName() +".h\"\n");
|
||||
if (v3Global.dpi()) {
|
||||
puts("#include \""+ topClassName() +"__Dpi.h\"\n");
|
||||
}
|
||||
|
||||
if (optSystemPerl() && (splitFilenum() || !m_fast)) {
|
||||
puts("\n");
|
||||
|
|
@ -2130,6 +2129,66 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// DPI definitions
|
||||
|
||||
class EmitCDpi : EmitCStmts {
|
||||
// METHODS
|
||||
void newOutCFile() {
|
||||
string filename = (v3Global.opt.makeDir()+"/"+ topClassName()
|
||||
+ "__Dpi.h");
|
||||
|
||||
AstCFile* cfilep = newCFile(filename, false/*slow*/, false/*source*/);
|
||||
cfilep->support(true);
|
||||
|
||||
if (m_ofp) v3fatalSrc("Previous file not closed");
|
||||
m_ofp = new V3OutCFile (filename);
|
||||
m_ofp->putsHeader();
|
||||
}
|
||||
|
||||
void emitTop() {
|
||||
puts("// DESCR" "IPTION: Verilator output: Prototypes for DPI import and export functions.\n");
|
||||
puts("//\n");
|
||||
puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n");
|
||||
puts("// Manually include this file where DPI .c import functions are declared to insure\n");
|
||||
puts("// the C functions match the expectations of the DPI imports.\n");
|
||||
puts("\n");
|
||||
puts("#ifdef __cplusplus\n");
|
||||
puts("extern \"C\" {\n");
|
||||
puts("#endif\n");
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
void emitBottom() {
|
||||
puts("\n");
|
||||
puts("#ifdef __cplusplus\n");
|
||||
puts("}\n");
|
||||
puts("#endif\n");
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
if (nodep->dpiImport()) {
|
||||
puts("// dpi import at "+nodep->fileline()->ascii()+"\n");
|
||||
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+");\n");
|
||||
}
|
||||
}
|
||||
public:
|
||||
EmitCDpi() {}
|
||||
virtual ~EmitCDpi() {}
|
||||
void main() {
|
||||
// Put out the file
|
||||
newOutCFile();
|
||||
emitTop();
|
||||
v3Global.rootp()->accept(*this);
|
||||
emitBottom();
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// EmitC class functions
|
||||
|
||||
|
|
@ -2149,7 +2208,14 @@ void V3EmitC::emitc() {
|
|||
void V3EmitC::emitcTrace() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
if (v3Global.opt.trace()) {
|
||||
{ EmitCTrace trace (true); trace.main(); }
|
||||
{ EmitCTrace trace (false); trace.main(); }
|
||||
{ EmitCTrace imp (true); imp.main(); }
|
||||
{ EmitCTrace imp (false); imp.main(); }
|
||||
}
|
||||
}
|
||||
|
||||
void V3EmitC::emitcDpi() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
if (v3Global.dpi()) {
|
||||
{ EmitCDpi imp; imp.main(); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public:
|
|||
static void emitcInlines();
|
||||
static void emitcSyms();
|
||||
static void emitcTrace();
|
||||
static void emitcDpi();
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ public:
|
|||
of.puts(" += \\\n");
|
||||
if (support==2 && !slow) {
|
||||
putMakeClassEntry(of, "verilated.cpp");
|
||||
if (v3Global.dpi()) {
|
||||
putMakeClassEntry(of, "verilateddpi.cpp");
|
||||
}
|
||||
if (v3Global.opt.systemPerl()) {
|
||||
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
puts("endmodule\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
putbs(nodep->castTask() ? "task ":"function ");
|
||||
putbs(nodep->isFunction() ? "function":"task");
|
||||
puts(" ");
|
||||
puts(nodep->name());
|
||||
puts(";\n");
|
||||
putbs("begin\n");
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ class V3Global {
|
|||
AstNetlist* m_rootp; // Root of entire netlist
|
||||
int m_debugFileNumber; // Number to append to debug files created
|
||||
bool m_assertWidthsSame; // Tree should have width()==widthMin()
|
||||
bool m_needHInlines; // Need a __Inlines file
|
||||
bool m_needHInlines; // Need __Inlines file
|
||||
bool m_dpi; // Need __Dpi include files
|
||||
|
||||
public:
|
||||
// Options
|
||||
|
|
@ -56,6 +57,7 @@ public:
|
|||
m_debugFileNumber = 0;
|
||||
m_assertWidthsSame = false;
|
||||
m_needHInlines = false;
|
||||
m_dpi = false;
|
||||
}
|
||||
void clear() {
|
||||
if (m_rootp) m_rootp->deleteTree(); m_rootp=NULL;
|
||||
|
|
@ -76,6 +78,8 @@ public:
|
|||
}
|
||||
bool needHInlines() const { return m_needHInlines; }
|
||||
void needHInlines(bool flag) { m_needHInlines=flag; }
|
||||
bool dpi() const { return m_dpi; }
|
||||
void dpi(bool flag) { m_dpi = flag; }
|
||||
};
|
||||
|
||||
extern V3Global v3Global;
|
||||
|
|
|
|||
|
|
@ -405,10 +405,21 @@ private:
|
|||
nodep->funcp()->accept(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
//UINFO(4," CCALL "<<nodep<<endl);
|
||||
if (nodep->dpiImport() && !nodep->pure()) {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstCMath* nodep, AstNUser*) {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstVar*, AstNUser*) {} // Don't want varrefs under it
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -326,22 +326,21 @@ private:
|
|||
// Convert the func's range to the output variable
|
||||
// This should probably be done in the Parser instead, as then we could
|
||||
// just attact normal signal attributes to it.
|
||||
if (AstFunc* funcp = nodep->castFunc()) {
|
||||
if (!funcp->fvarp()->castVar()) {
|
||||
AstNodeDType* dtypep = funcp->fvarp()->castNodeDType();
|
||||
// If unspecified, function returns one bit; however when we support NEW() it could
|
||||
// also return the class reference.
|
||||
if (dtypep) dtypep->unlinkFrBack();
|
||||
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(), dtypep);
|
||||
newvarp->isSigned(funcp->isSigned());
|
||||
newvarp->funcReturn(true);
|
||||
newvarp->trace(false); // Not user visible
|
||||
newvarp->attrIsolateAssign(funcp->attrIsolateAssign());
|
||||
funcp->addFvarp(newvarp);
|
||||
// Explicit insert required, as the var name shadows the upper level's task name
|
||||
symsInsert(newvarp->name(), newvarp);
|
||||
}
|
||||
if (nodep->fvarp()
|
||||
&& !nodep->fvarp()->castVar()) {
|
||||
AstNodeDType* dtypep = nodep->fvarp()->castNodeDType();
|
||||
// If unspecified, function returns one bit; however when we support NEW() it could
|
||||
// also return the class reference.
|
||||
if (dtypep) dtypep->unlinkFrBack();
|
||||
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(), dtypep);
|
||||
newvarp->isSigned(nodep->isSigned());
|
||||
newvarp->funcReturn(true);
|
||||
newvarp->trace(false); // Not user visible
|
||||
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
|
||||
nodep->addFvarp(newvarp);
|
||||
// Explicit insert required, as the var name shadows the upper level's task name
|
||||
symsInsert(newvarp->name(), newvarp);
|
||||
}
|
||||
m_ftaskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class V3Lexer;
|
|||
|
||||
typedef enum { uniq_NONE, uniq_UNIQUE, uniq_PRIORITY } V3UniqState;
|
||||
|
||||
typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty;
|
||||
|
||||
//============================================================================
|
||||
// We can't use bison's %union as we want to pass the fileline with all tokens
|
||||
|
||||
|
|
@ -53,6 +55,7 @@ struct V3ParseBisonYYSType {
|
|||
double cdouble;
|
||||
V3UniqState uniqstate;
|
||||
AstSignedState signstate;
|
||||
V3ImportProperty iprop;
|
||||
|
||||
AstNode* nodep;
|
||||
|
||||
|
|
|
|||
|
|
@ -156,18 +156,14 @@ private:
|
|||
// However a later operation may have changed the node->signed w/o changing
|
||||
// the number's sign. So we don't: nodep->isSigned(nodep->num().isSigned());
|
||||
}
|
||||
virtual void visit(AstFunc* nodep, AstNUser*) {
|
||||
// Avoid recursion; can't use user() as they're all full, and anyhow this is often called
|
||||
if (nodep->didSigning()) return;
|
||||
nodep->didSigning(true);
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->signedFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()
|
||||
}
|
||||
virtual void visit(AstTask* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
// Avoid recursion; can't use user() as they're all full, and anyhow this is often called
|
||||
if (nodep->didSigning()) return;
|
||||
nodep->didSigning(true);
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->fvarp()) {
|
||||
nodep->signedFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
||||
checkNodeInfo(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
|
@ -505,9 +506,9 @@ private:
|
|||
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
||||
UINFO(5," FUNCREF "<<nodep<<endl);
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
AstFunc* funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
if (m_params) { V3Width::widthParamsEdit(funcp); } funcp=NULL; // Make sure we've sized the function
|
||||
funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
// Apply function call values to function
|
||||
// Note we'd need a stack if we allowed recursive functions!
|
||||
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
|
||||
|
|
@ -532,7 +533,8 @@ private:
|
|||
// Evaluate the function
|
||||
funcp->accept(*this);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
// Grab return value from output variable
|
||||
// Grab return value from output variable (if it's a function)
|
||||
if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function");
|
||||
newNumber(nodep)->opAssign(*fetchNumber(funcp->fvarp()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
250
src/V3Task.cpp
250
src/V3Task.cpp
|
|
@ -201,6 +201,7 @@ private:
|
|||
UINFO(9," TASK "<<nodep<<endl);
|
||||
TaskBaseVertex* lastVxp = m_curVxp;
|
||||
m_curVxp = getFTaskVertex(nodep);
|
||||
if (nodep->dpiImport()) m_curVxp->noInline(true);
|
||||
nodep->iterateChildren(*this);
|
||||
m_curVxp = lastVxp;
|
||||
}
|
||||
|
|
@ -304,14 +305,17 @@ private:
|
|||
IM_AFTER, // Pointing at last inserted stmt, insert after
|
||||
IM_WHILE_PRECOND // Pointing to for loop, add to body end
|
||||
};
|
||||
typedef map<string,pair<AstCFunc*,string> > DpiNames;
|
||||
|
||||
// STATE
|
||||
TaskStateVisitor* m_statep; // Common state between visitors
|
||||
TaskStateVisitor* m_statep; // Common state between visitors
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
InsertMode m_insMode; // How to insert
|
||||
AstNode* m_insStmtp; // Where to insert statement
|
||||
int m_modNCalls; // Incrementing func # for making symbols
|
||||
DpiNames m_dpiNames; // Map of all created DPI functions
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
|
|
@ -423,7 +427,7 @@ private:
|
|||
// Create function output variables
|
||||
if (outvscp) {
|
||||
//UINFO(0, "setflag on "<<funcp->fvarp()<<" to "<<outvscp<<endl);
|
||||
refp->taskp()->castFunc()->fvarp()->user2p(outvscp);
|
||||
refp->taskp()->fvarp()->user2p(outvscp);
|
||||
}
|
||||
// Replace variable refs
|
||||
// Iteration requires a back, so put under temporary node
|
||||
|
|
@ -487,7 +491,8 @@ private:
|
|||
}
|
||||
}
|
||||
// First argument is symbol table, then output if a function
|
||||
ccallp->argTypes("vlSymsp");
|
||||
bool needContext = !refp->taskp()->dpiImport() || refp->taskp()->dpiContext();
|
||||
if (needContext) ccallp->argTypes("vlSymsp");
|
||||
if (outvscp) {
|
||||
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
|
||||
}
|
||||
|
|
@ -503,23 +508,128 @@ private:
|
|||
return beginp;
|
||||
}
|
||||
|
||||
AstCFunc* makeDpiCFunc(AstNodeFTask* nodep, AstVar* rtnvarp) {
|
||||
if (nodep->cname() != AstNode::prettyName(nodep->cname())) {
|
||||
nodep->v3error("DPI function has illegal characters in C identifier name: "<<AstNode::prettyName(nodep->cname()));
|
||||
}
|
||||
AstCFunc* dpip = new AstCFunc(nodep->fileline(),
|
||||
nodep->cname(),
|
||||
m_scopep,
|
||||
(rtnvarp ? rtnvarp->dpiArgType(true,true)
|
||||
// Tasks (but not void functions) return bool indicating disabled
|
||||
: nodep->dpiTask() ? "int"
|
||||
: ""));
|
||||
dpip->dontCombine(true);
|
||||
dpip->entryPoint (false);
|
||||
dpip->funcPublic (true);
|
||||
dpip->isStatic (false);
|
||||
dpip->pure (nodep->pure());
|
||||
dpip->dpiImport (true);
|
||||
// Add DPI reference to top, since it's a global function
|
||||
m_topScopep->scopep()->addActivep(dpip);
|
||||
return dpip;
|
||||
}
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool forUser) {
|
||||
void bodyDpiCFunc(AstNodeFTask* nodep, AstVarScope* rtnvscp, AstCFunc* cfuncp) {
|
||||
// Convert input/inout arguments to DPI types
|
||||
string args;
|
||||
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
AstVarScope* portvscp = portp->user2p()->castNode()->castVarScope(); // Remembered when we created it earlier
|
||||
if (portp->isIO() && !portp->isFuncReturn() && portvscp != rtnvscp) {
|
||||
bool bitvec = (portp->basicp()->isBitLogic() && portp->width() > 32);
|
||||
|
||||
if (args != "") { args+= ", "; }
|
||||
if (bitvec) {}
|
||||
else if (portp->isOutput()) args += "&";
|
||||
else if (portp->basicp() && portp->basicp()->isBitLogic() && portp->widthMin() != 1) args += "&"; // it's a svBitVecVal
|
||||
|
||||
args += "__Vcvt_"+portp->name();
|
||||
|
||||
string stmt;
|
||||
if (bitvec) {
|
||||
stmt += "svBitVecVal __Vcvt_"+portp->name();
|
||||
stmt += " ["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
stmt += portp->dpiArgType(true,true);
|
||||
stmt += " __Vcvt_"+portp->name();
|
||||
}
|
||||
if (portp->isInput()) {
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
// But for now, we'll just text-bash it.
|
||||
if (bitvec) {
|
||||
// We only support quads, so don't need to sweat longer stuff
|
||||
stmt += "; VL_SET_WQ(__Vcvt_"+portp->name()+", "+portp->name()+")";
|
||||
} else {
|
||||
stmt += " = ";
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
stmt += "(void*)";
|
||||
}
|
||||
stmt += portp->name();
|
||||
}
|
||||
}
|
||||
stmt += ";\n";
|
||||
cfuncp->addStmtsp(new AstCStmt(portp->fileline(), stmt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store context, if needed
|
||||
if (nodep->dpiContext()) {
|
||||
// TBD
|
||||
}
|
||||
|
||||
{// Call the user function
|
||||
string stmt;
|
||||
if (rtnvscp) { // isFunction will no longer work as we unlinked the return var
|
||||
stmt += rtnvscp->varp()->dpiArgType(true,true) + " __Vcvt_"+rtnvscp->varp()->name() + " = ";
|
||||
}
|
||||
stmt += nodep->cname()+"("+args+");\n";
|
||||
cfuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
|
||||
// Convert output/inout arguments back to internal type
|
||||
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO()) {
|
||||
AstVarScope* portvscp = portp->user2p()->castNode()->castVarScope(); // Remembered when we created it earlier
|
||||
if (portp->isOutput() || portp->isFuncReturn()) {
|
||||
string stmt;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
stmt += "(QData)";
|
||||
}
|
||||
stmt += "__Vcvt_"+portp->name();
|
||||
// Use a AstCMath, as we want V3Clean to mask off bits that don't make sense.
|
||||
int cwidth = VL_WORDSIZE; if (portp->basicp()) cwidth = portp->basicp()->keyword().width();
|
||||
if (portp->basicp() && portp->basicp()->isBitLogic()) cwidth = VL_WORDSIZE*portp->widthWords();
|
||||
cfuncp->addStmtsp(new AstAssign(portp->fileline(),
|
||||
new AstVarRef(portp->fileline(), portvscp, true),
|
||||
new AstSel(portp->fileline(),
|
||||
new AstCMath(portp->fileline(), stmt, cwidth, false),
|
||||
0, portp->width())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool ftaskNoInline) {
|
||||
// Given a already cloned node, make a public C function, or a non-inline C function
|
||||
// Probably some of this work should be done later, but...
|
||||
// should the type of the function be bool/uint32/64 etc (based on lookup) or IData?
|
||||
AstNode::user2ClearTree();
|
||||
AstVar* rtnvarp = NULL;
|
||||
AstVarScope* rtnvscp = NULL;
|
||||
if (nodep->castFunc()) {
|
||||
if (nodep->isFunction()) {
|
||||
AstVar* portp = NULL;
|
||||
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
|
||||
if (NULL!=(portp = nodep->fvarp()->castVar())) {
|
||||
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
|
||||
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
|
||||
if (!forUser) portp->funcReturn(false); // Converting return to 'outputs'
|
||||
if (ftaskNoInline) portp->funcReturn(false); // Converting return to 'outputs'
|
||||
portp->unlinkFrBack();
|
||||
rtnvarp = portp;
|
||||
rtnvarp->funcLocal(true);
|
||||
rtnvarp->name(rtnvarp->name()+"__Vfuncrtn"); // Avoid conflict with DPI function name
|
||||
rtnvscp = new AstVarScope (rtnvarp->fileline(), m_scopep, rtnvarp);
|
||||
m_scopep->addVarp(rtnvscp);
|
||||
rtnvarp->user2p(rtnvscp);
|
||||
|
|
@ -527,30 +637,58 @@ private:
|
|||
nodep->v3fatalSrc("function without function output variable");
|
||||
}
|
||||
}
|
||||
string prefix = "";
|
||||
if (nodep->dpiImport()) prefix = "__Vdpiimwrap_";
|
||||
else if (ftaskNoInline) prefix = "__VnoInFunc_";
|
||||
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
|
||||
string(forUser?"":"__VnoInFunc_") + nodep->name(),
|
||||
prefix + nodep->name(),
|
||||
m_scopep,
|
||||
((forUser && rtnvarp)?rtnvarp->cType():""));
|
||||
cfuncp->dontCombine(true);
|
||||
cfuncp->entryPoint(true);
|
||||
cfuncp->funcPublic(forUser);
|
||||
cfuncp->isStatic(!forUser);
|
||||
((nodep->taskPublic() && rtnvarp)?rtnvarp->cpubArgType(true,true):""));
|
||||
// It's ok to combine imports because this is just a wrapper; duplicate wrappers can get merged.
|
||||
cfuncp->dontCombine(!nodep->dpiImport());
|
||||
cfuncp->entryPoint (!nodep->dpiImport());
|
||||
cfuncp->funcPublic (nodep->taskPublic());
|
||||
cfuncp->isStatic (!(nodep->dpiImport()||nodep->taskPublic()));
|
||||
cfuncp->pure (nodep->pure());
|
||||
//cfuncp->dpiImport // Not set in the wrapper - the called function has it set
|
||||
|
||||
if (forUser) {
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
cfuncp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
} else {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
bool needContext = !nodep->dpiImport() || nodep->dpiContext();
|
||||
if (needContext) {
|
||||
if (nodep->taskPublic()) {
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
cfuncp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
} else {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
}
|
||||
}
|
||||
// Fake output variable if was a function
|
||||
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
||||
|
||||
cfuncp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
if (!nodep->dpiImport()) {
|
||||
cfuncp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
}
|
||||
|
||||
AstCFunc* dpip = NULL;
|
||||
string dpiproto;
|
||||
if (nodep->dpiImport()) {
|
||||
if (nodep->pure()) dpiproto += "pure ";
|
||||
if (nodep->dpiContext()) dpiproto += "context ";
|
||||
dpiproto += rtnvarp ? rtnvarp->dpiArgType(true,true):"void";
|
||||
dpiproto += " "+nodep->cname()+" (";
|
||||
|
||||
// Only create one DPI extern for each specified cname,
|
||||
// as it's legal for the user to attach multiple tasks to one dpi cname
|
||||
if (m_dpiNames.find(nodep->cname()) == m_dpiNames.end()) {
|
||||
// m_dpiNames insert below
|
||||
dpip = makeDpiCFunc(nodep, rtnvarp);
|
||||
}
|
||||
}
|
||||
|
||||
// Create list of arguments and move to function
|
||||
string args;
|
||||
for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) {
|
||||
nextp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
|
|
@ -559,6 +697,18 @@ private:
|
|||
portp->unlinkFrBack();
|
||||
portp->funcLocal(true);
|
||||
cfuncp->addArgsp(portp);
|
||||
if (dpip) {
|
||||
dpip->addArgsp(portp->cloneTree(false));
|
||||
if (!portp->basicp() || portp->basicp()->keyword().isDpiUnsupported()) {
|
||||
portp->v3error("Unsupported: DPI argument of type "<<portp->basicp()->prettyTypeName());
|
||||
portp->v3error("... For best portability, use bit, byte, int, or longint");
|
||||
}
|
||||
}
|
||||
if (!portp->isFuncReturn()) {
|
||||
if (args != "") { args+= ", "; dpiproto+= ", "; }
|
||||
args += portp->name(); // Leftover so ,'s look nice
|
||||
if (nodep->dpiImport()) dpiproto += portp->dpiArgType(false,false);
|
||||
}
|
||||
} else {
|
||||
// "Normal" variable, mark inside function
|
||||
portp->funcLocal(true);
|
||||
|
|
@ -568,11 +718,30 @@ private:
|
|||
portp->user2p(newvscp);
|
||||
}
|
||||
}
|
||||
dpiproto += ")";
|
||||
|
||||
if (nodep->dpiImport()) {
|
||||
// Only create one DPI extern for each specified cname,
|
||||
// as it's legal for the user to attach multiple tasks to one dpi cname
|
||||
DpiNames::iterator iter = m_dpiNames.find(nodep->cname());
|
||||
if (iter == m_dpiNames.end()) {
|
||||
m_dpiNames.insert(make_pair(nodep->cname(), make_pair(dpip, dpiproto)));
|
||||
} else if (iter->second.second != dpiproto) {
|
||||
nodep->v3error("Duplicate declaration of DPI function with different formal arguments: "<<nodep->prettyName());
|
||||
nodep->v3error("... New prototype: "<<dpiproto);
|
||||
iter->second.first->v3error("... Original prototype: "<<iter->second.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Move body
|
||||
AstNode* bodysp = nodep->stmtsp();
|
||||
if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); }
|
||||
if (nodep->dpiImport()) {
|
||||
bodyDpiCFunc(nodep, rtnvscp, cfuncp);
|
||||
}
|
||||
|
||||
// Return statement
|
||||
if (rtnvscp && forUser) {
|
||||
if (rtnvscp && nodep->taskPublic()) {
|
||||
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
|
||||
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
|
||||
}
|
||||
|
|
@ -585,8 +754,7 @@ private:
|
|||
}
|
||||
// Delete rest of cloned task and return new func
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
|
||||
if (debug()>=9 && !forUser) { cfuncp->dumpTree(cout,"-noInFunc: "); }
|
||||
if (debug()>=9) { cfuncp->dumpTree(cout,"-userFunc: "); }
|
||||
return cfuncp;
|
||||
}
|
||||
|
||||
|
|
@ -633,6 +801,10 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstTopScope* nodep, AstNUser*) {
|
||||
m_topScopep = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
m_scopep = nodep;
|
||||
m_insStmtp = NULL;
|
||||
|
|
@ -659,12 +831,13 @@ private:
|
|||
UINFO(4," Func REF "<<nodep<<endl);
|
||||
if (debug()>=9) { nodep->dumpTree(cout,"-preref:"); }
|
||||
// First, do hierarchical funcs
|
||||
AstFunc* funcp = nodep->taskp()->castFunc();
|
||||
AstNodeFTask* funcp = nodep->taskp();
|
||||
if (!funcp) nodep->v3fatalSrc("unlinked");
|
||||
if (!funcp->isFunction()) nodep->v3fatalSrc("func reference to non-function");
|
||||
// Inline func refs in the function
|
||||
iterateIntoFTask(funcp);
|
||||
// Create output variable
|
||||
string namePrefix = "__Vfunc_"+funcp->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
||||
namePrefix+"__out");
|
||||
// Create cloned statements
|
||||
|
|
@ -693,30 +866,26 @@ private:
|
|||
AstNode* prevInsStmtp = m_insStmtp;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||
if (!nodep->user1()) {
|
||||
if (!nodep->user1()) { // Just one creation needed per function
|
||||
// Expand functions in it
|
||||
nodep->user1(true);
|
||||
if (nodep->taskPublic()) {
|
||||
if (nodep->dpiImport() || nodep->taskPublic() || m_statep->ftaskNoInline(nodep)) {
|
||||
// Clone it first, because we may have later FTaskRef's that still need
|
||||
// the original version.
|
||||
if (m_statep->ftaskNoInline(nodep)) m_statep->checkPurity(nodep);
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false);
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, true);
|
||||
nodep->addNextHere(cfuncp);
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
if (m_statep->ftaskNoInline(nodep)) {
|
||||
m_statep->checkPurity(nodep);
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false);
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
|
||||
m_statep->ftaskCFuncp(nodep, cfuncp);
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, m_statep->ftaskNoInline(nodep));
|
||||
nodep->addNextHere(cfuncp);
|
||||
if (nodep->dpiImport() || m_statep->ftaskNoInline(nodep)) {
|
||||
m_statep->ftaskCFuncp(nodep, cfuncp);
|
||||
}
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
|
||||
// Any variables inside the function still have varscopes pointing to them.
|
||||
// We're going to delete the vars, so delete the varscopes.
|
||||
if (nodep->castFunc()) {
|
||||
if (AstVar* portp = nodep->castFunc()->fvarp()->castVar()) {
|
||||
if (nodep->isFunction()) {
|
||||
if (AstVar* portp = nodep->fvarp()->castVar()) {
|
||||
AstVarScope* vscp = m_statep->findVarScope(m_scopep, portp);
|
||||
UINFO(9," funcremovevsc "<<vscp<<endl);
|
||||
pushDeletep(vscp->unlinkFrBack()); vscp=NULL;
|
||||
|
|
@ -773,6 +942,7 @@ public:
|
|||
TaskVisitor(AstNetlist* nodep, TaskStateVisitor* statep)
|
||||
: m_statep(statep) {
|
||||
m_modp = NULL;
|
||||
m_topScopep = NULL;
|
||||
m_scopep = NULL;
|
||||
m_insStmtp = NULL;
|
||||
AstNode::user1ClearTree();
|
||||
|
|
|
|||
|
|
@ -855,13 +855,15 @@ private:
|
|||
nodep->paramsp()->iterateAndNext(*this);
|
||||
m_cellRangep = NULL;
|
||||
}
|
||||
virtual void visit(AstFunc* nodep, AstNUser* vup) {
|
||||
// Grab width from the output variable
|
||||
UINFO(5," FUNC "<<nodep<<endl);
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser* vup) {
|
||||
// Grab width from the output variable (if it's a function)
|
||||
UINFO(5," FTASK "<<nodep<<endl);
|
||||
if (nodep->width()==0) {
|
||||
// Function hasn't been widthed, so make it so.
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
||||
if (nodep->fvarp()) {
|
||||
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFuncRef* nodep, AstNUser* vup) {
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ void process () {
|
|||
V3EmitC::emitcInlines();
|
||||
V3EmitC::emitcSyms();
|
||||
V3EmitC::emitcTrace();
|
||||
V3EmitC::emitcDpi();
|
||||
}
|
||||
// Unfortunately we have some lint checks in emitc.
|
||||
V3EmitC::emitc();
|
||||
|
|
|
|||
|
|
@ -369,11 +369,13 @@ escid \\[^ \t\f\r\n]+
|
|||
"byte" { FL; return yBYTE; }
|
||||
"chandle" { FL; return yCHANDLE; }
|
||||
"clocking" { FL; return yCLOCKING; }
|
||||
"context" { FL; return yCONTEXT; }
|
||||
"do" { FL; return yDO; }
|
||||
"endclocking" { FL; return yENDCLOCKING; }
|
||||
"endpackage" { FL; return yENDPACKAGE; }
|
||||
"endprogram" { FL; return yENDPROGRAM; }
|
||||
"endproperty" { FL; return yENDPROPERTY; }
|
||||
"export" { FL; return yEXPORT; }
|
||||
"final" { FL; return yFINAL; }
|
||||
"iff" { FL; return yIFF; }
|
||||
"import" { FL; return yIMPORT; }
|
||||
|
|
@ -383,6 +385,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"package" { FL; return yPACKAGE; }
|
||||
"priority" { FL; return yPRIORITY; }
|
||||
"program" { FL; return yPROGRAM; }
|
||||
"pure" { FL; return yPURE; }
|
||||
"shortint" { FL; return ySHORTINT; }
|
||||
"static" { FL; return ySTATIC; }
|
||||
"timeprecision" { FL; return yTIMEPRECISION; }
|
||||
|
|
@ -401,7 +404,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"break" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"context" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"continue" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"covergroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"coverpoint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
|
|
@ -413,7 +415,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"enum" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"export" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"extern" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"first_match" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
|
|
@ -433,7 +434,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"packed" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"pure" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"rand" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randc" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randcase" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
|
|
|
|||
|
|
@ -131,6 +131,9 @@ public:
|
|||
}
|
||||
}
|
||||
string deQuote(FileLine* fileline, string text);
|
||||
void checkDpiVer(FileLine* fileline, const string& str) {
|
||||
if (str != "DPI-C") { fileline->v3error("Unsupported DPI type '"<<str<<"': Use 'DPI-C'"); }
|
||||
}
|
||||
};
|
||||
|
||||
const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC"
|
||||
|
|
@ -250,6 +253,7 @@ class AstSenTree;
|
|||
%token<fl> yCASEZ "casez"
|
||||
%token<fl> yCHANDLE "chandle"
|
||||
%token<fl> yCLOCKING "clocking"
|
||||
%token<fl> yCONTEXT "context"
|
||||
%token<fl> yCOVER "cover"
|
||||
%token<fl> yDEFAULT "default"
|
||||
%token<fl> yDEFPARAM "defparam"
|
||||
|
|
@ -269,6 +273,7 @@ class AstSenTree;
|
|||
%token<fl> yENDSPECIFY "endspecify"
|
||||
%token<fl> yENDTABLE "endtable"
|
||||
%token<fl> yENDTASK "endtask"
|
||||
%token<fl> yEXPORT "export"
|
||||
%token<fl> yFINAL "final"
|
||||
%token<fl> yFOR "for"
|
||||
%token<fl> yFOREVER "forever"
|
||||
|
|
@ -304,6 +309,7 @@ class AstSenTree;
|
|||
%token<fl> yPROPERTY "property"
|
||||
%token<fl> yPULLDOWN "pulldown"
|
||||
%token<fl> yPULLUP "pullup"
|
||||
%token<fl> yPURE "pure"
|
||||
%token<fl> yREG "reg"
|
||||
%token<fl> yREPEAT "repeat"
|
||||
%token<fl> ySCALARED "scalared"
|
||||
|
|
@ -594,7 +600,7 @@ package_or_generate_item_declaration<nodep>: // ==IEEE: package_or_generate_item
|
|||
| data_declaration { $$ = $1; }
|
||||
| task_declaration { $$ = $1; }
|
||||
| function_declaration { $$ = $1; }
|
||||
//UNSUP dpi_import_export { $$ = $1; }
|
||||
| dpi_import_export { $$ = $1; }
|
||||
//UNSUP extern_constraint_declaration { $$ = $1; }
|
||||
//UNSUP class_declaration { $$ = $1; }
|
||||
// // class_constructor_declaration is part of function_declaration
|
||||
|
|
@ -1993,12 +1999,20 @@ task_declaration<ftaskp>: // ==IEEE: task_declaration
|
|||
{ $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); }
|
||||
;
|
||||
|
||||
task_prototype<ftaskp>: // ==IEEE: task_prototype
|
||||
yTASK taskId '(' tf_port_listE ')' { $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
|
||||
;
|
||||
|
||||
function_declaration<ftaskp>: // IEEE: function_declaration + function_body_declaration
|
||||
yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE
|
||||
{ $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5);
|
||||
SYMP->popScope($$); }
|
||||
;
|
||||
|
||||
function_prototype<ftaskp>: // IEEE: function_prototype
|
||||
yFUNCTION funcId '(' tf_port_listE ')' { $$=$2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); }
|
||||
;
|
||||
|
||||
funcIsolateE<cint>:
|
||||
/* empty */ { $$ = 0; }
|
||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
|
||||
|
|
@ -2137,6 +2151,30 @@ parenE:
|
|||
// // method_call_root not needed, part of expr resolution
|
||||
// // What's left is below array_methodNoRoot
|
||||
|
||||
dpi_import_export<nodep>: // ==IEEE: dpi_import_export
|
||||
yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';'
|
||||
{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
||||
$5->dpiImport(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
||||
| yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';'
|
||||
{ $$ = $5; if (*$4!="") $5->cname(*$4); $5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
||||
$5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
||||
| yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';' { $$ = new AstDpiExport($1,*$5,*$3);
|
||||
GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
||||
| yEXPORT yaSTRING dpi_importLabelE yTASK idAny ';' { $$ = new AstDpiExport($1,*$5,*$3);
|
||||
GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true); }
|
||||
;
|
||||
|
||||
dpi_importLabelE<strp>: // IEEE: part of dpi_import_export
|
||||
/* empty */ { static string s = ""; $$ = &s; }
|
||||
| idAny/*c_identifier*/ '=' { $$ = $1; $<fl>$=$<fl>1; }
|
||||
;
|
||||
|
||||
dpi_tf_import_propertyE<iprop>: // IEEE: [ dpi_function_import_property + dpi_task_import_property ]
|
||||
/* empty */ { $$ = iprop_NONE; }
|
||||
| yCONTEXT { $$ = iprop_CONTEXT; }
|
||||
| yPURE { $$ = iprop_PURE; }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// Expressions
|
||||
//
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ endif
|
|||
|
||||
#######################################################################
|
||||
|
||||
# Needed by DPI tests
|
||||
CPPFLAGS += -DVERILATOR=1
|
||||
|
||||
# Needed by tracing routines
|
||||
CPPFLAGS += -DVL_DEBUG=1
|
||||
CPPFLAGS += -DVM_PREFIX=$(VM_PREFIX)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_dup_bad.v:\d+: Duplicate declaration of DPI function with different formal arguments: v.oth_f_int2
|
||||
%Error: t/t_dpi_dup_bad.v:\d+: ... New prototype: pure int dpii_fa_bit \(int, int\)
|
||||
%Error: t/t_dpi_dup_bad.v:\d+: ... Original prototype: int dpii_fa_bit \(int\)
|
||||
%Error: Exiting due to .*'
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t ();
|
||||
|
||||
// Same name w/ different args
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int1(input int i);
|
||||
import "DPI-C" pure dpii_fa_bit = function int oth_f_int2(input int i, input int bad);
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
# Amazingly VCS, NC and Verilator all just accept the C file here!
|
||||
v_flags2 => ["t/t_dpi_import_c.cpp"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t ();
|
||||
|
||||
// Allowed import return types:
|
||||
// void, byte, shortint, int, longint, real, shortreal, chandle, and string
|
||||
// Scalar bit and logic
|
||||
//
|
||||
// Allowed argument types:
|
||||
// Same as above plus packed arrays
|
||||
|
||||
import "DPI-C" pure function bit dpii_f_bit (input bit i);
|
||||
import "DPI-C" pure function bit [8-1:0] dpii_f_bit8 (input bit [8-1:0] i);
|
||||
import "DPI-C" pure function bit [9-1:0] dpii_f_bit9 (input bit [9-1:0] i);
|
||||
import "DPI-C" pure function bit [16-1:0] dpii_f_bit16 (input bit [16-1:0] i);
|
||||
import "DPI-C" pure function bit [17-1:0] dpii_f_bit17 (input bit [17-1:0] i);
|
||||
import "DPI-C" pure function bit [32-1:0] dpii_f_bit32 (input bit [32-1:0] i);
|
||||
// Illegal to return > 32 bits, so we use longint
|
||||
import "DPI-C" pure function longint dpii_f_bit33 (input bit [33-1:0] i);
|
||||
import "DPI-C" pure function longint dpii_f_bit64 (input bit [64-1:0] i);
|
||||
import "DPI-C" pure function int dpii_f_int (input int i);
|
||||
import "DPI-C" pure function byte dpii_f_byte (input byte i);
|
||||
import "DPI-C" pure function shortint dpii_f_shortint (input shortint i);
|
||||
import "DPI-C" pure function longint dpii_f_longint (input longint i);
|
||||
import "DPI-C" pure function chandle dpii_f_chandle (input chandle i);
|
||||
//import "DPI-C" pure function real dpii_f_real (input real i);
|
||||
//import "DPI-C" pure function shortreal dpii_f_shortreal (input shortreal i);
|
||||
//import "DPI-C" pure function string dpii_f_string (input string i);
|
||||
|
||||
import "DPI-C" pure function void dpii_v_bit (input bit i, output bit o);
|
||||
import "DPI-C" pure function void dpii_v_int (input int i, output int o);
|
||||
import "DPI-C" pure function void dpii_v_byte (input byte i, output byte o);
|
||||
import "DPI-C" pure function void dpii_v_shortint (input shortint i, output shortint o);
|
||||
import "DPI-C" pure function void dpii_v_longint (input longint i, output longint o);
|
||||
import "DPI-C" pure function void dpii_v_chandle (input chandle i, output chandle o);
|
||||
//import "DPI-C" pure function void dpii_v_real (input real i, output real o);
|
||||
//import "DPI-C" pure function void dpii_v_shortreal(input shortreal i, output shortreal o);
|
||||
//import "DPI-C" pure function void dpii_v_string (input string i, output string o);
|
||||
|
||||
import "DPI-C" function void dpii_f_void ();
|
||||
|
||||
// Try a task
|
||||
import "DPI-C" task dpii_t_void ();
|
||||
import "DPI-C" context task dpii_t_void_context ();
|
||||
|
||||
import "DPI-C" task dpii_t_int (input int i, output int o);
|
||||
|
||||
// Try non-pure, aliasing with name
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int1(input int i);
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int2(input int i);
|
||||
|
||||
// Try context
|
||||
import "DPI-C" context function int dpii_context();
|
||||
|
||||
bit i_b, o_b;
|
||||
bit [7:0] i_b8, o_b8;
|
||||
bit [8:0] i_b9, o_b9;
|
||||
bit [15:0] i_b16, o_b16;
|
||||
bit [16:0] i_b17, o_b17;
|
||||
bit [31:0] i_b32, o_b32;
|
||||
bit [32:0] i_b33, o_b33;
|
||||
bit [63:0] i_b64, o_b64;
|
||||
|
||||
int i_i, o_i;
|
||||
byte i_y, o_y;
|
||||
shortint i_s, o_s;
|
||||
longint i_l, o_l;
|
||||
chandle i_c, o_c;
|
||||
|
||||
bit [127:0] wide;
|
||||
|
||||
initial begin
|
||||
wide = 128'h36f3e51d15caff7a73c48afee4ffcb57;
|
||||
|
||||
i_b = 1'b1;
|
||||
i_b8 = {1'b1,wide[8-2:0]};
|
||||
i_b9 = {1'b1,wide[9-2:0]};
|
||||
i_b16 = {1'b1,wide[16-2:0]};
|
||||
i_b17 = {1'b1,wide[17-2:0]};
|
||||
i_b32 = {1'b1,wide[32-2:0]};
|
||||
i_b33 = {1'b1,wide[33-2:0]};
|
||||
i_b64 = {1'b1,wide[64-2:0]};
|
||||
|
||||
i_i = {1'b1,wide[32-2:0]};
|
||||
i_y = {1'b1,wide[8-2:0]};
|
||||
i_s = {1'b1,wide[16-2:0]};
|
||||
i_l = {1'b1,wide[64-2:0]};
|
||||
|
||||
if (dpii_f_bit (i_b) !== ~i_b) $stop;
|
||||
if (dpii_f_bit8 (i_b8) !== ~i_b8) $stop;
|
||||
if (dpii_f_bit9 (i_b9) !== ~i_b9) $stop;
|
||||
if (dpii_f_bit16 (i_b16) !== ~i_b16) $stop;
|
||||
if (dpii_f_bit17 (i_b17) !== ~i_b17) $stop;
|
||||
if (dpii_f_bit32 (i_b32) !== ~i_b32) $stop;
|
||||
|
||||
// These return different sizes, so we need to truncate
|
||||
// verilator lint_off WIDTH
|
||||
o_b33 = dpii_f_bit33 (i_b33);
|
||||
o_b64 = dpii_f_bit64 (i_b64);
|
||||
// verilator lint_on WIDTH
|
||||
if (o_b33 !== ~i_b33) $stop;
|
||||
if (o_b64 !== ~i_b64) $stop;
|
||||
|
||||
if (dpii_f_bit (i_b) !== ~i_b) $stop;
|
||||
if (dpii_f_int (i_i) !== ~i_i) $stop;
|
||||
if (dpii_f_byte (i_y) !== ~i_y) $stop;
|
||||
if (dpii_f_shortint(i_s) !== ~i_s) $stop;
|
||||
if (dpii_f_longint (i_l) !== ~i_l) $stop;
|
||||
if (dpii_f_chandle (i_c) !== i_c) $stop;
|
||||
|
||||
dpii_v_bit (i_b,o_b); if (o_b !== ~i_b) $stop;
|
||||
dpii_v_int (i_i,o_i); if (o_i !== ~i_i) $stop;
|
||||
dpii_v_byte (i_y,o_y); if (o_y !== ~i_y) $stop;
|
||||
dpii_v_shortint(i_s,o_s); if (o_s !== ~i_s) $stop;
|
||||
dpii_v_longint (i_l,o_l); if (o_l !== ~i_l) $stop;
|
||||
dpii_v_chandle (i_c,o_c); if (o_c !== i_c) $stop;
|
||||
|
||||
dpii_f_void();
|
||||
dpii_t_void();
|
||||
dpii_t_void_context();
|
||||
|
||||
i_i = 32'h456789ab;
|
||||
dpii_t_int (i_i,o_i); if (o_b !== ~i_b) $stop;
|
||||
|
||||
// Check alias
|
||||
if (oth_f_int1(32'd123) !== ~32'd123) $stop;
|
||||
if (oth_f_int2(32'd124) !== ~32'd124) $stop;
|
||||
|
||||
`ifndef verilator // Not all sims support SV2009 `__LINE__, and some that do fail the specific-line test
|
||||
if (!dpii_context()) $stop;
|
||||
`else
|
||||
//UNSUP if (dpii_context() !== `__LINE__) $stop;
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include <stdio.h>
|
||||
#include <svdpi.h>
|
||||
|
||||
//======================================================================
|
||||
|
||||
#if defined(VERILATOR)
|
||||
# include "Vt_dpi_import__Dpi.h"
|
||||
#elif defined(VCS)
|
||||
# include "../vc_hdrs.h"
|
||||
#elif defined(CADENCE)
|
||||
# define NEED_EXTERNS
|
||||
#else
|
||||
# error "Unknown simulator for DPI test"
|
||||
#endif
|
||||
|
||||
#ifdef NEED_EXTERNS
|
||||
extern "C" {
|
||||
|
||||
extern unsigned char dpii_f_bit (unsigned char i);
|
||||
extern svBitVecVal dpii_f_bit8 (const svBitVecVal *i);
|
||||
extern svBitVecVal dpii_f_bit9 (const svBitVecVal *i);
|
||||
extern svBitVecVal dpii_f_bit16 (const svBitVecVal *i);
|
||||
extern svBitVecVal dpii_f_bit17 (const svBitVecVal *i);
|
||||
extern svBitVecVal dpii_f_bit32 (const svBitVecVal *i);
|
||||
extern long long dpii_f_bit33 (const svBitVecVal *i);
|
||||
extern long long dpii_f_bit64 (const svBitVecVal *i);
|
||||
extern int dpii_f_int (int i);
|
||||
extern char dpii_f_byte (char i);
|
||||
extern short int dpii_f_shortint(short int i);
|
||||
extern long long dpii_f_longint (long long i);
|
||||
extern void* dpii_f_chandle (void* i);
|
||||
|
||||
extern void dpii_v_bit (unsigned char i, unsigned char *o);
|
||||
extern void dpii_v_int (int i, int *o);
|
||||
extern void dpii_v_byte (char i, char *o);
|
||||
extern void dpii_v_shortint (short int i, short int *o);
|
||||
extern void dpii_v_longint (long long i, long long *o);
|
||||
extern void dpii_v_chandle (void* i, void* *o);
|
||||
|
||||
extern void dpii_f_void ();
|
||||
extern int dpii_t_void ();
|
||||
extern int dpii_t_void_context ();
|
||||
extern int dpii_t_int (int i, int *o);
|
||||
|
||||
extern int dpii_fa_bit(int i);
|
||||
|
||||
extern int dpii_context();
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
unsigned char dpii_f_bit (unsigned char i) { return SV_MASK(1) & ~i; }
|
||||
svBitVecVal dpii_f_bit8 (const svBitVecVal *i) { return SV_MASK(8) & ~*i; }
|
||||
svBitVecVal dpii_f_bit9 (const svBitVecVal *i) { return SV_MASK(9) & ~*i; }
|
||||
svBitVecVal dpii_f_bit16(const svBitVecVal *i) { return SV_MASK(16) & ~*i; }
|
||||
svBitVecVal dpii_f_bit17(const svBitVecVal *i) { return SV_MASK(17) & ~*i; }
|
||||
svBitVecVal dpii_f_bit32(const svBitVecVal *i) { return ~*i; }
|
||||
long long dpii_f_bit33(const svBitVecVal *i) { return ((1ULL<<33)-1) & ~((long long)(i[1])<<32ULL | i[0]); }
|
||||
long long dpii_f_bit64(const svBitVecVal *i) { return ~((long long)(i[1])<<32ULL | i[0]); }
|
||||
|
||||
int dpii_f_int (int i) { return ~i; }
|
||||
char dpii_f_byte (char i) { return ~i; }
|
||||
short int dpii_f_shortint(short int i) { return ~i; }
|
||||
long long dpii_f_longint (long long i) { return ~i; }
|
||||
void* dpii_f_chandle (void* i) { return i; }
|
||||
|
||||
void dpii_v_bit (unsigned char i, unsigned char *o) { *o = SV_MASK(1) & ~i; }
|
||||
void dpii_v_int (int i, int *o) { *o = ~i; }
|
||||
void dpii_v_byte (char i, char *o) { *o = ~i; }
|
||||
void dpii_v_shortint (short int i, short int *o) { *o = ~i; }
|
||||
void dpii_v_longint (long long i, long long *o) { *o = ~i; }
|
||||
void dpii_v_chandle (void* i, void* *o) { *o = i; }
|
||||
|
||||
//======================================================================
|
||||
|
||||
void dpii_f_void () {}
|
||||
|
||||
#ifdef VCS
|
||||
void dpii_t_void () {}
|
||||
void dpii_t_void_context () {}
|
||||
void dpii_t_int (int i, int *o) {
|
||||
*o = i;
|
||||
}
|
||||
#else
|
||||
int dpii_t_void () { return svIsDisabledState(); }
|
||||
int dpii_t_void_context () { return svIsDisabledState(); }
|
||||
int dpii_t_int (int i, int *o) {
|
||||
*o = i;
|
||||
return svIsDisabledState(); // Tasks generally need this
|
||||
}
|
||||
#endif
|
||||
|
||||
int dpii_fa_bit (int i) {
|
||||
return ~i;
|
||||
}
|
||||
|
||||
int dpii_context() {
|
||||
const char* filename = "";
|
||||
int lineno = 0;
|
||||
if (svGetCallerInfo(&filename, &lineno)) {
|
||||
return lineno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_logic_bad.v:\d+: Unsupported: DPI argument of type .*
|
||||
%Error: t/t_dpi_logic_bad.v:\d+: ... For best portability, use bit, byte, int, or longint
|
||||
%Error: Exiting due to .*'
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t ();
|
||||
|
||||
// Can't handle logic (yet?)
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int1(input logic [2:0] i);
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_name_bad.v:\d+: DPI function has illegal characters in C identifier name: badly.named
|
||||
%Error: Exiting due to .*'
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t ();
|
||||
|
||||
// Can't handle logic (yet?)
|
||||
import "DPI-C" function int \badly.named (int i);
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue