DPI import: Allow system calls to call imports

This commit is contained in:
Wilson Snyder 2009-12-04 07:05:44 -05:00
parent a40fae04ce
commit 5a9309de78
10 changed files with 164 additions and 16 deletions

View File

@ -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

View File

@ -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()) {

View File

@ -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)
};

View File

@ -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.

View File

@ -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);
}

View File

@ -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); }
}
}
/************************************************************************/

View File

@ -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);

19
test_regress/t/t_dpi_sys.pl Executable file
View File

@ -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;

View File

@ -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

View File

@ -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;
}