2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Resolve module/signal name references
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// LINKTOP TRANSFORMATIONS:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Utility functions
|
|
|
|
|
// Sort cells by depth
|
|
|
|
|
// Create new MODULE TOP with connections to below signals
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 04:50:27 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3LinkLevel.h"
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Levelizing class functions
|
|
|
|
|
|
2024-01-20 21:06:46 +01:00
|
|
|
struct CmpLevel final {
|
2020-12-02 00:49:03 +01:00
|
|
|
bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const {
|
2019-05-19 22:13:13 +02:00
|
|
|
return lhsp->level() < rhsp->level();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void V3LinkLevel::modSortByLevel() {
|
|
|
|
|
// Sort modules by levels, root down to lowest children
|
|
|
|
|
// Calculate levels again in case we added modules
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, "modSortByLevel()");
|
2008-03-25 20:57:41 +01:00
|
|
|
|
2008-12-10 03:05:47 +01:00
|
|
|
// level() was computed for us in V3LinkCells
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-07-14 21:06:49 +02:00
|
|
|
ModVec mods; // Modules
|
|
|
|
|
ModVec tops; // Top level modules
|
2020-03-15 23:34:09 +01:00
|
|
|
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep->nextp(), NodeModule)) {
|
2025-08-23 21:20:58 +02:00
|
|
|
if (nodep->level() <= 2 && !VN_IS(nodep, NotFoundModule)) {
|
|
|
|
|
UINFO(9, "top candidate " << nodep);
|
|
|
|
|
tops.push_back(nodep);
|
|
|
|
|
}
|
2019-07-14 21:06:49 +02:00
|
|
|
mods.push_back(nodep);
|
|
|
|
|
}
|
|
|
|
|
if (tops.size() >= 2) {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstNode* const secp = tops[1]; // Complain about second one, as first often intended
|
2019-07-14 21:06:49 +02:00
|
|
|
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
2025-05-10 19:29:30 +02:00
|
|
|
auto warnTopModules = [](const AstNode* const secp, ModVec tops)
|
2023-02-10 04:15:37 +01:00
|
|
|
VL_REQUIRES(V3Error::s().m_mutex) -> std::string {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
for (AstNode* alsop : tops) {
|
2025-05-10 19:29:30 +02:00
|
|
|
ss << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
|
2023-02-10 04:15:37 +01:00
|
|
|
<< alsop->warnContextSecondary();
|
|
|
|
|
}
|
|
|
|
|
return ss.str();
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-14 21:06:49 +02:00
|
|
|
secp->v3warn(MULTITOP, "Multiple top level modules\n"
|
2020-04-15 13:58:34 +02:00
|
|
|
<< secp->warnMore()
|
|
|
|
|
<< "... Suggest see manual; fix the duplicates, or use "
|
|
|
|
|
"--top-module to select top."
|
2023-02-10 04:15:37 +01:00
|
|
|
<< V3Error::s().warnContextNone()
|
|
|
|
|
<< V3Error::warnAdditionalInfo()
|
2025-05-10 19:29:30 +02:00
|
|
|
<< warnTopModules(secp, tops));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-07-14 21:06:49 +02:00
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
timescaling(mods);
|
|
|
|
|
|
2019-06-30 22:46:48 +02:00
|
|
|
// Reorder the netlist's modules to have modules in level sorted order
|
2019-07-14 21:06:49 +02:00
|
|
|
stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(9, "modSortByLevel() sorted"); // Comment required for gcc4.6.3 / bug666
|
2022-07-13 13:20:30 +02:00
|
|
|
for (AstNodeModule* nodep : mods) nodep->unlinkFrBack();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work");
|
2022-09-15 20:43:56 +02:00
|
|
|
for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulesp(nodep);
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(9, "modSortByLevel() done"); // Comment required for gcc4.6.3 / bug666
|
2024-12-01 23:38:02 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("cellsort", false, dumpTreeEitherLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
void V3LinkLevel::timescaling(const ModVec& mods) {
|
|
|
|
|
// Timescale determination
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstNodeModule* modTimedp = nullptr;
|
2025-05-06 12:34:49 +02:00
|
|
|
VTimescale unit{VTimescale::NONE};
|
|
|
|
|
|
|
|
|
|
// Move timeunit attributes from parse to module unit
|
|
|
|
|
// Grammar only allows timeunit as module_item, so no need to recurse full tree
|
|
|
|
|
for (AstNodeModule* modp : mods) {
|
|
|
|
|
for (AstNode *nextp, *childp = modp->stmtsp(); childp; childp = nextp) {
|
|
|
|
|
nextp = childp->nextp();
|
2025-08-21 10:43:37 +02:00
|
|
|
// cppcheck-suppress constVariablePointer
|
2025-05-06 12:34:49 +02:00
|
|
|
if (AstPragma* pragp = VN_CAST(childp, Pragma)) {
|
|
|
|
|
if (pragp->pragType() == VPragmaType::TIMEUNIT_SET) {
|
|
|
|
|
modp->timeunit(pragp->timescale());
|
|
|
|
|
VL_DO_DANGLING(pragp->unlinkFrBack()->deleteTree(), pragp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
// Use highest level module as default unit - already sorted in proper order
|
2025-05-06 12:34:49 +02:00
|
|
|
// Combine timing into later modules
|
|
|
|
|
for (AstNodeModule* modp : mods) {
|
2020-11-11 04:10:38 +01:00
|
|
|
if (!modTimedp && !modp->timeunit().isNone()) {
|
|
|
|
|
modTimedp = modp;
|
2020-04-16 01:39:03 +02:00
|
|
|
unit = modTimedp->timeunit();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unit = v3Global.opt.timeComputeUnit(unit); // Apply override
|
2022-09-16 01:58:01 +02:00
|
|
|
if (unit.isNone()) unit = VTimescale{VTimescale::TS_DEFAULT};
|
2020-04-16 01:39:03 +02:00
|
|
|
v3Global.rootp()->timeunit(unit);
|
|
|
|
|
|
2021-07-29 14:40:41 +02:00
|
|
|
bool dunitTimed = false; // $unit had a timeunit
|
|
|
|
|
if (const AstPackage* const upkgp = v3Global.rootp()->dollarUnitPkgp()) {
|
|
|
|
|
if (!upkgp->timeunit().isNone()) dunitTimed = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-06 12:34:49 +02:00
|
|
|
for (AstNodeModule* modp : mods) {
|
|
|
|
|
if (!v3Global.opt.timeOverrideUnit().isNone()) modp->timeunit(unit);
|
|
|
|
|
if (modp->timeunit().isNone()) {
|
2021-03-17 03:42:28 +01:00
|
|
|
if (modTimedp // Got previous
|
2021-07-29 14:40:41 +02:00
|
|
|
&& !dunitTimed
|
2021-03-17 03:42:28 +01:00
|
|
|
&& ( // unit doesn't already include an override
|
|
|
|
|
v3Global.opt.timeOverrideUnit().isNone()
|
|
|
|
|
&& v3Global.opt.timeDefaultUnit().isNone())
|
2025-05-06 12:34:49 +02:00
|
|
|
&& modp->timescaleMatters()) {
|
|
|
|
|
modp->v3warn(TIMESCALEMOD,
|
|
|
|
|
"Timescale missing on this module as other modules have "
|
|
|
|
|
"it (IEEE 1800-2023 3.14.2.3)\n"
|
|
|
|
|
<< modp->warnContextPrimary() << '\n'
|
|
|
|
|
<< modTimedp->warnOther()
|
|
|
|
|
<< "... Location of module with timescale\n"
|
|
|
|
|
<< modTimedp->warnContextSecondary());
|
2020-04-16 01:39:03 +02:00
|
|
|
}
|
2025-05-06 12:34:49 +02:00
|
|
|
modp->timeunit(unit);
|
2020-04-16 01:39:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 00:31:27 +01:00
|
|
|
v3Global.rootp()->timescaleSpecified(modTimedp); // true if some module specifies timescale
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
if (v3Global.rootp()->timeprecision().isNone()) {
|
|
|
|
|
v3Global.rootp()->timeprecisionMerge(v3Global.rootp()->fileline(),
|
2022-09-16 01:58:01 +02:00
|
|
|
VTimescale{VTimescale::TS_DEFAULT});
|
2020-04-16 01:39:03 +02:00
|
|
|
}
|
2021-09-09 01:31:26 +02:00
|
|
|
|
2022-12-26 10:30:41 +01:00
|
|
|
// Classes under package have timescale propagated in V3LinkParse
|
2020-04-16 01:39:03 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Wrapping
|
|
|
|
|
|
2018-10-15 00:39:33 +02:00
|
|
|
void V3LinkLevel::wrapTop(AstNetlist* rootp) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2006-08-26 13:35:28 +02:00
|
|
|
// We do ONLY the top module
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNodeModule* const oldmodp = rootp->modulesp();
|
2019-06-30 22:46:48 +02:00
|
|
|
if (!oldmodp) { // Later V3LinkDot will warn
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(1, "No module found to wrap");
|
2019-06-30 22:46:48 +02:00
|
|
|
return;
|
|
|
|
|
}
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
|
2025-06-30 02:17:27 +02:00
|
|
|
AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root", oldmodp->libname()};
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice
|
2006-08-26 13:35:28 +02:00
|
|
|
// Make the new module first in the list
|
|
|
|
|
oldmodp->unlinkFrBackWithNext();
|
|
|
|
|
newmodp->addNext(oldmodp);
|
2025-09-24 04:05:51 +02:00
|
|
|
newmodp->depth(1);
|
2006-08-26 13:35:28 +02:00
|
|
|
newmodp->level(1);
|
|
|
|
|
newmodp->modPublic(true);
|
2019-10-06 19:24:21 +02:00
|
|
|
newmodp->protect(false);
|
2020-04-16 01:39:03 +02:00
|
|
|
newmodp->timeunit(oldmodp->timeunit());
|
2022-09-15 20:43:56 +02:00
|
|
|
rootp->addModulesp(newmodp);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2013-05-25 16:15:10 +02:00
|
|
|
// TODO the module creation above could be done after linkcells, but
|
|
|
|
|
// the rest must be done after data type resolution
|
2018-10-15 00:39:33 +02:00
|
|
|
wrapTopCell(rootp);
|
2019-01-03 00:38:49 +01:00
|
|
|
|
2009-11-08 03:05:02 +01:00
|
|
|
// Instantiate all packages under the top wrapper
|
|
|
|
|
// This way all later SCOPE based optimizations can ignore packages
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstNodeModule* modp = rootp->modulesp(); modp; modp = VN_AS(modp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (VN_IS(modp, Package)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstCell* const cellp
|
2022-11-20 19:11:01 +01:00
|
|
|
= new AstCell{modp->fileline(), modp->fileline(),
|
2021-11-26 23:55:36 +01:00
|
|
|
// Could add __03a__03a="::" to prevent conflict
|
|
|
|
|
// with module names/"v"
|
2022-11-20 19:11:01 +01:00
|
|
|
modp->name(), modp->name(), nullptr, nullptr, nullptr};
|
2019-05-19 22:13:13 +02:00
|
|
|
cellp->modp(modp);
|
2022-09-15 20:43:56 +02:00
|
|
|
newmodp->addStmtsp(cellp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-11-08 03:05:02 +01:00
|
|
|
}
|
2019-06-30 22:46:48 +02:00
|
|
|
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTreeEitherLevel() >= 6);
|
2019-06-30 22:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstNodeModule* const newmodp = rootp->modulesp();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(newmodp && newmodp->isTop(), rootp, "No TOP module found to insert under");
|
2019-06-30 22:46:48 +02:00
|
|
|
|
|
|
|
|
// Find all duplicate signal names (if multitop)
|
2021-03-13 00:10:45 +01:00
|
|
|
using NameSet = std::unordered_set<std::string>;
|
2019-06-30 22:46:48 +02:00
|
|
|
NameSet ioNames;
|
|
|
|
|
NameSet dupNames;
|
2019-09-09 13:50:21 +02:00
|
|
|
// For all modules, skipping over new top
|
2025-08-21 10:43:37 +02:00
|
|
|
// cppcheck-suppress constVariablePointer
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstNodeModule* oldmodp = VN_AS(rootp->modulesp()->nextp(), NodeModule);
|
|
|
|
|
oldmodp && oldmodp->level() <= 2; oldmodp = VN_AS(oldmodp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVar* const oldvarp = VN_CAST(subnodep, Var)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (oldvarp->isIO()) {
|
2023-10-28 14:38:02 +02:00
|
|
|
if (!ioNames.insert(oldvarp->name()).second) {
|
2025-05-23 02:29:32 +02:00
|
|
|
// UINFO(8, "Multitop dup I/O found: " << oldvarp);
|
2019-06-30 22:46:48 +02:00
|
|
|
dupNames.insert(oldvarp->name());
|
|
|
|
|
}
|
2022-10-01 16:53:40 +02:00
|
|
|
} else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) {
|
2022-10-01 16:48:37 +02:00
|
|
|
const AstNodeDType* const subtypep = oldvarp->subDTypep();
|
|
|
|
|
if (VN_IS(subtypep, IfaceRefDType)) {
|
|
|
|
|
const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType);
|
|
|
|
|
if (!ifacerefp->cellp()) {
|
2023-10-28 14:38:02 +02:00
|
|
|
if (!ioNames.insert(oldvarp->name()).second) {
|
2025-05-23 02:29:32 +02:00
|
|
|
// UINFO(8, "Multitop dup interface found: " << oldvarp);
|
2022-10-01 16:48:37 +02:00
|
|
|
dupNames.insert(oldvarp->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (VN_IS(subtypep, UnpackArrayDType)) {
|
|
|
|
|
const AstUnpackArrayDType* const arrp = VN_AS(subtypep, UnpackArrayDType);
|
|
|
|
|
const AstNodeDType* const arrsubtypep = arrp->subDTypep();
|
|
|
|
|
if (VN_IS(arrsubtypep, IfaceRefDType)) {
|
2022-10-01 16:53:40 +02:00
|
|
|
const AstIfaceRefDType* const ifacerefp
|
|
|
|
|
= VN_AS(arrsubtypep, IfaceRefDType);
|
2022-10-01 16:48:37 +02:00
|
|
|
if (!ifacerefp->cellp()) {
|
2023-10-28 14:38:02 +02:00
|
|
|
if (!ioNames.insert(oldvarp->name()).second) {
|
2025-05-23 02:29:32 +02:00
|
|
|
// UINFO(8, "Multitop dup interface array found: " << oldvarp);
|
2022-10-01 16:48:37 +02:00
|
|
|
dupNames.insert(oldvarp->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-30 22:46:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 13:50:21 +02:00
|
|
|
// For all modules, skipping over new top
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstNodeModule* oldmodp = VN_AS(rootp->modulesp()->nextp(), NodeModule);
|
|
|
|
|
oldmodp && oldmodp->level() <= 2; oldmodp = VN_AS(oldmodp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (VN_IS(oldmodp, Package)) continue;
|
|
|
|
|
// Add instance
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(5, "LOOP " << oldmodp);
|
2022-11-20 19:11:01 +01:00
|
|
|
AstCell* const cellp = new AstCell{
|
|
|
|
|
newmodp->fileline(),
|
|
|
|
|
newmodp->fileline(),
|
2020-04-15 13:58:34 +02:00
|
|
|
(!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()),
|
2022-11-20 19:11:01 +01:00
|
|
|
oldmodp->name(),
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr};
|
2019-06-30 22:46:48 +02:00
|
|
|
cellp->modp(oldmodp);
|
2022-09-15 20:43:56 +02:00
|
|
|
newmodp->addStmtsp(cellp);
|
2019-06-30 22:46:48 +02:00
|
|
|
|
|
|
|
|
// Add pins
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVar* const oldvarp = VN_CAST(subnodep, Var)) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, "VARWRAP " << oldvarp);
|
2019-06-30 22:46:48 +02:00
|
|
|
if (oldvarp->isIO()) {
|
|
|
|
|
string name = oldvarp->name();
|
|
|
|
|
if (dupNames.find(name) != dupNames.end()) {
|
|
|
|
|
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
|
2020-04-15 13:58:34 +02:00
|
|
|
name = oldmodp->name() + "__02E" + name;
|
2019-06-30 22:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVar* const varp = oldvarp->cloneTree(false);
|
2019-06-30 22:46:48 +02:00
|
|
|
varp->name(name);
|
2019-10-06 19:24:21 +02:00
|
|
|
varp->protect(false);
|
2022-09-15 20:43:56 +02:00
|
|
|
newmodp->addStmtsp(varp);
|
2019-06-30 22:46:48 +02:00
|
|
|
varp->sigPublic(true); // User needs to be able to get to it...
|
2022-11-27 11:52:40 +01:00
|
|
|
oldvarp->primaryIO(false);
|
|
|
|
|
varp->primaryIO(true);
|
2023-09-20 13:33:11 +02:00
|
|
|
if (varp->isRef() || varp->isConstRef()) {
|
2020-06-10 01:20:16 +02:00
|
|
|
varp->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"Unsupported: ref/const ref as primary input/output: "
|
|
|
|
|
<< varp->prettyNameQ());
|
2019-06-30 22:46:48 +02:00
|
|
|
}
|
|
|
|
|
if (varp->isIO() && v3Global.opt.systemC()) {
|
|
|
|
|
varp->sc(true);
|
|
|
|
|
// User can see trace one level down from the wrapper
|
|
|
|
|
// Avoids packing & unpacking SC signals a second time
|
|
|
|
|
varp->trace(false);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 22:57:49 +01:00
|
|
|
if (v3Global.opt.noTraceTop() && varp->isIO()) varp->trace(false);
|
2023-08-19 10:51:29 +02:00
|
|
|
|
2022-11-20 19:11:01 +01:00
|
|
|
AstPin* const pinp = new AstPin{
|
2020-09-07 23:09:25 +02:00
|
|
|
oldvarp->fileline(), 0, varp->name(),
|
2022-11-20 19:11:01 +01:00
|
|
|
new AstVarRef{varp->fileline(), varp,
|
|
|
|
|
oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ}};
|
2019-06-30 22:46:48 +02:00
|
|
|
// Skip length and width comp; we know it's a direct assignment
|
|
|
|
|
pinp->modVarp(oldvarp);
|
|
|
|
|
cellp->addPinsp(pinp);
|
2022-10-01 16:53:40 +02:00
|
|
|
} else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) {
|
|
|
|
|
// for each interface port on oldmodp instantiate a corresponding interface
|
|
|
|
|
// cell in $root
|
2022-10-01 16:48:37 +02:00
|
|
|
const AstNodeDType* const subtypep = oldvarp->subDTypep();
|
|
|
|
|
if (VN_IS(subtypep, IfaceRefDType)) {
|
|
|
|
|
const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType);
|
|
|
|
|
if (!ifacerefp->cellp()) {
|
|
|
|
|
string name = oldvarp->name();
|
|
|
|
|
if (dupNames.find(name) != dupNames.end()) {
|
|
|
|
|
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
|
|
|
|
|
name = oldmodp->name() + "__02E" + name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstCell* ifacecellp = new AstCell{newmodp->fileline(),
|
|
|
|
|
newmodp->fileline(),
|
|
|
|
|
name,
|
|
|
|
|
ifacerefp->ifaceName(),
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr};
|
2022-10-01 16:48:37 +02:00
|
|
|
ifacecellp->modp(ifacerefp->ifacep());
|
|
|
|
|
newmodp->addStmtsp(ifacecellp);
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstIfaceRefDType* const idtypep = new AstIfaceRefDType{
|
|
|
|
|
newmodp->fileline(), name, ifacerefp->ifaceName()};
|
2022-10-01 16:48:37 +02:00
|
|
|
idtypep->ifacep(nullptr);
|
|
|
|
|
idtypep->dtypep(idtypep);
|
|
|
|
|
idtypep->cellp(ifacecellp);
|
|
|
|
|
rootp->typeTablep()->addTypesp(idtypep);
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF,
|
|
|
|
|
name + "__Viftop", idtypep};
|
2022-10-01 16:48:37 +02:00
|
|
|
varp->isIfaceParent(true);
|
|
|
|
|
ifacecellp->addNextHere(varp);
|
|
|
|
|
ifacecellp->hasIfaceVar(true);
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstPin* const pinp
|
|
|
|
|
= new AstPin{oldvarp->fileline(), 0, varp->name(),
|
|
|
|
|
new AstVarRef{varp->fileline(), varp,
|
|
|
|
|
oldvarp->isWritable() ? VAccess::WRITE
|
|
|
|
|
: VAccess::READ}};
|
2022-10-01 16:48:37 +02:00
|
|
|
pinp->modVarp(oldvarp);
|
|
|
|
|
cellp->addPinsp(pinp);
|
|
|
|
|
}
|
2022-10-01 16:53:40 +02:00
|
|
|
} else if (VN_IS(subtypep, UnpackArrayDType)) {
|
|
|
|
|
const AstUnpackArrayDType* const oldarrp
|
|
|
|
|
= VN_AS(subtypep, UnpackArrayDType);
|
2022-10-01 16:48:37 +02:00
|
|
|
const AstNodeDType* const arrsubtypep = oldarrp->subDTypep();
|
|
|
|
|
if (VN_IS(arrsubtypep, IfaceRefDType)) {
|
2022-10-01 16:53:40 +02:00
|
|
|
const AstIfaceRefDType* const ifacerefp
|
|
|
|
|
= VN_AS(arrsubtypep, IfaceRefDType);
|
2022-10-01 16:48:37 +02:00
|
|
|
if (!ifacerefp->cellp()) {
|
|
|
|
|
string name = oldvarp->name();
|
|
|
|
|
if (dupNames.find(name) != dupNames.end()) {
|
|
|
|
|
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
|
|
|
|
|
name = oldmodp->name() + "__02E" + name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstUnpackArrayDType* arraydtypep
|
|
|
|
|
= VN_AS(oldvarp->dtypep(), UnpackArrayDType);
|
|
|
|
|
AstCell* ifacearraycellp
|
|
|
|
|
= new AstCell{newmodp->fileline(),
|
|
|
|
|
newmodp->fileline(),
|
|
|
|
|
name,
|
|
|
|
|
ifacerefp->ifaceName(),
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
arraydtypep->rangep()->cloneTree(true)};
|
2022-10-01 16:48:37 +02:00
|
|
|
ifacearraycellp->modp(ifacerefp->ifacep());
|
|
|
|
|
newmodp->addStmtsp(ifacearraycellp);
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstIfaceRefDType* const idtypep = new AstIfaceRefDType{
|
|
|
|
|
newmodp->fileline(), name, ifacerefp->ifaceName()};
|
2022-10-01 16:48:37 +02:00
|
|
|
idtypep->ifacep(nullptr);
|
|
|
|
|
idtypep->dtypep(idtypep);
|
|
|
|
|
idtypep->cellp(ifacearraycellp);
|
|
|
|
|
rootp->typeTablep()->addTypesp(idtypep);
|
|
|
|
|
|
2022-10-01 16:53:40 +02:00
|
|
|
AstNodeArrayDType* const arrp = new AstUnpackArrayDType{
|
|
|
|
|
newmodp->fileline(), idtypep,
|
|
|
|
|
arraydtypep->rangep()->cloneTree(true)};
|
|
|
|
|
AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF,
|
|
|
|
|
name + "__Viftop", arrp};
|
2022-10-01 16:48:37 +02:00
|
|
|
varp->isIfaceParent(true);
|
|
|
|
|
ifacearraycellp->addNextHere(varp);
|
|
|
|
|
ifacearraycellp->hasIfaceVar(true);
|
|
|
|
|
rootp->typeTablep()->addTypesp(arrp);
|
|
|
|
|
|
|
|
|
|
AstPin* const pinp = new AstPin{
|
|
|
|
|
oldvarp->fileline(), 0, varp->name(),
|
|
|
|
|
new AstVarRef{varp->fileline(), varp,
|
2022-10-01 16:53:40 +02:00
|
|
|
oldvarp->isWritable() ? VAccess::WRITE
|
|
|
|
|
: VAccess::READ}};
|
2022-10-01 16:48:37 +02:00
|
|
|
pinp->modVarp(oldvarp);
|
|
|
|
|
cellp->addPinsp(pinp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-30 22:46:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|