diff --git a/Changes b/Changes index 9258fa6ae..7cb125790 100644 --- a/Changes +++ b/Changes @@ -27,6 +27,7 @@ Verilator 5.029 devel * Support named event locals (#5422). [Krzysztof Bieganski, Antmicro Ltd.] * Support basic dist constraints (#5431). [Arkadiusz Kozdra, Antmicro Ltd.] * Support inside array constraints (#5448). [Arkadiusz Kozdra, Antmicro Ltd.] +* Support DPI imports and exports with double underscores. * Add error on instances without parenthesis. * Add partial coverage symbol and branch data in lcov info files (#5388). [Andrew Nolte] * Add method to check if there are VPI callbacks of the given type (#5399). [Kaleb Barrett] diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 141d1c633..f96ab727f 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -723,6 +723,14 @@ class TaskVisitor final : public VNVisitor { return dpiproto; } + static void checkLegalCIdentifier(AstNode* nodep, const string& name) { + if (name.end() != std::find_if(name.begin(), name.end(), [](char c) { + return !std::isalnum(c) && c != '_'; + })) { + nodep->v3error("DPI function has illegal characters in C identifier name: " << name); + } + } + static AstNode* createDpiTemp(AstVar* portp, const string& suffix) { const string stmt = portp->dpiTmpVarType(portp->name() + suffix) + ";\n"; return new AstCStmt{portp->fileline(), stmt}; @@ -822,8 +830,11 @@ class TaskVisitor final : public VNVisitor { } AstCFunc* makeDpiExportDispatcher(AstNodeFTask* nodep, AstVar* rtnvarp) { + // Verilog name has __ conversion and other tricks, to match DPI C code, back that out + const string name = AstNode::prettyName(nodep->cname()); + checkLegalCIdentifier(nodep, name); const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix(); - AstCFunc* const funcp = new AstCFunc{nodep->fileline(), nodep->cname(), m_scopep, + AstCFunc* const funcp = new AstCFunc{nodep->fileline(), name, m_scopep, (rtnvarp ? rtnvarp->dpiArgType(true, true) : "")}; funcp->dpiExportDispatcher(true); funcp->dpiContext(nodep->dpiContext()); @@ -831,7 +842,7 @@ class TaskVisitor final : public VNVisitor { funcp->entryPoint(true); funcp->isStatic(true); funcp->protect(false); - funcp->cname(nodep->cname()); + funcp->cname(name); // Add DPI Export to top, since it's a global function m_topScopep->scopep()->addBlocksp(funcp); @@ -949,15 +960,14 @@ class TaskVisitor final : public VNVisitor { } AstCFunc* makeDpiImportPrototype(AstNodeFTask* nodep, AstVar* rtnvarp) { - if (nodep->cname() != AstNode::prettyName(nodep->cname())) { - nodep->v3error("DPI function has illegal characters in C identifier name: " - << AstNode::prettyNameQ(nodep->cname())); - } + // Verilog name has __ conversion and other tricks, to match DPI C code, back that out + const string name = AstNode::prettyName(nodep->cname()); + checkLegalCIdentifier(nodep, name); // Tasks (but not void functions) return a boolean 'int' indicating disabled const string rtnType = rtnvarp ? rtnvarp->dpiArgType(true, true) : nodep->dpiTask() ? "int" : ""; - AstCFunc* const funcp = new AstCFunc{nodep->fileline(), nodep->cname(), m_scopep, rtnType}; + AstCFunc* const funcp = new AstCFunc{nodep->fileline(), name, m_scopep, rtnType}; funcp->dpiContext(nodep->dpiContext()); funcp->dpiImportPrototype(true); funcp->dontCombine(true); diff --git a/test_regress/t/t_dpi_export.v b/test_regress/t/t_dpi_export.v index ad27183a8..c224b1fae 100644 --- a/test_regress/t/t_dpi_export.v +++ b/test_regress/t/t_dpi_export.v @@ -66,6 +66,9 @@ module t; `endif task dpix_t_time(input time i, output time o); o = ~i; endtask + export "DPI-C" function dpix__under___score; + function int dpix__under___score(input int i); return i + 1; endfunction + int lineno; initial begin diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index 8b60a1c66..5f6cd45f3 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -59,6 +59,8 @@ extern void dpix_t_reg15(const svLogicVecVal* i, svLogicVecVal* o); extern void dpix_t_reg95(const svLogicVecVal* i, svLogicVecVal* o); extern void dpix_t_integer(const svLogicVecVal* i, svLogicVecVal* o); extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o); + +extern int dpix__under___score(int i); } #endif @@ -225,6 +227,8 @@ int dpix_run_tests() { } #endif + CHECK_RESULT(int, dpix__under___score(77), 78); + if (int bad = check_sub("top.t.a", 1)) return bad; if (int bad = check_sub("top.t.b", 2)) return bad; diff --git a/test_regress/t/t_dpi_import.v b/test_regress/t/t_dpi_import.v index bc35b3161..abe7d18d6 100644 --- a/test_regress/t/t_dpi_import.v +++ b/test_regress/t/t_dpi_import.v @@ -99,6 +99,9 @@ module t (/*AUTOARG*/ 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); + // Check Verilator doesn't convert double underscores + import "DPI-C" pure function int dpii__under___score(input int i); + bit i_b, o_b; bit [7:0] i_b8; bit [8:0] i_b9; @@ -256,6 +259,8 @@ module t (/*AUTOARG*/ if (oth_f_int1(32'd123) !== ~32'd123) $stop; if (oth_f_int2(32'd124) !== ~32'd124) $stop; + if (dpii__under___score(32'd60) != 32'd61) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_dpi_import_c.cpp b/test_regress/t/t_dpi_import_c.cpp index e48b261a3..8bd090c6e 100644 --- a/test_regress/t/t_dpi_import_c.cpp +++ b/test_regress/t/t_dpi_import_c.cpp @@ -183,6 +183,8 @@ void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o) { int dpii_f_strlen(const char* i) { return strlen(i); } +int dpii__under___score(int i) { return i + 1; } + //====================================================================== void dpii_f_void() {} diff --git a/test_regress/t/t_dpi_name_bad.out b/test_regress/t/t_dpi_name_bad.out index a061f6f78..04f4e97ba 100644 --- a/test_regress/t/t_dpi_name_bad.out +++ b/test_regress/t/t_dpi_name_bad.out @@ -1,4 +1,7 @@ -%Error: t/t_dpi_name_bad.v:12:32: DPI function has illegal characters in C identifier name: 'badly.named' - 12 | import "DPI-C" function int \badly.named (int i); +%Error: t/t_dpi_name_bad.v:11:32: DPI function has illegal characters in C identifier name: badly.named + 11 | import "DPI-C" function int \badly.named (int i); | ^~~~~~~~~~~~ +%Error: t/t_dpi_name_bad.v:14:17: DPI function has illegal characters in C identifier name: badly.expt + 14 | function int \badly.expt ; return 0; endfunction + | ^~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_dpi_name_bad.v b/test_regress/t/t_dpi_name_bad.v index e8c066912..bf07235c0 100644 --- a/test_regress/t/t_dpi_name_bad.v +++ b/test_regress/t/t_dpi_name_bad.v @@ -8,9 +8,11 @@ module t (); - // Can't handle logic (yet?) import "DPI-C" function int \badly.named (int i); + export "DPI-C" function \badly.expt ; + function int \badly.expt ; return 0; endfunction + initial begin $stop; end