diff --git a/Changes b/Changes index 3135436cc..6ea179dbb 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Fix ordering of clock enables with delayed assigns, bug613. [Jeremy Bennett] +*** Fix vpi_iterate on memory words, bug655. [Rich Porter] + * Verilator 3.850 2013-06-02 diff --git a/include/verilated_vpi.h b/include/verilated_vpi.h index 1cfe562c5..9f249dc76 100644 --- a/include/verilated_vpi.h +++ b/include/verilated_vpi.h @@ -94,6 +94,9 @@ public: virtual const char* name() { return ""; } virtual const char* fullname() { return ""; } virtual const char* defname() { return ""; } + virtual const vluint32_t type() { return 0; } + virtual const vluint32_t size() { return 0; } + virtual const VerilatedRange* rangep() { return 0; } virtual vpiHandle dovpi_scan() { return 0; } }; @@ -112,6 +115,7 @@ public: } virtual ~VerilatedVpioCb() {} static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiCallback; } 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); } @@ -124,19 +128,20 @@ public: VerilatedVpioConst(vlsint32_t num) : m_num(num) {} virtual ~VerilatedVpioConst() {} static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiUndefined; } vlsint32_t num() const { return m_num; } }; class VerilatedVpioRange : public VerilatedVpio { - vlsint32_t m_lhs; // Ranges can be signed - vlsint32_t m_rhs; + const VerilatedRange* m_range; bool m_iteration; public: - VerilatedVpioRange(vlsint32_t lhs, vlsint32_t rhs) : m_lhs(lhs), m_rhs(rhs), m_iteration(0) {} + VerilatedVpioRange(const VerilatedRange* range) : m_range(range), 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; } + virtual const vluint32_t type() { return vpiRange; } + virtual const vluint32_t size() const { return m_range->bits(); } + virtual const VerilatedRange* rangep() const { return m_range; } int iteration() const { return m_iteration; } void iterationInc() { ++m_iteration; } virtual vpiHandle dovpi_scan() { @@ -157,6 +162,7 @@ public: : m_scopep(scopep) {} virtual ~VerilatedVpioScope() {} static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiScope; } const VerilatedScope* scopep() const { return m_scopep; } virtual const char* name() { return m_scopep->name(); } virtual const char* fullname() { return m_scopep->name(); } @@ -191,6 +197,11 @@ public: 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; } + const vluint32_t index() { return m_index; } + virtual const vluint32_t type() { return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */ } + virtual const vluint32_t size() { return range().bits(); } + const VerilatedRange& range() { return m_varp->dims()?m_varp->array():m_varp->range(); } + virtual const VerilatedRange* rangep() { return &range(); } virtual const char* name() { return m_varp->name(); } virtual const char* fullname() { VL_STATIC_OR_THREAD string out; @@ -207,16 +218,19 @@ public: } }; -class VerilatedVpioVarIndex : public VerilatedVpioVar { +class VerilatedVpioMemoryWord : public VerilatedVpioVar { public: - VerilatedVpioVarIndex(const VerilatedVar* varp, const VerilatedScope* scopep, + VerilatedVpioMemoryWord(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 ~VerilatedVpioMemoryWord() {} + static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiMemoryWord; } + virtual const vluint32_t size() { return varp()->range().bits(); } + virtual const VerilatedRange* rangep() { return &(varp()->range()); } virtual const char* fullname() { VL_STATIC_OR_THREAD string out; char num[20]; sprintf(num,"%d",m_index); @@ -234,6 +248,7 @@ public: : m_scopep(scopep), m_started(false) { } virtual ~VerilatedVpioVarIter() {} static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiIterator; } virtual vpiHandle dovpi_scan() { if (VL_LIKELY(m_scopep->varsp())) { if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; } @@ -248,6 +263,28 @@ public: } }; +class VerilatedVpioMemoryWordIter : public VerilatedVpio { + const vpiHandle m_handle; + const VerilatedVar* m_varp; + vlsint32_t m_iteration; + vlsint32_t m_direction; + bool m_done; +public: + VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp) + : m_handle(handle), m_varp(varp), m_iteration(varp->array().rhs()), m_direction(VL_LIKELY(varp->array().lhs()>varp->array().rhs())?1:-1), m_done(false) { } + virtual ~VerilatedVpioMemoryWordIter() {} + static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } + virtual const vluint32_t type() { return vpiIterator; } + void iterationInc() { if (!(m_done = m_iteration == m_varp->array().lhs())) m_iteration+=m_direction; } + virtual vpiHandle dovpi_scan() { + vpiHandle result; + if (m_done) return 0; + result = vpi_handle_by_index(m_handle, m_iteration); + iterationInc(); + return result; + } +}; + //====================================================================== struct VerilatedVpiTimedCbsCmp { @@ -267,6 +304,11 @@ class VerilatedVpi { typedef set VpioCbSet; typedef set,VerilatedVpiTimedCbsCmp > VpioTimedCbs; + struct product_info { + PLI_BYTE8* product; + PLI_BYTE8* version; + }; + 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 @@ -547,12 +589,12 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { 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, + return (new VerilatedVpioMemoryWord(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, + return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx, indx - varop->varp()->array().lhs())) ->castVpiHandle(); } @@ -568,21 +610,32 @@ 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 vpiLeftRange: { + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop->rangep())) return 0; + return (new VerilatedVpioConst(vop->rangep()->lhs()))->castVpiHandle(); + } 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; - } + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop->rangep())) return 0; + return (new VerilatedVpioConst(vop->rangep()->rhs()))->castVpiHandle(); + } + case vpiIndex: { + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + return (new VerilatedVpioConst(vop->index()))->castVpiHandle(); + } + case vpiScope: { + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle(); + } + case vpiParent: { + VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle(); } default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", @@ -600,13 +653,25 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { _VL_VPI_ERROR_RESET(); // reset vpi error status switch (type) { case vpiMemoryWord: { + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + if (vop->varp()->dims() < 2) return 0; + if (vop->varp()->dims() > 2) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims()); + } + return (new VerilatedVpioMemoryWordIter(object, vop->varp()))->castVpiHandle(); + } + case vpiRange: { 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()); + if (vop->varp()->dims() > 2) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims()); + } + return ((new VerilatedVpioRange(vop->rangep()))->castVpiHandle()); } case vpiReg: { VerilatedVpioScope* vop = VerilatedVpioScope::castp(object); @@ -639,9 +704,9 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { return VL_TIME_PRECISION; } case vpiType: { - VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + VerilatedVpio* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; - return ((vop->varp()->dims()>1) ? vpiMemory : vpiReg); + return vop->type(); } case vpiDirection: { // By forthought, the directions already are vpi enumerated @@ -649,11 +714,16 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { if (VL_UNLIKELY(!vop)) return 0; return vop->varp()->vldir(); } + case vpiScalar: // FALLTHRU case vpiVector: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VL_UNLIKELY(!vop)) return 0; - if (vop->varp()->dims()==0) return 0; - else return 1; + return (property==vpiVector)^(vop->varp()->dims()==0); + } + case vpiSize: { + VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + return vop->size(); } default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 3b9d3641e..ec2ad1bf9 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -317,6 +317,7 @@ sub new { pl_filename => undef, # Name of .pl file to get setup from make_top_shell => 1, # Make a default __top.v file make_main => 1, # Make __main.cpp + make_pli => 0, # need to compile pli sim_time => 1100, benchmark => $opt_benchmark, run_env => '', @@ -331,7 +332,8 @@ sub new { v_flags2 => [], # Overridden in some sim files v_other_filenames => [], # After the filename so we can spec multiple files all_run_flags => [], - # ATSIM + pli_flags => ["-I$ENV{VERILATOR_ROOT}/include/vltstd -fPIC -export-dynamic -shared -o $self->{obj_dir}/libvpi.so"], + # ATSIM atsim => 0, atsim_flags => [split(/\s+/,"-c +sv +define+ATSIM"), "+sv_dir+$self->{obj_dir}/.athdl_compile"], @@ -348,6 +350,7 @@ sub new { iv => 0, iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")], iv_flags2 => [], # Overridden in some sim files + iv_pli => 0, # need to use pli iv_run_flags => [], # VCS vcs => 0, @@ -658,6 +661,16 @@ sub compile { else { $self->error("No compile step for this simulator"); } + + if ($param{make_pli}) { + $self->oprint("Compile vpi\n"); + my @cmd = ('g++', @{$param{pli_flags}}, "-DIS_VPI", "$self->{t_dir}/$self->{name}.cpp"); + + $self->_run(logfile=>"$self->{obj_dir}/pli_compile.log", + fails=>$param{fails}, + cmd=>\@cmd); + } + return 1; } @@ -694,12 +707,16 @@ sub execute { ); } elsif ($param{iv}) { + my @cmd = ($run_env."$self->{obj_dir}/simiv", + @{$param{iv_run_flags}}, + @{$param{all_run_flags}}, + ); + if ($param{iv_pli}) { + unshift @cmd, "vvp -m $self->{obj_dir}/libvpi.so"; + } $self->_run(logfile=>"$self->{obj_dir}/iv_sim.log", fails=>$param{fails}, - cmd=>[$run_env."$self->{obj_dir}/simiv", - @{$param{iv_run_flags}}, - @{$param{all_run_flags}}, - ], + cmd=> \@cmd, %param, expect=>$param{iv_run_expect}, # non-verilator expect isn't the same ); diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp new file mode 100644 index 000000000..0a9ad78da --- /dev/null +++ b/test_regress/t/t_vpi_memory.cpp @@ -0,0 +1,278 @@ +// -*- 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. +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#else + +#include "Vt_vpi_memory.h" +#include "verilated.h" +#include "svdpi.h" + +#include "Vt_vpi_memory__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vpi.cpp" +#include "verilated_vcd_c.h" + +#endif + +#include +#include +#include +using namespace std; + +// __FILE__ is too long +#define FILENM "t_vpi_memory.cpp" + +#define DEBUG if (0) printf + +unsigned int main_time = 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_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009 + 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) + +// ideally we should be able to iterate on vpiRange against a list of this struct +typedef struct range { + int size; + int left; + int right; +} range_s, *range_p; + +int _mon_check_range(VlVpiHandle& handle, int size, int left, int right) { + VlVpiHandle iter_h, rng_h, left_h, right_h; + s_vpi_value value = { + vpiIntVal + }; + // check size of object + int vpisize = vpi_get(vpiSize, handle); + CHECK_RESULT(vpisize, size); +/* + // get range and check against expected + iter_h = vpi_iterate(vpiRange, handle); + CHECK_RESULT_NZ(iter_h); + rng_h = vpi_scan(iter_h); + CHECK_RESULT_NZ(rng_h); + int vpitype = vpi_get(vpiType, rng_h); + CHECK_RESULT(vpitype, vpiRange); +*/ + // check size of range + vpisize = vpi_get(vpiSize, handle); + CHECK_RESULT(vpisize, size); + // check left hand side of range + left_h = vpi_handle(vpiLeftRange, handle); + CHECK_RESULT_NZ(left_h); + vpi_get_value(left_h, &value); + CHECK_RESULT(value.value.integer, left); + // check right hand side of range + right_h = vpi_handle(vpiRightRange, handle); + CHECK_RESULT_NZ(right_h); + vpi_get_value(right_h, &value); + CHECK_RESULT(value.value.integer, right); + return 0; // Ok +} + +int _mon_check_memory() { + int cnt; + VlVpiHandle mem_h, lcl_h; + vpiHandle iter_h; // icarus does not like auto free of iterator handles + s_vpi_value value = { + vpiIntVal + }; + vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n"); + mem_h = vpi_handle_by_name((PLI_BYTE8*)"t.mem0", NULL); + CHECK_RESULT_NZ(mem_h); + // check type + int vpitype = vpi_get(vpiType, mem_h); + CHECK_RESULT(vpitype, vpiMemory); + _mon_check_range(mem_h, 16, 16, 1); + // iterate and store + iter_h = vpi_iterate(vpiMemoryWord, mem_h); + cnt = 0; + while (lcl_h = vpi_scan(iter_h)) { + value.value.integer = ++cnt; + vpi_put_value(lcl_h, &value, NULL, vpiNoDelay); + // check size and range + _mon_check_range(lcl_h, 32, 31, 0); + } + CHECK_RESULT(cnt, 16); // should be 16 addresses + // iterate and accumulate + iter_h = vpi_iterate(vpiMemoryWord, mem_h); + cnt = 0; + while (lcl_h = vpi_scan(iter_h)) { + ++cnt; + vpi_get_value(lcl_h, &value); + CHECK_RESULT(value.value.integer, cnt); + } + CHECK_RESULT(cnt, 16); // should be 16 addresses + // don't care for non verilator + // (crashes on Icarus) + s_vpi_vlog_info info; + vpi_get_vlog_info(&info); + if (strcmp(info.product, "Verilator") != 0) { + vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", info.product); + return 0; // Ok + } + // make sure trying to get properties that don't exist + // doesn't crash + int should_be_0 = vpi_get(vpiSize, iter_h); + CHECK_RESULT(should_be_0, 0); + should_be_0 = vpi_get(vpiIndex, iter_h); + CHECK_RESULT(should_be_0, 0); + vpiHandle should_be_NULL = vpi_handle(vpiLeftRange, iter_h); + CHECK_RESULT(should_be_NULL, 0); + should_be_NULL = vpi_handle(vpiRightRange, iter_h); + CHECK_RESULT(should_be_NULL, 0); + should_be_NULL = vpi_handle(vpiScope, iter_h); + CHECK_RESULT(should_be_NULL, 0); + return 0; // Ok +} + +int mon_check() { + // Callback from initial block in monitor + if (int status = _mon_check_memory()) return status; + return 0; // Ok +} + +//====================================================================== + +#ifdef IS_VPI + + +static s_vpi_systf_data vpi_systf_data[] = { + {vpiSysFunc, vpiSysFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check, 0, 0, 0}, + 0 +}; + +// cver entry +void vpi_compat_bootstrap(void) { + p_vpi_systf_data systf_data_p; + systf_data_p = &(vpi_systf_data[0]); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); +} + +// icarus entry +void (*vlog_startup_routines[])() = { + vpi_compat_bootstrap, + 0 +}; + +#else +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 + } + 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); +} + +#endif + diff --git a/test_regress/t/t_vpi_memory.pl b/test_regress/t/t_vpi_memory.pl new file mode 100755 index 000000000..5a1982eaa --- /dev/null +++ b/test_regress/t/t_vpi_memory.pl @@ -0,0 +1,25 @@ +#!/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, + make_pli => 1, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -s t -o obj_dir/iv_t_vpi_memory/simiv"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_memory.cpp"], + ); + +execute ( + iv_pli => 1, + check_finished=>1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v new file mode 100644 index 000000000..1ae92a6d3 --- /dev/null +++ b/test_regress/t/t_vpi_memory.v @@ -0,0 +1,47 @@ +// 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 USE_VPI_NOT_DPI +//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 [31:0] mem0 [16:1] /*verilator public_flat_rw @(posedge clk) */; + integer i, status; + + // Test loop + initial begin +`ifdef VERILATOR + status = $c32("mon_check()"); +`endif +`ifdef iverilog + status = $mon_check(); +`endif +`ifndef USE_VPI_NOT_DPI + status = mon_check(); +`endif + for (i = 16; i > 0; i--) + if (mem0[i] !== i) $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i); + $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 bbb7fa97b..893f91860 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -93,7 +93,7 @@ public: int _mon_check_mcd() { PLI_INT32 status; - + PLI_UINT32 mcd; PLI_BYTE8* filename = (PLI_BYTE8*)"obj_dir/t_vpi_var/mcd_open.tmp"; mcd = vpi_mcd_open(filename); @@ -247,13 +247,13 @@ int _mon_check_var() { VlVpiHandle vh10 = vpi_handle(vpiLeftRange, vh4); CHECK_RESULT_NZ(vh10); vpi_get_value(vh10, &tmpValue); - CHECK_RESULT(tmpValue.value.integer,2); + CHECK_RESULT(tmpValue.value.integer,4); } { VlVpiHandle vh10 = vpi_handle(vpiRightRange, vh4); CHECK_RESULT_NZ(vh10); vpi_get_value(vh10, &tmpValue); - CHECK_RESULT(tmpValue.value.integer,1); + CHECK_RESULT(tmpValue.value.integer,3); } { VlVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4); @@ -263,11 +263,11 @@ int _mon_check_var() { VlVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11); CHECK_RESULT_NZ(vh12); vpi_get_value(vh12, &tmpValue); - CHECK_RESULT(tmpValue.value.integer,4); + CHECK_RESULT(tmpValue.value.integer,2); VlVpiHandle vh13 = vpi_handle(vpiRightRange, vh11); CHECK_RESULT_NZ(vh13); vpi_get_value(vh13, &tmpValue); - CHECK_RESULT(tmpValue.value.integer,3); + CHECK_RESULT(tmpValue.value.integer,1); } return 0;