From 85989af0316d3d23141f63200c858fd95bbb6621 Mon Sep 17 00:00:00 2001 From: Rich Porter Date: Sun, 13 Oct 2013 20:05:57 -0400 Subject: [PATCH] Fix vpi_get of vpiSize, bug680. Signed-off-by: Wilson Snyder --- Changes | 2 + include/verilated_vpi.h | 14 +- test_regress/t/TestSimulator.h | 78 ++++++++ test_regress/t/TestVpi.h | 34 ++++ test_regress/t/t_dpi_string_c.cpp | 1 + test_regress/t/t_vpi_get.cpp | 283 ++++++++++++++++++++++++++++++ test_regress/t/t_vpi_get.pl | 25 +++ test_regress/t/t_vpi_get.v | 71 ++++++++ test_regress/t/t_vpi_memory.cpp | 69 +++----- test_regress/t/t_vpi_memory.pl | 2 +- test_regress/t/t_vpi_memory.v | 13 +- test_regress/t/t_vpi_unimpl.cpp | 18 +- test_regress/t/t_vpi_var.cpp | 215 +++++++++++++---------- test_regress/t/t_vpi_var.pl | 5 + test_regress/t/t_vpi_var.v | 28 ++- 15 files changed, 701 insertions(+), 157 deletions(-) create mode 100644 test_regress/t/TestSimulator.h create mode 100644 test_regress/t/TestVpi.h create mode 100644 test_regress/t/t_vpi_get.cpp create mode 100755 test_regress/t/t_vpi_get.pl create mode 100644 test_regress/t/t_vpi_get.v diff --git a/Changes b/Changes index 654e2eb47..80e6662ac 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix multiple VPI variable callbacks, bug679. [Rich Porter] +**** Fix vpi_get of vpiSize, bug680. [Rich Porter] + * Verilator 3.853 2013-09-30 diff --git a/include/verilated_vpi.h b/include/verilated_vpi.h index e1d9d1e7f..7e2644c2e 100644 --- a/include/verilated_vpi.h +++ b/include/verilated_vpi.h @@ -182,6 +182,10 @@ class VerilatedVpioVar : public VerilatedVpio { protected: void* m_varDatap; // varp()->datap() adjusted for array entries vlsint32_t m_index; + const VerilatedRange& get_range() { + // Determine number of dimensions and return outermost + return (m_varp->dims()>1) ? m_varp->array() : m_varp->range(); + } public: VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep) : m_varp(varp), m_scopep(scopep), m_index(0) { @@ -200,10 +204,12 @@ public: 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().elements(); } - const VerilatedRange& range() { return m_varp->dims()?m_varp->array():m_varp->range(); } - virtual const VerilatedRange* rangep() { return &range(); } + virtual const vluint32_t type() { + if (varp()->vldir() != vpiNoDirection) return vpiPort; + return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */ + } + virtual const vluint32_t size() { return get_range().elements(); } + virtual const VerilatedRange* rangep() { return &get_range(); } virtual const char* name() { return m_varp->name(); } virtual const char* fullname() { VL_STATIC_OR_THREAD string out; diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h new file mode 100644 index 000000000..4a875e616 --- /dev/null +++ b/test_regress/t/TestSimulator.h @@ -0,0 +1,78 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2013-2013 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 "vpi_user.h" + +class TestSimulator { +private: + struct SimTypes { + int verilator; + int icarus; + int mti; + int ncsim; + int vcs; + }; + s_vpi_vlog_info m_info; + SimTypes m_simulators; +public: + TestSimulator() { + vpi_get_vlog_info(&m_info); + if (0 == strcmp(m_info.product, "Verilator")) { + m_simulators.verilator = true; + } else if (0 == strcmp(m_info.product, "Verilator")) { + m_simulators.icarus = true; + } else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) { + m_simulators.vcs = true; + } else { + printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", + __FILE__, __LINE__, m_info.product); + } + } + ~TestSimulator() { } + // METHORS +private: + static TestSimulator& singleton() { + static TestSimulator s_singleton; + return s_singleton; + } + static const SimTypes& simulators() { return singleton().m_simulators; } +public: + static const s_vpi_vlog_info& get_info() { return singleton().m_info; } + // Simulator names + static bool is_icarus() { return simulators().icarus; } + static bool is_verilator() { return simulators().verilator; } + static bool is_mti() { return simulators().mti; } + static bool is_ncsim() { return simulators().ncsim; } + static bool is_vcs() { return simulators().vcs; } + // Simulator properties + static bool is_event_driven() { return !simulators().verilator; } + static bool has_get_scalar() { return !simulators().icarus; } + // return test level scope + static const char* top() { + if (simulators().verilator) { + return "t"; + } else { + return "top.t"; + } + } + // return absolute scope of obj + static const char* rooted(const char *obj) { + static char buf[256]; + snprintf(buf, sizeof(buf), "%s.%s", top(), obj); + return buf; + } +}; + +#define VPI_HANDLE(signal) vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(signal), NULL); diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h new file mode 100644 index 000000000..642c37849 --- /dev/null +++ b/test_regress/t/TestVpi.h @@ -0,0 +1,34 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2013-2013 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 "vpi_user.h" + +//====================================================================== + +class TestVpiHandle { + /// For testing, etc, wrap vpiHandle in an auto-releasing class + vpiHandle m_handle; + bool m_free; +public: + TestVpiHandle() : m_handle(NULL), m_free(true) { } + TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { } + ~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009 + operator vpiHandle () const { return m_handle; } + inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; } + TestVpiHandle& nofree() { + m_free = false; + return *this; + } +}; diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index cba607162..540beed26 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -14,6 +14,7 @@ //************************************************************************* #include +#include #include "svdpi.h" //====================================================================== diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp new file mode 100644 index 000000000..e1e78dc87 --- /dev/null +++ b/test_regress/t/t_vpi_get.cpp @@ -0,0 +1,283 @@ +// -*- 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" +#include + +#else + +#include "Vt_vpi_get.h" +#include "verilated.h" +#include "svdpi.h" + +#include "Vt_vpi_get__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vpi.cpp" +#include "verilated_vcd_c.h" + +#endif + +#include +#include +#include +using namespace std; + +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_get.cpp" + +#define TEST_MSG if (0) printf + +unsigned int main_time = false; + +//====================================================================== + +#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) + +static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int scalar, int type) { + s_vpi_value value = { + vpiIntVal + }; + // check size of object + int vpisize = vpi_get(vpiSize, handle); + CHECK_RESULT(vpisize, size); + + // icarus verilog does not support vpiScalar, vpiVector or vpi*Range + if (TestSimulator::has_get_scalar()) { + int vpiscalar = vpi_get(vpiScalar, handle); + CHECK_RESULT((bool)vpiscalar, (bool)scalar); + int vpivector = vpi_get(vpiVector, handle); + CHECK_RESULT((bool)vpivector, (bool)!scalar); + } + + // Icarus only supports ranges on memories + if (!scalar && !(TestSimulator::is_icarus() && type != vpiMemory)) { + TestVpiHandle left_h, right_h; + + // check coherency for vectors + // get left hand side of range + left_h = vpi_handle(vpiLeftRange, handle); + CHECK_RESULT_NZ(left_h); + vpi_get_value(left_h, &value); + int coherency = value.value.integer; + // get right hand side of range + right_h = vpi_handle(vpiRightRange, handle); + CHECK_RESULT_NZ(right_h); + vpi_get_value(right_h, &value); + TEST_MSG("%d:%d\n", coherency, value.value.integer); + coherency -= value.value.integer; + // calculate size & check + coherency = abs(coherency) + 1; + CHECK_RESULT(coherency, size); + } + + // Only check direction on ports + if (type == vpiPort) { + // check direction of object + int vpidir = vpi_get(vpiDirection, handle); + // Don't check port directions in verilator + // see #681 + if (!TestSimulator::is_verilator()) { + CHECK_RESULT(vpidir, direction); + } + } + + // check type of object + int vpitype = vpi_get(vpiType, handle); + if (!(TestSimulator::is_verilator() && type == vpiPort)) { + // Don't check for ports in verilator + // see #681 + CHECK_RESULT(vpitype, type); + } + + return 0; // Ok +} + +struct params { + const char* signal; + struct { + unsigned int size; + unsigned int direction; + unsigned int scalar; + unsigned int type; + } attributes, children; +} values[] = { + {"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}}, + {"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, + {"onetwo", {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory}, {0, 0, 0, 0}}, + {"fourthreetwoone", {2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiMemoryWord}}, + {"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}}, + {"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}}, + {"testout", {24, vpiOutput, 0, vpiPort}, {0, 0, 0, 0}}, + {"sub.subin", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}}, + {"sub.subout", {1, vpiOutput, 1, vpiPort}, {0, 0, 0, 0}}, + {NULL, {0, 0, 0, 0}, {0, 0, 0, 0}} +}; + +int mon_check_props() { + struct params* value = values; + while (value->signal) { + TestVpiHandle h = VPI_HANDLE(value->signal); + CHECK_RESULT_NZ(h); + TEST_MSG("%s\n", value->signal); + if (int status = _mon_check_props(h, value->attributes.size, value->attributes.direction, value->attributes.scalar, value->attributes.type)) return status; + if (value->children.size) { + int size = 0; + TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, h); + while (TestVpiHandle word_h = vpi_scan(iter_h.nofree())) { + // check size and range + if (int status = _mon_check_props(word_h, value->children.size, value->children.direction, value->children.scalar, value->children.type)) return status; + size++; + } + CHECK_RESULT(size, value->attributes.size); + } + value++; + } + return 0; +} + +int mon_check() { + // Callback from initial block in monitor + if (int status = mon_check_props()) return status; + return 0; // Ok +} + +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + vpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = { + {vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 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); + + 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_get.pl b/test_regress/t/t_vpi_get.pl new file mode 100755 index 000000000..bb8c84c39 --- /dev/null +++ b/test_regress/t/t_vpi_get.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, + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_get.cpp"], + make_pli => 1, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], +); + +execute ( + iv_pli => 1, + check_finished=>1 +); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_get.v b/test_regress/t/t_vpi_get.v new file mode 100644 index 000000000..4bc474050 --- /dev/null +++ b/test_regress/t/t_vpi_get.v @@ -0,0 +1,71 @@ +// 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 + input clk /*verilator public_flat_rd */, + + // test ports + input [15:0] testin /*verilator public_flat_rd */, + output [23:0] testout /*verilator public_flat_rw @(posedge clk) */ + + ); + +`ifdef VERILATOR +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + reg onebit /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; + reg onetwo [1:2] /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; + + integer status; + +`ifdef iverilog + // stop icarus optimizing signals away + wire redundant = onebit | onetwo[1] | twoone | fourthreetwoone[3]; +`endif + + wire subin /*verilator public_flat_rd*/; + wire subout /*verilator public_flat_rd*/; + sub sub(.*); + + // 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 + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t + +module sub ( + input subin /*verilator public_flat_rd*/, + output subout /*verilator public_flat_rd*/ +); +endmodule : sub diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 0a9ad78da..785ef94a9 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -16,6 +16,7 @@ #ifdef IS_VPI #include "vpi_user.h" +#include #else @@ -36,6 +37,9 @@ #include using namespace std; +#include "TestSimulator.h" +#include "TestVpi.h" + // __FILE__ is too long #define FILENM "t_vpi_memory.cpp" @@ -45,19 +49,6 @@ 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", \ @@ -96,30 +87,14 @@ public: #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; +int _mon_check_range(TestVpiHandle& handle, int size, int left, int right) { + TestVpiHandle iter_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); @@ -128,28 +103,33 @@ int _mon_check_range(VlVpiHandle& handle, int size, int left, int right) { CHECK_RESULT_NZ(left_h); vpi_get_value(left_h, &value); CHECK_RESULT(value.value.integer, left); + int coherency = value.value.integer; // 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); + coherency -= value.value.integer; + // calculate size & check + coherency = abs(coherency) + 1; + CHECK_RESULT(coherency, size); return 0; // Ok } int _mon_check_memory() { int cnt; - VlVpiHandle mem_h, lcl_h; + TestVpiHandle 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); + mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("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); + if (int status = _mon_check_range(mem_h, 16, 16, 1)) return status; // iterate and store iter_h = vpi_iterate(vpiMemoryWord, mem_h); cnt = 0; @@ -157,7 +137,7 @@ int _mon_check_memory() { value.value.integer = ++cnt; vpi_put_value(lcl_h, &value, NULL, vpiNoDelay); // check size and range - _mon_check_range(lcl_h, 32, 31, 0); + if (int status = _mon_check_range(lcl_h, 32, 31, 0)) return status; } CHECK_RESULT(cnt, 16); // should be 16 addresses // iterate and accumulate @@ -171,10 +151,8 @@ int _mon_check_memory() { 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); + if (TestSimulator::is_icarus()) { + vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", TestSimulator::get_info().product); return 0; // Ok } // make sure trying to get properties that don't exist @@ -202,9 +180,19 @@ int mon_check() { #ifdef IS_VPI +static int mon_check_vpi() { + vpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} static s_vpi_systf_data vpi_systf_data[] = { - {vpiSysFunc, vpiSysFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check, 0, 0, 0}, + {vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0}, 0 }; @@ -222,6 +210,7 @@ void (*vlog_startup_routines[])() = { }; #else + double sc_time_stamp () { return main_time; } diff --git a/test_regress/t/t_vpi_memory.pl b/test_regress/t/t_vpi_memory.pl index 5a1982eaa..ee515df9d 100755 --- a/test_regress/t/t_vpi_memory.pl +++ b/test_regress/t/t_vpi_memory.pl @@ -11,7 +11,7 @@ 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"], + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], v_flags2 => ["+define+USE_VPI_NOT_DPI"], verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_memory.cpp"], ); diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v index 1ae92a6d3..ea1681071 100644 --- a/test_regress/t/t_vpi_memory.v +++ b/test_regress/t/t_vpi_memory.v @@ -38,8 +38,19 @@ extern "C" int mon_check(); `ifndef USE_VPI_NOT_DPI status = mon_check(); `endif + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end for (i = 16; i > 0; i--) - if (mem0[i] !== i) $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i); + if (mem0[i] !== i) begin + $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i); + status = 1; + end + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 51f52c42c..4fb396590 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -25,6 +25,8 @@ #include +#include "TestVpi.h" + // __FILE__ is too long #define FILENM "t_vpi_unimpl.cpp" @@ -35,20 +37,6 @@ 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", \ @@ -88,7 +76,7 @@ public: CHECK_RESULT_CSTR(got+strspn(got, " "), exp) int _mon_check_unimpl(p_cb_data cb_data) { - static VlVpiHandle cb, clk_h; + static TestVpiHandle cb, clk_h; if (cb_data) { // this is the callback s_vpi_error_info info; diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 42ae963a3..ce8996615 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -13,6 +13,12 @@ // //************************************************************************* +#ifdef IS_VPI + +#include "vpi_user.h" + +#else + #include "Vt_vpi_var.h" #include "verilated.h" #include "svdpi.h" @@ -23,48 +29,28 @@ #include "verilated_vpi.cpp" #include "verilated_vcd_c.h" +#endif + +#include +#include +#include #include +using namespace std; + +#include "TestSimulator.h" +#include "TestVpi.h" // __FILE__ is too long #define FILENM "t_vpi_var.cpp" #define TEST_MSG if (0) printf -struct countdown { - int count; - vpiHandle callback; - countdown(int count) : count(count) {}; - int decrement() { - if (!--count) { - vpi_remove_cb(callback); - } - return count; - } - PLI_BYTE8* ptr() { - return (PLI_BYTE8*)this; - } -}; - 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; -countdown cd(200); -//====================================================================== - - -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; } -}; //====================================================================== @@ -127,7 +113,8 @@ int _mon_check_mcd() { CHECK_RESULT(status, 0); status = vpi_mcd_close(mcd); - CHECK_RESULT(status, 0); + // Icarus says 'error' on ones we're not using, so check only used ones return 0. + CHECK_RESULT(status & mcd, 0); status = vpi_flush(); CHECK_RESULT(status, 0); @@ -135,12 +122,18 @@ int _mon_check_mcd() { return 0; } +int _mon_check_callbacks_error(p_cb_data cb_data) { + vpi_printf((PLI_BYTE8*)"%%Error: callback should not be executed\n"); + return 1; +} + int _mon_check_callbacks() { t_cb_data cb_data; cb_data.reason = cbEndOfSimulation; - cb_data.cb_rtn = NULL; + cb_data.cb_rtn = _mon_check_callbacks_error; cb_data.user_data = 0; cb_data.value = NULL; + cb_data.time = NULL; vpiHandle vh = vpi_register_cb(&cb_data); CHECK_RESULT_NZ(vh); @@ -152,17 +145,20 @@ int _mon_check_callbacks() { } int _value_callback(p_cb_data cb_data) { - CHECK_RESULT(cb_data->value->value.integer+10, main_time); + + if (TestSimulator::is_verilator()) { + // this check only makes sense in Verilator + CHECK_RESULT(cb_data->value->value.integer+10, main_time); + } callback_count++; return 0; } -int _value_callback_countdown(p_cb_data cb_data) { - return ((countdown*)(cb_data->user_data))->decrement() < 1; -}; - int _value_callback_half(p_cb_data cb_data) { - CHECK_RESULT(cb_data->value->value.integer*2+10, main_time); + if (TestSimulator::is_verilator()) { + // this check only makes sense in Verilator + CHECK_RESULT(cb_data->value->value.integer*2+10, main_time); + } callback_count_half++; return 0; } @@ -177,7 +173,7 @@ int _value_callback_quad(p_cb_data cb_data) { } int _mon_check_value_callbacks() { - vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL); + vpiHandle vh1 = VPI_HANDLE("count"); CHECK_RESULT_NZ(vh1); s_vpi_value v; @@ -189,16 +185,12 @@ int _mon_check_value_callbacks() { cb_data.cb_rtn = _value_callback; cb_data.obj = vh1; cb_data.value = &v; + cb_data.time = NULL; + vpiHandle vh = vpi_register_cb(&cb_data); CHECK_RESULT_NZ(vh); - // add another callback to same signal - cb_data.cb_rtn = _value_callback_countdown; - cb_data.user_data = cd.ptr(); - cd.callback = vpi_register_cb(&cb_data); - CHECK_RESULT_NZ(cd.callback); - - vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.half_count", NULL); + vh1 = VPI_HANDLE("half_count"); CHECK_RESULT_NZ(vh1); cb_data.obj = vh1; @@ -207,7 +199,7 @@ int _mon_check_value_callbacks() { vh = vpi_register_cb(&cb_data); CHECK_RESULT_NZ(vh); - vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.quads", NULL); + vh1 = VPI_HANDLE("quads"); CHECK_RESULT_NZ(vh1); v.format = vpiVectorVal; @@ -229,10 +221,10 @@ int _mon_check_value_callbacks() { } int _mon_check_var() { - VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL); + TestVpiHandle vh1 = VPI_HANDLE("onebit"); CHECK_RESULT_NZ(vh1); - VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t", NULL); + TestVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::top(), NULL); CHECK_RESULT_NZ(vh2); // scope attributes @@ -240,55 +232,57 @@ int _mon_check_var() { p = vpi_get_str(vpiName, vh2); CHECK_RESULT_CSTR(p, "t"); p = vpi_get_str(vpiFullName, vh2); - CHECK_RESULT_CSTR(p, "t"); + CHECK_RESULT_CSTR(p, TestSimulator::top()); - VlVpiHandle vh3 = vpi_handle_by_name((PLI_BYTE8*)"onebit", vh2); + TestVpiHandle vh3 = vpi_handle_by_name((PLI_BYTE8*)"onebit", vh2); CHECK_RESULT_NZ(vh3); // onebit attributes PLI_INT32 d; d = vpi_get(vpiType, vh3); CHECK_RESULT(d, vpiReg); - d = vpi_get(vpiDirection, vh3); - CHECK_RESULT(d, vpiNoDirection); - d = vpi_get(vpiVector, vh3); - CHECK_RESULT(d, 0); + if (TestSimulator::has_get_scalar()) { + d = vpi_get(vpiVector, vh3); + CHECK_RESULT(d, 0); + } p = vpi_get_str(vpiName, vh3); CHECK_RESULT_CSTR(p, "onebit"); p = vpi_get_str(vpiFullName, vh3); - CHECK_RESULT_CSTR(p, "t.onebit"); + CHECK_RESULT_CSTR(p, TestSimulator::rooted("onebit")); // array attributes - VlVpiHandle vh4 = vpi_handle_by_name((PLI_BYTE8*)"t.fourthreetwoone", NULL); + TestVpiHandle vh4 = VPI_HANDLE("fourthreetwoone"); CHECK_RESULT_NZ(vh4); - d = vpi_get(vpiVector, vh4); - CHECK_RESULT(d, 1); + if (TestSimulator::has_get_scalar()) { + d = vpi_get(vpiVector, vh4); + CHECK_RESULT(d, 1); + } t_vpi_value tmpValue; tmpValue.format = vpiIntVal; { - VlVpiHandle vh10 = vpi_handle(vpiLeftRange, vh4); + TestVpiHandle vh10 = vpi_handle(vpiLeftRange, vh4); CHECK_RESULT_NZ(vh10); vpi_get_value(vh10, &tmpValue); CHECK_RESULT(tmpValue.value.integer,4); } { - VlVpiHandle vh10 = vpi_handle(vpiRightRange, vh4); + TestVpiHandle vh10 = vpi_handle(vpiRightRange, vh4); CHECK_RESULT_NZ(vh10); vpi_get_value(vh10, &tmpValue); CHECK_RESULT(tmpValue.value.integer,3); } { - VlVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4); + TestVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4); CHECK_RESULT_NZ(vh10); - VlVpiHandle vh11 = vpi_scan(vh10); + TestVpiHandle vh11 = vpi_scan(vh10); CHECK_RESULT_NZ(vh11); - VlVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11); + TestVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11); CHECK_RESULT_NZ(vh12); vpi_get_value(vh12, &tmpValue); CHECK_RESULT(tmpValue.value.integer,2); - VlVpiHandle vh13 = vpi_handle(vpiRightRange, vh11); + TestVpiHandle vh13 = vpi_handle(vpiRightRange, vh11); CHECK_RESULT_NZ(vh13); vpi_get_value(vh13, &tmpValue); CHECK_RESULT(tmpValue.value.integer,1); @@ -300,30 +294,30 @@ int _mon_check_var() { int _mon_check_varlist() { const char* p; - VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.sub", NULL); + TestVpiHandle vh2 = VPI_HANDLE("sub"); CHECK_RESULT_NZ(vh2); - VlVpiHandle vh10 = vpi_iterate(vpiReg, vh2); - CHECK_RESULT_NZ(vh10); + TestVpiHandle vh10 = vpi_iterate(vpiReg, vh2); + CHECK_RESULT_NZ(vh10.nofree()); - VlVpiHandle vh11 = vpi_scan(vh10); + TestVpiHandle vh11 = vpi_scan(vh10); CHECK_RESULT_NZ(vh11); p = vpi_get_str(vpiFullName, vh11); - CHECK_RESULT_CSTR(p, "t.sub.subsig1"); + CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig1")); - VlVpiHandle vh12 = vpi_scan(vh10); + TestVpiHandle vh12 = vpi_scan(vh10); CHECK_RESULT_NZ(vh12); p = vpi_get_str(vpiFullName, vh12); - CHECK_RESULT_CSTR(p, "t.sub.subsig2"); + CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig2")); - VlVpiHandle vh13 = vpi_scan(vh10); + TestVpiHandle vh13 = vpi_scan(vh10); CHECK_RESULT(vh13,0); return 0; } int _mon_check_getput() { - VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL); + TestVpiHandle vh2 = VPI_HANDLE("onebit"); CHECK_RESULT_NZ(vh2); s_vpi_value v; @@ -345,7 +339,7 @@ int _mon_check_getput() { } int _mon_check_quad() { - VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.quads", NULL); + TestVpiHandle vh2 = VPI_HANDLE("quads"); CHECK_RESULT_NZ(vh2); s_vpi_value v; @@ -356,9 +350,9 @@ int _mon_check_quad() { t.high = 0; t.low = 0; - VlVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2); + TestVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2); CHECK_RESULT_NZ(vhidx2); - VlVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3); + TestVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3); CHECK_RESULT_NZ(vhidx2); v.format = vpiVectorVal; @@ -390,15 +384,15 @@ int _mon_check_string() { const char *initial; const char *value; } text_test_obs[] = { - {"t.text_byte", "B", "xxA"}, // x's dropped - {"t.text_half", "Hf", "xxT2"}, // x's dropped - {"t.text_word", "Word", "Tree"}, - {"t.text_long", "Long64b", "44Four44"}, - {"t.text" , "Verilog Test module", "lorem ipsum"}, + {"text_byte", "B", "xxA"}, // x's dropped + {"text_half", "Hf", "xxT2"}, // x's dropped + {"text_word", "Word", "Tree"}, + {"text_long", "Long64b", "44Four44"}, + {"text" , "Verilog Test module", "lorem ipsum"}, }; for (int i=0; i<5; i++) { - VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)text_test_obs[i].name, NULL); + TestVpiHandle vh1 = VPI_HANDLE(text_test_obs[i].name); CHECK_RESULT_NZ(vh1); s_vpi_value v; @@ -421,9 +415,9 @@ int _mon_check_string() { } int _mon_check_putget_str(p_cb_data cb_data) { - static VlVpiHandle cb; + static TestVpiHandle cb; static struct { - VlVpiHandle scope, sig, rfr, check, verbose; + TestVpiHandle scope, sig, rfr, check, verbose; char str[128+1]; // char per bit plus null terminator int type; // value type in .str union { @@ -516,7 +510,7 @@ int _mon_check_putget_str(p_cb_data cb_data) { // setup and install for (int i=1; i<=128; i++) { char buf[32]; - snprintf(buf, sizeof(buf), "t.arr[%d].arr", i); + snprintf(buf, sizeof(buf), TestSimulator::rooted("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)); @@ -526,12 +520,13 @@ int _mon_check_putget_str(p_cb_data cb_data) { static t_cb_data cb_data; static s_vpi_value v; - static VlVpiHandle count_h = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL); + static TestVpiHandle count_h = VPI_HANDLE("count"); cb_data.reason = cbValueChange; cb_data.cb_rtn = _mon_check_putget_str; // this function cb_data.obj = count_h; cb_data.value = &v; + cb_data.time = NULL; v.format = vpiIntVal; cb = vpi_register_cb(&cb_data); @@ -548,12 +543,15 @@ int _mon_check_vlog_info() { 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); - + if (TestSimulator::is_verilator()) { + CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); + CHECK_RESULT(strlen(vlog_info.version) > 0, 1); + } return 0; } +#ifndef IS_VPI + #define CHECK_ENUM_STR(fn, enum) \ do { \ const char* strVal = VerilatedVpiError::fn(enum); \ @@ -591,6 +589,8 @@ int _mon_check_vl_str() { return 0; } +#endif + int mon_check() { // Callback from initial block in monitor if (int status = _mon_check_mcd()) return status; @@ -603,12 +603,46 @@ int mon_check() { 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; +#ifndef IS_VPI if (int status = _mon_check_vl_str()) return status; +#endif return 0; // Ok } //====================================================================== +#ifdef IS_VPI + +static int mon_check_vpi() { + vpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = { + {vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 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; @@ -652,7 +686,6 @@ int main(int argc, char **argv, char **env) { CHECK_RESULT(callback_count_half, 250); CHECK_RESULT(callback_count_quad, 2); CHECK_RESULT(callback_count_strs, callback_count_strs_max); - CHECK_RESULT(cd.count, 0) if (!Verilated::gotFinish()) { vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish"); } @@ -665,3 +698,5 @@ int main(int argc, char **argv, char **env) { delete topp; topp=NULL; exit(0L); } + +#endif diff --git a/test_regress/t/t_vpi_var.pl b/test_regress/t/t_vpi_var.pl index bb1c70f16..5061134a6 100755 --- a/test_regress/t/t_vpi_var.pl +++ b/test_regress/t/t_vpi_var.pl @@ -10,10 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di compile ( make_top_shell => 0, make_main => 0, + make_pli => 1, + sim_time => 2100, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_var.cpp"], ); execute ( + iv_pli => 1, check_finished=>1, all_run_flags => ['+PLUS +INT=1234 +STRSTR'] ); diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 26515d766..624f3e0b4 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -5,7 +5,7 @@ // Lesser General Public License Version 3 or the Perl Artistic License // Version 2.0. -`ifdef VERILATOR +`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(); @@ -45,7 +45,9 @@ extern "C" int mon_check(); // Test loop initial begin + count = 0; onebit = 1'b0; + fourthreetwoone[3] = 0; // stop icarus optimizing away text_byte = "B"; text_half = "Hf"; text_word = "Word"; @@ -53,13 +55,18 @@ extern "C" int mon_check(); text = "Verilog Test module"; `ifdef VERILATOR status = $c32("mon_check()"); -`else - status = mon_check(); +`endif +`ifdef iverilog + status = $mon_check(); +`endif +`ifndef USE_VPI_NOT_DPI + status = mon_check(); `endif if (status!=0) begin $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); $stop; end + $write("%%Info: Checking results\n"); if (onebit != 1'b1) $stop; if (quads[2] != 62'h12819213_abd31a1c) $stop; if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; @@ -83,16 +90,20 @@ extern "C" int mon_check(); genvar i; generate - for (i=1;i<=128;i++) begin : arr + for (i=1; i<=128; i=i+1) begin : arr arr #(.LENGTH(i)) arr(); end endgenerate -endmodule +endmodule : t module sub; reg subsig1 /*verilator public_flat_rd*/; reg subsig2 /*verilator public_flat_rd*/; -endmodule +`ifdef iverilog + // stop icarus optimizing signals away + wire redundant = subsig1 | subsig2; +`endif +endmodule : sub module arr; @@ -104,6 +115,11 @@ module arr; reg check /*verilator public_flat_rw*/; reg verbose /*verilator public_flat_rw*/; + initial begin + sig = {LENGTH{1'b0}}; + rfr = {LENGTH{1'b0}}; + end + always @(posedge check) begin if (verbose) $display("%m : %x %x", sig, rfr); if (check && sig != rfr) $stop;