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: Add temporaries, such as for inst nodes
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2020-03-21 16:24:24 +01:00
|
|
|
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
|
|
|
|
// 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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Inst's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Each module:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Pins:
|
|
|
|
|
// Create a wire assign to interconnect to submodule
|
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 "V3Inst.h"
|
|
|
|
|
#include "V3Ast.h"
|
2015-11-25 03:28:04 +01:00
|
|
|
#include "V3Const.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Inst state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class InstVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared each Cell:
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstPin::user1p() -> bool. True if created assignment already
|
2020-04-15 13:58:34 +02:00
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// STATE
|
2020-04-15 13:58:34 +02:00
|
|
|
AstCell* m_cellp; // Current cell
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-05-14 12:50:47 +02:00
|
|
|
// METHODS
|
|
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " CELL " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_cellp = nodep;
|
2020-04-15 13:58:34 +02:00
|
|
|
// VV***** We reset user1p() on each cell!!!
|
2019-05-19 22:13:13 +02:00
|
|
|
AstNode::user1ClearTree();
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_cellp = NULL;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
2018-10-27 23:29:00 +02:00
|
|
|
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
|
|
|
|
|
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " PIN " << nodep << endl);
|
2020-04-10 05:26:03 +02:00
|
|
|
if (!nodep->user1()) {
|
|
|
|
|
// Simplify it
|
|
|
|
|
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
if (!nodep->exprp()) return; // No-connect
|
2020-04-15 13:58:34 +02:00
|
|
|
if (debug() >= 9) nodep->dumpTree(cout, " Pin_oldb: ");
|
2019-02-28 03:06:07 +01:00
|
|
|
V3Inst::checkOutputShort(nodep);
|
2018-10-27 23:29:00 +02:00
|
|
|
// Use user1p on the PIN to indicate we created an assign for this pin
|
|
|
|
|
if (!nodep->user1SetOnce()) {
|
2018-03-16 04:19:43 +01:00
|
|
|
// Make an ASSIGNW (expr, pin)
|
|
|
|
|
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(exprp->width() == nodep->modVarp()->width(), nodep,
|
|
|
|
|
"Width mismatch, should have been handled in pinReconnectSimple");
|
2018-10-27 23:29:00 +02:00
|
|
|
if (nodep->modVarp()->isInoutish()) {
|
|
|
|
|
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
|
|
|
|
} else if (nodep->modVarp()->isWritable()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNode* rhsp
|
|
|
|
|
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
2018-08-25 15:52:45 +02:00
|
|
|
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
|
2018-03-17 13:43:19 +01:00
|
|
|
m_cellp->addNextHere(assp);
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (nodep->modVarp()->isNonOutput()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Don't bother moving constants now,
|
|
|
|
|
// we'll be pushing the const down to the cell soon enough.
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNode* assp = new AstAssignW(
|
|
|
|
|
exprp->fileline(),
|
|
|
|
|
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
|
|
|
|
|
exprp);
|
2018-03-17 13:43:19 +01:00
|
|
|
m_cellp->addNextHere(assp);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (nodep->modVarp()->isIfaceRef()
|
2018-02-02 03:32:58 +01:00
|
|
|
|| (VN_IS(nodep->modVarp()->subDTypep(), UnpackArrayDType)
|
2020-04-15 13:58:34 +02:00
|
|
|
&& VN_IS(VN_CAST(nodep->modVarp()->subDTypep(), UnpackArrayDType)
|
|
|
|
|
->subDTypep(),
|
|
|
|
|
IfaceRefDType))) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create an AstAssignVarScope for Vars to Cells so we can
|
|
|
|
|
// link with their scope later
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNode* lhsp
|
|
|
|
|
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
2018-02-02 03:32:58 +01:00
|
|
|
const AstVarRef* refp = VN_CAST(exprp, VarRef);
|
|
|
|
|
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(refp || xrefp, exprp,
|
|
|
|
|
"Interfaces: Pin is not connected to a VarRef or VarXRef");
|
2019-05-19 22:13:13 +02:00
|
|
|
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, exprp);
|
2018-03-17 13:43:19 +01:00
|
|
|
m_cellp->addNextHere(assp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
nodep->v3error("Assigned pin is neither input nor output");
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// We're done with the pin
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!v3Global.opt.bboxUnsup()) {
|
|
|
|
|
// If we support primitives, update V3Undriven to remove special case
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. "
|
|
|
|
|
"Use --bbox-unsup to ignore tables.");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2010-01-07 22:41:19 +01:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Save some time
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
|
|
|
|
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
|
|
|
|
|
virtual void visit(AstAlways*) VL_OVERRIDE {}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//--------------------
|
2020-04-04 14:31:14 +02:00
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2017-03-16 01:03:53 +01:00
|
|
|
explicit InstVisitor(AstNetlist* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_cellp = NULL;
|
|
|
|
|
//
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
virtual ~InstVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2017-04-29 02:03:38 +02:00
|
|
|
class InstDeModVarVisitor : public AstNVisitor {
|
|
|
|
|
// Expand all module variables, and save names for later reference
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
2020-04-15 13:58:34 +02:00
|
|
|
typedef std::map<string, AstVar*> VarNameMap;
|
|
|
|
|
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
|
2017-04-29 02:03:38 +02:00
|
|
|
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2017-04-29 02:03:38 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " dm-1-VAR " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
insert(nodep);
|
|
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2017-04-29 02:03:38 +02:00
|
|
|
}
|
2020-04-04 14:31:14 +02:00
|
|
|
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
|
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
|
|
|
|
|
2017-04-29 02:03:38 +02:00
|
|
|
public:
|
|
|
|
|
// METHODS
|
|
|
|
|
void insert(AstVar* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " dmINSERT " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_modVarNameMap.insert(make_pair(nodep->name(), nodep));
|
2017-04-29 02:03:38 +02:00
|
|
|
}
|
|
|
|
|
AstVar* find(const string& name) {
|
2019-05-19 22:13:13 +02:00
|
|
|
VarNameMap::iterator it = m_modVarNameMap.find(name);
|
|
|
|
|
if (it != m_modVarNameMap.end()) {
|
|
|
|
|
return it->second;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2017-04-29 02:03:38 +02:00
|
|
|
}
|
|
|
|
|
void dump() {
|
2020-04-15 13:58:34 +02:00
|
|
|
for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end();
|
|
|
|
|
++it) {
|
|
|
|
|
cout << "-namemap: " << it->first << " -> " << it->second << endl;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2017-04-29 02:03:38 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2017-04-29 02:03:38 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2017-04-29 02:03:38 +02:00
|
|
|
explicit InstDeModVarVisitor() {}
|
2017-09-16 17:06:35 +02:00
|
|
|
void main(AstNodeModule* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " dmMODULE " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_modVarNameMap.clear();
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2017-04-29 02:03:38 +02:00
|
|
|
}
|
|
|
|
|
virtual ~InstDeModVarVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
class InstDeVisitor : public AstNVisitor {
|
|
|
|
|
// Find all cells with arrays, and convert to non-arrayed
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
2020-04-15 13:58:34 +02:00
|
|
|
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
|
|
|
|
int m_instSelNum; // Current instantiation count 0..N-1
|
2019-05-19 22:13:13 +02:00
|
|
|
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
|
|
|
|
|
&& VN_IS(VN_CAST(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " dv-vec-VAR " << nodep << endl);
|
2018-02-02 03:32:58 +01:00
|
|
|
AstUnpackArrayDType* arrdtype = VN_CAST(nodep->dtypep(), UnpackArrayDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
AstNode* prevp = NULL;
|
|
|
|
|
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
|
|
|
|
|
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, "VAR name insert " << varNewName << " " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_deModVars.find(varNewName)) {
|
|
|
|
|
AstIfaceRefDType* ifaceRefp
|
|
|
|
|
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
|
|
|
|
|
arrdtype->addNextHere(ifaceRefp);
|
|
|
|
|
ifaceRefp->cellp(NULL);
|
|
|
|
|
|
|
|
|
|
AstVar* varNewp = nodep->cloneTree(false);
|
|
|
|
|
varNewp->name(varNewName);
|
|
|
|
|
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
|
|
|
|
|
varNewp->dtypep(ifaceRefp);
|
|
|
|
|
m_deModVars.insert(varNewp);
|
|
|
|
|
if (!prevp) {
|
|
|
|
|
prevp = varNewp;
|
|
|
|
|
} else {
|
|
|
|
|
prevp->addNextHere(varNewp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (prevp) nodep->addNextHere(prevp);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (prevp && debug() == 9) {
|
|
|
|
|
prevp->dumpTree(cout, "newintf: ");
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2017-03-16 01:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " CELL " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Find submodule vars
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(nodep->modp(), nodep, "Unlinked");
|
2019-05-19 22:13:13 +02:00
|
|
|
m_deModVars.main(nodep->modp());
|
|
|
|
|
//
|
|
|
|
|
if (nodep->rangep()) {
|
|
|
|
|
m_cellRangep = nodep->rangep();
|
2015-10-24 05:06:24 +02:00
|
|
|
|
2018-02-02 03:32:58 +01:00
|
|
|
AstVar* ifaceVarp = VN_CAST(nodep->nextp(), Var);
|
2020-04-15 13:58:34 +02:00
|
|
|
bool isIface = ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
|
|
|
|
|
&& VN_IS(VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
|
|
|
|
|
IfaceRefDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Make all of the required clones
|
|
|
|
|
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_instSelNum
|
|
|
|
|
= m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
2019-05-19 22:13:13 +02:00
|
|
|
int instNum = m_cellRangep->lsbConst() + i;
|
|
|
|
|
|
|
|
|
|
AstCell* newp = nodep->cloneTree(false);
|
|
|
|
|
nodep->addNextHere(newp);
|
|
|
|
|
// Remove ranging and fix name
|
|
|
|
|
newp->rangep()->unlinkFrBack()->deleteTree();
|
2019-09-09 13:50:21 +02:00
|
|
|
// Somewhat illogically, we need to rename the original name of the cell too.
|
2019-05-19 22:13:13 +02:00
|
|
|
// as that is the name users expect for dotting
|
|
|
|
|
// The spec says we add [x], but that won't work in C...
|
2020-04-15 13:58:34 +02:00
|
|
|
newp->name(newp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
|
|
|
|
newp->origName(newp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
|
|
|
|
UINFO(8, " CELL loop " << newp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
|
|
|
|
// within the same parent module as the cell
|
|
|
|
|
if (isIface) {
|
2018-02-02 03:32:58 +01:00
|
|
|
AstUnpackArrayDType* arrdtype = VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType);
|
2020-04-15 13:58:34 +02:00
|
|
|
AstIfaceRefDType* origIfaceRefp
|
|
|
|
|
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
origIfaceRefp->cellp(NULL);
|
|
|
|
|
AstVar* varNewp = ifaceVarp->cloneTree(false);
|
|
|
|
|
AstIfaceRefDType* ifaceRefp
|
|
|
|
|
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
|
|
|
|
|
arrdtype->addNextHere(ifaceRefp);
|
|
|
|
|
ifaceRefp->cellp(newp);
|
|
|
|
|
ifaceRefp->cellName(newp->name());
|
|
|
|
|
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
2020-04-15 13:58:34 +02:00
|
|
|
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum)
|
|
|
|
|
+ "__KET__");
|
2019-05-19 22:13:13 +02:00
|
|
|
varNewp->dtypep(ifaceRefp);
|
|
|
|
|
newp->addNextHere(varNewp);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (debug() == 9) {
|
|
|
|
|
varNewp->dumpTree(cout, "newintf: ");
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Fixup pins
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(newp->pinsp());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (debug() == 9) {
|
|
|
|
|
newp->dumpTree(cout, "newcell: ");
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Done. Delete original
|
|
|
|
|
m_cellRangep = NULL;
|
|
|
|
|
if (isIface) {
|
2020-01-17 02:17:11 +01:00
|
|
|
ifaceVarp->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(ifaceVarp), ifaceVarp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
m_cellRangep = NULL;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2015-10-24 05:06:24 +02:00
|
|
|
|
2020-01-21 23:35:56 +01:00
|
|
|
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Any non-direct pins need reconnection with a part-select
|
|
|
|
|
if (!nodep->exprp()) return; // No-connect
|
|
|
|
|
if (m_cellRangep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " PIN " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
int pinwidth = nodep->modVarp()->width();
|
|
|
|
|
int expwidth = nodep->exprp()->width();
|
2020-04-15 13:58:34 +02:00
|
|
|
std::pair<uint32_t, uint32_t> pinDim = nodep->modVarp()->dtypep()->dimensions(false);
|
|
|
|
|
std::pair<uint32_t, uint32_t> expDim = nodep->exprp()->dtypep()->dimensions(false);
|
|
|
|
|
UINFO(4, " PINVAR " << nodep->modVarp() << endl);
|
|
|
|
|
UINFO(4, " EXP " << nodep->exprp() << endl);
|
|
|
|
|
UINFO(4, " pinwidth ew=" << expwidth << " pw=" << pinwidth << " ed=" << expDim.first
|
|
|
|
|
<< "," << expDim.second << " pd=" << pinDim.first << ","
|
|
|
|
|
<< pinDim.second << endl);
|
|
|
|
|
if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Connection to array, where array dimensions match the instant dimension
|
2019-12-11 23:15:45 +01:00
|
|
|
AstRange* rangep = VN_CAST(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep();
|
|
|
|
|
int arraySelNum = rangep->littleEndian()
|
2020-04-15 13:58:34 +02:00
|
|
|
? (rangep->elementsConst() - 1 - m_instSelNum)
|
|
|
|
|
: m_instSelNum;
|
2019-05-19 22:13:13 +02:00
|
|
|
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
2019-12-11 23:15:45 +01:00
|
|
|
exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->exprp(exprp);
|
|
|
|
|
} else if (expwidth == pinwidth) {
|
|
|
|
|
// NOP: Arrayed instants: widths match so connect to each instance
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (expwidth == pinwidth * m_cellRangep->elementsConst()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Arrayed instants: one bit for each of the instants (each
|
|
|
|
|
// assign is 1 pinwidth wide)
|
|
|
|
|
if (m_cellRangep->littleEndian()) {
|
2019-07-14 18:09:40 +02:00
|
|
|
nodep->exprp()->v3warn(
|
|
|
|
|
LITENDIAN,
|
|
|
|
|
"Little endian cell range connecting to vector: MSB < LSB of cell range: "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< m_cellRangep->lsbConst() << ":" << m_cellRangep->msbConst());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
|
|
|
|
bool inputPin = nodep->modVarp()->isNonOutput();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!inputPin
|
|
|
|
|
&& !VN_IS(exprp, VarRef)
|
|
|
|
|
// V3Const will collapse the SEL with the one we're about to make
|
|
|
|
|
&& !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) {
|
|
|
|
|
nodep->v3error("Unsupported: Per-bit array instantiations with output "
|
|
|
|
|
"connections to non-wires.");
|
2019-05-19 22:13:13 +02:00
|
|
|
// Note spec allows more complicated matches such as slices and such
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth);
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->exprp(exprp);
|
|
|
|
|
} else {
|
|
|
|
|
nodep->v3fatalSrc("Width mismatch; V3Width should have errored out.");
|
|
|
|
|
}
|
2020-04-18 01:30:53 +02:00
|
|
|
} // end expanding ranged cell
|
|
|
|
|
else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (AstUnpackArrayDType* arrp = VN_CAST(arrselp->lhsp()->dtypep(), UnpackArrayDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
|
2020-04-18 01:30:53 +02:00
|
|
|
// Interface pin attaches to one element of arrayed interface
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Const::constifyParamsEdit(arrselp->rhsp());
|
2018-02-02 03:32:58 +01:00
|
|
|
const AstConst* constp = VN_CAST(arrselp->rhsp(), Const);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!constp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(
|
|
|
|
|
"Unsupported: Non-constant index when passing interface to module");
|
2019-05-19 22:13:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
string index = AstNode::encodeNumber(constp->toSInt());
|
2018-02-02 03:32:58 +01:00
|
|
|
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
|
2020-04-15 13:58:34 +02:00
|
|
|
AstVarXRef* newp = new AstVarXRef(
|
|
|
|
|
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
|
2019-05-19 22:13:13 +02:00
|
|
|
newp->dtypep(nodep->modVarp()->dtypep());
|
|
|
|
|
newp->packagep(varrefp->packagep());
|
|
|
|
|
arrselp->addNextHere(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(arrselp->unlinkFrBack()->deleteTree(), arrselp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
AstVar* pinVarp = nodep->modVarp();
|
2018-02-02 03:32:58 +01:00
|
|
|
AstUnpackArrayDType* pinArrp = VN_CAST(pinVarp->dtypep(), UnpackArrayDType);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return;
|
2020-04-18 01:30:53 +02:00
|
|
|
// Arrayed pin/var attaches to arrayed submodule lower port/var, expand it
|
2019-05-19 22:13:13 +02:00
|
|
|
AstNode* prevp = NULL;
|
|
|
|
|
AstNode* prevPinp = NULL;
|
|
|
|
|
// Clone the var referenced by the pin, and clone each var referenced by the varref
|
|
|
|
|
// Clone pin varp:
|
|
|
|
|
for (int i = pinArrp->lsb(); i <= pinArrp->msb(); ++i) {
|
|
|
|
|
string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
|
|
|
|
AstVar* varNewp = NULL;
|
|
|
|
|
|
|
|
|
|
// Only clone the var once for all usages of a given child module
|
|
|
|
|
if (!pinVarp->backp()) {
|
|
|
|
|
varNewp = m_deModVars.find(varNewName);
|
|
|
|
|
} else {
|
2018-02-02 03:32:58 +01:00
|
|
|
AstIfaceRefDType* ifaceRefp = VN_CAST(pinArrp->subDTypep(), IfaceRefDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
ifaceRefp->cellp(NULL);
|
|
|
|
|
varNewp = pinVarp->cloneTree(false);
|
|
|
|
|
varNewp->name(varNewName);
|
|
|
|
|
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
|
|
|
|
|
varNewp->dtypep(ifaceRefp);
|
|
|
|
|
m_deModVars.insert(varNewp);
|
|
|
|
|
if (!prevp) {
|
|
|
|
|
prevp = varNewp;
|
|
|
|
|
} else {
|
|
|
|
|
prevp->addNextHere(varNewp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!varNewp) {
|
2020-05-23 16:34:58 +02:00
|
|
|
if (debug() >= 9) m_deModVars.dump(); // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Module dearray failed for "
|
2020-04-15 13:58:34 +02:00
|
|
|
<< AstNode::prettyNameQ(varNewName));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// But clone the pin for each module instance
|
|
|
|
|
// Now also clone the pin itself and update its varref
|
|
|
|
|
AstPin* newp = nodep->cloneTree(false);
|
|
|
|
|
newp->modVarp(varNewp);
|
|
|
|
|
newp->name(newp->name() + "__BRA__" + cvtToStr(i) + "__KET__");
|
|
|
|
|
// And replace exprp with a new varxref
|
2020-04-18 01:30:53 +02:00
|
|
|
int offset = 0;
|
2018-02-02 03:32:58 +01:00
|
|
|
const AstVarRef* varrefp = VN_CAST(newp->exprp(), VarRef);
|
2020-04-18 01:30:53 +02:00
|
|
|
if (varrefp) {
|
|
|
|
|
} else if (AstSliceSel* slicep = VN_CAST(newp->exprp(), SliceSel)) {
|
|
|
|
|
varrefp = VN_CAST(slicep->fromp(), VarRef);
|
|
|
|
|
UASSERT(VN_IS(slicep->rhsp(), Const), "Slices should be constant");
|
|
|
|
|
offset = VN_CAST(slicep->rhsp(), Const)->toSInt();
|
|
|
|
|
}
|
|
|
|
|
if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); }
|
|
|
|
|
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
|
2018-08-25 15:52:45 +02:00
|
|
|
AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true);
|
2019-05-19 22:13:13 +02:00
|
|
|
newVarXRefp->varp(newp->modVarp());
|
|
|
|
|
newVarXRefp->dtypep(newp->modVarp()->dtypep());
|
|
|
|
|
newp->exprp()->unlinkFrBack()->deleteTree();
|
|
|
|
|
newp->exprp(newVarXRefp);
|
|
|
|
|
if (!prevPinp) {
|
|
|
|
|
prevPinp = newp;
|
|
|
|
|
} else {
|
|
|
|
|
prevPinp->addNextHere(newp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (prevp) {
|
|
|
|
|
pinVarp->replaceWith(prevp);
|
|
|
|
|
pushDeletep(pinVarp);
|
|
|
|
|
} // else pinVarp already unlinked when another instance did this step
|
|
|
|
|
nodep->replaceWith(prevPinp);
|
|
|
|
|
pushDeletep(nodep);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------
|
2020-04-04 14:31:14 +02:00
|
|
|
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
|
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2017-03-16 01:03:53 +01:00
|
|
|
explicit InstDeVisitor(AstNetlist* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_cellRangep = NULL;
|
|
|
|
|
m_instSelNum = 0;
|
|
|
|
|
//
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
virtual ~InstDeVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2015-05-14 02:56:16 +02:00
|
|
|
// Inst static function
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2015-05-14 02:56:16 +02:00
|
|
|
class InstStatic {
|
|
|
|
|
private:
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2019-05-19 22:13:13 +02:00
|
|
|
InstStatic() {} // Static class
|
2015-05-14 02:56:16 +02:00
|
|
|
|
|
|
|
|
static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (cmpWidthp->width() > rhsp->width()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
rhsp = (rhsp->isSigned() ? static_cast<AstNode*>(new AstExtendS(fl, rhsp))
|
|
|
|
|
: static_cast<AstNode*>(new AstExtend(fl, rhsp)));
|
|
|
|
|
// Need proper widthMin, which may differ from AstSel created above
|
|
|
|
|
rhsp->dtypeFrom(cmpWidthp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else if (cmpWidthp->width() < rhsp->width()) {
|
2018-08-25 15:52:45 +02:00
|
|
|
rhsp = new AstSel(fl, rhsp, 0, cmpWidthp->width());
|
2020-04-15 13:58:34 +02:00
|
|
|
// Need proper widthMin, which may differ from AstSel created above
|
|
|
|
|
rhsp->dtypeFrom(cmpWidthp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// else don't change dtype, as might be e.g. array of something
|
|
|
|
|
return rhsp;
|
2015-05-14 02:56:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2020-04-15 13:58:34 +02:00
|
|
|
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
|
|
|
|
|
bool alwaysCvt) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// If a pin connection is "simple" leave it as-is
|
|
|
|
|
// Else create a intermediate wire to perform the interconnect
|
|
|
|
|
// Return the new assignment, if one was made
|
|
|
|
|
// Note this module calles cloneTree() via new AstVar
|
|
|
|
|
AstVar* pinVarp = pinp->modVarp();
|
2020-04-10 05:26:03 +02:00
|
|
|
if (!pinp->exprp()) {
|
|
|
|
|
// No-connect, perhaps promote based on `unconnected_drive,
|
|
|
|
|
// otherwise done
|
|
|
|
|
if (pinVarp->direction() == VDirection::INPUT
|
|
|
|
|
&& cellp->modp()->unconnectedDrive().isSetTrue()) {
|
|
|
|
|
pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'1"));
|
|
|
|
|
} else if (pinVarp->direction() == VDirection::INPUT
|
|
|
|
|
&& cellp->modp()->unconnectedDrive().isSetFalse()) {
|
|
|
|
|
pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'0"));
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-02-02 03:32:58 +01:00
|
|
|
AstVarRef* connectRefp = VN_CAST(pinp->exprp(), VarRef);
|
|
|
|
|
AstVarXRef* connectXRefp = VN_CAST(pinp->exprp(), VarXRef);
|
|
|
|
|
AstBasicDType* pinBasicp = VN_CAST(pinVarp->dtypep(), BasicDType); // Maybe NULL
|
2019-05-19 22:13:13 +02:00
|
|
|
AstBasicDType* connBasicp = NULL;
|
|
|
|
|
AstAssignW* assignp = NULL;
|
2018-02-02 03:32:58 +01:00
|
|
|
if (connectRefp) connBasicp = VN_CAST(connectRefp->varp()->dtypep(), BasicDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
//
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!alwaysCvt && connectRefp && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
|
2019-05-19 22:13:13 +02:00
|
|
|
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
|
|
|
|
|
// Done. Same data type
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (!alwaysCvt && connectRefp && connectRefp->varp()->isIfaceRef()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Done. Interface
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (!alwaysCvt && connectXRefp && connectXRefp->varp()
|
2019-05-19 22:13:13 +02:00
|
|
|
&& connectXRefp->varp()->isIfaceRef()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (!alwaysCvt && connBasicp && pinBasicp
|
2019-05-19 22:13:13 +02:00
|
|
|
&& connBasicp->width() == pinBasicp->width()
|
|
|
|
|
&& connBasicp->lsb() == pinBasicp->lsb()
|
2020-04-15 13:58:34 +02:00
|
|
|
&& !connectRefp->varp()
|
|
|
|
|
->isSc() // Need the signal as a 'shell' to convert types
|
2019-05-19 22:13:13 +02:00
|
|
|
&& connBasicp->width() == pinVarp->width()) {
|
|
|
|
|
// Done. One to one interconnect won't need a temporary variable.
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (!alwaysCvt && !forTristate && VN_IS(pinp->exprp(), Const)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Done. Constant.
|
|
|
|
|
} else {
|
|
|
|
|
// Make a new temp wire
|
2020-04-15 13:58:34 +02:00
|
|
|
// if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); }
|
2019-02-28 03:06:07 +01:00
|
|
|
V3Inst::checkOutputShort(pinp);
|
|
|
|
|
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
2020-04-15 13:58:34 +02:00
|
|
|
string newvarname
|
|
|
|
|
= (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
|
|
|
|
// Prevent name conflict if both tri & non-tri add signals
|
|
|
|
|
+ (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name());
|
|
|
|
|
AstVar* newvarp
|
|
|
|
|
= new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
|
2018-10-27 23:29:00 +02:00
|
|
|
// Important to add statement next to cell, in case there is a
|
|
|
|
|
// generate with same named cell
|
|
|
|
|
cellp->addNextHere(newvarp);
|
|
|
|
|
if (pinVarp->isInoutish()) {
|
2018-03-10 22:32:04 +01:00
|
|
|
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be"
|
|
|
|
|
" direct one-to-one connection (without any expression)");
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (pinVarp->isWritable()) {
|
|
|
|
|
// See also V3Inst
|
|
|
|
|
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
|
|
|
|
|
<< pinexprp->width() << endl);
|
2018-08-25 15:52:45 +02:00
|
|
|
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
|
|
|
|
|
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
|
|
|
|
|
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
|
|
|
|
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
|
2018-10-27 23:29:00 +02:00
|
|
|
} else {
|
|
|
|
|
// V3 width should have range/extended to make the widths correct
|
2018-08-25 15:52:45 +02:00
|
|
|
assignp = new AstAssignW(pinp->fileline(),
|
2020-04-15 13:58:34 +02:00
|
|
|
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
|
2018-08-25 15:52:45 +02:00
|
|
|
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (assignp) cellp->addNextHere(assignp);
|
2020-04-15 13:58:34 +02:00
|
|
|
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
|
|
|
|
|
// if (debug()) { assignp->dumpTree(cout, "- aout:"); }
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
return assignp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2015-05-14 02:56:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Inst class functions
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
|
|
|
|
|
bool alwaysCvt) {
|
2018-03-16 04:19:43 +01:00
|
|
|
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-28 03:06:07 +01:00
|
|
|
void V3Inst::checkOutputShort(AstPin* nodep) {
|
|
|
|
|
if (nodep->modVarp()->direction() == VDirection::OUTPUT) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(nodep->exprp(), Const) || VN_IS(nodep->exprp(), Extend)
|
2019-02-28 03:06:07 +01:00
|
|
|
|| (VN_IS(nodep->exprp(), Concat)
|
|
|
|
|
&& (VN_IS(VN_CAST(nodep->exprp(), Concat)->lhsp(), Const)))) {
|
|
|
|
|
// Uses v3warn for error, as might be found multiple times
|
|
|
|
|
nodep->v3warn(E_PORTSHORT, "Output port is connected to a constant pin,"
|
2020-04-15 13:58:34 +02:00
|
|
|
" electrical short");
|
2019-02-28 03:06:07 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Inst class visitor
|
|
|
|
|
|
|
|
|
|
void V3Inst::instAll(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
{ InstVisitor visitor(nodep); } // Destruct before checking
|
2017-09-18 04:52:57 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("inst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3Inst::dearrayAll(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
|
|
|
|
{ InstDeVisitor visitor(nodep); } // Destruct before checking
|
2017-09-18 04:52:57 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("dearray", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|