diff --git a/Changes b/Changes index eb44aa0c5..6760b9f47 100644 --- a/Changes +++ b/Changes @@ -12,6 +12,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support bind, to module names only, bug602. [Ed Lander] +*** Support VPI product info, warning calls, etc, bug588. [Rick Porter] + *** Define SYSTEMVERILOG, SV_COV_START and other IEEE mandated predefines. **** Fix pin width mismatch error, bug595. [Alex Solomatnikov] diff --git a/Makefile.in b/Makefile.in index 8e2b56e21..0ca6b7219 100644 --- a/Makefile.in +++ b/Makefile.in @@ -455,7 +455,7 @@ clean mostlyclean distclean maintainer-clean:: distclean maintainer-clean:: rm -f Makefile config.status config.cache config.log verilator_bin* TAGS - rm -f include/verilated.mk + rm -f include/verilated.mk include/verilated_config.h TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \ ${srcdir}/*.in ${srcdir}/*.pod diff --git a/configure.ac b/configure.ac index 01709b820..403b2df56 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ #AC_INIT([Verilator],[#.### devel]) AC_INIT([Verilator],[3.845 devel]) AC_CONFIG_HEADER(src/config_build.h) -AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk) +AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h) AC_MSG_RESULT([configuring for $PACKAGE_STRING]) diff --git a/include/.gitignore b/include/.gitignore index 5ecf2901c..b9d2981cb 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -1 +1,2 @@ verilated.mk +verilated_config.h diff --git a/include/verilated.cpp b/include/verilated.cpp index 63736ad07..23e345cf0 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -40,6 +40,7 @@ Verilated::Serialized Verilated::s_s; VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL; VL_THREAD const char* Verilated::t_dpiFilename = ""; VL_THREAD int Verilated::t_dpiLineno = 0; +struct Verilated::CommandArgValues Verilated::s_args = {0, NULL}; VerilatedImp VerilatedImp::s_s; @@ -86,6 +87,7 @@ Verilated::Serialized::Serialized() { s_calcUnusedSigs = false; s_gotFinish = false; s_assertOn = true; + s_fatalOnVpiError = true; // retains old default behaviour } //=========================================================================== @@ -1064,6 +1066,8 @@ void Verilated::flushCb(VerilatedVoidCb cb) { } void Verilated::commandArgs(int argc, const char** argv) { + s_args.argc = argc; + s_args.argv = argv; VerilatedImp::commandArgs(argc,argv); } diff --git a/include/verilated.h b/include/verilated.h index 298203840..cf14cce0b 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -28,6 +28,7 @@ #ifndef _VERILATED_H_ #define _VERILATED_H_ 1 ///< Header Guard +#include "verilated_config.h" #include "verilatedos.h" #include @@ -229,6 +230,7 @@ private: bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated bool s_gotFinish; ///< A $finish statement executed bool s_assertOn; ///< Assertions are enabled + bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported Serialized(); } s_s; @@ -236,6 +238,13 @@ private: static VL_THREAD const char* t_dpiFilename; ///< DPI context filename static VL_THREAD int t_dpiLineno; ///< DPI context line number + // no need to be save-restored (serialized) the + // assumption is that the restore is allowed to pass different arguments + static struct CommandArgValues { + int argc; + const char** argv; + } s_args; + public: // METHODS - User called @@ -268,6 +277,9 @@ public: /// Enable/disable assertions static void assertOn(bool flag) { s_s.s_assertOn=flag; } static bool assertOn() { return s_s.s_assertOn; } + /// Enable/disable vpi fatal + static void fatalOnVpiError(bool flag) { s_s.s_fatalOnVpiError=flag; } + static bool fatalOnVpiError() { return s_s.s_fatalOnVpiError; } /// Flush callback for VCD waves static void flushCb(VerilatedVoidCb cb); static void flushCall() { if (s_flushCb) (*s_flushCb)(); } @@ -275,8 +287,13 @@ public: /// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs static void commandArgs(int argc, const char** argv); static void commandArgs(int argc, char** argv) { commandArgs(argc,(const char**)argv); } + static CommandArgValues* getCommandArgs() {return &s_args;} static const char* commandArgsPlusMatch(const char* prefixp); + /// Produce name & version for (at least) VPI + static const char* productName() { return VERILATOR_PRODUCT; } + static const char* productVersion() { return VERILATOR_VERSION; } + /// For debugging, print text list of all scope names with /// dpiImport/Export context. This function may change in future /// releases - contact the authors before production use. diff --git a/include/verilated_config.h.in b/include/verilated_config.h.in new file mode 100644 index 000000000..a9d63ccec --- /dev/null +++ b/include/verilated_config.h.in @@ -0,0 +1,28 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License. +// Version 2.0. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* +/// +/// \file +/// \brief Verilator: Auto version information include for all Verilated C files +/// +/// Code available from: http://www.veripool.org/verilator +/// +//************************************************************************* + + +///**** Product and Version name + +// Autoconf substitutes this with the strings from AC_INIT. +#define VERILATOR_PRODUCT "@PACKAGE_NAME@" +#define VERILATOR_VERSION "@PACKAGE_VERSION@" diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 2300f55fa..c5906e0ea 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -31,3 +31,334 @@ VerilatedVpi VerilatedVpi::s_s; // Singleton vluint8_t* VerilatedVpio::s_freeHead = NULL; //====================================================================== + +const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) { + static const char *names[] = { + "*undefined*", + "vpiBinStrVal", + "vpiOctStrVal", + "vpiDecStrVal", + "vpiHexStrVal", + "vpiScalarVal", + "vpiIntVal", + "vpiRealVal", + "vpiStringVal", + "vpiVectorVal", + "vpiStrengthVal", + "vpiTimeVal", + "vpiObjTypeVal", + "vpiSuppressVal", + "vpiShortIntVal", + "vpiLongIntVal", + "vpiShortRealVal", + "vpiRawTwoStateVal", + "vpiRawFourStateVal", + }; + if (vpiVal < 0) return names[0]; + return names[(vpiVal<=vpiRawFourStateVal)?vpiVal:0]; +} +const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) { + static const char *names[] = { + "*undefined*", + "vpiAlways", + "vpiAssignStmt", + "vpiAssignment", + "vpiBegin", + "vpiCase", + "vpiCaseItem", + "vpiConstant", + "vpiContAssign", + "vpiDeassign", + "vpiDefParam", + "vpiDelayControl", + "vpiDisable", + "vpiEventControl", + "vpiEventStmt", + "vpiFor", + "vpiForce", + "vpiForever", + "vpiFork", + "vpiFuncCall", + "vpiFunction", + "vpiGate", + "vpiIf", + "vpiIfElse", + "vpiInitial", + "vpiIntegerVar", + "vpiInterModPath", + "vpiIterator", + "vpiIODecl", + "vpiMemory", + "vpiMemoryWord", + "vpiModPath", + "vpiModule", + "vpiNamedBegin", + "vpiNamedEvent", + "vpiNamedFork", + "vpiNet", + "vpiNetBit", + "vpiNullStmt", + "vpiOperation", + "vpiParamAssign", + "vpiParameter", + "vpiPartSelect", + "vpiPathTerm", + "vpiPort", + "vpiPortBit", + "vpiPrimTerm", + "vpiRealVar", + "vpiReg", + "vpiRegBit", + "vpiRelease", + "vpiRepeat", + "vpiRepeatControl", + "vpiSchedEvent", + "vpiSpecParam", + "vpiSwitch", + "vpiSysFuncCall", + "vpiSysTaskCall", + "vpiTableEntry", + "vpiTask", + "vpiTaskCall", + "vpiTchk", + "vpiTchkTerm", + "vpiTimeVar", + "vpiTimeQueue", + "vpiUdp", + "vpiUdpDefn", + "vpiUserSystf", + "vpiVarSelect", + "vpiWait", + "vpiWhile", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "vpiAttribute", + "vpiBitSelect", + "vpiCallback", + "vpiDelayTerm", + "vpiDelayDevice", + "vpiFrame", + "vpiGateArray", + "vpiModuleArray", + "vpiPrimitiveArray", + "vpiNetArray", + "vpiRange", + "vpiRegArray", + "vpiSwitchArray", + "vpiUdpArray", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "*undefined*", + "vpiContAssignBit", + "vpiNamedEventArray", + "vpiIndexedPartSelect", + "*undefined*", + "*undefined*", + "vpiGenScopeArray", + "vpiGenScope", + "vpiGenVar" + }; + if (vpiVal < 0) return names[0]; + return names[(vpiVal<=vpiGenVar)?vpiVal:0]; +} +const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) { + static const char *names[] = { + "vpiCondition", + "vpiDelay", + "vpiElseStmt", + "vpiForIncStmt", + "vpiForInitStmt", + "vpiHighConn", + "vpiLhs", + "vpiIndex", + "vpiLeftRange", + "vpiLowConn", + "vpiParent", + "vpiRhs", + "vpiRightRange", + "vpiScope", + "vpiSysTfCall", + "vpiTchkDataTerm", + "vpiTchkNotifier", + "vpiTchkRefTerm", + "vpiArgument", + "vpiBit", + "vpiDriver", + "vpiInternalScope", + "vpiLoad", + "vpiModDataPathIn", + "vpiModPathIn", + "vpiModPathOut", + "vpiOperand", + "vpiPortInst", + "vpiProcess", + "vpiVariables", + "vpiUse", + "vpiExpr", + "vpiPrimitive", + "vpiStmt" + }; + if (vpiVal>vpiStmt || vpiValsetMessage(vpiInternal)->setMessage +#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage +#define _VL_VPI_ERROR VerilatedVpi::error_info()->setMessage(vpiError )->setMessage +#define _VL_VPI_WARNING VerilatedVpi::error_info()->setMessage(vpiWarning )->setMessage +#define _VL_VPI_NOTICE VerilatedVpi::error_info()->setMessage(vpiNotice )->setMessage +#define _VL_VPI_ERROR_RESET VerilatedVpi::error_info()->resetError + // Not supported yet #define _VL_VPI_UNIMP() \ - vl_fatal(__FILE__,__LINE__,"",Verilated::catName("Unsupported VPI function: ",VL_FUNC)) + _VL_VPI_ERROR(__FILE__,__LINE__,Verilated::catName("Unsupported VPI function: ",VL_FUNC)); //====================================================================== // Implementation @@ -49,6 +54,7 @@ #include #define VL_DEBUG_IF_PLI VL_DEBUG_IF +#define VL_VPI_LINE_SIZE 8192 // Base VPI handled object class VerilatedVpio { @@ -160,7 +166,10 @@ class VerilatedVpioVar : public VerilatedVpio { const VerilatedVar* m_varp; const VerilatedScope* m_scopep; vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange - vluint32_t m_mask; // memoized variable mask + union { + vluint8_t u8[4]; + vluint32_t u32; + } m_mask; // memoized variable mask vluint32_t m_entSize; // memoized variable size protected: void* m_varDatap; // varp()->datap() adjusted for array entries @@ -169,7 +178,7 @@ public: VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep) : m_varp(varp), m_scopep(scopep), m_index(0) { m_prevDatap = NULL; - m_mask = VL_MASK_I(varp->range().bits()); + m_mask.u32 = VL_MASK_I(varp->range().bits()); m_entSize = varp->entSize(); m_varDatap = varp->datap(); } @@ -179,7 +188,8 @@ public: static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } const VerilatedVar* varp() const { return m_varp; } const VerilatedScope* scopep() const { return m_scopep; } - vluint32_t mask() const { return m_mask; } + vluint32_t mask() const { return m_mask.u32; } + vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; } vluint32_t entSize() const { return m_entSize; } virtual const char* name() { return m_varp->name(); } virtual const char* fullname() { @@ -250,6 +260,8 @@ struct VerilatedVpiTimedCbsCmp { } }; +struct VerilatedVpiError; + class VerilatedVpi { enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason typedef set VpioCbSet; @@ -257,6 +269,7 @@ class VerilatedVpi { VpioCbSet m_cbObjSets[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason VpioTimedCbs m_timedCbs; // Time based callbacks + VerilatedVpiError* m_errorInfop; // Container for vpi error info static VerilatedVpi s_s; // Singleton @@ -338,12 +351,104 @@ public: } } } + + static VerilatedVpiError* error_info(); // getter for vpi error info }; +#define _VL_VPI_ERROR_SET \ + do { \ + va_list args; \ + va_start(args, message); \ + vsnprintf(m_buff, sizeof(m_buff), message.c_str(), args); \ + va_end(args); \ + } while (0) + +class VerilatedVpiError { + //// Container for vpi error info + + t_vpi_error_info m_errorInfo; + bool m_flag; + char m_buff[VL_VPI_LINE_SIZE]; + void setError(PLI_BYTE8 *message, PLI_BYTE8 *file, PLI_INT32 line) { + m_errorInfo.message = message; + m_errorInfo.file = file; + m_errorInfo.line = line; + m_errorInfo.code = NULL; + do_callbacks(); + } + void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) { + setError( message, file, line); + m_errorInfo.code = code; + do_callbacks(); + } + void do_callbacks() { + if (getError()->level >= vpiError && Verilated::fatalOnVpiError()) { + // Stop on vpi error/unsupported + vpi_unsupported(); + } + // We need to run above code first because in the case that the callback executes further vpi + // functions we will loose the error as it will be overwritten. + VerilatedVpi::callCbs(cbPLIError); + } +public: + + VerilatedVpiError() : m_flag(false) { + m_errorInfo.product = (PLI_BYTE8*)Verilated::productName(); + } + ~VerilatedVpiError() {} + VerilatedVpiError* setMessage(PLI_INT32 level) { + m_flag=true; + m_errorInfo.level = level; + return this; + } + void setMessage(string file, PLI_INT32 line, string message, ...) { + _VL_VPI_ERROR_SET; + m_errorInfo.state = vpiPLI; + setError((PLI_BYTE8*)m_buff, (PLI_BYTE8*)file.c_str(), line); + } + void setMessage(PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line, string message, ...) { + _VL_VPI_ERROR_SET; + m_errorInfo.state = vpiPLI; + setError((PLI_BYTE8*)message.c_str(), code, file, line); + } + p_vpi_error_info getError() { + if (m_flag) return &m_errorInfo; + return NULL; + } + void resetError() { + m_flag=false; + } + static void vpi_unsupported() { + // Not supported yet + p_vpi_error_info error_info_p = VerilatedVpi::error_info()->getError(); + if (error_info_p) { + vl_fatal(error_info_p->file, error_info_p->line, "", error_info_p->message); + return; + } + vl_fatal(error_info_p->file, error_info_p->line, "", "vpi_unsupported called without error info set"); + } + static const char* strFromVpiVal(PLI_INT32 vpiVal); + static const char* strFromVpiObjType(PLI_INT32 vpiVal); + static const char* strFromVpiMethod(PLI_INT32 vpiVal); + static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal); + static const char* strFromVpiProp(PLI_INT32 vpiVal); +}; + +VerilatedVpiError* VerilatedVpi::error_info() { + if (s_s.m_errorInfop == NULL) { + s_s.m_errorInfop = new VerilatedVpiError(); + } + return s_s.m_errorInfop; +} + // callback related vpiHandle vpi_register_cb(p_cb_data cb_data_p) { - if (VL_UNLIKELY(!cb_data_p)) return NULL; + _VL_VPI_ERROR_RESET(); // reset vpi error status + if (VL_UNLIKELY(!cb_data_p)) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s : callback data pointer is null", VL_FUNC); + return NULL; + } switch (cb_data_p->reason) { case cbAfterDelay: { QData time = 0; @@ -359,6 +464,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) { case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp + case cbPLIError: // FALLTHRU // NOP, but need to return handle, so make object case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object case cbInteractiveScopeChange: { // FALLTHRU // NOP, but need to return handle, so make object @@ -368,13 +474,16 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) { return vop->castVpiHandle(); } default: - _VL_VPI_UNIMP(); return NULL; + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", + VL_FUNC, VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason)); + return NULL; }; } PLI_INT32 vpi_remove_cb(vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_remove_cb %p\n",object);); VerilatedVpioCb* vop = VerilatedVpioCb::castp(object); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!vop)) return 0; if (vop->cb_datap()->reason == cbAfterDelay) { VerilatedVpi::cbTimedRemove(vop); @@ -384,19 +493,20 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) { return 1; } -//-void vpi_get_cb_info(vpiHandle object, p_cb_data cb_data_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-vpiHandle vpi_register_systf(p_vpi_systf_data systf_data_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-void vpi_get_systf_info(vpiHandle object, p_vpi_systf_data systf_data_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} +void vpi_get_cb_info(vpiHandle object, p_cb_data cb_data_p) { + _VL_VPI_UNIMP(); return; +} +vpiHandle vpi_register_systf(p_vpi_systf_data systf_data_p) { + _VL_VPI_UNIMP(); return 0; +} +void vpi_get_systf_info(vpiHandle object, p_vpi_systf_data systf_data_p) { + _VL_VPI_UNIMP(); return; +} // for obtaining handles vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!namep)) return NULL; VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_name %s %p\n",namep,scope);); VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope); @@ -432,6 +542,7 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { // Used to get array entries VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_index %p %d\n",object, indx);); VerilatedVpioVar* varop = VerilatedVpioVar::castp(object); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_LIKELY(varop)) { if (varop->varp()->dims()<2) return 0; if (VL_LIKELY(varop->varp()->array().lhs() >= varop->varp()->array().rhs())) { @@ -446,7 +557,8 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { ->castVpiHandle(); } } else { - _VL_VPI_UNIMP(); return 0; + _VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC); + return 0; } } @@ -454,6 +566,7 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle %d %p\n",type,object);); + _VL_VPI_ERROR_RESET(); // reset vpi error status switch (type) { case vpiLeftRange: // FALLTHRU case vpiRightRange: { @@ -472,17 +585,19 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) { } } default: - _VL_VPI_UNIMP(); + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", + VL_FUNC, VerilatedVpiError::strFromVpiMethod(type)); return 0; } } -//-vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle refHandle1, vpiHandle refHandle2, ... ) { -//- _VL_VPI_UNIMP(); return 0; -//-} +vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle refHandle1, vpiHandle refHandle2, ... ) { + _VL_VPI_UNIMP(); return 0; +} vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_iterate %d %p\n",type,object);); + _VL_VPI_ERROR_RESET(); // reset vpi error status switch (type) { case vpiMemoryWord: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); @@ -499,15 +614,15 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { return ((new VerilatedVpioVarIter(vop->scopep())) ->castVpiHandle()); } - case vpiIODecl: // Skipping - we'll put under reg - case vpiNet: // Skipping - we'll put under reg - return 0; default: - _VL_VPI_UNIMP(); return 0; + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", + VL_FUNC, VerilatedVpiError::strFromVpiObjType(type)); + return 0; } } vpiHandle vpi_scan(vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_scan %p\n",object);); + _VL_VPI_ERROR_RESET(); // reset vpi error status VerilatedVpio* vop = VerilatedVpio::castp(object); if (VL_UNLIKELY(!vop)) return NULL; return vop->dovpi_scan(); @@ -518,6 +633,7 @@ vpiHandle vpi_scan(vpiHandle object) { PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { // Leave this in the header file - in many cases the compiler can constant propagate "object" VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get %d %p\n",property,object);); + _VL_VPI_ERROR_RESET(); // reset vpi error status switch (property) { case vpiTimePrecision: { return VL_TIME_PRECISION; @@ -540,18 +656,21 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { else return 1; } default: - _VL_VPI_UNIMP(); + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", + VL_FUNC, VerilatedVpiError::strFromVpiProp(property)); return 0; } } -//-PLI_INT64 vpi_get64(PLI_INT32 property, vpiHandle object) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_INT64 vpi_get64(PLI_INT32 property, vpiHandle object) { + _VL_VPI_UNIMP(); + return 0; +} PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_str %d %p\n",property,object);); VerilatedVpio* vop = VerilatedVpio::castp(object); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!vop)) return NULL; switch (property) { case vpiName: { @@ -564,27 +683,34 @@ PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) { return (PLI_BYTE8*)vop->defname(); } default: - _VL_VPI_UNIMP(); + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", + VL_FUNC, VerilatedVpiError::strFromVpiProp(property)); return 0; } } // delay processing -//-void vpi_get_delays(vpiHandle object, p_vpi_delay delay_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-void vpi_put_delays(vpiHandle object, p_vpi_delay delay_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} +void vpi_get_delays(vpiHandle object, p_vpi_delay delay_p) { + _VL_VPI_UNIMP(); + return; +} +void vpi_put_delays(vpiHandle object, p_vpi_delay delay_p) { + _VL_VPI_UNIMP(); + return; +} // value processing void vpi_get_value(vpiHandle object, p_vpi_value value_p) { + static VL_THREAD char outStr[1+VL_MULS_MAX_WORDS*32]; // Maximum required size is for binary string, one byte per bit plus null termination + static VL_THREAD int outStrSz = sizeof(outStr)-1; VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_value %p\n",object);); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!value_p)) return; if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - // We presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal + // We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal + // This may cause backward compatability issues with older code. if (value_p->format == vpiVectorVal) { // Vector pointer must come from our memory pool // It only needs to persist until the next vpi_get_value @@ -624,11 +750,173 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { return; } default: { - _VL_VPI_UNIMP(); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } - } else { + } else if (value_p->format == vpiBinStrVal) { + value_p->value.str = outStr; + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int bits = vop->varp()->range().bits(); + CData* datap = ((CData*)(vop->varDatap())); + int i; + if (bits > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + bits = outStrSz; + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits); + } + for (i=0; i>3]>>(i&7))&1; + outStr[bits-i-1] = val?'1':'0'; + } + outStr[i]=0; // NULL terminate + return; + } + default: + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return; + } + } else if (value_p->format == vpiOctStrVal) { + value_p->value.str = outStr; + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int chars = (vop->varp()->range().bits()+2)/3; + int bytes = VL_BYTES_I(vop->varp()->range().bits()); + CData* datap = ((CData*)(vop->varDatap())); + int i; + if (chars > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); + chars = outStrSz; + } + for (i=0; i>= idx.rem; + if (i==(chars-1)) { + // most signifcant char, mask off non existant bits when vector + // size is not a multiple of 3 + unsigned int rem = vop->varp()->range().bits() % 3; + if (rem) { + // generate bit mask & zero non existant bits + val &= (1<format), vop->fullname()); + return; + } + } else if (value_p->format == vpiDecStrVal) { + value_p->value.str = outStr; + switch (vop->varp()->vltype()) { + // outStrSz does not include NULL termination so add one + case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned int)*((CData*)(vop->varDatap()))); return; + case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned int)*((SData*)(vop->varDatap()))); return; + case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int)*((IData*)(vop->varDatap()))); return; + case VLVT_UINT64: snprintf(outStr, outStrSz+1, "%lu", (unsigned long)*((QData*)(vop->varDatap()))); return; + default: + strcpy(outStr, "-1"); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return; + } + } else if (value_p->format == vpiHexStrVal) { + value_p->value.str = outStr; + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int chars = (vop->varp()->range().bits()+3)>>2; + CData* datap = ((CData*)(vop->varDatap())); + int i; + if (chars > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); + chars = outStrSz; + } + for (i=0; i>1]>>((i&1)<<2))&15; + static char hex[] = "0123456789abcdef"; + if (i==(chars-1)) { + // most signifcant char, mask off non existant bits when vector + // size is not a multiple of 4 + unsigned int rem = vop->varp()->range().bits() & 3; + if (rem) { + // generate bit mask & zero non existant bits + val &= (1<format), vop->fullname()); + return; + } + } else if (value_p->format == vpiStringVal) { + value_p->value.str = outStr; + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int bytes = VL_BYTES_I(vop->varp()->range().bits()); + CData* datap = ((CData*)(vop->varDatap())); + int i; + if (bytes > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), + vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes); + bytes = outStrSz; + } + for (i=0; iformat), vop->fullname()); + return; + } + } else if (value_p->format == vpiIntVal) { switch (vop->varp()->vltype()) { case VLVT_UINT8: value_p->value.integer = *((CData*)(vop->varDatap())); @@ -644,65 +932,261 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) { // Not legal value_p->value.integer = 0; default: - _VL_VPI_UNIMP(); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } } - } - else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { - value_p->value.integer = vop->num(); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return; } - _VL_VPI_UNIMP(); + else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { + if (value_p->format == vpiIntVal) { + value_p->value.integer = vop->num(); + return; + } + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return; + } + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format)); } vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time time_p, PLI_INT32 flags) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value %p %p\n",object, value_p);); - if (VL_UNLIKELY(!value_p)) return 0; + _VL_VPI_ERROR_RESET(); // reset vpi error status + if (VL_UNLIKELY(!value_p)) { + _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with NULL value pointer"); + return 0; + } if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - // We presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(), value_p->format, value_p->value.integer); VL_PRINTF("-vltVpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap());); if (VL_UNLIKELY(!vop->varp()->isPublicRW())) { - VL_PRINTF("%%Warning: Ignoring vpi_put_value to signal marked read-only, use public_flat_rw instead: %s\n", - vop->fullname()); + _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only, use public_flat_rw instead: ", vop->fullname()); return 0; } if (value_p->format == vpiVectorVal) { if (VL_UNLIKELY(!value_p->value.vector)) return NULL; switch (vop->varp()->vltype()) { case VLVT_UINT8: - *((CData*)(vop->varDatap())) = value_p->value.vector[0].aval; + *((CData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask(); return object; case VLVT_UINT16: - *((SData*)(vop->varDatap())) = value_p->value.vector[0].aval; + *((SData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask(); return object; case VLVT_UINT32: - *((IData*)(vop->varDatap())) = value_p->value.vector[0].aval; + *((IData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask(); return object; case VLVT_WDATA: { int words = VL_WORDS_I(vop->varp()->range().bits()); WDataOutP datap = ((IData*)(vop->varDatap())); for (int i=0; ivalue.vector[i].aval; + if (i==(words-1)) { + datap[i] &= vop->mask(); + } } return object; } case VLVT_UINT64: { *((QData*)(vop->varDatap())) = _VL_SET_QII( - value_p->value.vector[1].aval, + value_p->value.vector[1].aval & vop->mask(), value_p->value.vector[0].aval); return object; } default: { - _VL_VPI_UNIMP(); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return NULL; } } - } else { + } else if (value_p->format == vpiBinStrVal) { + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int bits = vop->varp()->range().bits(); + int len = strlen(value_p->value.str); + CData* datap = ((CData*)(vop->varDatap())); + for (int i=0; ivalue.str[len-i-1]=='1'):0; + // zero bits 7:1 of byte when assigning to bit 0, else + // or in 1 if bit set + if (i&7) { + datap[i>>3] |= set<<(i&7); + } else { + datap[i>>3] = set; + } + } + return object; + } + default: + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return 0; + } + } else if (value_p->format == vpiOctStrVal) { + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int chars = (vop->varp()->range().bits()+2)/3; + int bytes = VL_BYTES_I(vop->varp()->range().bits()); + int len = strlen(value_p->value.str); + CData* datap = ((CData*)(vop->varDatap())); + div_t idx; + datap[0] = 0; // reset zero'th byte + for (int i=0; ivalue.str[len-i-1]; + if (digit >= '0' && digit <= '7') { + val.half = digit-'0'; + } else { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Non octal character '%c' in '%s' as value %s for %s", + VL_FUNC, digit, value_p->value.str, + VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + val.half = 0; + } + } else { + val.half = 0; + } + // align octal character to position within vector, note that + // the three bits may straddle a byte bounday so two byte wide + // assignments are made to adjacent bytes - but not if the least + // signifcant byte of the aligned value is the most significant + // byte of the destination. + val.half <<= idx.rem; + datap[idx.quot] |= val.byte[0]; // or in value + if ((idx.quot+1) < bytes) { + datap[idx.quot+1] = val.byte[1]; // this also resets all bits to 0 prior to or'ing above + } + } + // mask off non existant bits in the most significant byte + if (idx.quot == (bytes-1)) { + datap[idx.quot] &= vop->mask_byte(idx.quot); + } else if (idx.quot+1 == (bytes-1)) { + datap[idx.quot+1] &= vop->mask_byte(idx.quot+1); + } + // zero off remaining top bytes + for (int i=idx.quot+2; iformat), vop->fullname()); + return 0; + } + } else if (value_p->format == vpiDecStrVal) { + char remainder[16]; + unsigned long val; + int success = sscanf(value_p->value.str, "%lu%15s", &val, remainder); + if (success < 1) { + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s", + VL_FUNC, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return 0; + } + if (success > 1) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s", + VL_FUNC, remainder, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + } + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : *((CData*)(vop->varDatap())) = val & vop->mask(); break; + case VLVT_UINT16: *((SData*)(vop->varDatap())) = val & vop->mask(); break; + case VLVT_UINT32: *((IData*)(vop->varDatap())) = val & vop->mask(); break; + case VLVT_UINT64: *((QData*)(vop->varDatap())) = val; ((IData*)(vop->varDatap()))[1] &= vop->mask(); break; + case VLVT_WDATA: + default: + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return 0; + } + return object; + } else if (value_p->format == vpiHexStrVal) { + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int chars = (vop->varp()->range().bits()+3)>>2; + CData* datap = ((CData*)(vop->varDatap())); + char* val = value_p->value.str; + // skip hex ident if one is detected at the start of the string + if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) { + val += 2; + } + int len = strlen(val); + for (int i=0; i= '0' && digit <= '9') hex = digit - '0'; + else if (digit >= 'a' && digit <= 'f') hex = digit - 'a' + 10; + else if (digit >= 'A' && digit <= 'F') hex = digit - 'A' + 10; + else { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Non hex character '%c' in '%s' as value %s for %s", + VL_FUNC, digit, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + hex = 0; + } + } else { + hex = 0; + } + // assign hex digit value to destination + if (i&1) { + datap[i>>1] |= hex<<4; + } else { + datap[i>>1] = hex; // this also resets all bits to 0 prior to or'ing above of the msb + } + } + // apply bit mask to most significant byte + datap[(chars-1)>>1] &= vop->mask_byte((chars-1)>>1); + return object; + } + default: + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return 0; + } + } else if (value_p->format == vpiStringVal) { + switch (vop->varp()->vltype()) { + case VLVT_UINT8 : + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: { + int bytes = VL_BYTES_I(vop->varp()->range().bits()); + int len = strlen(value_p->value.str); + CData* datap = ((CData*)(vop->varDatap())); + for (int i=0; ivalue.str[len-i-1]:0; // prepend with 0 values before placing string the least signifcant bytes + } + return object; + } + default: + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return 0; + } + } else if (value_p->format == vpiIntVal) { switch (vop->varp()->vltype()) { case VLVT_UINT8: *((CData*)(vop->varDatap())) = vop->mask() & value_p->value.integer; @@ -716,45 +1200,54 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, case VLVT_WDATA: // FALLTHRU case VLVT_UINT64: // FALLTHRU default: - _VL_VPI_UNIMP(); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); return 0; } } + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + return NULL; } - _VL_VPI_UNIMP(); return NULL; + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for ??", + VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format)); + return NULL; } -//-void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, -//- PLI_INT32 *index_p, PLI_UINT32 num) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, -//- PLI_INT32 *index_p, PLI_UINT32 num) { -//- _VL_VPI_UNIMP(); return 0; -//-} +void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, + PLI_INT32 *index_p, PLI_UINT32 num) { + _VL_VPI_UNIMP(); return; +} +void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, + PLI_INT32 *index_p, PLI_UINT32 num) { + _VL_VPI_UNIMP(); return; +} // time processing -//-void vpi_get_time(vpiHandle object, p_vpi_time time_p) { -//- _VL_VPI_UNIMP(); -//-} +void vpi_get_time(vpiHandle object, p_vpi_time time_p) { + _VL_VPI_UNIMP(); return; +} // I/O routines PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *filenamep) { + _VL_VPI_ERROR_RESET(); // reset vpi error status return VL_FOPEN_S(filenamep,"wb"); } PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { + _VL_VPI_ERROR_RESET(); // reset vpi error status VL_FCLOSE_I(mcd); return 0; } -//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 mcd) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 mcd) { + _VL_VPI_UNIMP(); return 0; +} PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) { + _VL_VPI_ERROR_RESET(); // reset vpi error status va_list ap; va_start(ap,formatp); int chars = vpi_mcd_vprintf(mcd, formatp, ap); @@ -763,6 +1256,7 @@ PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) { } PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) { + _VL_VPI_ERROR_RESET(); // reset vpi error status va_list ap; va_start(ap,formatp); int chars = vpi_vprintf(formatp, ap); @@ -771,23 +1265,27 @@ PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) { } PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) { + _VL_VPI_ERROR_RESET(); // reset vpi error status return VL_VPRINTF(formatp, ap); } PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) { FILE* fp = VL_CVT_I_FP(mcd); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!fp)) return 0; int chars = vfprintf(fp, format, ap); return chars; } PLI_INT32 vpi_flush(void) { + _VL_VPI_ERROR_RESET(); // reset vpi error status Verilated::flushCall(); return 0; } PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { FILE* fp = VL_CVT_I_FP(mcd); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!fp)) return 1; fflush(fp); return 0; @@ -795,47 +1293,62 @@ PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { // utility routines -//-PLI_INT32 vpi_compare_objects(vpiHandle object1, vpiHandle object2) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_INT32 vpi_compare_objects(vpiHandle object1, vpiHandle object2) { + _VL_VPI_UNIMP(); return 0; +} +PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) { + // executing vpi_chk_error does not reset error + // error_info_p can be NULL, so only return level in that case + p_vpi_error_info _error_info_p = VerilatedVpi::error_info()->getError(); + if (error_info_p && _error_info_p) { + *error_info_p = *_error_info_p; + } + if (!_error_info_p) return 0; // no error occured + return _error_info_p->level; // return error severity level +}; PLI_INT32 vpi_free_object(vpiHandle object) { + _VL_VPI_ERROR_RESET(); // reset vpi error status return vpi_release_handle(object); // Deprecated } PLI_INT32 vpi_release_handle (vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_release_handle %p\n",object);); VerilatedVpio* vop = VerilatedVpio::castp(object); + _VL_VPI_ERROR_RESET(); // reset vpi error status if (VL_UNLIKELY(!vop)) return 0; vpi_remove_cb(object); // May not be a callback, but that's ok delete vop; return 1; } -//-PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) { + _VL_VPI_ERROR_RESET(); // reset vpi error status + vlog_info_p->argc = Verilated::getCommandArgs()->argc; + vlog_info_p->argv = (PLI_BYTE8**)Verilated::getCommandArgs()->argv; + vlog_info_p->product = (PLI_BYTE8*)Verilated::productName(); + vlog_info_p->version = (PLI_BYTE8*)Verilated::productVersion(); + return 1; +} // routines added with 1364-2001 -//-PLI_INT32 vpi_get_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_put_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-void *vpi_get_userdata(vpiHandle obj) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_put_userdata(vpiHandle obj, void *userdata) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_INT32 vpi_get_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) { + _VL_VPI_UNIMP(); return 0; +} +PLI_INT32 vpi_put_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) { + _VL_VPI_UNIMP(); return 0; +} +void *vpi_get_userdata(vpiHandle obj) { + _VL_VPI_UNIMP(); return 0; +} +PLI_INT32 vpi_put_userdata(vpiHandle obj, void *userdata) { + _VL_VPI_UNIMP(); return 0; +} PLI_INT32 vpi_control(PLI_INT32 operation, ...) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_control %d\n",operation);); + _VL_VPI_ERROR_RESET(); // reset vpi error status switch (operation) { case vpiFinish: { vl_finish(__FILE__,__LINE__,"*VPI*"); @@ -846,12 +1359,14 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) { return 1; } } - _VL_VPI_UNIMP(); return 0; + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", + VL_FUNC, VerilatedVpiError::strFromVpiProp(operation)); + return 0; } -//-vpiHandle vpi_handle_by_multi_index(vpiHandle obj, PLI_INT32 num_index, PLI_INT32 *index_array) { -//- _VL_VPI_UNIMP(); return 0; -//-} +vpiHandle vpi_handle_by_multi_index(vpiHandle obj, PLI_INT32 num_index, PLI_INT32 *index_array) { + _VL_VPI_UNIMP(); return 0; +} //====================================================================== diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp new file mode 100644 index 000000000..51f52c42c --- /dev/null +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -0,0 +1,208 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2011 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 "Vt_vpi_unimpl.h" +#include "verilated.h" +#include "svdpi.h" + +#include "Vt_vpi_unimpl__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vpi.cpp" +#include "verilated_vcd_c.h" + +#include + +// __FILE__ is too long +#define FILENM "t_vpi_unimpl.cpp" + +#define DEBUG if (0) printf + +unsigned int main_time = false; +unsigned int callback_count = false; + +//====================================================================== + + +class VlVpiHandle { + /// For testing, etc, wrap vpiHandle in an auto-releasing class + vpiHandle m_handle; +public: + VlVpiHandle() : m_handle(NULL) { } + VlVpiHandle(vpiHandle h) : m_handle(h) { } + ~VlVpiHandle() { if (m_handle) { vpi_release_handle(m_handle); m_handle=NULL; } } + operator vpiHandle () const { return m_handle; } + inline VlVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; } +}; + +//====================================================================== + +#define CHECK_RESULT_VH(got, exp) \ + if ((got) != (exp)) { \ + printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \ + FILENM,__LINE__, (got), (exp)); \ + return __LINE__; \ + } + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM,__LINE__); \ + return __LINE__; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got != exp)) { \ + cout<", (exp)?(exp):""); \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR_STRIP(got, exp) \ + CHECK_RESULT_CSTR(got+strspn(got, " "), exp) + +int _mon_check_unimpl(p_cb_data cb_data) { + static VlVpiHandle cb, clk_h; + if (cb_data) { + // this is the callback + s_vpi_error_info info; + vpi_chk_error(&info); + callback_count++; + printf("%%Info: got pli message %s\n", info.message); + } else { + // setup and install + static t_cb_data cb_data; + clk_h = vpi_handle_by_name((PLI_BYTE8*)"t.clk", NULL); + + cb_data.reason = cbPLIError; + cb_data.cb_rtn = _mon_check_unimpl; // this function + + cb = vpi_register_cb(&cb_data); + CHECK_RESULT_NZ(cb); + + // now exercise unimplemented fns + vpi_get_cb_info(cb, NULL); + CHECK_RESULT(callback_count, 1); + vpi_register_systf(NULL); + CHECK_RESULT(callback_count, 2); + vpi_get_systf_info(NULL, NULL); + CHECK_RESULT(callback_count, 3); + vpi_handle_multi(0, NULL, NULL); + CHECK_RESULT(callback_count, 4); + vpi_get64(0, NULL); + CHECK_RESULT(callback_count, 5); + vpi_get_delays(NULL, NULL); + CHECK_RESULT(callback_count, 6); + vpi_put_delays(NULL, NULL); + CHECK_RESULT(callback_count, 7); + vpi_get_value_array(NULL, NULL, NULL, 0); + CHECK_RESULT(callback_count, 8); + vpi_put_value_array(NULL, NULL, NULL, 0); + CHECK_RESULT(callback_count, 9); + vpi_get_time(NULL, NULL); + CHECK_RESULT(callback_count, 10); + vpi_mcd_name(0); + CHECK_RESULT(callback_count, 11); + vpi_compare_objects(NULL, NULL); + CHECK_RESULT(callback_count, 12); + vpi_get_data(0, NULL, 0); + CHECK_RESULT(callback_count, 13); + vpi_put_data(0, NULL, 0); + CHECK_RESULT(callback_count, 14); + vpi_get_userdata(NULL); + CHECK_RESULT(callback_count, 15); + vpi_put_userdata(NULL, NULL); + CHECK_RESULT(callback_count, 16); + vpi_handle_by_multi_index(NULL, 0, NULL); + CHECK_RESULT(callback_count, 17); + } + return 0; // Ok +} + +int mon_check() { + // Callback from initial block in monitor + if (int status = _mon_check_unimpl(NULL)) return status; + return 0; // Ok +} + +//====================================================================== + + +double sc_time_stamp () { + return main_time; +} +int main(int argc, char **argv, char **env) { + double sim_time = 1100; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + Verilated::fatalOnVpiError(0); // we're going to be checking for these errors do don't crash out + + VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out + +#ifdef VERILATOR +# ifdef TEST_VERBOSE + Verilated::scopesDump(); +# endif +#endif + + Verilated::traceEverOn(true); + VerilatedVcdC* tfp = new VerilatedVcdC; +#if VM_TRACE + VL_PRINTF("Enabling waves...\n"); + topp->trace (tfp, 99); + tfp->open ("obj_dir/t_vpi_var/simx.vcd"); +#endif + + topp->eval(); + topp->clk = 0; + main_time += 10; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + main_time += 1; + topp->eval(); + VerilatedVpi::callValueCbs(); + topp->clk = !topp->clk; + //mon_do(); +#if VM_TRACE + if (tfp) tfp->dump (main_time); +#endif + } + CHECK_RESULT(callback_count, 17); + if (!Verilated::gotFinish()) { + vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + delete topp; topp=NULL; + exit(0L); +} diff --git a/test_regress/t/t_vpi_unimpl.pl b/test_regress/t/t_vpi_unimpl.pl new file mode 100644 index 000000000..105ab3452 --- /dev/null +++ b/test_regress/t/t_vpi_unimpl.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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 ( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_unimpl.cpp"], + ); + +execute ( + check_finished=>1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_unimpl.v b/test_regress/t/t_vpi_unimpl.v new file mode 100644 index 000000000..f56270883 --- /dev/null +++ b/test_regress/t/t_vpi_unimpl.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 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 +//We call it via $c so we can verify DPI isn't required - see bug572 +`else +import "DPI-C" context function integer mon_check(); +`endif + +module t (/*AUTOARG*/ + // Inputs + clk + ); + +`ifdef VERILATOR +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + input clk; + + reg onebit /*verilator public_flat_rw @(posedge clk) */; + + integer status; + + // Test loop + initial begin +`ifdef VERILATOR + status = $c32("mon_check()"); +`else + status = mon_check(); +`endif + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 9ce87a29a..f5491c988 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -28,10 +28,14 @@ // __FILE__ is too long #define FILENM "t_vpi_var.cpp" +#define TEST_MSG if (0) printf + unsigned int main_time = false; unsigned int callback_count = false; unsigned int callback_count_half = false; unsigned int callback_count_quad = false; +unsigned int callback_count_strs = false; +unsigned int callback_count_strs_max = 500; //====================================================================== @@ -64,15 +68,15 @@ public: // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ - if ((got != exp)) { \ + if ((got) != (exp)) { \ cout<>5; + TEST_MSG("========== %d ==========\n", i); + if (callback_count_strs) { + // check persistance + if (data[i].type) { + v.format = data[i].type; + } else { + static PLI_INT32 vals[] = {vpiBinStrVal, vpiOctStrVal, vpiHexStrVal, vpiDecStrVal}; + v.format = vals[rand_r(&seed) % ((words>2)?3:4)]; + TEST_MSG("new format %d\n", v.format); + } + vpi_get_value(data[i].sig, &v); + TEST_MSG("%s\n", v.value.str); + if (data[i].type) { + CHECK_RESULT_CSTR(v.value.str, data[i].str); + } else { + data[i].type = v.format; + strcpy(data[i].str, v.value.str); + } + } + + // check for corruption + v.format = (words==1)?vpiIntVal:vpiVectorVal; + vpi_get_value(data[i].sig, &v); + if (v.format == vpiIntVal) { + TEST_MSG("%08x %08x\n", v.value.integer, data[i].value.integer); + CHECK_RESULT(v.value.integer, data[i].value.integer); + } else { + for (int k=0; k < words; k++) { + TEST_MSG("%d %08x %08x\n", k, v.value.vector[k].aval, data[i].value.vector[k].aval); + CHECK_RESULT_HEX(v.value.vector[k].aval, data[i].value.vector[k].aval); + } + } + + if (callback_count_strs & 7) { + // put same value back - checking encoding/decoding equivalent + v.format = data[i].type; + v.value.str = data[i].str; + vpi_put_value(data[i].sig, &v, &t, vpiNoDelay); + v.format = vpiIntVal; + v.value.integer = 1; + //vpi_put_value(data[i].verbose, &v, &t, vpiNoDelay); + vpi_put_value(data[i].check, &v, &t, vpiNoDelay); + } else { + // stick a new random value in + unsigned int mask = ((i&31)?(1<<(i&31)):0)-1; + if (words == 1) { + v.value.integer = rand_r(&seed); + data[i].value.integer = v.value.integer &= mask; + v.format = vpiIntVal; + TEST_MSG("new value %08x\n", data[i].value.integer); + } else { + TEST_MSG("new value\n"); + for (int j=0; j<4; j++) { + data[i].value.vector[j].aval = rand_r(&seed); + if (j==(words-1)) { + data[i].value.vector[j].aval &= mask; + } + TEST_MSG(" %08x\n", data[i].value.vector[j].aval); + } + v.value.vector = data[i].value.vector; + v.format = vpiVectorVal; + } + vpi_put_value(data[i].sig, &v, &t, vpiNoDelay); + vpi_put_value(data[i].rfr, &v, &t, vpiNoDelay); + } + if ((callback_count_strs & 1) == 0) data[i].type = 0; + } + if (++callback_count_strs == callback_count_strs_max) { + int success = vpi_remove_cb(cb); + CHECK_RESULT_NZ(success); + }; + } else { + // setup and install + for (int i=1; i<=128; i++) { + char buf[32]; + snprintf(buf, sizeof(buf), "t.arr[%d].arr", i); + CHECK_RESULT_NZ(data[i].scope = vpi_handle_by_name((PLI_BYTE8*)buf, NULL)); + CHECK_RESULT_NZ(data[i].sig = vpi_handle_by_name((PLI_BYTE8*)"sig", data[i].scope)); + CHECK_RESULT_NZ(data[i].rfr = vpi_handle_by_name((PLI_BYTE8*)"rfr", data[i].scope)); + CHECK_RESULT_NZ(data[i].check = vpi_handle_by_name((PLI_BYTE8*)"check", data[i].scope)); + CHECK_RESULT_NZ(data[i].verbose = vpi_handle_by_name((PLI_BYTE8*)"verbose", data[i].scope)); + } + + static t_cb_data cb_data; + static s_vpi_value v; + static VlVpiHandle count_h = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL); + + cb_data.reason = cbValueChange; + cb_data.cb_rtn = _mon_check_putget_str; // this function + cb_data.obj = count_h; + cb_data.value = &v; + v.format = vpiIntVal; + + cb = vpi_register_cb(&cb_data); + CHECK_RESULT_NZ(cb); + } + return 0; +} + +int _mon_check_vlog_info() { + s_vpi_vlog_info vlog_info; + PLI_INT32 rtn = vpi_get_vlog_info(&vlog_info); + CHECK_RESULT(rtn, 1); + CHECK_RESULT(vlog_info.argc, 4); + CHECK_RESULT_CSTR(vlog_info.argv[1], "+PLUS"); + CHECK_RESULT_CSTR(vlog_info.argv[2], "+INT=1234"); + CHECK_RESULT_CSTR(vlog_info.argv[3], "+STRSTR"); + CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); + CHECK_RESULT(strlen(vlog_info.version) > 0, 1); + + return 0; +} + +#define CHECK_ENUM_STR(fn, enum) \ + do { \ + const char* strVal = VerilatedVpiError::fn(enum); \ + CHECK_RESULT_CSTR(strVal, #enum); \ + } while (0) + +int _mon_check_vl_str() { + + CHECK_ENUM_STR(strFromVpiVal, vpiBinStrVal); + CHECK_ENUM_STR(strFromVpiVal, vpiRawFourStateVal); + + CHECK_ENUM_STR(strFromVpiObjType, vpiAlways); + CHECK_ENUM_STR(strFromVpiObjType, vpiWhile); + CHECK_ENUM_STR(strFromVpiObjType, vpiAttribute); + CHECK_ENUM_STR(strFromVpiObjType, vpiUdpArray); + CHECK_ENUM_STR(strFromVpiObjType, vpiContAssignBit); + CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar); + + CHECK_ENUM_STR(strFromVpiMethod, vpiCondition); + CHECK_ENUM_STR(strFromVpiMethod, vpiStmt); + + CHECK_ENUM_STR(strFromVpiCallbackReason, cbValueChange); + CHECK_ENUM_STR(strFromVpiCallbackReason, cbAtEndOfSimTime); + + CHECK_ENUM_STR(strFromVpiProp, vpiType); + CHECK_ENUM_STR(strFromVpiProp, vpiProtected); + CHECK_ENUM_STR(strFromVpiProp, vpiDirection); + CHECK_ENUM_STR(strFromVpiProp, vpiTermIndex); + CHECK_ENUM_STR(strFromVpiProp, vpiConstType); + CHECK_ENUM_STR(strFromVpiProp, vpiAutomatic); + CHECK_ENUM_STR(strFromVpiProp, vpiOffset); + CHECK_ENUM_STR(strFromVpiProp, vpiStop); + CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected); + + return 0; +} + int mon_check() { // Callback from initial block in monitor if (int status = _mon_check_mcd()) return status; @@ -361,6 +575,10 @@ int mon_check() { if (int status = _mon_check_varlist()) return status; if (int status = _mon_check_getput()) return status; if (int status = _mon_check_quad()) return status; + if (int status = _mon_check_string()) return status; + if (int status = _mon_check_putget_str(NULL)) return status; + if (int status = _mon_check_vlog_info()) return status; + if (int status = _mon_check_vl_str()) return status; return 0; // Ok } @@ -408,6 +626,7 @@ int main(int argc, char **argv, char **env) { CHECK_RESULT(callback_count, 501); CHECK_RESULT(callback_count_half, 250); CHECK_RESULT(callback_count_quad, 2); + CHECK_RESULT(callback_count_strs, callback_count_strs_max); if (!Verilated::gotFinish()) { vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish"); } diff --git a/test_regress/t/t_vpi_var.pl b/test_regress/t/t_vpi_var.pl index d2a50b810..bb1c70f16 100755 --- a/test_regress/t/t_vpi_var.pl +++ b/test_regress/t/t_vpi_var.pl @@ -10,11 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di compile ( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["-CFLAGS '-ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_var.cpp"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_var.cpp"], ); execute ( check_finished=>1, + all_run_flags => ['+PLUS +INT=1234 +STRSTR'] ); ok(1); diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index b316f2c68..26515d766 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -32,6 +32,12 @@ extern "C" int mon_check(); reg [31:0] count /*verilator public_flat_rd */; reg [31:0] half_count /*verilator public_flat_rd */; + + reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */; + reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */; + reg [31:0] text_word /*verilator public_flat_rw @(posedge clk) */; + reg [63:0] text_long /*verilator public_flat_rw @(posedge clk) */; + reg [511:0] text /*verilator public_flat_rw @(posedge clk) */; integer status; @@ -40,6 +46,11 @@ extern "C" int mon_check(); // Test loop initial begin onebit = 1'b0; + text_byte = "B"; + text_half = "Hf"; + text_word = "Word"; + text_long = "Long64b"; + text = "Verilog Test module"; `ifdef VERILATOR status = $c32("mon_check()"); `else @@ -52,6 +63,11 @@ extern "C" int mon_check(); if (onebit != 1'b1) $stop; if (quads[2] != 62'h12819213_abd31a1c) $stop; if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; + if (text_byte != "A") $stop; + if (text_half != "T2") $stop; + if (text_word != "Tree") $stop; + if (text_long != "44Four44") $stop; + if (text != "lorem ipsum") $stop; end always @(posedge clk) begin @@ -65,9 +81,33 @@ extern "C" int mon_check(); end end + genvar i; + generate + for (i=1;i<=128;i++) begin : arr + arr #(.LENGTH(i)) arr(); + end endgenerate + endmodule module sub; reg subsig1 /*verilator public_flat_rd*/; reg subsig2 /*verilator public_flat_rd*/; endmodule + +module arr; + + parameter LENGTH = 1; + + reg [LENGTH-1:0] sig /*verilator public_flat_rw*/; + reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/; + + reg check /*verilator public_flat_rw*/; + reg verbose /*verilator public_flat_rw*/; + + always @(posedge check) begin + if (verbose) $display("%m : %x %x", sig, rfr); + if (check && sig != rfr) $stop; + check <= 0; + end + +endmodule : arr