From 49fe4d081c03664f0813cea304323aa38e2e656d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 17 Dec 2017 16:28:58 -0500 Subject: [PATCH] Support DPI open arrays, bug909, bug1245. --- Changes | 2 + include/verilated.cpp | 28 +- include/verilated.h | 3 +- include/verilated_dpi.cpp | 500 +++++++++++++++++++++++---- include/verilated_dpi.h | 3 +- include/verilated_sym_props.h | 159 ++++++++- src/V3Ast.h | 58 +++- src/V3AstNodes.cpp | 60 +++- src/V3AstNodes.h | 70 +++- src/V3ParseImp.h | 2 +- src/V3Task.cpp | 73 ++-- src/V3Width.cpp | 74 +++- src/verilog.y | 105 +++--- test_regress/t/t_dpi_lib.v | 7 +- test_regress/t/t_dpi_lib_c.cpp | 3 +- test_regress/t/t_dpi_open.pl | 20 ++ test_regress/t/t_dpi_open.v | 150 ++++++++ test_regress/t/t_dpi_open_c.cpp | 233 +++++++++++++ test_regress/t/t_dpi_openfirst.pl | 20 ++ test_regress/t/t_dpi_openfirst.v | 45 +++ test_regress/t/t_dpi_openfirst_c.cpp | 77 +++++ test_regress/t/t_dpi_openreg_bad.pl | 20 ++ test_regress/t/t_dpi_openreg_bad.v | 20 ++ 23 files changed, 1533 insertions(+), 199 deletions(-) create mode 100755 test_regress/t/t_dpi_open.pl create mode 100644 test_regress/t/t_dpi_open.v create mode 100644 test_regress/t/t_dpi_open_c.cpp create mode 100755 test_regress/t/t_dpi_openfirst.pl create mode 100644 test_regress/t/t_dpi_openfirst.v create mode 100644 test_regress/t/t_dpi_openfirst_c.cpp create mode 100755 test_regress/t/t_dpi_openreg_bad.pl create mode 100644 test_regress/t/t_dpi_openreg_bad.v diff --git a/Changes b/Changes index e2ebac43a..1fa05c188 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Workaround GCC/clang bug with huge compile times, bug1248. +*** Support DPI open arrays, bug909, bug1245. [David Pierce, Victor Besyakov] + **** Support > 64 bit decimal $display. **** Support DPI time and svLogicVal. [Victor Besyakov] diff --git a/include/verilated.cpp b/include/verilated.cpp index bbebfa27d..355f73a72 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1634,7 +1634,7 @@ VerilatedModule::~VerilatedModule() { // VerilatedVar:: Methods // cppcheck-suppress unusedFunction // Used by applications -vluint32_t VerilatedVar::entSize() const { +vluint32_t VerilatedVarProps::entSize() const { vluint32_t size = 1; switch (vltype()) { case VLVT_PTR: size=sizeof(void*); break; @@ -1648,6 +1648,26 @@ vluint32_t VerilatedVar::entSize() const { return size; } +size_t VerilatedVarProps::totalSize() const { + size_t size = entSize(); + for (int dim=1; dim<=dims(); ++dim) { + size *= m_unpacked[dim].elements(); + } + return size; +} + +void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const { + if (VL_UNLIKELY(dim <=0 || dim > m_udims || dim > 3)) return NULL; + if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL; + int indxAdj = indx - low(dim); + vluint8_t* bytep = reinterpret_cast(datap); + // If on index 1 of a 2 index array, then each index 1 is index2sz*entsz + size_t slicesz = entSize(); + for (int d=dim+1; d<=m_udims; ++d) slicesz *= elements(d); + bytep += indxAdj*slicesz; + return bytep; +} + //====================================================================== // VerilatedScope:: Methods @@ -1717,9 +1737,9 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, if (i==0) { var.m_packed.m_left = msb; var.m_packed.m_right = lsb; - } else if (i==1) { - var.m_unpacked[0].m_left = msb; - var.m_unpacked[0].m_right = lsb; + } else if (i>=1 && i<=3) { + var.m_unpacked[i-1].m_left = msb; + var.m_unpacked[i-1].m_right = lsb; } else { // We could have a linked list of ranges, but really this whole thing needs // to be generalized to support structs and unions, etc. diff --git a/include/verilated.h b/include/verilated.h index 11570aa7a..ae935e7a9 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -99,7 +99,8 @@ enum VerilatedVarFlags { VLVF_MASK_DIR=7, // Bit mask for above directions // Flags VLVF_PUB_RD=(1<<8), // Public readable - VLVF_PUB_RW=(1<<9) // Public writable + VLVF_PUB_RW=(1<<9), // Public writable + VLVF_DPI_CLAY=(1<<10) // DPI compatible C standard layout }; //========================================================================= diff --git a/include/verilated_dpi.cpp b/include/verilated_dpi.cpp index 83c65c368..8b4e603c3 100644 --- a/include/verilated_dpi.cpp +++ b/include/verilated_dpi.cpp @@ -44,15 +44,12 @@ #define _VL_SVDPI_UNIMP() \ VL_FATAL_MT(__FILE__,__LINE__,"",(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str()) +#define _VL_SVDPI_WARN(message...) \ + VL_PRINTF_MT(message) + // Function requires a "context" in the import declaration #define _VL_SVDPI_CONTEXT_WARN() \ - VL_PRINTF_MT("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n"); - -// Function requires svOpenArrayHandle dimensionality -#define _VL_SVDPI_DIMENSION_CHECK(d, dimensions) \ - do { if (VL_UNLIKELY(svDimensions(d) != (dimensions))) { \ - VL_PRINTF_MT("%%Warning: %s called on array that is not %d dimensional.\n", __FUNCTION__, dimensions); \ - } } while(0) + _VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n"); //====================================================================== //====================================================================== @@ -190,84 +187,357 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w } //====================================================================== -// Open array querying functions +// Open array internals -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 svSize(const svOpenArrayHandle h, int d) { - _VL_SVDPI_UNIMP(); return 0; -} -int svDimensions(const svOpenArrayHandle h) { - _VL_SVDPI_UNIMP(); return 0; -} -void* svGetArrayPtr(const svOpenArrayHandle h) { - _VL_SVDPI_UNIMP(); return NULL; -} -int svSizeOfArray(const svOpenArrayHandle h) { - _VL_SVDPI_UNIMP(); return 0; -} - -void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) { - _VL_SVDPI_UNIMP(); return NULL; -} -void* svGetArrElemPtr1(const svOpenArrayHandle h, int indx1) { - _VL_SVDPI_UNIMP(); return NULL; -} -void* svGetArrElemPtr2(const svOpenArrayHandle h, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); return NULL; -} -void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); return NULL; +static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) { + if (VL_UNLIKELY(!h)) { + VL_FATAL_MT(__FILE__,__LINE__,"","%%Error: DPI svOpenArrayHandle function called with NULL handle"); + } + const VerilatedDpiOpenVar* varp = reinterpret_cast(h); + if (VL_UNLIKELY(!varp->magicOk())) { + VL_FATAL_MT(__FILE__,__LINE__,"","%%Error: DPI svOpenArrayHandle function called with non-Verilator handle"); + } + return varp; } //====================================================================== -// s=source, d=destination -// From user space into simulator storage +// Open array querying functions + +int svLeft(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->left(d); +} +int svRight(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->right(d); +} +int svLow(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->low(d); +} +int svHigh(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->high(d); +} +int svIncrement(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->increment(d); +} +int svSize(const svOpenArrayHandle h, int d) { + return _vl_openhandle_varp(h)->elements(d); +} +int svDimensions(const svOpenArrayHandle h) { + return _vl_openhandle_varp(h)->udims(); +} +/// Return pointer to open array data, or NULL if not in IEEE standard C layout +void* svGetArrayPtr(const svOpenArrayHandle h) { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); + if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL; + return varp->datap(); +} +/// Return size of open array, or 0 if not in IEEE standard C layout +int svSizeOfArray(const svOpenArrayHandle h) { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); + if (VL_UNLIKELY(!varp->isDpiStdLayout())) return 0; + // Truncate 64 bits to int; DPI is limited to 4GB + return static_cast(varp->totalSize()); +} + +//====================================================================== +// Open array access internals + +static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, + int nargs, int indx1, int indx2, int indx3) { + void* datap = varp->datap(); + if (VL_UNLIKELY(nargs != varp->udims())) { + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on %d dimensional array using %d dimensional function.\n", + varp->udims(), nargs); + return NULL; + } + if (nargs>=1) { + datap = varp->datapAdjustIndex(datap, 1, indx1); + if (VL_UNLIKELY(!datap)) { + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 out of bounds; %d outside [%d:%d].\n", + indx1, varp->left(1), varp->right(1)); + return NULL; + } + } + if (nargs>=2) { + datap = varp->datapAdjustIndex(datap, 2, indx2); + if (VL_UNLIKELY(!datap)) { + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 out of bounds; %d outside [%d:%d].\n", + indx2, varp->left(2), varp->right(2)); + return NULL; + } + } + if (nargs>=3) { + datap = varp->datapAdjustIndex(datap, 3, indx3); + if (VL_UNLIKELY(!datap)) { + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 out of bounds; %d outside [%d:%d].\n", + indx1, varp->left(3), varp->right(3)); + return NULL; + } + } + return datap; +} + +static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) { + if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) { + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d outside [%d:%d].\n", + indx, varp->left(0), varp->right(0)); + return 0; + } + return indx - varp->low(0); +} + +/// Return pointer to simulator open array element, or NULL if outside range +static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, + int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); + if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL; + void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + return datap; +} + +/// Copy to user bit array from simulator open array +static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, + int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + if (VL_UNLIKELY(!datap)) return; + switch (varp->vltype()) { + case VLVT_UINT8: d[0] = *(reinterpret_cast(datap)); return; + case VLVT_UINT16: d[0] = *(reinterpret_cast(datap)); return; + case VLVT_UINT32: d[0] = *(reinterpret_cast(datap)); return; + case VLVT_UINT64: { + WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast(datap))); + d[0] = lwp[0]; d[1] = lwp[1]; + break; + } + case VLVT_WDATA: { + WDataOutP wdatap = (reinterpret_cast(datap)); + for (int i=0; ipacked().elements()); ++i) d[i] = wdatap[i]; + return; + } + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return; + } +} +/// Copy to user logic array from simulator open array +static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, + int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + if (VL_UNLIKELY(!datap)) return; + switch (varp->vltype()) { + case VLVT_UINT8: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; + case VLVT_UINT16: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; + case VLVT_UINT32: d[0].aval = *(reinterpret_cast(datap)); d[0].bval=0; return; + case VLVT_UINT64: { + WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast(datap))); + d[0].aval = lwp[0]; d[0].bval=0; + d[1].aval = lwp[1]; d[0].bval=0; + break; + } + case VLVT_WDATA: { + WDataOutP wdatap = (reinterpret_cast(datap)); + for (int i=0; ipacked().elements()); ++i) { + d[i].aval = wdatap[i]; d[i].bval = 0; + } + return; + } + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return; + } +} + +/// Copy to simulator open array from from user bit array +static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, + int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + if (VL_UNLIKELY(!datap)) return; + switch (varp->vltype()) { + case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0]; return; + case VLVT_UINT16: *(reinterpret_cast(datap)) = s[0]; return; + case VLVT_UINT32: *(reinterpret_cast(datap)) = s[0]; return; + case VLVT_UINT64: *(reinterpret_cast(datap)) = _VL_SET_QII(s[1], s[0]); break; + case VLVT_WDATA: { + WDataOutP wdatap = (reinterpret_cast(datap)); + for (int i=0; ipacked().elements()); ++i) wdatap[i] = s[i]; + return; + } + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return; + } +} +/// Copy to simulator open array from from user logic array +static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, + int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + if (VL_UNLIKELY(!datap)) return; + switch (varp->vltype()) { + case VLVT_UINT8: *(reinterpret_cast(datap)) = s[0].aval; return; + case VLVT_UINT16: *(reinterpret_cast(datap)) = s[0].aval; return; + case VLVT_UINT32: *(reinterpret_cast(datap)) = s[0].aval; return; + case VLVT_UINT64: *(reinterpret_cast(datap)) = _VL_SET_QII(s[1].aval, s[0].aval); break; + case VLVT_WDATA: { + WDataOutP wdatap = (reinterpret_cast(datap)); + for (int i=0; ipacked().elements()); ++i) wdatap[i] = s[i].aval; + return; + } + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return; + } +} + +/// Return bit from simulator open array +static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, + int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE { + // One extra index supported, as need bit number + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + void* datap; + int lsb; + if (varp->packed().elements()) { + datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3); + lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1 + : (nargs==2) ? indx2 + : (nargs==3) ? indx3 + : indx4)); + } else { + datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + lsb = 0; + } + if (VL_UNLIKELY(!datap)) return 0; + switch (varp->vltype()) { + case VLVT_UINT8: return (*(reinterpret_cast(datap)) >> lsb) & 1; + case VLVT_UINT16: return (*(reinterpret_cast(datap)) >> lsb) & 1; + case VLVT_UINT32: return (*(reinterpret_cast(datap)) >> lsb) & 1; + case VLVT_UINT64: return (*(reinterpret_cast(datap)) >> static_cast(lsb)) & VL_ULL(1); + case VLVT_WDATA: { + WDataOutP wdatap = (reinterpret_cast(datap)); + return VL_BITRSHIFT_W(wdatap, lsb) & 1; + } + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return 0; + } +} +/// Update simulator open array from bit +static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, + int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE { + // One extra index supported, as need bit number + value &= 1; // Make sure clean + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + void* datap; + int lsb; + if (varp->packed().elements()) { + datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3); + lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1 + : (nargs==2) ? indx2 + : (nargs==3) ? indx3 + : indx4)); + } else { + datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3); + lsb = 0; + } + if (VL_UNLIKELY(!datap)) return; + switch (varp->vltype()) { + case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; + case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; + case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast(datap)), value); return; + case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast(datap)), value); return; + case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast(datap)), value); return; + default: + _VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype()); + return; + } +} + +//====================================================================== +// DPI accessors that simply call above functions + +void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) { + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h); + void* datap; + va_list ap; + va_start(ap, indx1); + // va_arg is a macro, so need temporaries as used below + switch (varp->udims()) { + case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); break; } + default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break; // Will error + } + va_end(ap); + return datap; +} +void* svGetArrElemPtr1(const svOpenArrayHandle h, int indx1) { + return _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); +} +void* svGetArrElemPtr2(const svOpenArrayHandle h, int indx1, int indx2) { + return _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); +} +void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx3) { + return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); +} void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...) { - _VL_SVDPI_UNIMP(); + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + void* datap; + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error + } + va_end(ap); } void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); } void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); } void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); } void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...) { - _VL_SVDPI_UNIMP(); + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error + } + va_end(ap); } void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1) { - _VL_SVDPI_UNIMP(); + _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); } void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); + _vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); } void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); + _vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); } //====================================================================== @@ -275,51 +545,104 @@ void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...) { - _VL_SVDPI_UNIMP(); + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error + } + va_end(ap); } void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1) { - _VL_SVDPI_UNIMP(); + _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); } void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); + _vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); } void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); + _vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); } void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...) { - _VL_SVDPI_UNIMP(); + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; } + default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error + } + va_end(ap); } void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1) { - _VL_SVDPI_UNIMP(); + _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); } void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); + _vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); } void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); + _vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); } svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) { - _VL_SVDPI_UNIMP(); return 0; + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + svBit out; + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; } + case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; } + default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error + } + va_end(ap); + return out; } svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1) { - _VL_SVDPI_UNIMP(); return 0; + return _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); } svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); return 0; + return _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); } svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); return 0; + return _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); } svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) { - _VL_SVDPI_UNIMP(); return sv_x; + // Verilator doesn't support X/Z so can just call Bit version + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s); + svBit out; + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; } + case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); + out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; } + default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error + } + va_end(ap); + return out; } svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) { // Verilator doesn't support X/Z so can just call Bit version @@ -335,19 +658,46 @@ svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int } void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) { - _VL_SVDPI_UNIMP(); + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; } + case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; } + default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error + } + va_end(ap); } void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); } void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); } void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) { - _VL_SVDPI_UNIMP(); + _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); } void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) { - _VL_SVDPI_UNIMP(); + // Verilator doesn't support X/Z so can just call Bit version + const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d); + va_list ap; + va_start(ap, indx1); + switch (varp->udims()) { + case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break; + case 2: { int indx2=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; } + case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; } + case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int); + _vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; } + default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error + } + va_end(ap); } void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) { // Verilator doesn't support X/Z so can just call Bit version diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index 590f18b7c..fee80d5a4 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -28,7 +28,8 @@ #ifndef _VERILATED_DPI_H_ #define _VERILATED_DPI_H_ 1 ///< Header Guard -#include "verilated.h" // Presumed done by caller +#include "verilated.h" // Also presumably included by caller +#include "verilated_sym_props.h" #include "svdpi.h" //=================================================================== diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index 52fbcd70e..6d46e3df1 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -41,47 +41,174 @@ class VerilatedRange { int m_left; int m_right; protected: - friend class VerilatedVar; + friend class VerilatedVarProps; friend class VerilatedScope; VerilatedRange() : m_left(0), m_right(0) {} + VerilatedRange(int left, int right) : m_left(left), m_right(right) {} void init(int left, int right) { m_left=left; m_right=right; } public: ~VerilatedRange() {} int left() const { return m_left; } int right() const { return m_right; } - int elements() const { return (VL_LIKELY(m_left>=m_right)?(m_left-m_right+1):(m_right-m_left+1)); } + int low() const { return (m_left < m_right) ? m_left : m_right; } + int high() const { return (m_left > m_right) ? m_left : m_right; } + int elements() const { return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); } + int increment() const { return (m_left >= m_right) ? 1 : -1; } }; //=========================================================================== /// Verilator variable /// Thread safety: Assume is constructed only with model, then any number of readers -class VerilatedVar { - void* m_datap; // Location of data - VerilatedVarType m_vltype; // Data type - VerilatedVarFlags m_vlflags; // Direction - VerilatedRange m_packed; // Packed array range - VerilatedRange m_unpacked[1]; // Unpacked array range - int m_dims; // Dimensions - const char* m_namep; // Name - slowpath +class VerilatedVarProps { + // TYPES + enum { MAGIC = 0xddc4f829 }; + // MEMBERS + const vluint32_t m_magic; // Magic number + const VerilatedVarType m_vltype; // Data type + const VerilatedVarFlags m_vlflags; // Direction + const int m_pdims; // Packed dimensions + const int m_udims; // Unpacked dimensions + VerilatedRange m_packed; // Packed array range + VerilatedRange m_unpacked[3]; // Unpacked array range + // CONSTRUCTORS protected: friend class VerilatedScope; - VerilatedVar(const char* namep, void* datap, - VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims) - : m_datap(datap), m_vltype(vltype), m_vlflags(vlflags), m_dims(dims), m_namep(namep) {} + VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, + int pdims, int udims) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(vlflags), m_pdims(pdims), m_udims(udims) {} public: - ~VerilatedVar() {} - void* datap() const { return m_datap; } + class Unpacked {}; + // Without packed + VerilatedVarProps(VerilatedVarType vltype, int vlflags) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Unpacked, int u0l, int u0r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) { + m_unpacked[0].init(u0l, u0r); } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Unpacked, int u0l, int u0r, int u1l, int u1r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) { + m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) { + m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); } + // With packed + class Packed {}; + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Packed, int pl, int pr) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Packed, int pl, int pr, + Unpacked, int u0l, int u0r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) { + m_unpacked[0].init(u0l, u0r); } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Packed, int pl, int pr, + Unpacked, int u0l, int u0r, int u1l, int u1r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(2), m_packed(pl,pr) { + m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); } + VerilatedVarProps(VerilatedVarType vltype, int vlflags, + Packed, int pl, int pr, + Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) + : m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) { + m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); } +public: + ~VerilatedVarProps() {} + // METHODS + bool magicOk() const { return m_magic==MAGIC; } VerilatedVarType vltype() const { return m_vltype; } VerilatedVarFlags vldir() const { return static_cast(static_cast(m_vlflags) & VLVF_MASK_DIR); } vluint32_t entSize() const; bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); } + /// DPI compatible C standard layout + bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); } + int udims() const { return m_udims; } + int dims() const { return m_pdims + m_udims; } const VerilatedRange& packed() const { return m_packed; } const VerilatedRange& unpacked() const { return m_unpacked[0]; } + // DPI accessors + int left(int dim) const { + return dim==0 ? m_packed.left() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].left() : 0; + } + int right(int dim) const { + return dim==0 ? m_packed.right() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].right() : 0; + } + int low(int dim) const { + return dim==0 ? m_packed.low() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].low() : 0; + } + int high(int dim) const { + return dim==0 ? m_packed.high() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].high() : 0; + } + int increment(int dim) const { + return dim==0 ? m_packed.increment() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].increment() : 0; + } + int elements(int dim) const { + return dim==0 ? m_packed.elements() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].elements() : 0; + } + /// Total size in bytes (note DPI limited to 4GB) + size_t totalSize() const; + /// Adjust a data pointer to access a given array element, NuLL if something goes bad + void* datapAdjustIndex(void* datap, int dim, int indx) const; +}; + +//=========================================================================== +/// Verilator DPI open array variable + +class VerilatedDpiOpenVar { + // MEMBERS + const VerilatedVarProps* m_propsp; // Variable properties + void* m_datap; // Location of data (local to thread always, so safe) +public: + // CONSTRUCTORS + VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap) + : m_propsp(propsp), m_datap(datap) {} + VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap) + : m_propsp(propsp), m_datap(const_cast(datap)) {} + ~VerilatedDpiOpenVar() {} + // METHODS + void* datap() const { return m_datap; } + // METHODS - from VerilatedVarProps + bool magicOk() const { return m_propsp->magicOk(); } + VerilatedVarType vltype() const { return m_propsp->vltype(); } + bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); } + const VerilatedRange& packed() const { return m_propsp->packed(); } + const VerilatedRange& unpacked() const { return m_propsp->unpacked(); } + int udims() const { return m_propsp->udims(); } + int left(int dim) const { return m_propsp->left(dim); } + int right(int dim) const { return m_propsp->right(dim); } + int low(int dim) const { return m_propsp->low(dim); } + int high(int dim) const { return m_propsp->high(dim); } + int increment(int dim) const { return m_propsp->increment(dim); } + int elements(int dim) const { return m_propsp->elements(dim); } + size_t totalSize() const { return m_propsp->totalSize(); } + void* datapAdjustIndex(void* datap, int dim, int indx) const { + return m_propsp->datapAdjustIndex(datap, dim, indx); } +}; + +//=========================================================================== +/// Verilator variable +/// Thread safety: Assume is constructed only with model, then any number of readers + +class VerilatedVar : public VerilatedVarProps { + // MEMBERS + void* m_datap; // Location of data + const char* m_namep; // Name - slowpath +protected: + friend class VerilatedScope; + // CONSTRUCTORS + VerilatedVar(const char* namep, void* datap, + VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims) + : VerilatedVarProps(vltype, vlflags, (dims>0?1:0), ((dims>1)?dims-1:0)) + , m_datap(datap), m_namep(namep) {} +public: + ~VerilatedVar() {} + // ACCESSORS + void* datap() const { return m_datap; } const VerilatedRange& range() const { return packed(); } // Deprecated const VerilatedRange& array() const { return unpacked(); } // Deprecated const char* name() const { return m_namep; } - int dims() const { return m_dims; } }; #endif // Guard diff --git a/src/V3Ast.h b/src/V3Ast.h index dc85a5f10..e0a24510c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -430,6 +430,10 @@ public: bool isDpiUnsignable() const { // Can add "unsigned" to DPI return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER); } + bool isDpiCLayout() const { // Uses standard C layout, for DPI runtime access + return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT + || m_e==LONGINT || m_e==DOUBLE || m_e==SHORTINT || m_e==UINT32 || m_e==UINT64); + } bool isOpaque() const { // IE not a simple number we can bit optimize return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT); } @@ -1885,21 +1889,24 @@ class AstNodeFTask : public AstNode { private: string m_name; // Name of task string m_cname; // Name of task if DPI import + uint64_t m_dpiOpenParent; // DPI import open array, if !=0, how many callees bool m_taskPublic:1; // Public task bool m_attrIsolateAssign:1;// User isolate_assignments attribute bool m_prototype:1; // Just a prototype bool m_dpiExport:1; // DPI exported bool m_dpiImport:1; // DPI imported bool m_dpiContext:1; // DPI import context + bool m_dpiOpenChild:1; // DPI import open array child wrapper bool m_dpiTask:1; // DPI import task (vs. void function) bool m_pure:1; // DPI import pure public: AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp) : AstNode(fileline) - , m_name(name), m_taskPublic(false) + , m_name(name) + , m_dpiOpenParent(0), m_taskPublic(false) , m_attrIsolateAssign(false), m_prototype(false) , m_dpiExport(false), m_dpiImport(false), m_dpiContext(false) - , m_dpiTask(false), m_pure(false) { + , m_dpiOpenChild(false), m_dpiTask(false), m_pure(false) { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -1921,23 +1928,29 @@ public: void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } // op4 = scope name AstScopeName* scopeNamep() const { return op4p()->castScopeName(); } - void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } - void taskPublic(bool flag) { m_taskPublic=flag; } - bool taskPublic() const { return m_taskPublic; } - 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 dpiExport(bool flag) { m_dpiExport = flag; } - bool dpiExport() const { return m_dpiExport; } - 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; } + // MORE ACCESSORS + void dpiOpenParentInc() { ++m_dpiOpenParent; } + void dpiOpenParentClear() { m_dpiOpenParent=0; } + uint64_t dpiOpenParent() const { return m_dpiOpenParent; } + void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } + void taskPublic(bool flag) { m_taskPublic=flag; } + bool taskPublic() const { return m_taskPublic; } + 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 dpiExport(bool flag) { m_dpiExport = flag; } + bool dpiExport() const { return m_dpiExport; } + 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 dpiOpenChild(bool flag) { m_dpiOpenChild = flag; } + bool dpiOpenChild() const { return m_dpiOpenChild; } + 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; } }; class AstNodeFTaskRef : public AstNode { @@ -2045,6 +2058,13 @@ public: bool recursiveClone() const { return m_recursiveClone; } }; +class AstNodeRange : public AstNode { + // A range, sized or unsized +public: + AstNodeRange(FileLine* fl) : AstNode (fl) { } + ASTNODE_BASE_FUNCS(NodeRange) +}; + //###################################################################### #include "V3AstNodes.h" diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 4d86f3106..e3dc4a758 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -239,11 +239,20 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const { } else if (isWide()) { arg += "WData"; // []'s added later } - if (isWide() && !strtype) { - arg += " (& "+name(); - arg += ")["+cvtToStr(widthWords())+"]"; + if (isDpiOpenArray() || (isWide() && !strtype)) { + arg += " (& "+name()+")"; + for (AstNodeDType* dtp=dtypep(); dtp; ) { + dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node + if (AstUnpackArrayDType* adtypep = dtp->castUnpackArrayDType()) { + arg += "["+cvtToStr(adtypep->declRange().elements())+"]"; + dtp = adtypep->subDTypep(); + } else break; + } + if (isWide() && !strtype) { + arg += "["+cvtToStr(widthWords())+"]"; + } } else { - if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&"; + if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&"; if (named) arg += " "+name(); } return arg; @@ -288,6 +297,34 @@ string AstVar::vlEnumDir() const { // if (isSigUserRWPublic()) out += "|VLVF_PUB_RW"; else if (isSigUserRdPublic()) out += "|VLVF_PUB_RD"; + // + if (AstBasicDType* bdtypep = basicp()) { + if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY"; + } + return out; +} + +string AstVar::vlPropInit() const { + string out; + out = vlEnumType(); // VLVT_UINT32 etc + out += ", "+vlEnumDir(); // VLVD_IN etc + if (AstBasicDType* bdtypep = basicp()) { + out += ", VerilatedVarProps::Packed()"; + out += ", "+cvtToStr(bdtypep->left())+", "+cvtToStr(bdtypep->right()); + } + bool first = true; + for (AstNodeDType* dtp=dtypep(); dtp; ) { + dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node + if (AstNodeArrayDType* adtypep = dtp->castNodeArrayDType()) { + if (first) { + out += ", VerilatedVarProps::Unpacked()"; + first = false; + } + out += ", "+cvtToStr(adtypep->declRange().left())+", "+cvtToStr(adtypep->declRange().right()); + dtp = adtypep->subDTypep(); + } + else break; // AstBasicDType - nothing below + } return out; } @@ -318,8 +355,11 @@ string AstVar::cPubArgType(bool named, bool forReturn) const { string AstVar::dpiArgType(bool named, bool forReturn) const { if (forReturn) named=false; string arg; - if (!basicp()) arg = "UNKNOWN"; - else if (basicp()->keyword().isDpiBitVal()) { + if (isDpiOpenArray()) { + arg = "const svOpenArrayHandle"; + } else if (!basicp()) { + arg = "UNKNOWN"; + } else if (basicp()->keyword().isDpiBitVal()) { if (widthMin() == 1) { arg = "unsigned char"; if (!forReturn && isOutput()) arg += "*"; @@ -968,7 +1008,10 @@ void AstTypeTable::dump(ostream& str) { } // Note get newline from caller too. } - +void AstUnsizedArrayDType::dumpSmall(ostream& str) { + this->AstNodeDType::dumpSmall(str); + str<<"[]"; +} void AstVarScope::dump(ostream& str) { this->AstNode::dump(str); if (isCircular()) str<<" [CIRC]"; @@ -1015,6 +1058,7 @@ void AstVar::dump(ostream& str) { if (attrFileDescr()) str<<" [aFD]"; if (isFuncReturn()) str<<" [FUNCRTN]"; else if (isFuncLocal()) str<<" [FUNC]"; + if (isDpiOpenArray()) str<<" [DPIOPENA]"; if (!attrClocker().unknown()) str<<" ["<brokeExists()) + || (!m_refDTypep && childDTypep()))); return NULL; } + virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { + m_refDTypep = m_refDTypep->clonep(); + }} + virtual bool same(const AstNode* samep) const { + const AstNodeArrayDType* asamep = static_cast(samep); + return (subDTypep()==asamep->subDTypep()); } + virtual bool similarDType(AstNodeDType* samep) const { + const AstNodeArrayDType* asamep = static_cast(samep); + return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + } + virtual void dumpSmall(ostream& str); + virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } + AstNodeDType* getChildDTypep() const { return childDTypep(); } + AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } +}; + class AstBasicDType : public AstNodeDType { // Builtin atomic/vectored data type // Children: RANGE (converted to constant in V3Width) @@ -1057,6 +1111,7 @@ private: bool m_isPulldown:1; // Tri0 bool m_isPullup:1; // Tri1 bool m_isIfaceParent:1; // dtype is reference to interface present in this module + bool m_isDpiOpenArray:1; // DPI import open array bool m_noSubst:1; // Do not substitute out references bool m_trace:1; // Trace this variable AstVarAttrClocker m_attrClocker; @@ -1070,8 +1125,8 @@ private: m_funcLocal=false; m_funcReturn=false; m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false; m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false; - m_isIfaceParent=false; m_attrClocker=AstVarAttrClocker::CLOCKER_UNKNOWN; m_noSubst=false; - m_trace=false; + m_isIfaceParent=false; m_isDpiOpenArray=false; m_noSubst=false; m_trace=false; + m_attrClocker=AstVarAttrClocker::CLOCKER_UNKNOWN; } public: AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) @@ -1131,6 +1186,7 @@ public: string vlArgType(bool named, bool forReturn, bool forFunc) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc + string vlPropInit() const; // Return VerilatorVarProps initializer void combineType(AstVarType type); AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable @@ -1164,6 +1220,8 @@ public: void isIfaceParent(bool flag) { m_isIfaceParent = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } + void isDpiOpenArray(bool flag) { m_isDpiOpenArray=flag; } + bool isDpiOpenArray() const { return m_isDpiOpenArray; } void noSubst(bool flag) { m_noSubst=flag; } bool noSubst() const { return m_noSubst; } void trace(bool flag) { m_trace=flag; } diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 20f9eec85..7a29d203b 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -74,6 +74,7 @@ struct V3ParseBisonYYSType { AstNodeDType* dtypep; AstNodeFTask* ftaskp; AstNodeFTaskRef* ftaskrefp; + AstNodeRange* rangep; AstNodeSenItem* senitemp; AstNodeVarRef* varnodep; AstPackage* packagep; @@ -82,7 +83,6 @@ struct V3ParseBisonYYSType { AstPatMember* patmemberp; AstPattern* patternp; AstPin* pinp; - AstRange* rangep; AstSenTree* sentreep; AstVar* varp; AstVarRef* varrefp; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index b6d3f617d..88d9fdfd2 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -471,7 +471,6 @@ private: // outvscp is the variable for functions only, if NULL, it's a task if (!refp->taskp()) refp->v3fatalSrc("Unlinked?"); AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp()); - if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?"); // AstNode* beginp = new AstComment(refp->fileline(), (string)("Function: ")+refp->name()); @@ -774,7 +773,7 @@ private: makePortList(nodep, rtnvarp, dpip); } - void makeDpiImportWrapper(AstNodeFTask* nodep, AstVar* rtnvarp) { + void makeDpiImportProto(AstNodeFTask* nodep, AstVar* rtnvarp) { if (nodep->cname() != AstNode::prettyName(nodep->cname())) { nodep->v3error("DPI function has illegal characters in C identifier name: "<cname())); } @@ -797,7 +796,7 @@ private: } bool duplicatedDpiProto(AstNodeFTask* nodep, string dpiproto) { - // Only create one DPI extern for each specified cname, + // Only create one DPI extern prototype 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()) { @@ -845,21 +844,41 @@ private: && portp->name() != "__Vscopep" // Passed to dpiContext, not callee && portp->name() != "__Vfilenamep" && portp->name() != "__Vlineno") { + bool openarray = portp->isDpiOpenArray(); bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32); bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1); if (args != "") { args+= ", "; } - if (bitvec) {} - else if (logicvec) {} - else if (portp->isOutput()) args += "&"; - else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() - && portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide) - args += portp->name()+"__Vcvt"; + if (openarray) { + // Ideally we'd make a table of variable characteristics, and reuse it wherever we can + // At least put them into the module's CTOR as static? + string propName = portp->name()+"__Vopenprops"; + string propCode = ("static const VerilatedVarProps "+propName + +"("+portp->vlPropInit()+");\n"); + cfuncp->addStmtsp(new AstCStmt(portp->fileline(), propCode)); + // + // At runtime we need the svOpenArrayHandle to point to this task & thread's data, + // in addition to static info about the variable + string name = portp->name()+"__Vopenarray"; + string varCode = ("VerilatedDpiOpenVar "+name + +" (&"+propName+", &"+portp->name()+");\n"); + cfuncp->addStmtsp(new AstCStmt(portp->fileline(), varCode)); + args += "&"+name; + } + else { + if (bitvec) {} + else if (logicvec) {} + else if (portp->isOutput()) args += "&"; + else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() + && portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide) - cfuncp->addStmtsp(createDpiTemp(portp,"__Vcvt")); - if (portp->isInput()) { - cfuncp->addStmtsp(createAssignInternalToDpi(portp,false,false,"","__Vcvt")); + args += portp->name()+"__Vcvt"; + + cfuncp->addStmtsp(createDpiTemp(portp,"__Vcvt")); + if (portp->isInput()) { + cfuncp->addStmtsp(createAssignInternalToDpi(portp,false,false,"","__Vcvt")); + } } } } @@ -883,7 +902,8 @@ private: // 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() && (portp->isOutput() || portp->isFuncReturn())) { + if (portp->isIO() && (portp->isOutput() || portp->isFuncReturn()) + && !portp->isDpiOpenArray()) { AstVarScope* portvscp = portp->user2p()->castVarScope(); // Remembered when we created it earlier cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt",true)); } @@ -916,10 +936,21 @@ private: } if (nodep->dpiImport()) { - string dpiproto = dpiprotoName(nodep, rtnvarp); - if (!duplicatedDpiProto(nodep, dpiproto)) { - makeDpiImportWrapper(nodep, rtnvarp); + if (nodep->dpiOpenChild()) { // The parent will make the dpi proto + if (nodep->dpiOpenParent()) nodep->v3fatalSrc("DPI task should be parent or wrapper, not both"); } + else { // Parent or not open child, make wrapper + string dpiproto = dpiprotoName(nodep, rtnvarp); + if (!duplicatedDpiProto(nodep, dpiproto)) { + makeDpiImportProto(nodep, rtnvarp); + } + if (nodep->dpiOpenParent()) { + // No need to make more than just the c prototype, children will + pushDeletep(nodep); VL_DANGLING(nodep); + return NULL; + } + } + } else if (nodep->dpiExport()) { string dpiproto = dpiprotoName(nodep, rtnvarp); if (!duplicatedDpiProto(nodep, dpiproto)) { @@ -1154,11 +1185,13 @@ private: if (m_statep->ftaskNoInline(nodep)) m_statep->checkPurity(nodep); AstNodeFTask* clonedFuncp = nodep->cloneTree(false); AstCFunc* cfuncp = makeUserFunc(clonedFuncp, m_statep->ftaskNoInline(nodep)); - nodep->addNextHere(cfuncp); - if (nodep->dpiImport() || m_statep->ftaskNoInline(nodep)) { - m_statep->ftaskCFuncp(nodep, cfuncp); + if (cfuncp) { + nodep->addNextHere(cfuncp); + if (nodep->dpiImport() || m_statep->ftaskNoInline(nodep)) { + m_statep->ftaskCFuncp(nodep, cfuncp); + } + iterateIntoFTask(clonedFuncp); // Do the clone too } - iterateIntoFTask(clonedFuncp); // Do the clone too } // Any variables inside the function still have varscopes pointing to them. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 5ef692af6..dcb277294 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -187,6 +187,7 @@ private: WidthVP* m_vup; // Current node state bool m_paramsOnly; // Computing parameter value; limit operation AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations + AstNodeFTask* m_ftaskp; // Current function/task AstFunc* m_funcp; // Current function AstInitial* m_initialp; // Current initial block AstAttrOf* m_attrp; // Current attribute @@ -970,6 +971,15 @@ private: } UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); + // Iterate into subDTypep() to resolve that type and update pointer. + nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + // Cleanup array size + nodep->dtypep(nodep); // The array itself, not subDtype + UINFO(4,"dtWidthed "<didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->generic()) return; // Already perfect @@ -1151,7 +1161,12 @@ private: if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype determined for var"); - if (nodep->isIO() && !(nodep->dtypeSkipRefp()->castBasicDType() + if (nodep->dtypeSkipRefp()->castUnsizedArrayDType()) { + if (!(m_ftaskp && m_ftaskp->dpiImport())) { + nodep->v3error("Unsized/open arrays ('[]') are only supported in DPI imports"); + } + } + else if (nodep->isIO() && !(nodep->dtypeSkipRefp()->castBasicDType() || nodep->dtypeSkipRefp()->castNodeArrayDType() || nodep->dtypeSkipRefp()->castNodeClassDType())) { nodep->v3error("Unsupported: Inputs and outputs must be simple data types"); @@ -2345,7 +2360,6 @@ private: virtual void visit(AstNodeFTask* nodep) { // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; - UINFO(5," FTASK "<doingWidth()) { nodep->v3error("Unsupported: Recursive function or task call"); nodep->dtypeSetLogicBool(); @@ -2354,6 +2368,7 @@ private: } // Function hasn't been widthed, so make it so. nodep->doingWidth(true); // Would use user1 etc, but V3Width called from too many places to spend a user + m_ftaskp = nodep; userIterateChildren(nodep, NULL); if (nodep->fvarp()) { m_funcp = nodep->castFunc(); @@ -2363,6 +2378,12 @@ private: nodep->didWidth(true); nodep->doingWidth(false); m_funcp = NULL; + m_ftaskp = NULL; + if (nodep->dpiImport() + && !nodep->dpiOpenParent() + && markHasOpenArray(nodep)) { + nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling func + } } virtual void visit(AstReturn* nodep) { // IEEE: Assignment-like context @@ -2469,6 +2490,10 @@ private: userIterate(pinp, WidthVP(portp->dtypep(),PRELIM).p()); } } + // Cleanup any open arrays + if (markHasOpenArray(nodep->taskp())) { + makeOpenArrayShell(nodep); + } // Stage 4 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); @@ -3686,6 +3711,50 @@ private: return patmap; } + void makeOpenArrayShell(AstNodeFTaskRef* nodep) { + UINFO(4,"Replicate openarray function "<taskp()<taskp(); + oldTaskp->dpiOpenParentInc(); + if (oldTaskp->dpiOpenChild()) oldTaskp->v3fatalSrc("DPI task should be parent or child, not both"); + AstNodeFTask* newTaskp = oldTaskp->cloneTree(false); + newTaskp->dpiOpenChild(true); + newTaskp->dpiOpenParentClear(); + newTaskp->name(newTaskp->name()+"__Vdpioc"+cvtToStr(oldTaskp->dpiOpenParent())); + oldTaskp->addNextHere(newTaskp); + // Relink reference to new function + nodep->taskp(newTaskp); + nodep->name(nodep->taskp()->name()); + // Replace open array arguments with the callee's task + V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); + for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { + AstVar* portp = it->first; + AstArg* argp = it->second; + AstNode* pinp = argp->exprp(); + if (!pinp) continue; // Argument error we'll find later + if (hasOpenArrayIterateDType(portp->dtypep())) { + portp->dtypep(pinp->dtypep()); + } + } + } + + bool markHasOpenArray(AstNodeFTask* nodep) { + bool hasOpen = false; + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { + if (AstVar* portp = stmtp->castVar()) { + if (portp->isDpiOpenArray() || hasOpenArrayIterateDType(portp->dtypep())) { + portp->isDpiOpenArray(true); + hasOpen = true; + } + } + } + return hasOpen; + } + bool hasOpenArrayIterateDType(AstNodeDType* nodep) { + // Return true iff this datatype or child has an openarray + if (nodep->castUnsizedArrayDType()) return true; + if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp()); + return false; + } //---------------------------------------------------------------------- // METHODS - special type detection @@ -3764,6 +3833,7 @@ public: // // don't wish to trigger errors m_paramsOnly = paramsOnly; m_cellRangep = NULL; + m_ftaskp = NULL; m_funcp = NULL; m_initialp = NULL; m_attrp = NULL; diff --git a/src/verilog.y b/src/verilog.y index 7cb489e26..6892f1f84 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -91,8 +91,9 @@ public: bool allTracingOn(FileLine* fl) { return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); } - AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked); - AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp); + AstRange* scrubRange(AstNodeRange* rangep); + AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked); + AstVar* createVariable(FileLine* fileline, string name, AstNodeRange* arrayp, AstNode* attrsp); AstNode* createSupplyExpr(FileLine* fileline, string name, int value); AstText* createTextQuoted(FileLine* fileline, string text) { string newtext = deQuote(fileline, text); @@ -131,7 +132,7 @@ public: } return pkgp; } - AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp, bool isPacked) { + AstNodeDType* addRange(AstBasicDType* dtypep, AstNodeRange* rangesp, bool isPacked) { // If dtypep isn't basic, don't use this, call createArray() instead if (!rangesp) { return dtypep; @@ -139,24 +140,26 @@ public: // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]" // then [1:1] becomes the basicdtype range; everything else is arraying // the final [5:5][4:4] will be passed in another call to createArray - AstRange* rangearraysp = NULL; - if (dtypep->isRanged()) { - rangearraysp = rangesp; // Already a range; everything is an array - } else { - AstRange* finalp = rangesp; - while (finalp->nextp()) finalp=finalp->nextp()->castRange(); - if (finalp != rangesp) { - finalp->unlinkFrBack(); - rangearraysp = rangesp; - } - if (dtypep->implicit()) { - // It's no longer implicit but a real logic type - AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC, - dtypep->numeric(), dtypep->width(), dtypep->widthMin()); - dtypep->deleteTree(); VL_DANGLING(dtypep); - dtypep = newp; - } - dtypep->rangep(finalp); + AstNodeRange* rangearraysp = NULL; + if (dtypep->isRanged()) { + rangearraysp = rangesp; // Already a range; everything is an array + } else { + AstNodeRange* finalp = rangesp; + while (finalp->nextp()) finalp=finalp->nextp()->castNodeRange(); + if (finalp != rangesp) { + finalp->unlinkFrBack(); + rangearraysp = rangesp; + } + if (AstRange* finalRangep = finalp->castRange()) { // not an UnsizedRange + if (dtypep->implicit()) { + // It's no longer implicit but a real logic type + AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC, + dtypep->numeric(), dtypep->width(), dtypep->widthMin()); + dtypep->deleteTree(); VL_DANGLING(dtypep); + dtypep = newp; + } + dtypep->rangep(finalRangep); + } } return createArray(dtypep, rangearraysp, isPacked); } @@ -1493,14 +1496,14 @@ variable_dimensionListE: // IEEE: variable_dimension + empty variable_dimensionList: // IEEE: variable_dimension + empty variable_dimension { $$ = $1; } - | variable_dimensionList variable_dimension { $$ = $1->addNext($2)->castRange(); } + | variable_dimensionList variable_dimension { $$ = $1->addNext($2)->castNodeRange(); } ; variable_dimension: // ==IEEE: variable_dimension // // IEEE: unsized_dimension - //UNSUP '[' ']' { UNSUP } + '[' ']' { $$ = new AstUnsizedRange($1); } // // IEEE: unpacked_dimension - anyrange { $$ = $1; } + | anyrange { $$ = $1; } | '[' constExpr ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstSub($1, $2, new AstConst($1, 1))); } // // IEEE: associative_dimension //UNSUP '[' data_type ']' { UNSUP } @@ -2005,7 +2008,7 @@ packed_dimensionListE: // IEEE: [{ packed_dimension }] packed_dimensionList: // IEEE: { packed_dimension } packed_dimension { $$ = $1; } - | packed_dimensionList packed_dimension { $$ = $1->addNext($2)->castRange(); } + | packed_dimensionList packed_dimension { $$ = $1->addNext($2)->castNodeRange(); } ; packed_dimension: // ==IEEE: packed_dimension @@ -2084,9 +2087,11 @@ instnameList: instnameParen: // // Must clone m_instParamp as may be comma'ed list of instances - id instRangeE '(' cellpinList ')' { $$ = new AstCell($1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp->cloneTree(true),$2); + id instRangeE '(' cellpinList ')' { $$ = new AstCell($1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp->cloneTree(true), + GRAMMARP->scrubRange($2)); $$->trace(GRAMMARP->allTracingOn($1)); } - | id instRangeE { $$ = new AstCell($1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp->cloneTree(true),$2); + | id instRangeE { $$ = new AstCell($1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp->cloneTree(true), + GRAMMARP->scrubRange($2)); $$->trace(GRAMMARP->allTracingOn($1)); } //UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP // // Adding above and switching to the Verilog-Perl syntax @@ -3391,7 +3396,7 @@ gateUnsupList: ; gateRangeE: - instRangeE { $$ = $1; GATERANGE($1); } + instRangeE { $$ = $1; GATERANGE(GRAMMARP->scrubRange($1)); } ; gateBuf: @@ -3831,26 +3836,42 @@ AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int v return nodep; } -AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked) { +AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { + // Remove any UnsizedRange's from list + for (AstNodeRange* nodep = nrangep, *nextp; nodep; nodep=nextp) { + nextp = nrangep->nextp()->castNodeRange(); + if (!nodep->castRange()) { + nodep->v3error("Unsupported or syntax error: Unsized range in cell or other declaration"); + nodep->unlinkFrBack(); nodep->deleteTree(); VL_DANGLING(nodep); + } + } + return nrangep->castRange(); +} + +AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep, bool isPacked) { // Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE) AstNodeDType* arrayp = basep; - if (rangep) { // Maybe no range - return unmodified base type - while (rangep->nextp()) rangep = rangep->nextp()->castRange(); - while (rangep) { - AstRange* prevp = rangep->backp()->castRange(); - if (prevp) rangep->unlinkFrBack(); - if (isPacked) { - arrayp = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); - } else { - arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); - } - rangep = prevp; - } + if (nrangep) { // Maybe no range - return unmodified base type + while (nrangep->nextp()) nrangep = nrangep->nextp()->castNodeRange(); + while (nrangep) { + AstNodeRange* prevp = nrangep->backp()->castNodeRange(); + if (prevp) nrangep->unlinkFrBack(); + AstRange* rangep = nrangep->castRange(); + if (!rangep) { + if (!nrangep->castUnsizedRange()) nrangep->v3fatalSrc("Expected range or unsized range"); + arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp); + } else if (isPacked) { + arrayp = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); + } else { + arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); + } + nrangep = prevp; + } } return arrayp; } -AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp) { +AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstNodeRange* arrayp, AstNode* attrsp) { AstNodeDType* dtypep = GRAMMARP->m_varDTypep; UINFO(5," creVar "<m_varIO == AstVarType::UNKNOWN diff --git a/test_regress/t/t_dpi_lib.v b/test_regress/t/t_dpi_lib.v index 480331199..296889601 100644 --- a/test_regress/t/t_dpi_lib.v +++ b/test_regress/t/t_dpi_lib.v @@ -17,9 +17,10 @@ module t (/*AUTOARG*/); $write("%%Error: Failure in DPI tests\n"); $stop; end - - $write("*-* All Finished *-*\n"); - $finish; + else begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule diff --git a/test_regress/t/t_dpi_lib_c.cpp b/test_regress/t/t_dpi_lib_c.cpp index 06572c831..f1c347c35 100644 --- a/test_regress/t/t_dpi_lib_c.cpp +++ b/test_regress/t/t_dpi_lib_c.cpp @@ -43,6 +43,7 @@ extern "C" { //====================================================================== int failure = 0; +int dpii_failure() { return failure; } #define CHECK_RESULT_HEX(got, exp) \ do { if ((got) != (exp)) { \ @@ -51,8 +52,6 @@ int failure = 0; failure = __LINE__; \ }} while(0) -int dpii_failure() { return failure; } - //====================================================================== void dpii_lib_bit_check() { diff --git a/test_regress/t/t_dpi_open.pl b/test_regress/t/t_dpi_open.pl new file mode 100755 index 000000000..08f291fbe --- /dev/null +++ b/test_regress/t/t_dpi_open.pl @@ -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 => ["t/t_dpi_open_c.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME -unroll-count 1"], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_open.v b/test_regress/t/t_dpi_open.v new file mode 100644 index 000000000..9690dc86f --- /dev/null +++ b/test_regress/t/t_dpi_open.v @@ -0,0 +1,150 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2017 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. + +`ifdef VERILATOR + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) +`else + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(0) +`endif + +module t (/*AUTOARG*/); + + // verilator lint_off UNUSED + reg i_rl_p0_u1 [-2:2]; + reg o_rl_p0_u1 [-2:2]; + reg [1:-1] i_rl_p1_u1 [-2:2]; + reg [1:-1] o_rl_p1_u1 [-2:2]; + reg [1:-1] i_rl_p1_u2 [-2:2] [-3:3]; + reg [1:-1] o_rl_p1_u2 [-2:2] [-3:3]; + reg [1:-1] i_rl_p1_u3 [-2:2] [-3:3] [-4:4]; + reg [1:-1] o_rl_p1_u3 [-2:2] [-3:3] [-4:4]; + + reg i_rb_p0_u1 [2:-2]; + reg o_rb_p0_u1 [2:-2]; + reg [1:-1] i_rb_p1_u1 [2:-2]; + reg [1:-1] o_rb_p1_u1 [2:-2]; + reg [1:-1] i_rb_p1_u2 [2:-2] [3:-3]; + reg [1:-1] o_rb_p1_u2 [2:-2] [3:-3]; + reg [1:-1] i_rb_p1_u3 [2:-2] [3:-3] [4:-4]; + reg [1:-1] o_rb_p1_u3 [2:-2] [3:-3] [4:-4]; + + reg i_rw_p0_u1 [2:-2]; + reg o_rw_p0_u1 [2:-2]; + reg [95:1] i_rw_p1_u1 [2:-2]; + reg [95:1] o_rw_p1_u1 [2:-2]; + reg [95:1] i_rw_p1_u2 [2:-2] [3:-3]; + reg [95:1] o_rw_p1_u2 [2:-2] [3:-3]; + reg [95:1] i_rw_p1_u3 [2:-2] [3:-3] [4:-4]; + reg [95:1] o_rw_p1_u3 [2:-2] [3:-3] [4:-4]; + + bit i_bit [1:0]; + bit o_bit [1:0]; + logic i_logic [1:0]; + logic o_logic [1:0]; + byte i_byte [1:0]; + byte o_byte [1:0]; + int i_int [1:0]; + int o_int [1:0]; + integer i_integer [1:0]; + integer o_integer [1:0]; + // verilator lint_on UNUSED + + import "DPI-C" function int dpii_failure(); + + import "DPI-C" function void dpii_unused(input reg u []); + + // [] on packed arrays is unsupported in VCS & NC, so not supporting this + + import "DPI-C" function void dpii_open_p0_u1(input int c,p,u, input reg i [], output reg o []); + import "DPI-C" function void dpii_open_p1_u1(input int c,p,u, input reg [1:-1] i [], output reg [1:-1] o []); + import "DPI-C" function void dpii_open_p1_u2(input int c,p,u, input reg [1:-1] i [] [], output reg [1:-1] o [] []); + import "DPI-C" function void dpii_open_p1_u3(input int c,p,u, input reg [1:-1] i [] [] [], output reg [1:-1] o [] [] []); + + import "DPI-C" function void dpii_open_pw_u1(input int c,p,u, input reg [95:1] i [], output reg [95:1] o []); + import "DPI-C" function void dpii_open_pw_u2(input int c,p,u, input reg [95:1] i [] [], output reg [95:1] o [] []); + import "DPI-C" function void dpii_open_pw_u3(input int c,p,u, input reg [95:1] i [] [] [], output reg [95:1] o [] [] []); + + import "DPI-C" function void dpii_open_bit(input bit i [], output bit o []); + import "DPI-C" function void dpii_open_logic(input logic i [], output logic o []); + import "DPI-C" function void dpii_open_byte(input byte i [], output byte o []); + import "DPI-C" function void dpii_open_int(input int i [], output int o []); + import "DPI-C" function void dpii_open_integer(input integer i [], output integer o []); + + import "DPI-C" function int dpii_failed(); + + reg [95:0] crc; + + initial begin + crc = 96'h8a10a572_5aef0c8d_d70a4497; + + for (int a=0; a<2; a=a+1) begin + i_bit[a] = crc[0]; + i_logic[a] = crc[0]; + i_byte[a] = crc[7:0]; + i_int[a] = crc[31:0]; + i_integer[a] = crc[31:0]; + crc = {crc[94:0], crc[95]^crc[2]^crc[0]}; + end + + dpii_open_bit(i_bit, o_bit); + dpii_open_logic(i_logic, o_logic); + dpii_open_byte(i_byte, o_byte); + dpii_open_int(i_int, o_int); + dpii_open_integer(i_integer, o_integer); + + for (int a=-2; a<=2; a=a+1) begin + i_rl_p0_u1[a] = crc[0]; + i_rb_p0_u1[a] = crc[0]; + i_rw_p0_u1[a] = crc[0]; + i_rl_p1_u1[a] = crc[2:0]; + i_rb_p1_u1[a] = crc[2:0]; + i_rw_p1_u1[a] = crc[94:0]; + for (int b=-3; b<=3; b=b+1) begin + i_rl_p1_u2[a][b] = crc[2:0]; + i_rb_p1_u2[a][b] = crc[2:0]; + i_rw_p1_u2[a][b] = crc[94:0]; + for (int c=-4; c<=4; c=c+1) begin + i_rl_p1_u3[a][b][c] = crc[2:0]; + i_rb_p1_u3[a][b][c] = crc[2:0]; + i_rw_p1_u3[a][b][c] = crc[94:0]; + crc = {crc[94:0], crc[95]^crc[2]^crc[0]}; + end + end + end + + dpii_open_p0_u1(0,0,1, i_rl_p0_u1, o_rl_p0_u1); + dpii_open_p0_u1(1,0,1, i_rb_p0_u1, o_rb_p0_u1); + dpii_open_p0_u1(2,0,1, i_rw_p0_u1, o_rw_p0_u1); + dpii_open_p1_u1(0,1,1, i_rl_p1_u1, o_rl_p1_u1); + dpii_open_p1_u2(0,1,2, i_rl_p1_u2, o_rl_p1_u2); + dpii_open_p1_u3(0,1,3, i_rl_p1_u3, o_rl_p1_u3); + dpii_open_p1_u1(1,1,1, i_rb_p1_u1, o_rb_p1_u1); + dpii_open_p1_u2(1,1,2, i_rb_p1_u2, o_rb_p1_u2); + dpii_open_p1_u3(1,1,3, i_rb_p1_u3, o_rb_p1_u3); + dpii_open_pw_u1(2,1,1, i_rw_p1_u1, o_rw_p1_u1); + dpii_open_pw_u2(2,1,2, i_rw_p1_u2, o_rw_p1_u2); + dpii_open_pw_u3(2,1,3, i_rw_p1_u3, o_rw_p1_u3); + + for (int a=-2; a<=2; a=a+1) begin + for (int b=-3; b<=3; b=b+1) begin + for (int c=-4; c<=4; c=c+1) begin + `checkh(o_rw_p1_u3[a][b][c], ~i_rw_p1_u3[a][b][c]); + end + end + end + + if (dpii_failure()!=0) begin + $write("%%Error: Failure in DPI tests\n"); + $stop; + end + else begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_dpi_open_c.cpp b/test_regress/t/t_dpi_open_c.cpp new file mode 100644 index 000000000..2bc672a6f --- /dev/null +++ b/test_regress/t/t_dpi_open_c.cpp @@ -0,0 +1,233 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2017 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 +#include +#include +#include "svdpi.h" + +//====================================================================== + +#if defined(VERILATOR) +# include "Vt_dpi_open__Dpi.h" +#elif defined(VCS) +# include "../vc_hdrs.h" +#elif defined(NC) +# define NEED_EXTERNS +#else +# error "Unknown simulator for DPI test" +#endif + +#ifdef NEED_EXTERNS +extern "C" { + // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. + // Then probably forgot to list a function here. + + extern void dpii_unused(const svOpenArrayHandle u); + + extern void dpii_open_p0_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_p1_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_p1_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_p1_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_p1_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_pw_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_pw_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_pw_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_pw_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); + + extern void dpii_open_bit (const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_byte (const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_int (const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_integer (const svOpenArrayHandle i, const svOpenArrayHandle o); + extern void dpii_open_logic (const svOpenArrayHandle i, const svOpenArrayHandle o); + + extern int dpii_failure(); +} +#endif + +//====================================================================== + +// Untested: +//void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...); +//void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...); +//void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1); +//void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...); +//void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1); +//void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...); +//void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1); +//void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...); +//void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1); +//svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...); +//svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1); +//svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...); +//svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1); +//void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...); +//void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1); +//void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...); +//void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1); + +//====================================================================== + +int failure = 0; +int dpii_failure() { return failure; } + +#ifdef _WIN32 +# define T_PRI64 "I64" +#else // Linux or compliant Unix flavors +# define T_PRI64 "ll" +#endif + +#define CHECK_RESULT_HEX(got, exp) \ + do { if ((got) != (exp)) { \ + std::cout<=1) { + int d=1; + if (c==0) { + CHECK_RESULT_HEX(svLeft(i, d), -2); + CHECK_RESULT_HEX(svRight(i, d), 2); + CHECK_RESULT_HEX(svLow(i, d), -2); + CHECK_RESULT_HEX(svHigh(i, d), 2); + //CHECK_RESULT_HEX(svIncrement(i, d), 0); + CHECK_RESULT_HEX(svSize(i, d), 5); + } else if (c==1) { + CHECK_RESULT_HEX(svLeft(i, d), 2); + CHECK_RESULT_HEX(svRight(i, d), -2); + CHECK_RESULT_HEX(svLow(i, d), -2); + CHECK_RESULT_HEX(svHigh(i, d), 2); + //CHECK_RESULT_HEX(svIncrement(i, d), 0); + CHECK_RESULT_HEX(svSize(i, d), 5); + } + } + if (u>=2) { + int d=2; + if (c==0) { + CHECK_RESULT_HEX(svLeft(i, d), -3); + CHECK_RESULT_HEX(svRight(i, d), 3); + CHECK_RESULT_HEX(svLow(i, d), -3); + CHECK_RESULT_HEX(svHigh(i, d), 3); + //CHECK_RESULT_HEX(svIncrement(i, d), 0); + CHECK_RESULT_HEX(svSize(i, d), 7); + } else if (c==1) { + CHECK_RESULT_HEX(svLeft(i, d), 3); + CHECK_RESULT_HEX(svRight(i, d), -3); + CHECK_RESULT_HEX(svLow(i, d), -3); + CHECK_RESULT_HEX(svHigh(i, d), 3); + //CHECK_RESULT_HEX(svIncrement(i, d), 0); + CHECK_RESULT_HEX(svSize(i, d), 7); + } + } + + if (c==2 && p==1 && u==3) { + for (int a=svLow(i,1); a<=svHigh(i,1); ++a) { + for (int b=svLow(i,2); b<=svHigh(i,2); ++b) { + for (int c=svLow(i,3); c<=svHigh(i,3); ++c) { + //printf("Copy abc %d,%d,%d\n", a,b,c); + svLogicVecVal vec[3]; + svGetLogicArrElemVecVal(vec, i, a, b, c); +#ifdef NC + //printf(" %08lx_%08lx_%08lx\n", vec[2].a, vec[1].a, vec[0].a); + vec[0].a = (~vec[0].a); + vec[1].a = (~vec[1].a); + vec[2].a = (~vec[2].a) & 0x7fffffff; + vec[0].b = vec[0].b; + vec[1].b = vec[1].b; + vec[2].b = vec[2].b; +#else + vec[0].aval = (~vec[0].aval); + vec[1].aval = (~vec[1].aval); + vec[2].aval = (~vec[2].aval) & 0x7fffffff; + vec[0].bval = vec[0].bval; + vec[1].bval = vec[1].bval; + vec[2].bval = vec[2].bval; +#endif + svPutLogicArrElemVecVal(o, vec, a, b, c); + } + } + } + } +} + +void dpii_open_p0_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_p1_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_p1_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_p1_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_p1_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_pw_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_pw_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_pw_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} +void dpii_open_pw_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { + _dpii_all(c,p,u,i,o); +} + +void dpii_open_bit (const svOpenArrayHandle i, const svOpenArrayHandle o) { } +void dpii_open_byte (const svOpenArrayHandle i, const svOpenArrayHandle o) { } +void dpii_open_int (const svOpenArrayHandle i, const svOpenArrayHandle o) { } +void dpii_open_integer (const svOpenArrayHandle i, const svOpenArrayHandle o) { } +void dpii_open_logic (const svOpenArrayHandle i, const svOpenArrayHandle o) { } + +int dpii_failed() { + return failure; +} diff --git a/test_regress/t/t_dpi_openfirst.pl b/test_regress/t/t_dpi_openfirst.pl new file mode 100755 index 000000000..cb699b0e8 --- /dev/null +++ b/test_regress/t/t_dpi_openfirst.pl @@ -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 => ["t/t_dpi_openfirst_c.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_openfirst.v b/test_regress/t/t_dpi_openfirst.v new file mode 100644 index 000000000..1fba53823 --- /dev/null +++ b/test_regress/t/t_dpi_openfirst.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2017 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. + +`ifdef VERILATOR + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) +`else + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(0) +`endif + +module t (/*AUTOARG*/); + + int i_i [2:0]; + int o_i [2:0]; + + import "DPI-C" function int dpii_failure(); + import "DPI-C" function void dpii_open_i(input int i [], output int o []); + + reg [95:0] crc; + + initial begin + crc = 96'h8a10a572_5aef0c8d_d70a4497; + + i_i[0] = crc[31:0]; + i_i[1] = crc[63:32]; + i_i[2] = crc[95:64]; + dpii_open_i(i_i, o_i); + `checkh(o_i[0], ~i_i[0]); + `checkh(o_i[1], ~i_i[1]); + `checkh(o_i[2], ~i_i[2]); + + if (dpii_failure()!=0) begin + $write("%%Error: Failure in DPI tests\n"); + $stop; + end + else begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_dpi_openfirst_c.cpp b/test_regress/t/t_dpi_openfirst_c.cpp new file mode 100644 index 000000000..4dea967e2 --- /dev/null +++ b/test_regress/t/t_dpi_openfirst_c.cpp @@ -0,0 +1,77 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2017 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 +#include +#include +#include "svdpi.h" + +//====================================================================== + +#if defined(VERILATOR) +# include "Vt_dpi_openfirst__Dpi.h" +#elif defined(VCS) +# include "../vc_hdrs.h" +#elif defined(NC) +# define NEED_EXTERNS +#else +# error "Unknown simulator for DPI test" +#endif + +#ifdef NEED_EXTERNS +extern "C" { + // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. + // Then probably forgot to list a function here. + + extern int dpii_failure(); + extern void dpii_open_i(const svOpenArrayHandle i, const svOpenArrayHandle o); +} +#endif + +//====================================================================== + +int failure = 0; +int dpii_failure() { return failure; } + +#define CHECK_RESULT_HEX(got, exp) \ + do { if ((got) != (exp)) { \ + std::cout< ["--lint-only"], + fails=>$Self->{v3}, + expect=> +'%Error: t/t_dpi_openreg_bad.v:\d+: Unsized/open arrays \(\'\[\]\'\) are only supported in DPI imports +%Error: t/t_dpi_openreg_bad.v:\d+: Unsized/open arrays \(\'\[\]\'\) are only supported in DPI imports +%Error: Exiting due to .*' + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_openreg_bad.v b/test_regress/t/t_dpi_openreg_bad.v new file mode 100644 index 000000000..f2b5375e0 --- /dev/null +++ b/test_regress/t/t_dpi_openreg_bad.v @@ -0,0 +1,20 @@ +// 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 (/*AUTOARG*/ + // Inputs + b + ); + + reg a []; + input b []; + + initial begin + $stop; + end + +endmodule