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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2021-01-01 16:29:54 +01:00
|
|
|
// Copyright 2003-2021 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
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3LinkLevel.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Levelizing class functions
|
|
|
|
|
|
|
|
|
|
struct CmpLevel {
|
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
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, "modSortByLevel()\n");
|
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;
|
|
|
|
|
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
|
|
|
|
|
if (nodep->level() <= 2) tops.push_back(nodep);
|
2019-07-14 21:06:49 +02:00
|
|
|
mods.push_back(nodep);
|
|
|
|
|
}
|
|
|
|
|
if (tops.size() >= 2) {
|
|
|
|
|
AstNode* secp = tops[1]; // Complain about second one, as first often intended
|
|
|
|
|
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
|
|
|
|
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."
|
|
|
|
|
<< V3Error::warnContextNone());
|
2020-08-16 18:54:32 +02:00
|
|
|
for (AstNode* alsop : tops) {
|
2021-07-20 14:00:14 +02:00
|
|
|
std::cerr << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
|
2020-04-15 13:58:34 +02:00
|
|
|
<< alsop->warnContextSecondary();
|
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
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
|
2020-08-16 18:54:32 +02:00
|
|
|
for (AstNodeModule* nodep : mods) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->clearIter(); // Because we didn't iterate to find the node
|
|
|
|
|
// pointers, may have a stale m_iterp() needing cleanup
|
|
|
|
|
nodep->unlinkFrBack();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work");
|
2020-08-16 18:54:32 +02:00
|
|
|
for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulep(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
|
2017-09-18 04:52:57 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 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
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNodeModule* modTimedp = nullptr;
|
2020-04-16 01:39:03 +02:00
|
|
|
VTimescale unit(VTimescale::NONE);
|
|
|
|
|
// Use highest level module as default unit - already sorted in proper order
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& modp : mods) {
|
|
|
|
|
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
|
|
|
|
|
if (unit.isNone()) unit = VTimescale(VTimescale::TS_DEFAULT);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 18:54:32 +02:00
|
|
|
for (AstNodeModule* nodep : mods) {
|
2021-03-17 03:52:29 +01:00
|
|
|
if (!v3Global.opt.timeOverrideUnit().isNone()) nodep->timeunit(unit);
|
2020-04-16 01:39:03 +02:00
|
|
|
if (nodep->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())
|
2021-03-17 03:52:29 +01:00
|
|
|
&& nodep->timescaleMatters()) {
|
2020-04-16 01:39:03 +02:00
|
|
|
nodep->v3warn(TIMESCALEMOD,
|
|
|
|
|
"Timescale missing on this module as other modules have "
|
2021-03-17 02:58:15 +01:00
|
|
|
"it (IEEE 1800-2017 3.14.2.3)\n"
|
2021-01-23 16:31:27 +01:00
|
|
|
<< nodep->warnContextPrimary() << '\n'
|
2020-04-16 01:39:03 +02:00
|
|
|
<< modTimedp->warnOther()
|
|
|
|
|
<< "... Location of module with timescale\n"
|
|
|
|
|
<< modTimedp->warnContextSecondary());
|
|
|
|
|
}
|
|
|
|
|
nodep->timeunit(unit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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(),
|
|
|
|
|
VTimescale(VTimescale::TS_DEFAULT));
|
|
|
|
|
}
|
2021-09-09 01:31:26 +02:00
|
|
|
|
|
|
|
|
// Classes under package have timescale propaged 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) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2006-08-26 13:35:28 +02:00
|
|
|
// We do ONLY the top module
|
2018-10-15 00:39:33 +02:00
|
|
|
AstNodeModule* oldmodp = rootp->modulesp();
|
2019-06-30 22:46:48 +02:00
|
|
|
if (!oldmodp) { // Later V3LinkDot will warn
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(1, "No module found to wrap\n");
|
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
|
|
|
|
|
|
|
|
AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), "$root");
|
|
|
|
|
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);
|
|
|
|
|
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());
|
2018-10-15 00:39:33 +02:00
|
|
|
rootp->addModulep(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
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeModule* modp = rootp->modulesp(); modp;
|
|
|
|
|
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (VN_IS(modp, Package)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
AstCell* cellp = new AstCell(modp->fileline(), modp->fileline(),
|
2019-05-19 22:13:13 +02:00
|
|
|
// Could add __03a__03a="::" to prevent conflict
|
|
|
|
|
// with module names/"v"
|
2020-08-15 16:12:55 +02:00
|
|
|
modp->name(), modp->name(), nullptr, nullptr, nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
cellp->modp(modp);
|
|
|
|
|
newmodp->addStmtp(cellp);
|
|
|
|
|
}
|
2009-11-08 03:05:02 +01:00
|
|
|
}
|
2019-06-30 22:46:48 +02:00
|
|
|
|
|
|
|
|
V3Global::dumpCheckGlobalTree("wraptop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|
|
|
|
AstNodeModule* 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
|
2019-06-30 22:46:48 +02:00
|
|
|
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
|
2020-04-15 13:58:34 +02:00
|
|
|
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
|
|
|
|
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
|
|
|
|
|
if (oldvarp->isIO()) {
|
|
|
|
|
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
// UINFO(8, "Multitop dup I/O found: " << oldvarp << endl);
|
2019-06-30 22:46:48 +02:00
|
|
|
dupNames.insert(oldvarp->name());
|
|
|
|
|
} else {
|
|
|
|
|
ioNames.insert(oldvarp->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 13:50:21 +02:00
|
|
|
// For all modules, skipping over new top
|
2019-06-30 22:46:48 +02:00
|
|
|
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
|
2020-04-15 13:58:34 +02:00
|
|
|
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (VN_IS(oldmodp, Package)) continue;
|
|
|
|
|
// Add instance
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, "LOOP " << oldmodp << endl);
|
|
|
|
|
AstCell* cellp = new AstCell(
|
|
|
|
|
newmodp->fileline(), newmodp->fileline(),
|
|
|
|
|
(!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()),
|
2020-08-15 16:12:55 +02:00
|
|
|
oldmodp->name(), nullptr, nullptr, nullptr);
|
2019-06-30 22:46:48 +02:00
|
|
|
cellp->modp(oldmodp);
|
|
|
|
|
newmodp->addStmtp(cellp);
|
|
|
|
|
|
|
|
|
|
// Add pins
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
2019-06-30 22:46:48 +02:00
|
|
|
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, "VARWRAP " << oldvarp << endl);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVar* varp = oldvarp->cloneTree(false);
|
|
|
|
|
varp->name(name);
|
2019-10-06 19:24:21 +02:00
|
|
|
varp->protect(false);
|
2019-06-30 22:46:48 +02:00
|
|
|
newmodp->addStmtp(varp);
|
|
|
|
|
varp->sigPublic(true); // User needs to be able to get to it...
|
|
|
|
|
if (oldvarp->isIO()) {
|
|
|
|
|
oldvarp->primaryIO(false);
|
|
|
|
|
varp->primaryIO(true);
|
|
|
|
|
}
|
|
|
|
|
if (varp->direction().isRefOrConstRef()) {
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 23:09:25 +02:00
|
|
|
AstPin* pinp = new AstPin(
|
|
|
|
|
oldvarp->fileline(), 0, varp->name(),
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|