forked from github/verilator
Fix vpi_get of vpiSize, bug680.
Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
parent
cf9ffd16dd
commit
85989af031
2
Changes
2
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
|
||||
|
||||
|
@ -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;
|
||||
|
78
test_regress/t/TestSimulator.h
Normal file
78
test_regress/t/TestSimulator.h
Normal file
@ -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);
|
34
test_regress/t/TestVpi.h
Normal file
34
test_regress/t/TestVpi.h
Normal file
@ -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;
|
||||
}
|
||||
};
|
@ -14,6 +14,7 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
283
test_regress/t/t_vpi_get.cpp
Normal file
283
test_regress/t/t_vpi_get.cpp
Normal file
@ -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 <cstdlib>
|
||||
|
||||
#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 <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
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<<dec<<"%Error: "<<FILENM<<":"<<__LINE__ \
|
||||
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
|
||||
return __LINE__; \
|
||||
}
|
||||
|
||||
#define CHECK_RESULT_HEX(got, exp) \
|
||||
if ((got) != (exp)) { \
|
||||
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__<<hex \
|
||||
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
|
||||
return __LINE__; \
|
||||
}
|
||||
|
||||
#define CHECK_RESULT_CSTR(got, exp) \
|
||||
if (strcmp((got),(exp))) { \
|
||||
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", \
|
||||
FILENM,__LINE__, (got)?(got):"<null>", (exp)?(exp):"<null>"); \
|
||||
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
|
25
test_regress/t/t_vpi_get.pl
Executable file
25
test_regress/t/t_vpi_get.pl
Executable file
@ -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;
|
71
test_regress/t/t_vpi_get.v
Normal file
71
test_regress/t/t_vpi_get.v
Normal file
@ -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
|
@ -16,6 +16,7 @@
|
||||
#ifdef IS_VPI
|
||||
|
||||
#include "vpi_user.h"
|
||||
#include <cstdlib>
|
||||
|
||||
#else
|
||||
|
||||
@ -36,6 +37,9 @@
|
||||
#include <iostream>
|
||||
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;
|
||||
}
|
||||
|
@ -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"],
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#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;
|
||||
|
@ -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 <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
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
|
||||
|
@ -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']
|
||||
);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user