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: Ast node structures
|
|
|
|
|
//
|
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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
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 "V3Ast.h"
|
2021-06-13 16:05:55 +02:00
|
|
|
#include "V3EmitCBase.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3File.h"
|
|
|
|
|
#include "V3Global.h"
|
2018-07-23 02:54:28 +02:00
|
|
|
#include "V3Graph.h"
|
2021-06-13 16:05:55 +02:00
|
|
|
#include "V3Hasher.h"
|
2018-07-23 02:54:28 +02:00
|
|
|
#include "V3PartitionGraph.h" // Just for mtask dumping
|
2020-08-15 15:43:53 +02:00
|
|
|
#include "V3String.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-05-22 12:13:02 +02:00
|
|
|
#include "V3AstNodes__gen_macros.h" // Generated by 'astgen'
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <iomanip>
|
2021-06-13 16:05:55 +02:00
|
|
|
#include <iterator>
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Special methods
|
|
|
|
|
|
|
|
|
|
// We need these here, because the classes they point to aren't defined when we declare the class
|
2013-05-28 03:39:19 +02:00
|
|
|
const char* AstIfaceRefDType::broken() const {
|
|
|
|
|
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
2018-02-02 03:32:58 +01:00
|
|
|
return ((m_cellp && m_cellp->modp()) ? VN_CAST(m_cellp->modp(), Iface) : m_ifacep);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
const char* AstNodeVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2013-05-19 01:45:40 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
void AstNodeVarRef::cloneRelink() {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 15:33:11 +02:00
|
|
|
string AstNodeVarRef::selfPointerProtect(bool useSelfForThis) const {
|
|
|
|
|
const string& sp
|
|
|
|
|
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
|
|
|
|
|
return VIdProtect::protectWordsIf(sp, protect());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstAddrOfCFunc::cloneRelink() {
|
|
|
|
|
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* AstAddrOfCFunc::broken() const {
|
|
|
|
|
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
|
|
|
|
return nullptr;
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
int AstNodeSel::bitConst() const {
|
2019-05-19 22:13:13 +02:00
|
|
|
AstConst* constp = VN_CAST(bitp(), Const);
|
2018-02-02 03:32:58 +01:00
|
|
|
return (constp ? constp->toSInt() : 0);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
void AstNodeUOrStructDType::repairMemberCache() {
|
2012-07-29 16:16:20 +02:00
|
|
|
clearCache();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
|
|
|
|
if (m_members.find(itemp->name()) != m_members.end()) {
|
|
|
|
|
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
|
|
|
|
|
} else {
|
2020-12-19 00:24:47 +01:00
|
|
|
m_members.emplace(itemp->name(), itemp);
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
const char* AstNodeUOrStructDType::broken() const {
|
2020-08-15 16:03:34 +02:00
|
|
|
std::unordered_set<AstMemberDType*> exists;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
exists.insert(itemp);
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
|
2019-07-01 04:37:03 +02:00
|
|
|
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
|
2020-04-15 13:58:34 +02:00
|
|
|
this->v3error("Internal: Structure member broken: " << it->first);
|
2019-05-19 22:13:13 +02:00
|
|
|
return "member broken";
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
|
2020-03-07 18:52:11 +01:00
|
|
|
void AstNodeCCall::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-03-07 18:52:11 +01:00
|
|
|
if (funcp()) {
|
|
|
|
|
str << " " << funcp()->name() << " => ";
|
|
|
|
|
funcp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " " << name();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstNodeCCall::cloneRelink() {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
|
2020-03-07 18:52:11 +01:00
|
|
|
}
|
|
|
|
|
const char* AstNodeCCall::broken() const {
|
|
|
|
|
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-03-07 18:52:11 +01:00
|
|
|
}
|
|
|
|
|
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
|
2021-07-13 18:42:17 +02:00
|
|
|
|
|
|
|
|
string AstCCall::selfPointerProtect(bool useSelfForThis) const {
|
2021-06-13 15:33:11 +02:00
|
|
|
const string& sp
|
|
|
|
|
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
|
|
|
|
|
return VIdProtect::protectWordsIf(sp, protect());
|
|
|
|
|
}
|
2020-03-07 18:52:11 +01:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
|
|
|
|
const V3Number& ths) {
|
2020-04-16 03:47:37 +02:00
|
|
|
if (lhs.isNeqZero()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.opAssign(rhs);
|
2020-04-16 03:47:37 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.opAssign(ths);
|
2020-04-16 03:47:37 +02:00
|
|
|
}
|
2019-05-10 02:03:19 +02:00
|
|
|
}
|
|
|
|
|
|
2009-11-05 04:31:53 +01:00
|
|
|
int AstBasicDType::widthAlignBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
2009-11-05 04:31:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AstBasicDType::widthTotalBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return widthWords() * (VL_EDATASIZE / 8);
|
|
|
|
|
}
|
2009-11-05 04:31:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthTotalBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return widthWords() * (VL_EDATASIZE / 8);
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthAlignBytes() const {
|
2012-07-29 16:16:20 +02:00
|
|
|
// Could do max across members but that would be slow,
|
|
|
|
|
// instead intuit based on total structure size
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (width() <= 32) {
|
|
|
|
|
return 4;
|
|
|
|
|
} else {
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2014-01-21 03:59:53 +01:00
|
|
|
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstEqN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqD(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEq(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstGteN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstGteD(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else if (lhsp->isSigned() && rhsp->isSigned()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstGteS(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstGte(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstLteN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstLteD(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else if (lhsp->isSigned() && rhsp->isSigned()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstLteS(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstLte(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-18 02:15:40 +02:00
|
|
|
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstEqN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqD(fl, lhsp, rhsp);
|
2017-05-18 02:15:40 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqWild(fl, lhsp, rhsp);
|
2017-05-18 02:15:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-21 03:59:53 +01:00
|
|
|
|
2018-07-23 02:54:28 +02:00
|
|
|
AstExecGraph::AstExecGraph(FileLine* fileline)
|
2021-06-16 13:18:56 +02:00
|
|
|
: ASTGEN_SUPER_ExecGraph(fileline)
|
|
|
|
|
, m_depGraphp{new V3Graph} {}
|
2018-07-23 02:54:28 +02:00
|
|
|
|
2021-06-16 13:18:56 +02:00
|
|
|
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
2021-06-13 15:33:11 +02:00
|
|
|
|
2020-03-31 00:12:50 +02:00
|
|
|
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
|
|
|
|
|
AstNode* ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
|
|
|
|
|
AstNode* bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
|
|
|
|
|
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
|
|
|
|
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
|
|
|
|
AstNode* newp = new AstAnd(fileline(), ap, bp);
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-02 13:29:52 +02:00
|
|
|
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
|
|
|
|
bool success = false;
|
|
|
|
|
if (literal[0] == '"') {
|
|
|
|
|
// This is a string
|
|
|
|
|
string v = literal.substr(1, literal.find('"', 1) - 1);
|
|
|
|
|
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
|
|
|
|
|
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
|
|
|
|
// This may be a real
|
|
|
|
|
double v = VString::parseDouble(literal, &success);
|
|
|
|
|
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
|
|
|
|
|
}
|
|
|
|
|
if (!success) {
|
|
|
|
|
// This is either an integer or an error
|
|
|
|
|
// We first try to convert it as C literal. If strtol returns
|
|
|
|
|
// 0 this is either an error or 0 was parsed. But in any case
|
|
|
|
|
// we will try to parse it as a verilog literal, hence having
|
|
|
|
|
// the false negative for 0 is okay. If anything remains in
|
|
|
|
|
// the string after the number, this is invalid C and we try
|
|
|
|
|
// the Verilog literal parser.
|
|
|
|
|
char* endp;
|
|
|
|
|
int v = strtol(literal.c_str(), &endp, 0);
|
|
|
|
|
if ((v != 0) && (endp[0] == 0)) { // C literal
|
2021-07-08 14:42:25 +02:00
|
|
|
return new AstConst(fl, AstConst::Signed32(), v);
|
2020-07-02 13:29:52 +02:00
|
|
|
} else { // Try a Verilog literal (fatals if not)
|
|
|
|
|
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-07-02 13:29:52 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstNetlist::AstNetlist()
|
|
|
|
|
: ASTGEN_SUPER_Netlist(new FileLine(FileLine::builtInFilename()))
|
|
|
|
|
, m_typeTablep{new AstTypeTable(fileline())}
|
|
|
|
|
, m_constPoolp{new AstConstPool(fileline())} {
|
|
|
|
|
addMiscsp(m_typeTablep);
|
|
|
|
|
addMiscsp(m_constPoolp);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const VTimescale prec = v3Global.opt.timeComputePrec(value);
|
2020-04-16 01:39:03 +02:00
|
|
|
if (prec.isNone() || prec == m_timeprecision) {
|
|
|
|
|
} else if (m_timeprecision.isNone()) {
|
|
|
|
|
m_timeprecision = prec;
|
|
|
|
|
} else if (prec < m_timeprecision) {
|
|
|
|
|
m_timeprecision = prec;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
bool AstVar::isSigPublic() const {
|
2008-09-30 14:58:07 +02:00
|
|
|
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
bool AstVar::isScQuad() const { return (isSc() && isQuad() && !isScBv() && !isScBigUint()); }
|
2009-03-13 19:17:30 +01:00
|
|
|
bool AstVar::isScBv() const {
|
2011-10-26 14:57:27 +02:00
|
|
|
return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2013-04-27 03:02:32 +02:00
|
|
|
bool AstVar::isScUint() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return ((isSc() && v3Global.opt.pinsScUint() && width() >= 2 && width() <= 64) && !isScBv());
|
2013-04-27 03:02:32 +02:00
|
|
|
}
|
|
|
|
|
bool AstVar::isScBigUint() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return ((isSc() && v3Global.opt.pinsScBigUint() && width() >= 65 && width() <= 512)
|
|
|
|
|
&& !isScBv());
|
2013-04-27 03:02:32 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
void AstVar::combineType(AstVarType type) {
|
2012-04-24 13:45:02 +02:00
|
|
|
// These flags get combined with the existing settings of the flags.
|
|
|
|
|
// We don't test varType for certain types, instead set flags since
|
|
|
|
|
// when we combine wires cross-hierarchy we need a union of all characteristics.
|
2018-10-27 23:29:00 +02:00
|
|
|
m_varType = type;
|
2006-08-26 13:35:28 +02:00
|
|
|
// These flags get combined with the existing settings of the flags.
|
2020-04-15 13:58:34 +02:00
|
|
|
if (type == AstVarType::TRIWIRE || type == AstVarType::TRI0 || type == AstVarType::TRI1) {
|
2018-10-27 23:29:00 +02:00
|
|
|
m_tristate = true;
|
2018-10-04 01:51:05 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (type == AstVarType::TRI0) m_isPulldown = true;
|
|
|
|
|
if (type == AstVarType::TRI1) m_isPullup = true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::verilogKwd() const {
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isIO()) {
|
|
|
|
|
return direction().verilogKwd();
|
2006-09-25 22:40:52 +02:00
|
|
|
} else if (isTristate()) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "tri";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (varType() == AstVarType::WIRE) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wire";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (varType() == AstVarType::WREAL) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wreal";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (varType() == AstVarType::IFACEREF) {
|
2018-12-06 13:12:39 +01:00
|
|
|
return "ifaceref";
|
2006-08-26 13:35:28 +02:00
|
|
|
} else {
|
2018-10-27 23:29:00 +02:00
|
|
|
return dtypep()->name();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
|
|
|
|
|
bool asRef) const {
|
2019-07-07 15:01:36 +02:00
|
|
|
UASSERT_OBJ(!forReturn, this,
|
|
|
|
|
"Internal data is never passed as return, but as first argument");
|
2019-11-13 03:52:25 +01:00
|
|
|
string ostatic;
|
2019-12-01 12:09:58 +01:00
|
|
|
if (isStatic() && namespc.empty()) ostatic = "static ";
|
|
|
|
|
|
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
|
|
|
const bool isRef = isDpiOpenArray()
|
|
|
|
|
|| (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef;
|
2020-10-17 22:04:29 +02:00
|
|
|
|
|
|
|
|
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
|
2019-12-01 12:09:58 +01:00
|
|
|
|
|
|
|
|
string oname;
|
|
|
|
|
if (named) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!namespc.empty()) oname += namespc + "::";
|
2019-12-01 12:09:58 +01:00
|
|
|
oname += VIdProtect::protectIf(name(), protect());
|
|
|
|
|
}
|
2020-10-17 22:48:11 +02:00
|
|
|
return ostatic + dtypep()->cType(oname, forFunc, isRef);
|
2009-12-03 12:55:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-17 13:22:49 +01:00
|
|
|
string AstVar::vlEnumType() const {
|
|
|
|
|
string arg;
|
|
|
|
|
AstBasicDType* bdtypep = basicp();
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "VLVT_PTR";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "VLVT_PTR";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (strtype) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_STRING";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (widthMin() <= 8) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT8";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (widthMin() <= 16) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT16";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT32";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (isQuad()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT64";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (isWide()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_WDATA";
|
2010-03-17 13:22:49 +01:00
|
|
|
}
|
|
|
|
|
// else return "VLVT_UNKNOWN"
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-06 02:01:17 +02:00
|
|
|
string AstVar::vlEnumDir() const {
|
2017-12-16 16:07:15 +01:00
|
|
|
string out;
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isInoutish()) {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_INOUT";
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (isWritable()) {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_OUT";
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (isNonOutput()) {
|
|
|
|
|
out = "VLVD_IN";
|
2010-04-06 02:01:17 +02:00
|
|
|
} else {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_NODIR";
|
2010-04-06 02:01:17 +02:00
|
|
|
}
|
2017-12-16 16:07:15 +01:00
|
|
|
//
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isSigUserRWPublic()) {
|
|
|
|
|
out += "|VLVF_PUB_RW";
|
|
|
|
|
} else if (isSigUserRdPublic()) {
|
|
|
|
|
out += "|VLVF_PUB_RD";
|
|
|
|
|
}
|
2017-12-17 22:28:58 +01:00
|
|
|
//
|
|
|
|
|
if (AstBasicDType* bdtypep = basicp()) {
|
|
|
|
|
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 20:55:46 +02:00
|
|
|
string AstVar::vlPropDecl(const string& propName) const {
|
2017-12-17 22:28:58 +01:00
|
|
|
string out;
|
2020-05-08 19:22:44 +02:00
|
|
|
|
|
|
|
|
std::vector<int> ulims; // Unpacked dimension limits
|
|
|
|
|
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
2017-12-17 22:28:58 +01:00
|
|
|
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2020-05-08 19:22:44 +02:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
|
|
|
|
|
ulims.push_back(adtypep->declRange().left());
|
|
|
|
|
ulims.push_back(adtypep->declRange().right());
|
2017-12-17 22:28:58 +01:00
|
|
|
dtp = adtypep->subDTypep();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
break; // AstBasicDType - nothing below
|
2017-12-17 22:28:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-08 19:22:44 +02:00
|
|
|
|
|
|
|
|
if (!ulims.empty()) {
|
|
|
|
|
out += "static const int " + propName + "__ulims[";
|
|
|
|
|
out += cvtToStr(ulims.size());
|
|
|
|
|
out += "] = {";
|
2020-08-16 17:43:49 +02:00
|
|
|
auto it = ulims.cbegin();
|
2020-05-08 19:22:44 +02:00
|
|
|
out += cvtToStr(*it);
|
2020-08-16 17:43:49 +02:00
|
|
|
while (++it != ulims.cend()) {
|
2020-05-08 19:22:44 +02:00
|
|
|
out += ", ";
|
|
|
|
|
out += cvtToStr(*it);
|
|
|
|
|
}
|
|
|
|
|
out += "};\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out += "static const VerilatedVarProps ";
|
|
|
|
|
out += propName;
|
|
|
|
|
out += "(";
|
|
|
|
|
out += vlEnumType(); // VLVT_UINT32 etc
|
|
|
|
|
out += ", " + vlEnumDir(); // VLVD_IN etc
|
|
|
|
|
if (const AstBasicDType* const bdtypep = basicp()) {
|
|
|
|
|
out += ", VerilatedVarProps::Packed()";
|
|
|
|
|
out += ", " + cvtToStr(bdtypep->left());
|
|
|
|
|
out += ", " + cvtToStr(bdtypep->right());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ulims.empty()) {
|
|
|
|
|
out += ", VerilatedVarProps::Unpacked()";
|
|
|
|
|
out += ", " + cvtToStr(ulims.size() / 2);
|
|
|
|
|
out += ", " + propName + "__ulims";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out += ");\n";
|
2017-12-16 16:07:15 +01:00
|
|
|
return out;
|
2010-04-06 02:01:17 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-09 03:35:15 +01:00
|
|
|
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (forReturn) named = false;
|
2009-12-03 12:55:29 +01:00
|
|
|
string arg;
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isWide() && isReadOnly()) arg += "const ";
|
2006-10-05 16:53:17 +02:00
|
|
|
if (widthMin() == 1) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "bool";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "uint32_t";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_QUADSIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "vluint64_t";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else {
|
|
|
|
|
arg += "uint32_t"; // []'s added later
|
2009-12-03 12:55:29 +01:00
|
|
|
}
|
|
|
|
|
if (isWide()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (forReturn) {
|
2020-06-10 01:20:16 +02:00
|
|
|
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
|
|
|
|
|
"make an output of a public task instead");
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
arg += " (& " + name();
|
|
|
|
|
arg += ")[" + cvtToStr(widthWords()) + "]";
|
2009-12-03 12:55:29 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!forReturn && (isWritable() || direction().isRefOrConstRef())) arg += "&";
|
|
|
|
|
if (named) arg += " " + name();
|
2009-12-03 12:55:29 +01:00
|
|
|
}
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 14:22:02 +01:00
|
|
|
class dpiTypesToStringConverter VL_NOT_FINAL {
|
2020-11-19 14:02:58 +01:00
|
|
|
public:
|
|
|
|
|
virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; }
|
|
|
|
|
virtual string bitLogicVector(const AstVar* varp, bool isBit) const {
|
|
|
|
|
return isBit ? "svBitVecVal" : "svLogicVecVal";
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const {
|
|
|
|
|
string type;
|
2020-12-13 08:05:06 +01:00
|
|
|
const AstBasicDTypeKwd keyword = varp->basicp()->keyword();
|
|
|
|
|
if (keyword.isDpiUnsignable() && !varp->basicp()->isSigned()) type = "unsigned ";
|
|
|
|
|
type += keyword.dpiType();
|
2020-11-19 14:02:58 +01:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
string convert(const AstVar* varp) const {
|
|
|
|
|
if (varp->isDpiOpenArray()) {
|
|
|
|
|
return openArray(varp);
|
2020-12-13 08:05:06 +01:00
|
|
|
} else if (const AstBasicDType* basicp = varp->basicp()) {
|
|
|
|
|
if (basicp->isDpiBitVec() || basicp->isDpiLogicVec()) {
|
|
|
|
|
return bitLogicVector(varp, basicp->isDpiBitVec());
|
|
|
|
|
} else {
|
|
|
|
|
return primitive(varp);
|
|
|
|
|
}
|
2017-12-10 02:17:37 +01:00
|
|
|
} else {
|
2020-12-13 08:05:06 +01:00
|
|
|
return "UNKNOWN";
|
2017-12-10 02:17:37 +01:00
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|
|
|
|
if (forReturn) {
|
|
|
|
|
return dpiTypesToStringConverter{}.convert(this);
|
2009-12-03 12:55:29 +01:00
|
|
|
} else {
|
2020-11-19 14:22:02 +01:00
|
|
|
class converter final : public dpiTypesToStringConverter {
|
2020-11-19 14:02:58 +01:00
|
|
|
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
|
|
|
|
return string(varp->isReadOnly() ? "const " : "")
|
|
|
|
|
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
|
|
|
|
if (!varp->isWritable()
|
|
|
|
|
&& varp->basicp()->keyword() != AstBasicDTypeKwd::STRING)
|
|
|
|
|
type = "const " + type;
|
|
|
|
|
type += "*";
|
|
|
|
|
}
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
string arg = converter{}.convert(this);
|
|
|
|
|
if (named) arg += " " + name();
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::dpiTmpVarType(const string& varName) const {
|
2020-11-19 14:22:02 +01:00
|
|
|
class converter final : public dpiTypesToStringConverter {
|
2020-11-19 14:02:58 +01:00
|
|
|
string m_name;
|
|
|
|
|
string arraySuffix(const AstVar* varp, size_t n) const {
|
|
|
|
|
if (AstUnpackArrayDType* unpackp
|
|
|
|
|
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
|
|
|
|
// Convert multi dimensional unpacked array to 1D array
|
|
|
|
|
if (n == 0) n = 1;
|
|
|
|
|
n *= unpackp->arrayUnpackedElements();
|
|
|
|
|
return '[' + cvtToStr(n) + ']';
|
|
|
|
|
} else if (n > 0) {
|
|
|
|
|
return '[' + cvtToStr(n) + ']';
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
virtual string openArray(const AstVar* varp) const override {
|
|
|
|
|
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
|
|
|
|
|
+ arraySuffix(varp, 0);
|
|
|
|
|
}
|
|
|
|
|
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
|
|
|
|
|
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
|
|
|
|
if (!varp->isWritable() && varp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE)
|
|
|
|
|
type = "const " + type;
|
|
|
|
|
}
|
|
|
|
|
type += ' ' + m_name + arraySuffix(varp, 0);
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit converter(const string& name)
|
|
|
|
|
: m_name(name) {}
|
|
|
|
|
};
|
|
|
|
|
return converter{varName}.convert(this);
|
2006-10-05 16:53:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::scType() const {
|
2013-04-27 03:02:32 +02:00
|
|
|
if (isScBigUint()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_biguint<") + cvtToStr(widthMin())
|
|
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScUint()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_uint<") + cvtToStr(widthMin())
|
|
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScBv()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
2009-03-13 19:17:30 +01:00
|
|
|
} else if (widthMin() == 1) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "bool";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
|
|
|
|
|
return "uint8_t";
|
|
|
|
|
} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
|
|
|
|
|
return "uint16_t";
|
|
|
|
|
} else {
|
|
|
|
|
return "uint32_t";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "vluint64_t";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 03:09:55 +01:00
|
|
|
AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
|
|
|
|
// See if this is a SC assignment; if so return that type
|
|
|
|
|
// Historically sc variables are identified by a variable
|
|
|
|
|
// attribute. TODO it would better be a data type attribute.
|
2018-02-02 03:32:58 +01:00
|
|
|
if (AstVar* anodep = VN_CAST(nodep, Var)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (anodep->isSc()) {
|
|
|
|
|
return anodep;
|
|
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep, VarRef)) {
|
|
|
|
|
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
|
|
|
|
|
return VN_CAST(nodep, VarRef)->varp();
|
|
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep, ArraySel)) {
|
|
|
|
|
if (nodep->op1p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op1p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op2p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op2p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op3p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op3p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op4p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
|
|
|
|
|
}
|
2015-02-26 03:09:55 +01:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2015-02-26 03:09:55 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class AstNodeDType::CTypeRecursed final {
|
2020-10-17 22:48:11 +02:00
|
|
|
public:
|
|
|
|
|
string m_type; // The base type, e.g.: "Foo_t"s
|
|
|
|
|
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
|
|
|
|
|
string render(const string& name, bool isRef) const {
|
|
|
|
|
string out;
|
|
|
|
|
out += m_type;
|
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
|
|
|
if (!name.empty()) out += " ";
|
|
|
|
|
if (isRef) {
|
|
|
|
|
if (!m_dims.empty()) out += "(";
|
|
|
|
|
out += "&";
|
|
|
|
|
out += name;
|
|
|
|
|
if (!m_dims.empty()) out += ")";
|
|
|
|
|
} else {
|
|
|
|
|
out += name;
|
|
|
|
|
}
|
2020-10-17 22:48:11 +02:00
|
|
|
out += m_dims;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const {
|
2021-06-21 00:32:57 +02:00
|
|
|
const CTypeRecursed info = cTypeRecurse(false);
|
2020-10-17 22:48:11 +02:00
|
|
|
return info.render(name, isRef);
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 03:40:14 +01:00
|
|
|
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
2021-03-13 18:32:35 +01:00
|
|
|
// Legacy compound argument currently just passed through and unused
|
2020-10-17 22:48:11 +02:00
|
|
|
CTypeRecursed info;
|
|
|
|
|
|
|
|
|
|
const AstNodeDType* dtypep = this->skipRefp();
|
|
|
|
|
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
|
|
|
|
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
|
|
|
|
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlQueue<" + sub.m_type + ">";
|
|
|
|
|
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlQueue<" + sub.m_type;
|
|
|
|
|
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
|
|
|
|
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
|
|
|
|
info.m_type += ">";
|
|
|
|
|
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
|
|
|
|
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
|
|
|
|
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
2020-12-13 01:19:16 +01:00
|
|
|
if (adtypep->isCompound()) compound = true;
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
2021-03-13 18:32:35 +01:00
|
|
|
info.m_type = "VlUnpacked<" + sub.m_type;
|
|
|
|
|
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
|
|
|
|
|
info.m_type += ">";
|
2020-10-17 22:48:11 +02:00
|
|
|
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
|
|
|
|
|
// We don't print msb()/lsb() as multidim packed would require recursion,
|
|
|
|
|
// and may confuse users as C++ data is stored always with bit 0 used
|
|
|
|
|
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
|
|
|
|
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
|
|
|
|
|
: "";
|
|
|
|
|
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
|
|
|
|
|
info.m_type = "const char*";
|
|
|
|
|
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
|
|
|
|
|
info.m_type = "const VerilatedScope*";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isDouble()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "double";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isString()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "std::string";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isMTaskState()) {
|
|
|
|
|
info.m_type = "VlMTaskVertex";
|
2020-10-17 22:48:11 +02:00
|
|
|
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
|
|
|
|
info.m_type = "CData" + bitvec;
|
|
|
|
|
} else if (dtypep->widthMin() <= 16) {
|
|
|
|
|
info.m_type = "SData" + bitvec;
|
|
|
|
|
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
|
|
|
|
info.m_type = "IData" + bitvec;
|
|
|
|
|
} else if (dtypep->isQuad()) {
|
|
|
|
|
info.m_type = "QData" + bitvec;
|
|
|
|
|
} else if (dtypep->isWide()) {
|
2021-03-13 18:32:35 +01:00
|
|
|
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + ">" + bitvec;
|
2020-10-17 22:48:11 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-15 03:49:22 +01:00
|
|
|
uint32_t AstNodeDType::arrayUnpackedElements() {
|
2019-05-19 22:13:13 +02:00
|
|
|
uint32_t entries = 1;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeDType* dtypep = this; dtypep;) {
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2018-02-02 03:32:58 +01:00
|
|
|
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
entries *= adtypep->elementsConst();
|
|
|
|
|
dtypep = adtypep->subDTypep();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstBasicDType - nothing below, 1
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return entries;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
2010-04-10 02:43:25 +02:00
|
|
|
// How many array dimensions (packed,unpacked) does this Var have?
|
|
|
|
|
uint32_t packed = 0;
|
|
|
|
|
uint32_t unpacked = 0;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeDType* dtypep = this; dtypep;) {
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2018-02-02 03:32:58 +01:00
|
|
|
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(adtypep, PackArrayDType)) {
|
|
|
|
|
++packed;
|
|
|
|
|
} else {
|
|
|
|
|
++unpacked;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = adtypep->subDTypep();
|
|
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
unpacked++;
|
|
|
|
|
dtypep = qdtypep->subDTypep();
|
|
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(dtypep, StructDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
packed++;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
2021-03-13 00:17:49 +01:00
|
|
|
return std::make_pair(packed, unpacked);
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
2012-04-29 17:34:25 +02:00
|
|
|
|
|
|
|
|
int AstNodeDType::widthPow2() const {
|
|
|
|
|
// I.e. width 30 returns 32, width 32 returns 32.
|
|
|
|
|
uint32_t width = this->width();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int p2 = 30; p2 >= 0; p2--) {
|
|
|
|
|
if (width > (1UL << p2)) return (1UL << (p2 + 1));
|
2012-04-29 17:34:25 +02:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2010-01-19 16:52:11 +01:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
/// What is the base variable (or const) this dereferences?
|
2021-03-13 19:04:13 +01:00
|
|
|
AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
2009-10-25 21:53:55 +01:00
|
|
|
// Else AstArraySel etc; search for the base
|
|
|
|
|
while (nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(nodep, ArraySel)) {
|
|
|
|
|
nodep = VN_CAST(nodep, ArraySel)->fromp();
|
|
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, Sel)) {
|
|
|
|
|
nodep = VN_CAST(nodep, Sel)->fromp();
|
|
|
|
|
continue;
|
2021-03-13 19:04:13 +01:00
|
|
|
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
|
|
|
|
nodep = VN_CAST(nodep, MemberSel)->fromp();
|
|
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-03-14 00:47:36 +01:00
|
|
|
// AstNodeSelPre stashes the associated variable under an ATTROF
|
|
|
|
|
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
2020-04-15 13:58:34 +02:00
|
|
|
else if (VN_IS(nodep, AttrOf)) {
|
|
|
|
|
nodep = VN_CAST(nodep, AttrOf)->fromp();
|
|
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, NodePreSel)) {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_CAST(nodep, NodePreSel)->attrp()) {
|
2019-03-14 00:47:36 +01:00
|
|
|
nodep = VN_CAST(nodep, NodePreSel)->attrp();
|
|
|
|
|
} else {
|
2020-12-08 00:45:54 +01:00
|
|
|
nodep = VN_CAST(nodep, NodePreSel)->fromp();
|
2019-03-14 00:47:36 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
break;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 03:33:05 +02:00
|
|
|
const char* AstJumpBlock::broken() const {
|
|
|
|
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-05-07 03:33:05 +02:00
|
|
|
}
|
|
|
|
|
void AstJumpBlock::cloneRelink() {
|
|
|
|
|
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
const char* AstScope::broken() const {
|
|
|
|
|
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
|
|
|
|
|
BROKEN_RTN(!m_modp);
|
|
|
|
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void AstScope::cloneRelink() {
|
2016-11-09 03:16:22 +01:00
|
|
|
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
|
|
|
|
|
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
|
2018-10-15 00:39:33 +02:00
|
|
|
if (m_modp && static_cast<AstNode*>(m_modp)->clonep()) {
|
|
|
|
|
static_cast<AstNode*>(m_modp)->clonep();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
string AstScope::nameDotless() const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out = shortName();
|
2006-08-26 13:35:28 +02:00
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
2009-12-05 16:38:49 +01:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-17 01:27:18 +02:00
|
|
|
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
out += textp->text();
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
// TOP will be replaced by top->name()
|
2019-05-19 22:13:13 +02:00
|
|
|
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
|
|
|
|
|
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
|
|
|
|
|
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
2009-12-05 16:38:49 +01:00
|
|
|
return AstNode::prettyName(out);
|
|
|
|
|
}
|
2015-06-17 01:27:18 +02:00
|
|
|
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
out += textp->text();
|
2014-07-22 02:55:52 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
|
|
|
|
|
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
|
|
|
|
|
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
2014-07-22 02:55:52 +02:00
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
|
|
|
|
while ((pos = out.find("__DOT__")) != string::npos) out.replace(pos, 7, "__");
|
2014-07-22 02:55:52 +02:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasClocked() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2020-07-05 19:13:03 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isClocked()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasSettle() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2020-07-05 19:13:03 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isSettle()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasInitial() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2020-07-05 19:13:03 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isInitial()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasCombo() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2020-07-05 19:13:03 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isCombo()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstTypeTable::AstTypeTable(FileLine* fl)
|
|
|
|
|
: ASTGEN_SUPER_TypeTable(fl) {
|
|
|
|
|
for (int i = 0; i < AstBasicDTypeKwd::_ENUM_MAX; ++i) m_basicps[i] = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-29 16:14:13 +02:00
|
|
|
void AstTypeTable::clearCache() {
|
|
|
|
|
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
|
|
|
|
// Just clear out the maps; the search functions will be used to rebuild the map
|
2020-11-11 04:10:38 +01:00
|
|
|
for (auto& itr : m_basicps) itr = nullptr;
|
2012-04-29 16:14:13 +02:00
|
|
|
m_detailedMap.clear();
|
|
|
|
|
// Clear generic()'s so dead detection will work
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
|
|
|
|
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstTypeTable::repairCache() {
|
|
|
|
|
// After we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
|
|
|
|
clearCache();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
2018-02-02 03:32:58 +01:00
|
|
|
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
(void)findInsertSameDType(bdtypep);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-01 17:52:48 +01:00
|
|
|
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_voidp)) {
|
|
|
|
|
AstVoidDType* newp = new AstVoidDType(fl);
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
m_voidp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_voidp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 16:56:07 +01:00
|
|
|
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_queueIndexp)) {
|
|
|
|
|
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
m_queueIndexp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_queueIndexp;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-29 16:14:13 +02:00
|
|
|
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
|
|
|
|
|
if (m_basicps[kwd]) return m_basicps[kwd];
|
|
|
|
|
//
|
|
|
|
|
AstBasicDType* new1p = new AstBasicDType(fl, kwd);
|
|
|
|
|
// Because the detailed map doesn't update this map,
|
|
|
|
|
// check the detailed map for this same node
|
|
|
|
|
// Also adds this new node to the detailed map
|
|
|
|
|
AstBasicDType* newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
//
|
|
|
|
|
m_basicps[kwd] = newp;
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width,
|
2020-04-20 03:19:09 +02:00
|
|
|
int widthMin, VSigning numeric) {
|
2013-01-17 13:16:19 +01:00
|
|
|
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
|
2012-04-29 16:14:13 +02:00
|
|
|
AstBasicDType* newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 20:55:46 +02:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
|
|
|
|
|
const VNumRange& range, int widthMin,
|
|
|
|
|
VSigning numeric) {
|
2013-01-17 02:58:48 +01:00
|
|
|
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
|
|
|
|
AstBasicDType* newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2013-01-17 02:58:48 +01:00
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-29 16:14:13 +02:00
|
|
|
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
|
|
|
|
nodep->nrange());
|
2012-04-29 16:14:13 +02:00
|
|
|
DetailedMap& mapr = m_detailedMap;
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = mapr.find(key);
|
2012-04-29 16:14:13 +02:00
|
|
|
if (it != mapr.end()) return it->second;
|
2020-12-19 00:24:47 +01:00
|
|
|
mapr.emplace(key, nodep);
|
2012-04-29 16:14:13 +02:00
|
|
|
nodep->generic(true);
|
|
|
|
|
// No addTypesp; the upper function that called new() is responsible for adding
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstConstPool::AstConstPool(FileLine* fl)
|
|
|
|
|
: ASTGEN_SUPER_ConstPool(fl)
|
|
|
|
|
, m_modp{new AstModule(fl, "@CONST-POOL@")}
|
|
|
|
|
, m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} {
|
|
|
|
|
addOp1p(m_modp);
|
|
|
|
|
m_modp->addStmtp(m_scopep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
|
|
|
|
|
FileLine* const fl = initp->fileline();
|
|
|
|
|
AstVar* const varp = new AstVar(fl, AstVarType::MODULETEMP, name, initp->dtypep());
|
|
|
|
|
varp->isConst(true);
|
|
|
|
|
varp->isStatic(true);
|
|
|
|
|
varp->valuep(initp->cloneTree(false));
|
|
|
|
|
m_modp->addStmtp(varp);
|
|
|
|
|
AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp);
|
|
|
|
|
m_scopep->addVarp(varScopep);
|
|
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
|
|
|
|
|
// Unpacked array initializers must have equivalent values
|
|
|
|
|
// Note, sadly we can't just call ap->sameTree(pb), because both:
|
|
|
|
|
// - the dtypes might be different instances
|
|
|
|
|
// - the default/inititem children might be in different order yet still yield the same table
|
|
|
|
|
// See note in AstInitArray::same about the same. This function instead compares by initializer
|
|
|
|
|
// value, rather than by tree structure.
|
|
|
|
|
const AstUnpackArrayDType* const aDTypep = VN_CAST(ap->dtypep(), UnpackArrayDType);
|
|
|
|
|
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
|
|
|
|
|
UASSERT_STATIC(aDTypep, "Bad type in array initializer");
|
|
|
|
|
UASSERT_STATIC(bDTypep, "Bad type in array initializer");
|
|
|
|
|
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) { // Element types differ
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!aDTypep->rangep()->sameTree(bDTypep->rangep())) { // Ranges differ
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Compare initializer arrays by value. Note this is only called when they hash the same,
|
|
|
|
|
// so they likely run at most once per call to 'AstConstPool::findTable'.
|
|
|
|
|
const uint32_t size = aDTypep->elementsConst();
|
|
|
|
|
for (uint32_t n = 0; n < size; ++n) {
|
|
|
|
|
const AstNode* const valAp = ap->getIndexDefaultedValuep(n);
|
|
|
|
|
const AstNode* const valBp = bp->getIndexDefaultedValuep(n);
|
|
|
|
|
if (!valAp->sameTree(valBp)) { return false; }
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
|
|
|
|
|
AstNode* const defaultp = initp->defaultp();
|
|
|
|
|
// Verify initializer is well formed
|
|
|
|
|
UASSERT_OBJ(VN_IS(initp->dtypep(), UnpackArrayDType), initp,
|
|
|
|
|
"Const pool table must have AstUnpackArrayDType dtype");
|
|
|
|
|
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
|
|
|
|
|
"Const pool table default must be Const");
|
|
|
|
|
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
|
|
|
|
|
AstNode* const valuep = VN_CAST(nodep, InitItem)->valuep();
|
|
|
|
|
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
|
|
|
|
|
}
|
|
|
|
|
// Try to find an existing table with the same content
|
|
|
|
|
const uint32_t hash = V3Hasher::uncachedHash(initp).value();
|
|
|
|
|
const auto& er = m_tables.equal_range(hash);
|
|
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
|
|
|
|
const AstInitArray* const init2p = VN_CAST(varScopep->varp()->valuep(), InitArray);
|
|
|
|
|
if (sameInit(initp, init2p)) {
|
|
|
|
|
return varScopep; // Found identical table
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such table yet, create it.
|
|
|
|
|
string name = "TABLE_";
|
|
|
|
|
name += cvtToHex(hash);
|
|
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
|
|
|
|
m_tables.emplace(hash, varScopep);
|
|
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sameInit(const AstConst* ap, const AstConst* bp) {
|
|
|
|
|
// Similarly to the AstInitArray comparison, we ignore the dtype instance, so long as they
|
|
|
|
|
// are compatible. For now, we assume the dtype is not relevant, as we only call this from
|
|
|
|
|
// V3Prelim which is a late pass.
|
|
|
|
|
// Compare initializers by value. This checks widths as well.
|
|
|
|
|
return ap->num().isCaseEq(bp->num());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
|
|
|
|
|
// Try to find an existing constant with the same value
|
|
|
|
|
const uint32_t hash = initp->num().toHash().value();
|
|
|
|
|
const auto& er = m_consts.equal_range(hash);
|
|
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
|
|
|
|
const AstConst* const init2p = VN_CAST(varScopep->varp()->valuep(), Const);
|
|
|
|
|
if (sameInit(initp, init2p)
|
|
|
|
|
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
|
|
|
|
|
return varScopep; // Found identical constant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such constant yet, create it.
|
|
|
|
|
string name = "CONST_";
|
|
|
|
|
name += cvtToHex(hash);
|
|
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
|
|
|
|
m_consts.emplace(hash, varScopep);
|
|
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-09 02:42:45 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Special walking tree inserters
|
|
|
|
|
|
|
|
|
|
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt");
|
2009-10-09 02:42:45 +02:00
|
|
|
// Look up; virtual call will find where to put it
|
|
|
|
|
this->backp()->addBeforeStmt(newp, this);
|
|
|
|
|
}
|
|
|
|
|
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt");
|
2009-10-09 02:42:45 +02:00
|
|
|
// Look up; virtual call will find where to put it
|
|
|
|
|
this->backp()->addNextStmt(newp, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) {
|
|
|
|
|
// Insert newp before current node
|
|
|
|
|
this->addHereThisAsNext(newp);
|
|
|
|
|
}
|
|
|
|
|
void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
|
|
|
|
|
// Insert newp after current node
|
|
|
|
|
this->addNextHere(newp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
|
|
|
|
|
// Special, as statements need to be put in different places
|
|
|
|
|
// Belowp is how we came to recurse up to this point
|
2019-05-19 22:13:13 +02:00
|
|
|
// Preconditions insert first just before themselves (the normal rule
|
|
|
|
|
// for other statement types)
|
2009-10-09 02:42:45 +02:00
|
|
|
if (belowp == precondsp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Must have been first statement in precondsp list, so newp is new first statement
|
|
|
|
|
belowp->addHereThisAsNext(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == condp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Goes before condition, IE in preconditions
|
|
|
|
|
addPrecondsp(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == bodysp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Was first statement in body, so new front
|
|
|
|
|
belowp->addHereThisAsNext(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
belowp->v3fatalSrc("Doesn't look like this was really under the while");
|
2009-10-09 02:42:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
|
|
|
|
|
// Special, as statements need to be put in different places
|
|
|
|
|
// Belowp is how we came to recurse up to this point
|
2019-05-19 22:13:13 +02:00
|
|
|
// Preconditions insert first just before themselves (the normal rule
|
|
|
|
|
// for other statement types)
|
2009-10-09 02:42:45 +02:00
|
|
|
if (belowp == precondsp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Next in precond list
|
|
|
|
|
belowp->addNextHere(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == condp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Becomes first statement in body, body may have been empty
|
|
|
|
|
if (bodysp()) {
|
|
|
|
|
bodysp()->addHereThisAsNext(newp);
|
|
|
|
|
} else {
|
|
|
|
|
addBodysp(newp);
|
|
|
|
|
}
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == bodysp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Next statement in body
|
|
|
|
|
belowp->addNextHere(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
belowp->v3fatalSrc("Doesn't look like this was really under the while");
|
2009-10-09 02:42:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Per-type Debugging
|
|
|
|
|
|
2020-05-23 19:31:30 +02:00
|
|
|
// Render node address for dumps. By default this is just the address
|
|
|
|
|
// printed as hex, but with --dump-tree-addrids we map addresses to short
|
|
|
|
|
// strings with a bijection to aid human readability. Observe that this might
|
|
|
|
|
// not actually be a unique identifier as the address can get reused after a
|
|
|
|
|
// node has been freed.
|
|
|
|
|
static std::string nodeAddr(const AstNode* nodep) {
|
|
|
|
|
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNode::dump(std::ostream& str) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << typeName() << " "
|
2020-05-23 19:31:30 +02:00
|
|
|
<< nodeAddr(this)
|
|
|
|
|
//<< " " << nodeAddr(m_backp)
|
2020-04-15 13:58:34 +02:00
|
|
|
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
|
2020-05-30 16:08:30 +02:00
|
|
|
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
|
|
|
|
|
<< fileline()->firstColumnLetters() << "}";
|
2020-05-23 19:31:30 +02:00
|
|
|
if (user1p()) str << " u1=" << nodeAddr(user1p());
|
|
|
|
|
if (user2p()) str << " u2=" << nodeAddr(user2p());
|
|
|
|
|
if (user3p()) str << " u3=" << nodeAddr(user3p());
|
|
|
|
|
if (user4p()) str << " u4=" << nodeAddr(user4p());
|
|
|
|
|
if (user5p()) str << " u5=" << nodeAddr(user5p());
|
2012-04-29 16:14:13 +02:00
|
|
|
if (hasDType()) {
|
2018-10-14 22:25:36 +02:00
|
|
|
// Final @ so less likely to by accident read it as a nodep
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dtypep() == this) {
|
|
|
|
|
str << " @dt=this@";
|
|
|
|
|
} else {
|
2020-05-23 19:31:30 +02:00
|
|
|
str << " @dt=" << nodeAddr(dtypep()) << "@";
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-02-22 03:25:21 +01:00
|
|
|
if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // V3Broken will throw an error
|
2020-05-23 19:31:30 +02:00
|
|
|
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (name() != "") {
|
|
|
|
|
if (VN_IS(this, Const)) {
|
|
|
|
|
str << " " << name(); // Already quoted
|
|
|
|
|
} else {
|
|
|
|
|
str << " " << V3OutFormatter::quoteNameControls(name());
|
|
|
|
|
}
|
2014-11-28 21:01:50 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2009-05-08 00:28:05 +02:00
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstAlways::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeProcedure::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
|
2013-05-01 04:55:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstAttrOf::dump(std::ostream& str) const {
|
2009-05-08 00:28:05 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << attrType().ascii() << "]";
|
2009-05-08 00:28:05 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstBasicDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " kwd=" << keyword().ascii();
|
|
|
|
|
if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]";
|
2009-11-02 14:06:04 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstBasicDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << keyword().ascii();
|
|
|
|
|
if (isRanged() && !rangep() && keyword().width() <= 1) {
|
|
|
|
|
os << "[" << left() << ":" << right() << "]";
|
|
|
|
|
}
|
|
|
|
|
return os.str();
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
|
|
|
|
|
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCCast::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeUniop::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " sz" << size();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCell::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (recursive()) str << " [RECURSIVE]";
|
|
|
|
|
if (modp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
modp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED:" << modName();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCellInline::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << origModName();
|
2020-11-12 01:00:10 +01:00
|
|
|
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
const char* AstClassPackage::broken() const {
|
|
|
|
|
BROKEN_BASE_RTN(AstNodeModule::broken());
|
|
|
|
|
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
void AstClass::insertCache(AstNode* nodep) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool doit
|
|
|
|
|
= (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
|
|
|
|
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
|
2020-08-23 01:46:21 +02:00
|
|
|
if (doit) {
|
2020-04-05 15:30:23 +02:00
|
|
|
if (m_members.find(nodep->name()) != m_members.end()) {
|
|
|
|
|
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
|
|
|
|
|
} else {
|
2020-12-19 00:24:47 +01:00
|
|
|
m_members.emplace(nodep->name(), nodep);
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstClass::repairCache() {
|
|
|
|
|
clearCache();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); }
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
2020-11-29 04:01:11 +01:00
|
|
|
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
|
|
|
|
|
// TAIL RECURSIVE
|
|
|
|
|
if (!refClassp || !baseClassp) return false;
|
|
|
|
|
if (refClassp == baseClassp) return true;
|
2020-11-30 00:26:06 +01:00
|
|
|
if (!refClassp->extendsp()) return false;
|
2020-11-29 04:01:11 +01:00
|
|
|
return isClassExtendedFrom(refClassp->extendsp()->classp(), baseClassp);
|
|
|
|
|
}
|
2020-08-24 02:00:39 +02:00
|
|
|
void AstClass::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isExtended()) str << " [EXT]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
AstClass* AstClassExtends::classp() const {
|
|
|
|
|
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
2020-11-26 17:06:59 +01:00
|
|
|
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
|
|
|
|
refp = VN_CAST(childDTypep(), ClassRefDType);
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
UASSERT_OBJ(refp, this, "class extends non-ref");
|
|
|
|
|
return refp->classp();
|
|
|
|
|
}
|
|
|
|
|
void AstClassRefDType::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (classp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
classp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "class:" << name();
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
2019-12-17 03:43:52 +01:00
|
|
|
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (immediate()) str << " [IMMEDIATE]";
|
2019-12-17 03:43:52 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstDisplay::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
// str<<" "<<displayType().ascii();
|
2008-03-26 15:58:30 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstEnumItemRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (itemp()) {
|
|
|
|
|
itemp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2009-12-27 14:29:55 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstIfaceRefDType::dump(std::ostream& str) const {
|
2013-05-28 03:39:19 +02:00
|
|
|
this->AstNode::dump(str);
|
2021-02-22 03:25:21 +01:00
|
|
|
if (cellName() != "") str << " cell=" << cellName();
|
|
|
|
|
if (ifaceName() != "") str << " if=" << ifaceName();
|
|
|
|
|
if (modportName() != "") str << " mp=" << modportName();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (cellp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
cellp()->dump(str);
|
|
|
|
|
} else if (ifacep()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
ifacep()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstIfaceRefDType::dumpSmall(std::ostream& str) const {
|
2013-05-28 03:39:19 +02:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "iface";
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-11-09 21:34:41 +01:00
|
|
|
void AstInitArray::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
int n = 0;
|
|
|
|
|
const AstInitArray::KeyItemMap& mapr = map();
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : mapr) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (n++ > 5) {
|
|
|
|
|
str << " ...";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-12 01:00:10 +01:00
|
|
|
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
2019-11-09 21:34:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstJumpGo::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (labelp()) {
|
|
|
|
|
labelp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2013-02-18 18:15:50 +01:00
|
|
|
}
|
2020-05-07 03:33:05 +02:00
|
|
|
void AstJumpLabel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-05-07 03:33:05 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (blockp()) {
|
|
|
|
|
blockp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-16 02:18:12 +01:00
|
|
|
void AstMemberSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2020-01-16 02:18:12 +01:00
|
|
|
str << " -> ";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2020-01-16 02:18:12 +01:00
|
|
|
}
|
2020-03-07 18:52:11 +01:00
|
|
|
void AstMethodCall::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-03-07 18:52:11 +01:00
|
|
|
if (isStatement()) str << " [STMT]";
|
|
|
|
|
str << " -> ";
|
|
|
|
|
if (taskp()) {
|
|
|
|
|
taskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstModportFTaskRef::dump(std::ostream& str) const {
|
2013-12-21 12:51:15 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isExport()) str << " EXPORT";
|
|
|
|
|
if (isImport()) str << " IMPORT";
|
|
|
|
|
if (ftaskp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
ftaskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-12-21 12:51:15 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstModportVarRef::dump(std::ostream& str) const {
|
2013-05-28 03:39:19 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (direction().isAny()) str << " " << direction();
|
|
|
|
|
if (varp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPin::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (modVarp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
modVarp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
if (svImplicit()) str << " [.SV]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstPrintTimeScale::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
|
|
|
|
|
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstTime::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTermop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
|
|
|
|
void AstTimeD::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTermop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
|
|
|
|
void AstTimeImport::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeUniop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTypedef::dump(std::ostream& str) const {
|
2014-11-07 13:50:11 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (attrPublic()) str << " [PUBLIC]";
|
2014-11-07 13:50:11 +01:00
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstRange::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeRange::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (littleEndian()) str << " [LITTLE]";
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstRefDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-05-24 20:22:06 +02:00
|
|
|
if (typedefp() || subDTypep()) {
|
2019-10-06 14:20:02 +02:00
|
|
|
static bool s_recursing = false;
|
2019-01-12 15:33:57 +01:00
|
|
|
if (!s_recursing) { // Prevent infinite dump if circular typedefs
|
|
|
|
|
s_recursing = true;
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2021-07-08 01:42:49 +02:00
|
|
|
if (const auto subp = typedefp()) {
|
|
|
|
|
subp->dump(str);
|
|
|
|
|
} else if (const auto subp = subDTypep()) {
|
|
|
|
|
subp->dump(str);
|
2020-05-24 20:22:06 +02:00
|
|
|
}
|
2019-01-12 15:33:57 +01:00
|
|
|
s_recursing = false;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
2019-01-12 15:33:57 +01:00
|
|
|
}
|
2009-11-07 05:16:06 +01:00
|
|
|
}
|
2019-12-17 04:46:09 +01:00
|
|
|
void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
2012-07-29 16:16:20 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (packed()) str << " [PACKED]";
|
|
|
|
|
if (isFourstate()) str << " [4STATE]";
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (generic()) str << " [GENERIC]";
|
2012-04-29 16:14:13 +02:00
|
|
|
if (AstNodeDType* dtp = virtRefDTypep()) {
|
2020-05-23 19:31:30 +02:00
|
|
|
str << " refdt=" << nodeAddr(dtp);
|
2019-05-19 22:13:13 +02:00
|
|
|
dtp->dumpSmall(str);
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeDType::dumpSmall(std::ostream& str) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "")
|
|
|
|
|
<< (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : "");
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!isDouble() && !isString()) str << "w" << (widthSized() ? "" : "u") << width();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!widthSized()) str << "/" << widthMin();
|
|
|
|
|
str << ")";
|
2012-02-20 15:55:20 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
|
2013-01-13 20:30:56 +01:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-12-13 01:19:16 +01:00
|
|
|
if (auto* adtypep = VN_CAST_CONST(this, UnpackArrayDType)) {
|
|
|
|
|
// uc = packed compound object, u = unpacked POD
|
|
|
|
|
str << (adtypep->isCompound() ? "uc" : "u");
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-12-13 01:19:16 +01:00
|
|
|
str << "p";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
str << declRange();
|
2013-01-13 20:30:56 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeArrayDType::dump(std::ostream& str) const {
|
2013-01-13 20:30:56 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-12-13 01:19:16 +01:00
|
|
|
if (isCompound()) str << " [COMPOUND]";
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " " << declRange();
|
2013-01-13 20:30:56 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstPackArrayDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
2021-07-08 01:42:49 +02:00
|
|
|
if (const auto subp = subDTypep()) os << subp->prettyDTypeName();
|
|
|
|
|
os << declRange();
|
2020-01-26 19:21:25 +01:00
|
|
|
return os.str();
|
|
|
|
|
}
|
|
|
|
|
string AstUnpackArrayDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
string ranges = cvtToStr(declRange());
|
|
|
|
|
// Unfortunately we need a single $ for the first unpacked, and all
|
|
|
|
|
// dimensions shown in "reverse" order
|
|
|
|
|
AstNodeDType* subp = subDTypep()->skipRefp();
|
|
|
|
|
while (AstUnpackArrayDType* adtypep = VN_CAST(subp, UnpackArrayDType)) {
|
|
|
|
|
ranges += cvtToStr(adtypep->declRange());
|
|
|
|
|
subp = adtypep->subDTypep()->skipRefp();
|
|
|
|
|
}
|
|
|
|
|
os << subp->prettyDTypeName() << "$" << ranges;
|
|
|
|
|
return os.str();
|
|
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
|
|
|
|
std::vector<AstUnpackArrayDType*> dims;
|
|
|
|
|
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
|
|
|
|
|
dims.push_back(unpackp);
|
|
|
|
|
if (AstNodeDType* subp = unpackp->subDTypep()) {
|
|
|
|
|
unpackp = VN_CAST(subp, UnpackArrayDType);
|
|
|
|
|
} else {
|
|
|
|
|
unpackp = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dims;
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstNetlist::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeModule::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " L" << level();
|
|
|
|
|
if (modPublic()) str << " [P]";
|
|
|
|
|
if (inLibrary()) str << " [LIB]";
|
|
|
|
|
if (dead()) str << " [DEAD]";
|
|
|
|
|
if (recursiveClone()) {
|
|
|
|
|
str << " [RECURSIVE-CLONE]";
|
|
|
|
|
} else if (recursive()) {
|
|
|
|
|
str << " [RECURSIVE]";
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " [" << timeunit() << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPackageExport::dump(std::ostream& str) const {
|
2017-09-21 03:04:59 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << packagep();
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPackageImport::dump(std::ostream& str) const {
|
2009-11-10 01:07:59 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << packagep();
|
2009-11-10 01:07:59 +01:00
|
|
|
}
|
2020-11-07 17:56:24 +01:00
|
|
|
void AstPatMember::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isDefault()) str << " [DEFAULT]";
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTriop::dump(str);
|
2013-01-15 03:49:22 +01:00
|
|
|
if (declRange().ranged()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " decl" << declRange() << "]";
|
|
|
|
|
if (declElWidth() != 1) str << "/" << declElWidth();
|
2013-01-15 03:49:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSliceSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTriop::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (declRange().ranged()) str << " decl" << declRange();
|
2017-11-23 20:55:32 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstMTaskBody::dump(std::ostream& str) const {
|
2018-07-23 02:54:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " ";
|
2018-07-23 02:54:28 +02:00
|
|
|
m_execMTaskp->dump(str);
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTypeTable::dump(std::ostream& str) const {
|
2012-04-29 16:14:13 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (AstBasicDType* subnodep = m_basicps[i]) {
|
2020-11-19 03:03:23 +01:00
|
|
|
str << '\n'; // Newline from caller, so newline first
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
|
|
|
|
|
str << " -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
subnodep->dump(str);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
{
|
2019-10-20 17:49:41 +02:00
|
|
|
const DetailedMap& mapr = m_detailedMap;
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : mapr) {
|
|
|
|
|
AstBasicDType* dtypep = itr.second;
|
2020-11-19 03:03:23 +01:00
|
|
|
str << '\n'; // Newline from caller, so newline first
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "\t\tdetailed -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep->dump(str);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
// Note get newline from caller too.
|
|
|
|
|
}
|
2019-12-01 17:52:48 +01:00
|
|
|
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-11-12 01:00:10 +01:00
|
|
|
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstAssocArrayDType::prettyDTypeName() const {
|
|
|
|
|
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
|
|
|
|
}
|
2020-03-07 16:24:27 +01:00
|
|
|
void AstDynArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[]";
|
2020-03-07 16:24:27 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
string AstDynArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[]"; }
|
2019-12-01 18:35:49 +01:00
|
|
|
void AstQueueDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[queue]";
|
2019-12-01 18:35:49 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstQueueDType::prettyDTypeName() const {
|
|
|
|
|
string str = subDTypep()->prettyDTypeName() + "[$";
|
|
|
|
|
if (boundConst()) str += ":" + cvtToStr(boundConst());
|
|
|
|
|
return str + "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
2017-12-17 22:28:58 +01:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[]";
|
2017-12-17 22:28:58 +01:00
|
|
|
}
|
2019-12-01 17:52:48 +01:00
|
|
|
void AstVoidDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "void";
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVarScope::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isCircular()) str << " [CIRC]";
|
|
|
|
|
if (varp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-25 03:28:04 +01:00
|
|
|
void AstNodeVarRef::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeMath::dump(str);
|
2020-11-25 03:56:03 +01:00
|
|
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
2020-11-01 22:59:23 +01:00
|
|
|
str << " " << access().arrow() << " ";
|
2020-11-25 03:28:04 +01:00
|
|
|
}
|
|
|
|
|
void AstVarXRef::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeVarRef::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << ".=" << dotted() << " ";
|
|
|
|
|
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
|
|
|
|
|
if (varScopep()) {
|
|
|
|
|
varScopep()->dump(str);
|
|
|
|
|
} else if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2012-07-20 03:18:39 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVarRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeVarRef::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varScopep()) {
|
|
|
|
|
varScopep()->dump(str);
|
|
|
|
|
} else if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVar::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isSc()) str << " [SC]";
|
|
|
|
|
if (isPrimaryIO()) str << (isInoutish() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]"));
|
|
|
|
|
if (isIO()) str << " " << direction().ascii();
|
|
|
|
|
if (isConst()) str << " [CONST]";
|
|
|
|
|
if (isPullup()) str << " [PULLUP]";
|
|
|
|
|
if (isPulldown()) str << " [PULLDOWN]";
|
|
|
|
|
if (isUsedClock()) str << " [CLK]";
|
|
|
|
|
if (isSigPublic()) str << " [P]";
|
2021-01-05 20:26:01 +01:00
|
|
|
if (isLatched()) str << " [LATCHED]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isUsedLoopIdx()) str << " [LOOP]";
|
|
|
|
|
if (attrClockEn()) str << " [aCLKEN]";
|
|
|
|
|
if (attrIsolateAssign()) str << " [aISO]";
|
|
|
|
|
if (attrFileDescr()) str << " [aFD]";
|
|
|
|
|
if (isFuncReturn()) {
|
|
|
|
|
str << " [FUNCRTN]";
|
|
|
|
|
} else if (isFuncLocal()) {
|
|
|
|
|
str << " [FUNC]";
|
|
|
|
|
}
|
|
|
|
|
if (isDpiOpenArray()) str << " [DPIOPENA]";
|
|
|
|
|
if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] ";
|
2020-04-26 18:45:06 +02:00
|
|
|
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " " << varType();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-12 01:00:10 +01:00
|
|
|
void AstScope::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
|
|
|
|
|
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
|
|
|
|
|
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSenTree::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isMulti()) str << " [MULTI]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSenItem::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << edgeType().ascii() << "]";
|
2006-12-21 22:53:51 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstParseRef::dump(std::ostream& str) const {
|
2006-12-21 22:53:51 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << expect().ascii() << "]";
|
2012-12-31 23:05:13 +01:00
|
|
|
}
|
2020-07-11 16:29:15 +02:00
|
|
|
void AstClassOrPackageRef::dump(std::ostream& str) const {
|
2012-12-31 23:05:13 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-12-05 22:23:20 +01:00
|
|
|
if (classOrPackageNodep()) str << " cpkg=" << nodeAddr(classOrPackageNodep());
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2020-12-05 22:23:20 +01:00
|
|
|
if (classOrPackageNodep()) {
|
|
|
|
|
classOrPackageNodep()->dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-05-23 18:44:15 +02:00
|
|
|
void AstDot::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
2020-07-12 02:32:27 +02:00
|
|
|
if (colon()) str << " [::]";
|
2020-05-23 18:44:15 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstActive::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " => ";
|
|
|
|
|
if (sensesp()) {
|
|
|
|
|
sensesp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-11-25 03:56:03 +01:00
|
|
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2021-02-22 03:25:21 +01:00
|
|
|
if (dotted() != "") str << ".=" << dotted() << " ";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (taskp()) {
|
|
|
|
|
taskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeFTask::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (classMethod()) str << " [METHOD]";
|
|
|
|
|
if (taskPublic()) str << " [PUBLIC]";
|
|
|
|
|
if (prototype()) str << " [PROTOTYPE]";
|
|
|
|
|
if (dpiImport()) str << " [DPII]";
|
|
|
|
|
if (dpiExport()) str << " [DPIX]";
|
|
|
|
|
if (dpiOpenChild()) str << " [DPIOPENCHILD]";
|
|
|
|
|
if (dpiOpenParent()) str << " [DPIOPENPARENT]";
|
|
|
|
|
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-23 03:31:40 +02:00
|
|
|
void AstNodeBlock::dump(std::ostream& str) const {
|
2009-10-12 02:50:31 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (unnamed()) str << " [UNNAMED]";
|
2020-04-23 03:31:40 +02:00
|
|
|
}
|
|
|
|
|
void AstBegin::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (generate()) str << " [GEN]";
|
|
|
|
|
if (genforp()) str << " [GENFOR]";
|
|
|
|
|
if (implied()) str << " [IMPLIED]";
|
2009-10-12 02:50:31 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCoverDecl::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-06-01 15:08:50 +02:00
|
|
|
if (!page().empty()) str << " page=" << page();
|
|
|
|
|
if (!linescov().empty()) str << " lc=" << linescov();
|
2008-12-12 21:34:02 +01:00
|
|
|
if (this->dataDeclNullp()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
this->dataDeclNullp()->dump(str);
|
2008-12-12 21:34:02 +01:00
|
|
|
} else {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (binNum()) str << " bin" << std::dec << binNum();
|
2008-12-12 21:34:02 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCoverInc::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (declp()) {
|
|
|
|
|
declp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-23 03:31:40 +02:00
|
|
|
void AstFork::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (!joinType().join()) str << " [" << joinType() << "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTraceInc::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (declp()) {
|
|
|
|
|
declp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeText::dump(std::ostream& str) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
string out = text();
|
|
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = out.find('\n')) != string::npos) {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.erase(pos, out.length() - pos);
|
2019-05-19 22:13:13 +02:00
|
|
|
out += "...";
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " \"" << out << "\"";
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
|
2019-09-27 09:44:23 +02:00
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCFile::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeFile::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (source()) str << " [SRC]";
|
|
|
|
|
if (slow()) str << " [SLOW]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCFunc::dump(std::ostream& str) const {
|
2008-08-06 23:09:33 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (slow()) str << " [SLOW]";
|
|
|
|
|
if (pure()) str << " [PURE]";
|
2021-06-16 14:52:37 +02:00
|
|
|
if (isStatic()) str << " [STATIC]";
|
2021-06-10 23:41:33 +02:00
|
|
|
if (dpiExportDispatcher()) str << " [DPIED]";
|
|
|
|
|
if (dpiExportImpl()) str << " [DPIEI]";
|
|
|
|
|
if (dpiImportPrototype()) str << " [DPIIP]";
|
|
|
|
|
if (dpiImportWrapper()) str << " [DPIIW]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isConstructor()) str << " [CTOR]";
|
|
|
|
|
if (isDestructor()) str << " [DTOR]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
2008-08-06 23:09:33 +02:00
|
|
|
}
|
2020-02-01 22:45:11 +01:00
|
|
|
void AstCUse::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << useType() << "]";
|
|
|
|
|
}
|