mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
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.
153 lines
5.0 KiB
C++
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;
|
|
}
|