diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 0a6c60373..18b768b7c 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -120,6 +120,7 @@ public: virtual const char* fullname() const { return ""; } virtual const char* defname() const { return ""; } virtual uint32_t type() const { return 0; } + virtual uint32_t constType() const { return vpiUndefined; } virtual uint32_t size() const { return 0; } virtual const VerilatedRange* rangep() const { return nullptr; } virtual vpiHandle dovpi_scan() { return nullptr; } @@ -158,6 +159,7 @@ public: return dynamic_cast(reinterpret_cast(h)); } uint32_t type() const override { return vpiConstant; } + uint32_t constType() const override { return vpiDecConst; } int32_t num() const { return m_num; } }; @@ -204,6 +206,18 @@ public: return dynamic_cast(reinterpret_cast(h)); } uint32_t type() const override { return vpiParameter; } + uint32_t constType() const override { + switch (m_varp->vltype()) { + case VLVT_UINT8: + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: return vpiDecConst; + case VLVT_STRING: return vpiStringConst; + case VLVT_REAL: return vpiRealConst; + default: return vpiUndefined; + } + } void* varDatap() const { return m_varp->datap(); } }; @@ -1960,6 +1974,11 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { if (VL_UNLIKELY(!vop)) return 0; return vop->type(); } + case vpiConstType: { + const VerilatedVpio* const vop = VerilatedVpio::castp(object); + if (VL_UNLIKELY(!vop)) return 0; + return vop->constType(); + } case vpiDirection: { // By forethought, the directions already are vpi enumerated const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object); diff --git a/test_regress/t/t_vpi_const_type.cpp b/test_regress/t/t_vpi_const_type.cpp new file mode 100644 index 000000000..587d2ac1d --- /dev/null +++ b/test_regress/t/t_vpi_const_type.cpp @@ -0,0 +1,200 @@ +// -*- 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. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifdef IS_VPI + +#include "sv_vpi_user.h" + +#include + +#else + +#include "verilated.h" +#include "verilated_vcd_c.h" +#include "verilated_vpi.h" + +#include "Vt_vpi_const_type.h" +#include "Vt_vpi_const_type__Dpi.h" +#include "svdpi.h" + +#endif + +#include +#include +#include + +// These require the above. Comment prevents clang-format moving them +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_const_type.cpp" + +#define DEBUG \ + if (0) printf + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +#define CHECK_RESULT_Z(got) \ + if (got) { \ + printf("%%Error: %s:%d: GOT = !NULL EXP = NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR(got, exp) \ + if (std::strcmp((got), (exp))) { \ + printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +extern "C" { +int mon_check() { +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + + TestVpiHandle intHandle = vpi_handle_by_name((PLI_BYTE8*)"t.intParam", NULL); + CHECK_RESULT_NZ(intHandle) + PLI_INT32 intConstType = vpi_get(vpiConstType, intHandle); + CHECK_RESULT(intConstType, vpiDecConst) + + TestVpiHandle realHandle = vpi_handle_by_name((PLI_BYTE8*)"t.realParam", NULL); + CHECK_RESULT_NZ(realHandle) + PLI_INT32 realConstType = vpi_get(vpiConstType, realHandle); + CHECK_RESULT(realConstType, vpiRealConst) + + TestVpiHandle strHandle = vpi_handle_by_name((PLI_BYTE8*)"t.strParam", NULL); + CHECK_RESULT_NZ(strHandle) + PLI_INT32 strConstType = vpi_get(vpiConstType, strHandle); + CHECK_RESULT(strConstType, vpiStringConst) + + TestVpiHandle sigHandle = vpi_handle_by_name((PLI_BYTE8*)"t.signal", NULL); + CHECK_RESULT_NZ(sigHandle) + PLI_INT32 sigConstType = vpi_get(vpiConstType, sigHandle); + // t.signal is not constant + CHECK_RESULT(sigConstType, vpiUndefined) + TestVpiHandle leftHandle = vpi_handle(vpiLeftRange, sigHandle); + CHECK_RESULT_NZ(leftHandle) + PLI_INT32 leftConstType = vpi_get(vpiConstType, leftHandle); + CHECK_RESULT(leftConstType, vpiDecConst) + + TestVpiHandle timeHandle = vpi_handle_by_name((PLI_BYTE8*)"t.timeParam", NULL); + CHECK_RESULT_NZ(timeHandle) + PLI_INT32 timeConstType = vpi_get(vpiConstType, timeHandle); + CHECK_RESULT(timeConstType, vpiDecConst) + + return 0; // Ok +} +} +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + TestVpiHandle 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 + +int main(int argc, char** argv) { + const std::unique_ptr contextp{new VerilatedContext}; + + uint64_t sim_time = 1100; + contextp->debug(0); + contextp->commandArgs(argc, argv); + // We're going to be checking for these errors so don't crash out + contextp->fatalOnVpiError(0); + + { + // Construct and destroy + const std::unique_ptr topp{ + new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + } + + // Test second construction + const std::unique_ptr topp{new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + contextp->scopesDump(); +#endif +#endif + +#if VM_TRACE + contextp->traceEverOn(true); + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; + topp->trace(tfp, 99); + tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + + topp->eval(); + contextp->timeInc(10); + + while (contextp->time() < sim_time && !contextp->gotFinish()) { + contextp->timeInc(1); + topp->eval(); + VerilatedVpi::callValueCbs(); + // mon_do(); +#if VM_TRACE + if (tfp) tfp->dump(contextp->time()); +#endif + } + if (!contextp->gotFinish()) { + vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + return 0; +} + +#endif diff --git a/test_regress/t/t_vpi_const_type.pl b/test_regress/t/t_vpi_const_type.pl new file mode 100755 index 000000000..31a37c26f --- /dev/null +++ b/test_regress/t/t_vpi_const_type.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + verilator_flags2 => ["--exe --vpi --no-l2name $Self->{t_dir}/t_vpi_const_type.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_const_type.v b/test_regress/t/t_vpi_const_type.v new file mode 100644 index 000000000..ef76c8f35 --- /dev/null +++ b/test_regress/t/t_vpi_const_type.v @@ -0,0 +1,33 @@ +// 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. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import "DPI-C" context function int mon_check(); + +module t (/*AUTOARG*/ + ); /*verilator public_module*/ + + parameter int intParam /*verilator public_flat_rd*/ = 5; + parameter real realParam /*verilator public_flat_rd*/ = 2.3; + parameter time timeParam /*verilator public_flat_rd*/ = 0; + parameter string strParam /*verilator public_flat_rd*/ = "abc"; + + logic [31:0] signal /*verilator public_flat_rw*/; + + int status; + + initial begin + status = mon_check(); + if (status!=0) begin + $write("%%Error: t_vpi_const_type.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t