DPI import: Allow system calls to call imports
This commit is contained in:
parent
a40fae04ce
commit
5a9309de78
|
|
@ -1148,6 +1148,14 @@ command line, or the link), you'd then:
|
|||
#include "Vour__Dpi.h"
|
||||
int add (int a, int b) { return a+b; }
|
||||
|
||||
Verilator also extends the DPI format to allow using the same scheme to
|
||||
efficiently add system functions. Simply use a dollar-sign prefixed system
|
||||
function name for the import, but note it must be escaped.
|
||||
|
||||
export "DPI-C" function integer \$myRand;
|
||||
|
||||
initial $display("myRand=%d", $myRand());
|
||||
|
||||
=head1 CROSS COMPILATION
|
||||
|
||||
Verilator supports cross-compiling Verilated code. This is generally used
|
||||
|
|
|
|||
14
src/V3Ast.h
14
src/V3Ast.h
|
|
@ -206,6 +206,8 @@ public:
|
|||
enum en {
|
||||
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
|
||||
REAL, REALTIME, SHORTINT, SHORTREAL, TIME,
|
||||
// Closer to a class type, but limited usage
|
||||
STRING,
|
||||
// Internal types
|
||||
LOGIC_IMPLICIT
|
||||
};
|
||||
|
|
@ -214,6 +216,7 @@ public:
|
|||
static const char* names[] = {
|
||||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "realtime", "shortint", "shortreal", "time",
|
||||
"string",
|
||||
"LOGIC_IMPLICIT"
|
||||
};
|
||||
return names[m_e];
|
||||
|
|
@ -222,6 +225,7 @@ public:
|
|||
static const char* names[] = {
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
"char*",
|
||||
""
|
||||
};
|
||||
return names[m_e];
|
||||
|
|
@ -241,6 +245,7 @@ public:
|
|||
case LONGINT: return 64;
|
||||
case SHORTINT: return 16;
|
||||
case TIME: return 64;
|
||||
case STRING: return 64; // Just the pointer, for today
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -251,7 +256,8 @@ public:
|
|||
return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT;
|
||||
}
|
||||
int isZeroInit() const { // Otherwise initializes to X
|
||||
return m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT;
|
||||
return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|
||||
|| m_e==STRING);
|
||||
}
|
||||
int isSloppy() const { // Don't be as anal about width warnings
|
||||
return !(m_e==LOGIC || m_e==BIT);
|
||||
|
|
@ -1250,7 +1256,6 @@ private:
|
|||
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)
|
||||
|
|
@ -1306,6 +1311,11 @@ public:
|
|||
, m_taskp(NULL), m_packagep(NULL) {
|
||||
setOp1p(namep); addNOp2p(pinsp);
|
||||
}
|
||||
AstNodeFTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNode(fl)
|
||||
, m_taskp(NULL), m_name(name), m_packagep(NULL) {
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFTaskRef)
|
||||
virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
|
||||
virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) {
|
||||
|
|
|
|||
|
|
@ -973,6 +973,8 @@ struct AstTaskRef : public AstNodeFTaskRef {
|
|||
// A reference to a task
|
||||
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
ASTNODE_NODE_FUNCS(TaskRef, TASKREF)
|
||||
};
|
||||
|
||||
|
|
@ -980,6 +982,8 @@ struct AstFuncRef : public AstNodeFTaskRef {
|
|||
// A reference to a function
|
||||
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
ASTNODE_NODE_FUNCS(FuncRef, FUNCREF)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -439,6 +439,14 @@ private:
|
|||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep, AstNUser*) {
|
||||
if (m_idState==ID_RESOLVE && nodep->keyword()==AstBasicDTypeKwd::STRING) {
|
||||
if (!(m_ftaskp && m_ftaskp->dpiImport() && 0/*UNIMP*/)) {
|
||||
nodep->v3error("Unsupported: SystemVerilog 'string' anywhere but DPI import __format");
|
||||
}
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
// Cell: Resolve its filename. If necessary, parse it.
|
||||
|
|
|
|||
|
|
@ -128,8 +128,10 @@ public:
|
|||
}
|
||||
}
|
||||
void reinsert(AstNode* nodep, V3SymTable* parentp=NULL) {
|
||||
reinsert(nodep, parentp, nodep->name());
|
||||
}
|
||||
void reinsert(AstNode* nodep, V3SymTable* parentp, string name) {
|
||||
if (!parentp) parentp = symCurrentp();
|
||||
string name = nodep->name();
|
||||
if (name == "") { // New name with space in name so can't collide with users
|
||||
name = string(" anon") + nodep->type().ascii() + cvtToStr(++s_anonNum);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ extern void yyerrorf(const char* format, ...);
|
|||
#define FL { yylval.fl = CRELINE(); }
|
||||
|
||||
#define RETURN_BBOX_SYS_OR_MSG(msg,yytext) { \
|
||||
if (v3Global.opt.bboxSys()) return yD_aIGNORE; \
|
||||
else yyerrorf(msg,yytext); }
|
||||
if (!v3Global.opt.bboxSys()) yyerrorf(msg,yytext); \
|
||||
return yaD_IGNORE; }
|
||||
|
||||
void V3ParseImp::ppline (const char* textp) {
|
||||
// Handle `line directive
|
||||
|
|
@ -388,6 +388,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"pure" { FL; return yPURE; }
|
||||
"shortint" { FL; return ySHORTINT; }
|
||||
"static" { FL; return ySTATIC; }
|
||||
"string" { FL; return ySTRING; }
|
||||
"timeprecision" { FL; return yTIMEPRECISION; }
|
||||
"timeunit" { FL; return yTIMEUNIT; }
|
||||
"typedef" { FL; return yTYPEDEF; }
|
||||
|
|
@ -443,7 +444,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"return" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"string" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"super" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"tagged" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
|
|
@ -473,7 +473,13 @@ escid \\[^ \t\f\r\n]+
|
|||
|
||||
/* Default PLI rule */
|
||||
<V95,V01,V05,S05,PSL>{
|
||||
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported or unknown PLI call: %s",yytext); }
|
||||
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext,yyleng);
|
||||
yylval.strp = PARSEP->newString(AstNode::encodeName(str));
|
||||
// Lookup unencoded name including the $, to avoid hitting normal signals
|
||||
if (SYMP->symCurrentp()->findIdUpward(str)) {
|
||||
FL; return yaD_DPI;
|
||||
} else { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported or unknown PLI call: %s",yytext); }
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
|
|
|||
|
|
@ -132,7 +132,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'"); }
|
||||
if (str != "DPI-C" && !v3Global.opt.bboxSys()) {
|
||||
fileline->v3error("Unsupported DPI type '"<<str<<"': Use 'DPI-C'");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -203,6 +205,9 @@ class AstSenTree;
|
|||
%token<strp> yaSCCTOR "`systemc_implementation BLOCK"
|
||||
%token<strp> yaSCDTOR "`systemc_imp_header BLOCK"
|
||||
|
||||
%token<strp> yaD_IGNORE "${ignored-bbox-sys}"
|
||||
%token<strp> yaD_DPI "${dpi-sys}"
|
||||
|
||||
// <fl> is the fileline, abbreviated to shorten "$<fl>1" references
|
||||
%token<fl> '!'
|
||||
%token<fl> '#'
|
||||
|
|
@ -318,6 +323,7 @@ class AstSenTree;
|
|||
%token<fl> ySPECIFY "specify"
|
||||
%token<fl> ySPECPARAM "specparam"
|
||||
%token<fl> ySTATIC "static"
|
||||
%token<fl> ySTRING "string"
|
||||
%token<fl> ySUPPLY0 "supply0"
|
||||
%token<fl> ySUPPLY1 "supply1"
|
||||
%token<fl> yTABLE "table"
|
||||
|
|
@ -375,7 +381,6 @@ class AstSenTree;
|
|||
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
|
||||
%token<fl> yD_WARNING "$warning"
|
||||
%token<fl> yD_WRITE "$write"
|
||||
%token<fl> yD_aIGNORE "${ignored-bbox-sys}"
|
||||
|
||||
%token<fl> yPSL "psl"
|
||||
%token<fl> yPSL_ASSERT "PSL assert"
|
||||
|
|
@ -1053,7 +1058,7 @@ data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc referenc
|
|||
//UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionListE
|
||||
//UNSUP { UNSUP }
|
||||
//UNSUP enumDecl { UNSUP }
|
||||
//UNSUP ySTRING { UNSUP }
|
||||
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
|
||||
| yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
|
||||
//UNSUP yEVENT { UNSUP }
|
||||
//UNSUP yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ { UNSUP }
|
||||
|
|
@ -1922,8 +1927,11 @@ function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_call (as f
|
|||
|
||||
system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
||||
//
|
||||
yD_aIGNORE '(' ')' { $$ = NULL; }
|
||||
| yD_aIGNORE '(' exprList ')' { $$ = NULL; }
|
||||
yaD_IGNORE '(' ')' { $$ = NULL; }
|
||||
| yaD_IGNORE '(' exprList ')' { $$ = NULL; }
|
||||
//
|
||||
| yaD_DPI '(' ')' { $$ = new AstTaskRef($2,*$1,NULL); }
|
||||
| yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($2,*$1,$3); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
|
||||
| yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); }
|
||||
|
|
@ -1962,8 +1970,11 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|||
;
|
||||
|
||||
system_f_call<nodep>: // IEEE: system_tf_call (as func)
|
||||
yD_aIGNORE '(' ')' { $$ = new AstConst($1,V3Number($1,"'b0")); } // Unsized 0
|
||||
| yD_aIGNORE '(' exprList ')' { $$ = new AstConst($1,V3Number($1,"'b0")); } // Unsized 0
|
||||
yaD_IGNORE '(' ')' { $$ = new AstConst($2,V3Number($2,"'b0")); } // Unsized 0
|
||||
| yaD_IGNORE '(' exprList ')' { $$ = new AstConst($2,V3Number($2,"'b0")); } // Unsized 0
|
||||
//
|
||||
| yaD_DPI '(' ')' { $$ = new AstFuncRef($2,*$1,NULL); }
|
||||
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); }
|
||||
//
|
||||
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::BITS,$3); }
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
|
||||
|
|
@ -2154,10 +2165,14 @@ parenE:
|
|||
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); }
|
||||
$5->dpiImport(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
||||
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName()); // For $SysTF overriding
|
||||
SYMP->reinsert($$); }
|
||||
| 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); }
|
||||
$5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
||||
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,NULL,$$->prettyName()); // For $SysTF overriding
|
||||
SYMP->reinsert($$); }
|
||||
| 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);
|
||||
|
|
|
|||
|
|
@ -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 => ["t/t_dpi_sys_c.cpp"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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 ();
|
||||
|
||||
import "DPI-C" dpii_sys_task = function void \$dpii_sys (integer i);
|
||||
import "DPI-C" dpii_sys_func = function int \$dpii_func (integer i);
|
||||
|
||||
`ifndef verilator
|
||||
`error "Only Verilator supports PLI-ish DPI calls."
|
||||
`endif
|
||||
|
||||
initial begin
|
||||
$dpii_sys(1);
|
||||
if ($dpii_func(2) != 3) $stop;
|
||||
$dpii_sys(10);
|
||||
if ($dpii_func(2) != 12) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// -*- 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_sys__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 void dpii_sys_task (int i);
|
||||
extern int dpii_sys_func (int i);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
static int hidden = 0;
|
||||
|
||||
void dpii_sys_task(int i) {
|
||||
hidden = i;
|
||||
}
|
||||
int dpii_sys_func(int i) {
|
||||
return i + hidden;
|
||||
}
|
||||
Loading…
Reference in New Issue