Files
verilator/test_regress/t/t_dpi_var.cpp
T
Geza Lore 1c86ff0af2 Fix corner case bugs in module and variable inlining (#6322)
There were a couple corner case bugs in V3Inline, and one in Dfg when
dealing with inlining of modules/variables.

V3Inline:
- Invalid code generated when inlining an input that also had an
  assignment to it (Throws an ASSIGNIN, but this is sometimes reasonable
  to do, e.g. hiererchical reference to an unonnected input port)
- Inlining (aliasing) publicly writeable input port.
- Inlining forcable port connected to constant.

Dfg:
- Inining publicly writeable variables

The tests that cover these are the same and fixing one will trigger the
other bug, so fixing them all in one go. Also cleanup V3Inline to be less
out of order and rely less on unique APIs only used by V3Inine (will
remove those in follow up patch).

Small step towards #6280.
2025-08-22 21:43:49 +01:00

153 lines
5.0 KiB
C++

// -*- 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
//
//*************************************************************************
#include VM_PREFIX_INCLUDE
#include "verilated.h"
#include "verilated_syms.h"
#include "svdpi.h"
//======================================================================
struct MyMon {
uint32_t* sigsp[2];
uint32_t addend = 0;
MyMon() {
sigsp[0] = NULL;
sigsp[1] = NULL;
}
};
MyMon mons[4];
void mon_register_a(const char* namep, void* sigp, bool isOut, int n, int addend) {
// Callback from initial block in monitor
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_register_a(\"%s\", %p, %d, %d, %d);\n", namep, sigp, isOut, n, addend);
#endif
mons[n].sigsp[isOut] = (uint32_t*)sigp;
mons[n].addend = addend;
}
void mon_do(MyMon* monp) {
if (!monp->sigsp[0]) vl_fatal(__FILE__, __LINE__, "", "never registered");
if (!monp->sigsp[1]) vl_fatal(__FILE__, __LINE__, "", "never registered");
*monp->sigsp[1] = (*(monp->sigsp[0])) + monp->addend;
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_do(%08x(&%p) -> %08x(&%p));\n", *(monp->sigsp[0]), monp->sigsp[0],
*(monp->sigsp[1]), monp->sigsp[1]);
#endif
}
void mon_class_name(const char* namep) {
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_class_name(\"%s\");\n", namep);
#endif
// Check the C's calling name of "" doesn't lead to extra dots in the name()
if (namep && namep[0] == '.')
vl_fatal(__FILE__, __LINE__, "", ("Unexp class name "s + namep).c_str());
}
extern "C" void mon_scope_name(const char* namep);
void mon_scope_name(const char* namep) {
const char* modp = svGetNameFromScope(svGetScope());
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep);
#endif
if (std::strcmp(namep, "t.sub"))
vl_fatal(__FILE__, __LINE__, "", ("Unexp scope name "s + namep).c_str());
if (std::strcmp(modp, "t.sub"))
vl_fatal(__FILE__, __LINE__, "", ("Unexp dpiscope name "s + modp).c_str());
}
extern "C" void mon_register_b(const char* namep, int isOut, int n, int addend) {
const char* modp = svGetNameFromScope(svGetScope());
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_register_b('%s', \"%s\", %d, %d %d);\n", modp, namep, isOut, n, addend);
#endif
// Use scope to get pointer and size of signal
const VerilatedScope* scopep = Verilated::dpiScope();
const VerilatedVar* varp = scopep->varFind(namep);
if (!varp) {
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
} else if (varp->vltype() != VLVT_UINT32) {
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
} else {
uint32_t* datap = (uint32_t*)(varp->datap());
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
mons[n].sigsp[isOut] = (uint32_t*)(varp->datap());
mons[n].addend = addend;
}
}
extern "C" void mon_register_done();
void mon_register_done() {
#ifdef TEST_VERBOSE
const char* modp = svGetNameFromScope(svGetScope());
VL_PRINTF("- mon_register_done('%s');\n", modp);
#endif
// Print list of all signals - if we didn't register2 anything we'd pick them off here
const VerilatedScope* scopep = Verilated::dpiScope();
if (VerilatedVarNameMap* varsp = scopep->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin(); it != varsp->end(); ++it) {
VL_PRINTF("- mon2: %s\n", it->first);
}
}
}
extern "C" void mon_eval();
void mon_eval() {
// Callback from always@ negedge
mon_do(&mons[0]);
mon_do(&mons[1]);
mon_do(&mons[2]);
mon_do(&mons[3]);
}
//======================================================================
int main(int argc, char** argv) {
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
uint64_t sim_time = 1100;
contextp->debug(0);
contextp->commandArgs(argc, argv);
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
// Note null name - we're flattening it out
""}};
// clang-format off
#ifdef VERILATOR
# ifdef TEST_VERBOSE
contextp->scopesDump();
# endif
#endif
// clang-format on
topp->eval();
topp->clk = 0;
contextp->timeInc(10);
while (contextp->time() < sim_time && !contextp->gotFinish()) {
contextp->timeInc(1);
topp->eval();
topp->clk = !topp->clk;
// mon_do();
}
if (!contextp->gotFinish()) {
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
}
topp->final();
return 0;
}