// -*- C++ -*- //************************************************************************* // // Copyright 2009-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. // //========================================================================= /// /// \file /// \brief Verilator: VPI implementation code /// /// This file must be compiled and linked against all objects /// created from Verilator or called by Verilator that use the VPI. /// /// "//-" indicates features that are as yet unimplemented. /// /// Code available from: http://www.veripool.org/verilator /// //========================================================================= #ifndef CHPI_VERILATED_VPI_H #define CHPI_VERILATED_VPI_H 1 #include "verilated.h" #include "verilated_syms.h" //====================================================================== // From IEEE 1800-2009 annex K #include "vltstd/vpi_user.h" //====================================================================== // Internal macros // Not supported yet #define _VL_VPI_UNIMP() \ vl_fatal(__FILE__,__LINE__,"",Verilated::catName("Unsupported VPI function: ",VL_FUNC)) //====================================================================== // Implementation #include #define VL_DEBUG_IF_PLI VL_DEBUG_IF // Base VPI handled object class VerilatedVpio { // MEM MANGLEMENT static vluint8_t* s_freeHead; public: // CONSTRUCTORS VerilatedVpio() {} virtual ~VerilatedVpio() {} inline static void* operator new(size_t size) { // We new and delete tons of vpi structures, so keep them around // To simplify our free list, we use a size large enough for all derived types // We reserve word zero for the next pointer, as that's safer in case a // dangling reference to the original remains around. static size_t chunk = 96; if (VL_UNLIKELY(size>chunk)) vl_fatal(__FILE__,__LINE__,"", "increase chunk"); if (VL_LIKELY(s_freeHead)) { vluint8_t* newp = s_freeHead; s_freeHead = *((vluint8_t**)newp); return newp+8; } else { // +8: 8 bytes for next vluint8_t* newp = (vluint8_t*)(::operator new(chunk+8)); return newp+8; } } inline static void operator delete(void* obj, size_t size) { vluint8_t* oldp = ((vluint8_t*)obj)-8; *((void**)oldp) = s_freeHead; s_freeHead = oldp; } // MEMBERS static inline VerilatedVpio* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } inline vpiHandle castVpiHandle() { return (vpiHandle)(this); } // ACCESSORS virtual const char* name() { return ""; } virtual const char* fullname() { return ""; } virtual const char* defname() { return ""; } virtual vpiHandle dovpi_scan() { return 0; } }; typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *); class VerilatedVpioCb : public VerilatedVpio { t_cb_data m_cbData; QData m_time; public: VerilatedVpioCb(const t_cb_data* cbDatap, QData time) : m_cbData(*cbDatap), m_time(time) {} virtual ~VerilatedVpioCb() {} static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } vluint32_t reason() const { return m_cbData.reason; } VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; } t_cb_data* cb_datap() { return &(m_cbData); } QData time() const { return m_time; } }; class VerilatedVpioConst : public VerilatedVpio { vlsint32_t m_num; public: VerilatedVpioConst(vlsint32_t num) : m_num(num) {} virtual ~VerilatedVpioConst() {} static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } vlsint32_t num() const { return m_num; } }; class VerilatedVpioRange : public VerilatedVpio { vlsint32_t m_lhs; // Ranges can be signed vlsint32_t m_rhs; bool m_iteration; public: VerilatedVpioRange(vlsint32_t lhs, vlsint32_t rhs) : m_lhs(lhs), m_rhs(rhs), m_iteration(0) {} virtual ~VerilatedVpioRange() {} static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } vlsint32_t lhs() const { return m_lhs; } vlsint32_t rhs() const { return m_rhs; } int iteration() const { return m_iteration; } void iterationInc() { ++m_iteration; } virtual vpiHandle dovpi_scan() { if (!iteration()) { VerilatedVpioRange* nextp = new VerilatedVpioRange(*this); nextp->iterationInc(); return ((nextp)->castVpiHandle()); } else { return 0; // End of list - only one deep } } }; class VerilatedVpioScope : public VerilatedVpio { const VerilatedScope* m_scopep; public: VerilatedVpioScope(const VerilatedScope* scopep) : m_scopep(scopep) {} virtual ~VerilatedVpioScope() {} static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } const VerilatedScope* scopep() const { return m_scopep; } virtual const char* name() { return m_scopep->name(); } virtual const char* fullname() { return m_scopep->name(); } }; 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 vluint32_t m_entSize; // memoized variable size protected: void* m_varDatap; // varp()->datap() adjusted for array entries vlsint32_t m_index; 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_entSize = varp->entSize(); m_varDatap = varp->datap(); } virtual ~VerilatedVpioVar() { if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; } } 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 entSize() const { return m_entSize; } virtual const char* name() { return m_varp->name(); } virtual const char* fullname() { static VL_THREAD string out; out = string(m_scopep->name())+"."+name(); return out.c_str(); } void* prevDatap() const { return m_prevDatap; } void* varDatap() const { return m_varDatap; } void createPrevDatap() { if (VL_UNLIKELY(!m_prevDatap)) { m_prevDatap = new vluint8_t [entSize()]; memcpy(prevDatap(), varp()->datap(), entSize()); } } }; class VerilatedVpioVarIndex : public VerilatedVpioVar { public: VerilatedVpioVarIndex(const VerilatedVar* varp, const VerilatedScope* scopep, vlsint32_t index, int offset) : VerilatedVpioVar(varp, scopep) { m_index = index; m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset; } virtual ~VerilatedVpioVarIndex() {} static inline VerilatedVpioVarIndex* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } virtual const char* fullname() { static VL_THREAD string out; char num[20]; sprintf(num,"%d",m_index); out = string(scopep()->name())+"."+name()+"["+num+"]"; return out.c_str(); } }; class VerilatedVpioVarIter : public VerilatedVpio { const VerilatedScope* m_scopep; VerilatedVarNameMap::iterator m_it; bool m_started; public: VerilatedVpioVarIter(const VerilatedScope* scopep) : m_scopep(scopep), m_started(false) { } virtual ~VerilatedVpioVarIter() {} static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } virtual vpiHandle dovpi_scan() { if (VL_LIKELY(m_scopep->varsp())) { if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; } else if (VL_UNLIKELY(m_it == m_scopep->varsp()->end())) return 0; else ++m_it; if (m_it == m_scopep->varsp()->end()) return 0; return ((new VerilatedVpioVar(&(m_it->second), m_scopep)) ->castVpiHandle()); } else { return 0; // End of list - only one deep } } }; //====================================================================== struct VerilatedVpiTimedCbsCmp { /// Ordering sets keyed by time, then callback descriptor bool operator() (const pair& a, const pair& b) const { if (a.first < b.first) return 1; if (a.first > b.first) return 0; return a.second < b.second; } }; class VerilatedVpi { enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason typedef set VpioCbSet; typedef set,VerilatedVpiTimedCbsCmp > VpioTimedCbs; VpioCbSet m_cbObjSets[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason VpioTimedCbs m_timedCbs; // Time based callbacks static VerilatedVpi s_s; // Singleton public: VerilatedVpi() {} ~VerilatedVpi() {} static void cbReasonAdd(VerilatedVpioCb* vop) { if (vop->reason() == cbValueChange) { if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) { varop->createPrevDatap(); } } if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) vl_fatal(__FILE__,__LINE__,"", "vpi bb reason too large"); s_s.m_cbObjSets[vop->reason()].insert(vop); } static void cbTimedAdd(VerilatedVpioCb* vop) { s_s.m_timedCbs.insert(make_pair(vop->time(), vop)); } static void cbReasonRemove(VerilatedVpioCb* cbp) { VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbp->reason()]; VpioCbSet::iterator it=cbObjSet.find(cbp); if (VL_LIKELY(it != cbObjSet.end())) { cbObjSet.erase(it); } } static void cbTimedRemove(VerilatedVpioCb* cbp) { VpioTimedCbs::iterator it=s_s.m_timedCbs.find(make_pair(cbp->time(),cbp)); if (VL_LIKELY(it != s_s.m_timedCbs.end())) { s_s.m_timedCbs.erase(it); } } static void callTimedCbs() { QData time = VL_TIME_Q(); for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) { if (VL_UNLIKELY(it->first <= time)) { VerilatedVpioCb* vop = it->second; ++it; // iterator may be deleted by callback VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: timed_callback %p\n",vop);); (vop->cb_rtnp()) (vop->cb_datap()); } else { ++it; } } } static QData cbNextDeadline() { VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); if (VL_LIKELY(it!=s_s.m_timedCbs.end())) { return it->first; } else { return ~VL_ULL(0); // maxquad } } static void callCbs(vluint32_t reason) { VpioCbSet& cbObjSet = s_s.m_cbObjSets[reason]; for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) { VerilatedVpioCb* vop = *it; ++it; // iterator may be deleted by callback VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: reason_callback %d %p\n",reason,vop);); (vop->cb_rtnp()) (vop->cb_datap()); } } static void callValueCbs() { VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbValueChange]; for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) { VerilatedVpioCb* vop = *it; ++it; // iterator may be deleted by callback if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) { void* newDatap = varop->varDatap(); void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_test %s v[0]=%d/%d %p %p\n", varop->fullname(), *((CData*)newDatap), *((CData*)prevDatap), newDatap, prevDatap);); if (memcmp(prevDatap, newDatap, varop->entSize())) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n", vop,varop->fullname(), *((CData*)newDatap));); memcpy(prevDatap, newDatap, varop->entSize()); (vop->cb_rtnp()) (vop->cb_datap()); } } } } }; // callback related vpiHandle vpi_register_cb(p_cb_data cb_data_p) { if (VL_UNLIKELY(!cb_data_p)) return NULL; switch (cb_data_p->reason) { case cbAfterDelay: { QData time = 0; if (cb_data_p->time) time = _VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low); VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q()+time); VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p delay=%" VL_PRI64 "d\n",cb_data_p->reason,vop,time);); VerilatedVpi::cbTimedAdd(vop); return vop->castVpiHandle(); } case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp 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 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 VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, 0); VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p\n",cb_data_p->reason,vop);); VerilatedVpi::cbReasonAdd(vop); return vop->castVpiHandle(); } default: _VL_VPI_UNIMP(); 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); if (VL_UNLIKELY(!vop)) return 0; if (vop->cb_datap()->reason == cbAfterDelay) { VerilatedVpi::cbTimedRemove(vop); } else { VerilatedVpi::cbReasonRemove(vop); } 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; //-} // for obtaining handles vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { 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); const VerilatedVar* varp; const VerilatedScope* scopep; string scopeAndName = namep; if (voScopep) { scopeAndName = string(voScopep->fullname()) + "." + namep; namep = (PLI_BYTE8*)scopeAndName.c_str(); } { // This doesn't yet follow the hierarchy in the proper way scopep = Verilated::scopeFind(namep); if (scopep) { // Whole thing found as a scope return (new VerilatedVpioScope(scopep))->castVpiHandle(); } const char* baseNamep = scopeAndName.c_str(); string scopename; const char* dotp = strrchr(namep, '.'); if (VL_LIKELY(dotp)) { baseNamep = dotp+1; scopename = string(namep,dotp-namep); } scopep = Verilated::scopeFind(scopename.c_str()); if (!scopep) return NULL; varp = scopep->varFind(baseNamep); } if (!varp) return NULL; return (new VerilatedVpioVar(varp, scopep))->castVpiHandle(); } 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); if (VL_LIKELY(varop)) { if (varop->varp()->dims()<2) return 0; if (VL_LIKELY(varop->varp()->array().lhs() >= varop->varp()->array().rhs())) { if (VL_UNLIKELY(indx > varop->varp()->array().lhs() || indx < varop->varp()->array().rhs())) return 0; return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx, indx - varop->varp()->array().rhs())) ->castVpiHandle(); } else { if (VL_UNLIKELY(indx < varop->varp()->array().lhs() || indx > varop->varp()->array().rhs())) return 0; return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx, indx - varop->varp()->array().lhs())) ->castVpiHandle(); } } else { _VL_VPI_UNIMP(); return 0; } } // for traversing relationships vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle %d %p\n",type,object);); switch (type) { case vpiLeftRange: // FALLTHRU case vpiRightRange: { if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { vluint32_t num = ((type==vpiLeftRange) ? vop->varp()->range().lhs() : vop->varp()->range().rhs()); return (new VerilatedVpioConst(num))->castVpiHandle(); } else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) { vluint32_t num = ((type==vpiLeftRange) ? vop->lhs() : vop->rhs()); return (new VerilatedVpioConst(num))->castVpiHandle(); } else { return 0; } } default: _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);); switch (type) { case vpiMemoryWord: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; if (vop->varp()->dims() < 2) return 0; // Unsupported is multidim list return ((new VerilatedVpioRange(vop->varp()->array().lhs(), vop->varp()->array().rhs())) ->castVpiHandle()); } case vpiReg: { VerilatedVpioScope* vop = VerilatedVpioScope::castp(object); if (VL_UNLIKELY(!vop)) return 0; 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; } } vpiHandle vpi_scan(vpiHandle object) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_scan %p\n",object);); VerilatedVpio* vop = VerilatedVpio::castp(object); if (VL_UNLIKELY(!vop)) return NULL; return vop->dovpi_scan(); } // for processing properties 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);); switch (property) { case vpiTimePrecision: { return VL_TIME_PRECISION; } case vpiType: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; return ((vop->varp()->dims()>1) ? vpiMemory : vpiReg); } case vpiDirection: { // By forthought, the directions already are vpi enumerated VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; return vop->varp()->vldir(); } case vpiVector: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; if (vop->varp()->dims()==0) return 0; else return 1; } default: _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); if (VL_UNLIKELY(!vop)) return NULL; switch (property) { case vpiName: { return (PLI_BYTE8*)vop->name(); } case vpiFullName: { return (PLI_BYTE8*)vop->fullname(); } case vpiDefName: { return (PLI_BYTE8*)vop->defname(); } default: _VL_VPI_UNIMP(); 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; //-} // value processing void vpi_get_value(vpiHandle object, p_vpi_value value_p) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_value %p\n",object);); if (VL_UNLIKELY(!value_p)) return; if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { // We presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal if (value_p->format == vpiVectorVal) { // Vector pointer must come from our memory pool // It only needs to persist until the next vpi_get_value static VL_THREAD t_vpi_vecval out[VL_MULS_MAX_WORDS*2]; value_p->value.vector = out; switch (vop->varp()->vltype()) { case VLVT_UINT8: out[0].aval = *((CData*)(vop->varDatap())); out[0].bval = 0; return; case VLVT_UINT16: out[0].aval = *((SData*)(vop->varDatap())); out[0].bval = 0; return; case VLVT_UINT32: out[0].aval = *((IData*)(vop->varDatap())); out[0].bval = 0; return; case VLVT_WDATA: { int words = VL_WORDS_I(vop->varp()->range().bits()); if (VL_UNLIKELY(words >= VL_MULS_MAX_WORDS)) { vl_fatal(__FILE__,__LINE__,"", "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile"); } WDataInP datap = ((IData*)(vop->varDatap())); for (int i=0; ivarDatap())); out[1].aval = (IData)(data>>VL_ULL(32)); out[1].bval = 0; out[0].aval = (IData)(data); out[0].bval = 0; return; } default: { _VL_VPI_UNIMP(); return; } } } else { switch (vop->varp()->vltype()) { case VLVT_UINT8: value_p->value.integer = *((CData*)(vop->varDatap())); return; case VLVT_UINT16: value_p->value.integer = *((SData*)(vop->varDatap())); return; case VLVT_UINT32: value_p->value.integer = *((IData*)(vop->varDatap())); return; case VLVT_WDATA: case VLVT_UINT64: // Not legal value_p->value.integer = 0; default: _VL_VPI_UNIMP(); return; } } } else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { value_p->value.integer = vop->num(); return; } _VL_VPI_UNIMP(); } 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; 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()); 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; return object; case VLVT_UINT16: *((SData*)(vop->varDatap())) = value_p->value.vector[0].aval; return object; case VLVT_UINT32: *((IData*)(vop->varDatap())) = value_p->value.vector[0].aval; 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; } return object; } case VLVT_UINT64: { *((QData*)(vop->varDatap())) = _VL_SET_QII( value_p->value.vector[1].aval, value_p->value.vector[0].aval); return object; } default: { _VL_VPI_UNIMP(); return NULL; } } } else { switch (vop->varp()->vltype()) { case VLVT_UINT8: *((CData*)(vop->varDatap())) = vop->mask() & value_p->value.integer; return object; case VLVT_UINT16: *((SData*)(vop->varDatap())) = vop->mask() & value_p->value.integer; return object; case VLVT_UINT32: *((IData*)(vop->varDatap())) = vop->mask() & value_p->value.integer; return object; case VLVT_WDATA: // FALLTHRU case VLVT_UINT64: // FALLTHRU default: _VL_VPI_UNIMP(); return 0; } } } _VL_VPI_UNIMP(); 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; //-} // time processing //-void vpi_get_time(vpiHandle object, p_vpi_time time_p) { //- _VL_VPI_UNIMP(); //-} // I/O routines //-PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *fileName) { //- _VL_VPI_UNIMP(); return 0; //-} //-PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { //- _VL_VPI_UNIMP(); return 0; //-} //-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 cd) { //- _VL_VPI_UNIMP(); return 0; //-} //-PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *format, ...) { //- _VL_VPI_UNIMP(); return 0; //-} PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) { va_list ap; va_start(ap,formatp); int chars = vpi_vprintf(formatp, ap); va_end(ap); return chars; } PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) { return VL_VPRINTF(formatp, ap); } //-PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) { //- _VL_VPI_UNIMP(); return 0; //-} //-PLI_INT32 vpi_flush(void) { //- _VL_VPI_UNIMP(); return 0; //-} //-PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { //- _VL_VPI_UNIMP(); return 0; //-} // 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_free_object(vpiHandle object) { 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); 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; //-} // 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_control(PLI_INT32 operation, ...) { VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_control %d\n",operation);); switch (operation) { case vpiFinish: { vl_finish(__FILE__,__LINE__,"*VPI*"); return 1; } case vpiStop: { vl_stop(__FILE__,__LINE__,"*VPI*"); return 1; } } _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; //-} //====================================================================== #endif // Guard