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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 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"
|
2023-08-07 11:54:30 +02:00
|
|
|
#include "V3Width.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-15 20:43:56 +02:00
|
|
|
#include "V3Ast__gen_macros.h" // Generated by 'astgen'
|
2021-05-22 12:13:02 +02:00
|
|
|
|
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 {
|
2021-10-22 14:56:48 +02:00
|
|
|
return ((m_cellp && m_cellp->modp()) ? VN_AS(m_cellp->modp(), Iface) : m_ifacep);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-13 00:10:52 +01:00
|
|
|
const char* AstNodeFTaskRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_taskp && !m_taskp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstNodeFTaskRef::cloneRelink() {
|
|
|
|
|
if (m_taskp && m_taskp->clonep()) m_taskp = m_taskp->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-28 21:21:58 +01:00
|
|
|
bool AstNodeFTaskRef::isPure() const {
|
|
|
|
|
// TODO: For non-DPI functions we could traverse the AST of function's body to determine
|
|
|
|
|
// pureness.
|
2023-09-08 08:51:19 +02:00
|
|
|
return this->taskp() && this->taskp()->dpiImport() && this->taskp()->dpiPure();
|
2023-02-28 21:21:58 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-12 11:19:21 +02:00
|
|
|
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
const char* AstNodeVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
2021-12-13 00:10:52 +01:00
|
|
|
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->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();
|
2021-12-13 00:10:52 +01:00
|
|
|
if (m_varScopep && m_varScopep->clonep()) m_varScopep = m_varScopep->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 15:33:11 +02:00
|
|
|
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 {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstConst* const constp = VN_AS(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
|
|
|
const char* AstNodeUOrStructDType::broken() const {
|
2023-03-17 02:14:49 +01:00
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
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 {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::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
|
|
|
}
|
2023-09-08 08:51:19 +02:00
|
|
|
bool AstNodeCCall::isPure() const { return funcp()->dpiPure(); }
|
2021-07-13 18:42:17 +02:00
|
|
|
|
2023-08-07 11:54:30 +02:00
|
|
|
AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
|
|
|
|
|
AstNodeExpr* elsep)
|
|
|
|
|
: AstNodeTriop{t, fl, condp, thenp, elsep} {
|
|
|
|
|
UASSERT_OBJ(thenp, this, "No thenp expression");
|
|
|
|
|
UASSERT_OBJ(elsep, this, "No elsep expression");
|
|
|
|
|
if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) {
|
|
|
|
|
// Get the most-deriving class type that both arguments can be casted to.
|
|
|
|
|
AstNodeDType* const commonClassTypep = V3Width::getCommonClassTypep(thenp, elsep);
|
|
|
|
|
UASSERT_OBJ(commonClassTypep, this, "No common base class exists");
|
|
|
|
|
dtypep(commonClassTypep);
|
|
|
|
|
} else {
|
|
|
|
|
dtypeFrom(thenp);
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
2022-09-15 14:10:39 +02:00
|
|
|
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
|
|
|
|
|
AstRange* rangep) {
|
|
|
|
|
// wantwidth=0 means figure it out, but if a widthmin is >=0
|
|
|
|
|
// we allow width 0 so that {{0{x}},y} works properly
|
|
|
|
|
// wantwidthmin=-1: default, use wantwidth if it is non zero
|
|
|
|
|
m.m_keyword = kwd;
|
|
|
|
|
// Implicitness: // "parameter X" is implicit and sized from initial
|
|
|
|
|
// value, "parameter reg x" not
|
|
|
|
|
if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) {
|
|
|
|
|
if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC;
|
|
|
|
|
}
|
|
|
|
|
if (numer == VSigning::NOSIGN) {
|
|
|
|
|
if (keyword().isSigned()) {
|
|
|
|
|
numer = VSigning::SIGNED;
|
|
|
|
|
} else if (keyword().isUnsigned()) {
|
|
|
|
|
numer = VSigning::UNSIGNED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
numeric(numer);
|
|
|
|
|
if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width
|
|
|
|
|
if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false);
|
|
|
|
|
const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth;
|
|
|
|
|
widthForce(wantwidth, wmin);
|
|
|
|
|
} else if (!rangep) { // Set based on keyword properties
|
|
|
|
|
// V3Width will pull from this width
|
|
|
|
|
if (keyword().width() > 1 && !isOpaque()) {
|
|
|
|
|
m.m_nrange.init(keyword().width() - 1, 0, false);
|
|
|
|
|
}
|
|
|
|
|
widthForce(keyword().width(), keyword().width());
|
|
|
|
|
} else {
|
|
|
|
|
widthForce(rangep->elementsConst(),
|
|
|
|
|
rangep->elementsConst()); // Maybe unknown if parameters underneath it
|
|
|
|
|
}
|
2022-09-15 20:43:56 +02:00
|
|
|
this->rangep(rangep);
|
|
|
|
|
this->dtypep(this);
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstBasicDType::cvtRangeConst() {
|
|
|
|
|
if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) {
|
|
|
|
|
m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()};
|
|
|
|
|
rangep()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
|
rangep(nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2023-04-14 12:51:33 +02:00
|
|
|
bool AstBasicDType::same(const AstNode* samep) const {
|
|
|
|
|
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
|
|
|
|
if (!rangep() && !sp->rangep() && m == sp->m) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return m == sp->m && rangep() && rangep()->sameTree(sp->rangep());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEqN{fl, lhsp, rhsp};
|
2019-10-05 01:13:39 +02:00
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEqD{fl, lhsp, rhsp};
|
2014-01-21 03:59:53 +01:00
|
|
|
} else {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEq{fl, lhsp, rhsp};
|
2014-01-21 03:59:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEqN{fl, lhsp, rhsp};
|
2019-10-05 01:13:39 +02:00
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEqD{fl, lhsp, rhsp};
|
2017-05-18 02:15:40 +02:00
|
|
|
} else {
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstEqWild{fl, lhsp, rhsp};
|
2017-05-18 02:15:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-21 03:59:53 +01:00
|
|
|
|
2022-04-10 12:37:41 +02:00
|
|
|
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
|
2021-06-16 13:18:56 +02:00
|
|
|
: ASTGEN_SUPER_ExecGraph(fileline)
|
2022-04-10 12:37:41 +02:00
|
|
|
, m_depGraphp{new V3Graph}
|
|
|
|
|
, m_name{name} {}
|
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
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp,
|
|
|
|
|
AstNodeExpr* rhsp) {
|
|
|
|
|
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp};
|
|
|
|
|
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp};
|
2020-03-31 00:12:50 +02:00
|
|
|
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
|
|
|
|
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstAnd{fileline(), ap, bp};
|
2020-03-31 00:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
2021-11-26 23:55:36 +01:00
|
|
|
const string v = literal.substr(1, literal.find('"', 1) - 1);
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstConst{fl, AstConst::VerilogStringLiteral{}, v};
|
2020-07-02 13:29:52 +02:00
|
|
|
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
|
|
|
|
// This may be a real
|
2021-11-26 23:55:36 +01:00
|
|
|
const double v = VString::parseDouble(literal, &success);
|
2022-11-20 21:06:49 +01:00
|
|
|
if (success) return new AstConst{fl, AstConst::RealDouble{}, v};
|
2020-07-02 13:29:52 +02:00
|
|
|
}
|
|
|
|
|
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;
|
2021-11-26 23:55:36 +01:00
|
|
|
const int v = strtol(literal.c_str(), &endp, 0);
|
2020-07-02 13:29:52 +02:00
|
|
|
if ((v != 0) && (endp[0] == 0)) { // C literal
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstConst{fl, AstConst::Signed32{}, v};
|
2020-07-02 13:29:52 +02:00
|
|
|
} else { // Try a Verilog literal (fatals if not)
|
2022-11-20 21:06:49 +01:00
|
|
|
return new AstConst{fl, AstConst::StringToParse{}, literal.c_str()};
|
2020-07-02 13:29:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
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()
|
2022-11-20 21:06:49 +01:00
|
|
|
: ASTGEN_SUPER_Netlist(new FileLine{FileLine::builtInFilename()})
|
|
|
|
|
, m_typeTablep{new AstTypeTable{fileline()}}
|
|
|
|
|
, m_constPoolp{new AstConstPool{fileline()}} {
|
2021-06-13 16:05:55 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
void AstVar::combineType(VVarType 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.
|
2022-01-02 19:56:40 +01:00
|
|
|
if (type == VVarType::TRIWIRE || type == VVarType::TRI0 || type == VVarType::TRI1) {
|
2018-10-27 23:29:00 +02:00
|
|
|
m_tristate = true;
|
2018-10-04 01:51:05 +02:00
|
|
|
}
|
2022-01-02 19:56:40 +01:00
|
|
|
if (type == VVarType::TRI0) m_isPulldown = true;
|
|
|
|
|
if (type == VVarType::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";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::WIRE) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wire";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::WREAL) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wreal";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::IFACEREF) {
|
2018-12-06 13:12:39 +01:00
|
|
|
return "ifaceref";
|
2023-05-05 19:47:34 +02:00
|
|
|
} else if (dtypep()) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return dtypep()->name();
|
2023-05-05 19:47:34 +02:00
|
|
|
} else {
|
|
|
|
|
return "UNKNOWN";
|
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,
|
2023-08-03 08:52:52 +02:00
|
|
|
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;
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstBasicDType* const bdtypep = basicp();
|
2022-01-02 19:56:40 +01:00
|
|
|
const bool strtype = bdtypep && bdtypep->keyword() == VBasicDTypeKwd::STRING;
|
|
|
|
|
if (bdtypep && bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "VLVT_PTR";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (bdtypep && bdtypep->keyword() == VBasicDTypeKwd::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
|
|
|
//
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstBasicDType* const bdtypep = basicp()) {
|
2017-12-17 22:28:58 +01:00
|
|
|
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
|
2021-10-22 16:15:42 +02:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
2020-05-08 19:22:44 +02:00
|
|
|
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 ";
|
2022-03-05 22:19:53 +01:00
|
|
|
const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef());
|
|
|
|
|
if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble()
|
|
|
|
|
&& !dtypeSkipRefp()->isString()) {
|
|
|
|
|
// Backward compatible type declaration
|
|
|
|
|
if (widthMin() == 1) {
|
|
|
|
|
arg += "bool";
|
|
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
|
|
|
|
arg += "uint32_t";
|
|
|
|
|
} else if (widthMin() <= VL_QUADSIZE) {
|
2022-03-27 21:27:40 +02:00
|
|
|
arg += "uint64_t";
|
2022-03-05 22:19:53 +01:00
|
|
|
} else {
|
|
|
|
|
arg += "uint32_t"; // []'s added later
|
|
|
|
|
}
|
|
|
|
|
if (isWide()) {
|
|
|
|
|
if (forReturn) {
|
|
|
|
|
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
|
|
|
|
|
"make an output of a public task instead");
|
|
|
|
|
}
|
|
|
|
|
arg += " (& " + name();
|
|
|
|
|
arg += ")[" + cvtToStr(widthWords()) + "]";
|
|
|
|
|
} else {
|
|
|
|
|
if (isRef) arg += "&";
|
|
|
|
|
if (named) arg += " " + name();
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2009-12-03 12:55:29 +01:00
|
|
|
} else {
|
2022-03-05 22:19:53 +01:00
|
|
|
// Newer internal-compatible types
|
2022-08-30 05:50:32 +02:00
|
|
|
arg += dtypep()->cType((named ? name() : std::string{}), true, isRef);
|
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"; }
|
2022-07-30 16:01:25 +02:00
|
|
|
virtual string bitLogicVector(const AstVar* /*varp*/, bool isBit) const {
|
2020-11-19 14:02:58 +01:00
|
|
|
return isBit ? "svBitVecVal" : "svLogicVecVal";
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const {
|
|
|
|
|
string type;
|
2022-01-02 19:56:40 +01:00
|
|
|
const VBasicDTypeKwd keyword = varp->basicp()->keyword();
|
2020-12-13 08:05:06 +01:00
|
|
|
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);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const basicp = varp->basicp()) {
|
2020-12-13 08:05:06 +01:00
|
|
|
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 {
|
2022-09-16 12:22:11 +02:00
|
|
|
string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
2023-04-07 03:00:10 +02:00
|
|
|
return string{varp->isReadOnly() ? "const " : ""}
|
2020-11-19 14:02:58 +01:00
|
|
|
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
string primitive(const AstVar* varp) const override {
|
2020-11-19 14:02:58 +01:00
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
2022-01-02 19:56:40 +01:00
|
|
|
if (!varp->isWritable() && varp->basicp()->keyword() != VBasicDTypeKwd::STRING)
|
2020-11-19 14:02:58 +01:00
|
|
|
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 {
|
2021-11-26 23:55:36 +01:00
|
|
|
const string m_name;
|
2020-11-19 14:02:58 +01:00
|
|
|
string arraySuffix(const AstVar* varp, size_t n) const {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstUnpackArrayDType* const unpackp
|
2020-11-19 14:02:58 +01:00
|
|
|
= 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
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
string openArray(const AstVar* varp) const override {
|
2020-11-19 14:02:58 +01:00
|
|
|
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
|
|
|
|
|
+ arraySuffix(varp, 0);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
2020-11-19 14:02:58 +01:00
|
|
|
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
|
|
|
|
|
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
string primitive(const AstVar* varp) const override {
|
2020-11-19 14:02:58 +01:00
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
2022-01-02 19:56:40 +01:00
|
|
|
if (!varp->isWritable() && varp->basicp()->keyword() == VBasicDTypeKwd::CHANDLE)
|
2020-11-19 14:02:58 +01:00
|
|
|
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()) {
|
2023-04-07 03:00:10 +02:00
|
|
|
return (string{"sc_biguint<"} + cvtToStr(widthMin())
|
2020-04-15 13:58:34 +02:00
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScUint()) {
|
2023-04-07 03:00:10 +02:00
|
|
|
return (string{"sc_uint<"} + cvtToStr(widthMin())
|
2020-04-15 13:58:34 +02:00
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScBv()) {
|
2023-04-07 03:00:10 +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 {
|
2022-03-27 21:27:40 +02:00
|
|
|
return "uint64_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.
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVar* const 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
|
|
|
}
|
2022-09-15 20:43:56 +02:00
|
|
|
} else if (AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) {
|
|
|
|
|
if (vrefp->varp()->isSc()) {
|
|
|
|
|
return vrefp->varp();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2022-09-15 20:43:56 +02:00
|
|
|
} else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) {
|
|
|
|
|
if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p;
|
|
|
|
|
if (AstVar* const p = scVarRecurse(arraySelp->bitp())) 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
|
|
|
}
|
|
|
|
|
|
2023-02-12 22:32:36 +01:00
|
|
|
bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); }
|
2022-09-16 14:17:38 +02: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]"
|
2022-10-18 23:07:09 +02:00
|
|
|
string render(const string& name, bool isRef) const VL_MT_SAFE {
|
2020-10-17 22:48:11 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-03 08:52:52 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 08:52:52 +02: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;
|
|
|
|
|
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeDType* const dtypep = this->skipRefp();
|
|
|
|
|
if (const auto* const adtypep = VN_CAST(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 + ">";
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
|
|
|
|
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(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 + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(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 += ">";
|
2022-12-23 13:34:49 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, SampleQueueDType)) {
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
|
|
|
|
info.m_type = "VlSampleQueue<" + sub.m_type + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
2023-03-18 17:05:29 +01:00
|
|
|
info.m_type = "VlClassRef<" + EmitCBase::prefixNameProtect(adtypep) + ">";
|
2022-10-20 12:31:00 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) {
|
2023-03-18 17:05:29 +01:00
|
|
|
info.m_type = EmitCBase::prefixNameProtect(adtypep->ifaceViaCellp()) + "*";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(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 += ">";
|
2023-01-28 04:41:12 +01:00
|
|
|
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
|
|
|
|
|
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
2023-03-18 17:05:29 +01:00
|
|
|
info.m_type = EmitCBase::prefixNameProtect(sdtypep);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
// 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*/"
|
|
|
|
|
: "";
|
2022-01-02 19:56:40 +01:00
|
|
|
if (bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "const char*";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (bdtypep->keyword() == VBasicDTypeKwd::SCOPEPTR) {
|
2020-10-17 22:48:11 +02:00
|
|
|
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";
|
2022-05-15 17:03:32 +02:00
|
|
|
} else if (bdtypep->isTriggerVec()) {
|
|
|
|
|
info.m_type = "VlTriggerVec<" + cvtToStr(dtypep->width()) + ">";
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
} else if (bdtypep->isDelayScheduler()) {
|
|
|
|
|
info.m_type = "VlDelayScheduler";
|
|
|
|
|
} else if (bdtypep->isTriggerScheduler()) {
|
|
|
|
|
info.m_type = "VlTriggerScheduler";
|
2022-10-22 16:05:39 +02:00
|
|
|
} else if (bdtypep->isDynamicTriggerScheduler()) {
|
|
|
|
|
info.m_type = "VlDynamicTriggerScheduler";
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
} else if (bdtypep->isForkSync()) {
|
|
|
|
|
info.m_type = "VlForkSync";
|
2023-06-01 16:02:08 +02:00
|
|
|
} else if (bdtypep->isProcessRef()) {
|
|
|
|
|
info.m_type = "VlProcessRef";
|
2022-05-15 17:03:32 +02:00
|
|
|
} else if (bdtypep->isEvent()) {
|
|
|
|
|
info.m_type = "VlEvent";
|
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
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstUnpackArrayDType* const 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
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstNodeArrayDType* const 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;
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
unpacked++;
|
|
|
|
|
dtypep = qdtypep->subDTypep();
|
|
|
|
|
continue;
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const 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.
|
2021-11-26 23:55:36 +01:00
|
|
|
const 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
|
|
|
|
2023-03-17 00:48:56 +01:00
|
|
|
bool AstNodeDType::isLiteralType() const VL_MT_STABLE {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
return dtypep->keyword().isLiteralType();
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
return dtypep->basicp()->isLiteralType();
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const dtypep = VN_CAST(skipRefp(), StructDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
// Currently all structs are packed, later this can be expanded to
|
|
|
|
|
// 'forall members _.isLiteralType()'
|
|
|
|
|
return dtypep->packed();
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, ArraySel)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, Sel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, Sel)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
2021-03-13 19:04:13 +01:00
|
|
|
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, MemberSel)->fromp();
|
2021-03-13 19:04:13 +01:00
|
|
|
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
|
2023-02-07 15:10:19 +01:00
|
|
|
// of VAttrType::VAR_BASE so it isn't constified
|
2020-04-15 13:58:34 +02:00
|
|
|
else if (VN_IS(nodep, AttrOf)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, AttrOf)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, NodePreSel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
if (VN_AS(nodep, NodePreSel)->attrp()) {
|
|
|
|
|
nodep = VN_AS(nodep, NodePreSel)->attrp();
|
2019-03-14 00:47:36 +01:00
|
|
|
} else {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(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 {
|
2023-04-09 04:11:28 +02:00
|
|
|
string result = shortName();
|
2006-08-26 13:35:28 +02:00
|
|
|
string::size_type pos;
|
2023-04-09 04:11:28 +02:00
|
|
|
while ((pos = result.find('.')) != string::npos) result.replace(pos, 1, "__");
|
|
|
|
|
return result;
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
AstVarScope* AstScope::createTemp(const string& name, unsigned width) {
|
|
|
|
|
FileLine* const flp = fileline();
|
|
|
|
|
AstVar* const varp
|
|
|
|
|
= new AstVar{flp, VVarType::MODULETEMP, name, VFlagBitPacked{}, static_cast<int>(width)};
|
2022-09-15 20:43:56 +02:00
|
|
|
modp()->addStmtsp(varp);
|
2022-05-15 17:03:32 +02:00
|
|
|
AstVarScope* const vscp = new AstVarScope{flp, this, varp};
|
2022-09-15 20:43:56 +02:00
|
|
|
addVarsp(vscp);
|
2022-05-15 17:03:32 +02:00
|
|
|
return vscp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstScope::createTemp(const string& name, AstNodeDType* dtypep) {
|
|
|
|
|
FileLine* const flp = fileline();
|
|
|
|
|
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtypep};
|
2022-09-15 20:43:56 +02:00
|
|
|
modp()->addStmtsp(varp);
|
2022-05-15 17:03:32 +02:00
|
|
|
AstVarScope* const vscp = new AstVarScope{flp, this, varp};
|
2022-09-15 20:43:56 +02:00
|
|
|
addVarsp(vscp);
|
2022-05-15 17:03:32 +02:00
|
|
|
return vscp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstScope::createTempLike(const string& name, AstVarScope* vscp) {
|
|
|
|
|
return createTemp(name, vscp->dtypep());
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-17 01:27:18 +02:00
|
|
|
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out;
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_AS(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;
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_AS(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");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(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;
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
bool AstSenTree::hasStatic() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
2022-05-15 17:03:32 +02:00
|
|
|
if (senp->isStatic()) 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");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(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;
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
bool AstSenTree::hasFinal() const {
|
|
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
|
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
|
|
|
|
if (senp->isFinal()) return true;
|
|
|
|
|
}
|
|
|
|
|
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");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(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;
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
bool AstSenTree::hasHybrid() const {
|
|
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
|
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
|
|
|
|
if (senp->isHybrid()) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstTypeTable::AstTypeTable(FileLine* fl)
|
|
|
|
|
: ASTGEN_SUPER_TypeTable(fl) {
|
2022-01-02 19:56:40 +01:00
|
|
|
for (int i = 0; i < VBasicDTypeKwd::_ENUM_MAX; ++i) m_basicps[i] = nullptr;
|
2021-06-13 16:05:55 +02:00
|
|
|
}
|
|
|
|
|
|
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()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const 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()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
(void)findInsertSameDType(bdtypep);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 23:23:35 +02:00
|
|
|
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_emptyQueuep)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
|
2021-08-28 23:23:35 +02:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_emptyQueuep = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_emptyQueuep;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-01 17:52:48 +01:00
|
|
|
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_voidp)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVoidDType* const newp = new AstVoidDType{fl};
|
2019-12-01 17:52:48 +01:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_voidp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_voidp;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 04:46:42 +02:00
|
|
|
AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_streamp)) {
|
|
|
|
|
AstStreamDType* const newp = new AstStreamDType{fl};
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
m_streamp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_streamp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 16:56:07 +01:00
|
|
|
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_queueIndexp)) {
|
2022-11-20 21:06:49 +01:00
|
|
|
AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr};
|
2020-11-01 16:56:07 +01:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_queueIndexp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_queueIndexp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
|
2012-04-29 16:14:13 +02:00
|
|
|
if (m_basicps[kwd]) return m_basicps[kwd];
|
|
|
|
|
//
|
2022-11-20 21:06:49 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType{fl, kwd};
|
2012-04-29 16:14:13 +02:00
|
|
|
// 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
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const 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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width,
|
2020-04-20 03:19:09 +02:00
|
|
|
int widthMin, VSigning numeric) {
|
2022-11-20 21:06:49 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType{fl, kwd, numeric, width, widthMin};
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const 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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
|
2020-08-16 20:55:46 +02:00
|
|
|
const VNumRange& range, int widthMin,
|
|
|
|
|
VSigning numeric) {
|
2022-11-20 21:06:49 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType{fl, kwd, numeric, range, widthMin};
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const 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) {
|
2022-11-20 21:06:49 +01:00
|
|
|
const 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)
|
2022-11-20 21:06:49 +01:00
|
|
|
, m_modp{new AstModule{fl, "@CONST-POOL@"}}
|
|
|
|
|
, m_scopep{new AstScope{fl, m_modp, "@CONST-POOL@", nullptr, nullptr}} {
|
2022-09-15 20:43:56 +02:00
|
|
|
this->modulep(m_modp);
|
|
|
|
|
m_modp->addStmtsp(m_scopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstConstPool::broken() const {
|
|
|
|
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2021-06-13 16:05:55 +02:00
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNodeExpr* initp) {
|
2021-06-13 16:05:55 +02:00
|
|
|
FileLine* const fl = initp->fileline();
|
2022-11-20 21:06:49 +01:00
|
|
|
AstVar* const varp = new AstVar{fl, VVarType::MODULETEMP, name, initp->dtypep()};
|
2021-06-13 16:05:55 +02:00
|
|
|
varp->isConst(true);
|
|
|
|
|
varp->isStatic(true);
|
|
|
|
|
varp->valuep(initp->cloneTree(false));
|
2022-09-15 20:43:56 +02:00
|
|
|
m_modp->addStmtsp(varp);
|
2022-11-20 21:06:49 +01:00
|
|
|
AstVarScope* const varScopep = new AstVarScope{fl, m_scopep, varp};
|
2022-09-15 20:43:56 +02:00
|
|
|
m_scopep->addVarsp(varScopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
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.
|
2021-12-11 17:29:01 +01:00
|
|
|
if (const AstAssocArrayDType* const aDTypep = VN_CAST(ap->dtypep(), AssocArrayDType)) {
|
|
|
|
|
const AstAssocArrayDType* const bDTypep = VN_CAST(bp->dtypep(), AssocArrayDType);
|
|
|
|
|
if (!bDTypep) return false;
|
|
|
|
|
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
|
|
|
|
|
if (!aDTypep->keyDTypep()->sameTree(bDTypep->keyDTypep())) return false;
|
|
|
|
|
UASSERT_OBJ(ap->defaultp(), ap, "Assoc InitArray should have a default");
|
|
|
|
|
UASSERT_OBJ(bp->defaultp(), bp, "Assoc InitArray should have a default");
|
|
|
|
|
if (!ap->defaultp()->sameTree(bp->defaultp())) 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'.
|
|
|
|
|
// This assumes that the defaults are used in the same way.
|
2022-12-23 17:32:38 +01:00
|
|
|
// TODO when building the AstInitArray, remove any values matching the default
|
2021-12-11 17:29:01 +01:00
|
|
|
const auto& amapr = ap->map();
|
|
|
|
|
const auto& bmapr = bp->map();
|
|
|
|
|
const auto ait = amapr.cbegin();
|
|
|
|
|
const auto bit = bmapr.cbegin();
|
|
|
|
|
while (ait != amapr.cend() || bit != bmapr.cend()) {
|
|
|
|
|
if (ait == amapr.cend() || bit == bmapr.cend()) return false; // Different size
|
|
|
|
|
if (ait->first != bit->first) return false; // Different key
|
|
|
|
|
if (ait->second->sameTree(bit->second)) return false; // Different value
|
|
|
|
|
}
|
|
|
|
|
} else if (const AstUnpackArrayDType* const aDTypep
|
|
|
|
|
= VN_CAST(ap->dtypep(), UnpackArrayDType)) {
|
|
|
|
|
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
|
|
|
|
|
if (!bDTypep) return false;
|
|
|
|
|
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
|
|
|
|
|
if (!aDTypep->rangep()->sameTree(bDTypep->rangep())) 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'.
|
2022-03-27 21:27:40 +02:00
|
|
|
const uint64_t size = aDTypep->elementsConst();
|
|
|
|
|
for (uint64_t n = 0; n < size; ++n) {
|
2021-12-11 17:29:01 +01:00
|
|
|
const AstNode* const valAp = ap->getIndexDefaultedValuep(n);
|
|
|
|
|
const AstNode* const valBp = bp->getIndexDefaultedValuep(n);
|
|
|
|
|
if (!valAp->sameTree(valBp)) return false;
|
|
|
|
|
}
|
2021-06-13 16:05:55 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNode* const defaultp = initp->defaultp();
|
2021-06-13 16:05:55 +02:00
|
|
|
// Verify initializer is well formed
|
2021-12-11 17:29:01 +01:00
|
|
|
UASSERT_OBJ(VN_IS(initp->dtypep(), AssocArrayDType)
|
|
|
|
|
|| VN_IS(initp->dtypep(), UnpackArrayDType),
|
|
|
|
|
initp, "Const pool table must have array dtype");
|
2021-06-13 16:05:55 +02:00
|
|
|
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
|
|
|
|
|
"Const pool table default must be Const");
|
|
|
|
|
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNode* const valuep = VN_AS(nodep, InitItem)->valuep();
|
2021-06-13 16:05:55 +02:00
|
|
|
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
|
|
|
|
|
}
|
|
|
|
|
// Try to find an existing table with the same content
|
2022-11-27 11:52:40 +01:00
|
|
|
// cppcheck-has-bug-suppress unreadVariable
|
2021-08-11 17:22:52 +02:00
|
|
|
const V3Hash hash = V3Hasher::uncachedHash(initp);
|
|
|
|
|
const auto& er = m_tables.equal_range(hash.value());
|
2021-06-13 16:05:55 +02:00
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
2021-10-22 14:56:48 +02:00
|
|
|
const AstInitArray* const init2p = VN_AS(varScopep->varp()->valuep(), InitArray);
|
2021-06-13 16:05:55 +02:00
|
|
|
if (sameInit(initp, init2p)) {
|
|
|
|
|
return varScopep; // Found identical table
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such table yet, create it.
|
|
|
|
|
string name = "TABLE_";
|
2021-08-11 17:22:52 +02:00
|
|
|
name += hash.toString();
|
2021-06-13 16:05:55 +02:00
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
2021-08-11 17:22:52 +02:00
|
|
|
m_tables.emplace(hash.value(), varScopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
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
|
2022-11-27 11:52:40 +01:00
|
|
|
// cppcheck-has-bug-suppress unreadVariable
|
2021-08-11 17:22:52 +02:00
|
|
|
const V3Hash hash = initp->num().toHash();
|
|
|
|
|
const auto& er = m_consts.equal_range(hash.value());
|
2021-06-13 16:05:55 +02:00
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
2021-10-22 14:56:48 +02:00
|
|
|
const AstConst* const init2p = VN_AS(varScopep->varp()->valuep(), Const);
|
2021-06-13 16:05:55 +02:00
|
|
|
if (sameInit(initp, init2p)
|
|
|
|
|
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
|
|
|
|
|
return varScopep; // Found identical constant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such constant yet, create it.
|
|
|
|
|
string name = "CONST_";
|
2021-08-11 17:22:52 +02:00
|
|
|
name += hash.toString();
|
2021-06-13 16:05:55 +02:00
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
2021-08-11 17:22:52 +02:00
|
|
|
m_consts.emplace(hash.value(), varScopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-09 02:42:45 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Special walking tree inserters
|
|
|
|
|
|
|
|
|
|
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::addNextStmt(AstNode* newp, AstNode*) {
|
|
|
|
|
// Insert newp after current node
|
|
|
|
|
this->addNextHere(newp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
2022-09-15 20:43:56 +02:00
|
|
|
if (stmtsp()) {
|
|
|
|
|
stmtsp()->addHereThisAsNext(newp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2022-09-15 20:43:56 +02:00
|
|
|
addStmtsp(newp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-09-15 20:43:56 +02:00
|
|
|
} else if (belowp == stmtsp()) {
|
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 {
|
2022-09-24 22:18:43 +02:00
|
|
|
str << typeName() << " " << nodeAddr(this)
|
|
|
|
|
#ifdef VL_DEBUG
|
2020-04-15 13:58:34 +02:00
|
|
|
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
|
2022-09-24 22:18:43 +02:00
|
|
|
#endif
|
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-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const 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
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
void AstNodeProcedure::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isSuspendable()) str << " [SUSP]";
|
2023-06-01 16:02:08 +02:00
|
|
|
if (needProcess()) str << " [NPRC]";
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
|
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
|
|
|
|
2022-10-12 11:19:21 +02:00
|
|
|
void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
|
2020-09-17 03:52:24 +02:00
|
|
|
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstCell::broken() const {
|
|
|
|
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstCellInline::broken() const {
|
|
|
|
|
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
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
|
|
|
}
|
2021-12-13 00:10:52 +01:00
|
|
|
void AstClassPackage::cloneRelink() {
|
|
|
|
|
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
|
|
|
|
|
}
|
2023-07-08 18:27:50 +02:00
|
|
|
bool AstClass::isCacheableChild(const AstNode* nodep) {
|
|
|
|
|
return (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
|
|
|
|
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|
|
|
|
|
|| VN_IS(nodep, CFunc));
|
|
|
|
|
}
|
2023-04-01 16:50:27 +02:00
|
|
|
AstClass* AstClass::baseMostClassp() {
|
|
|
|
|
AstClass* basep = this;
|
|
|
|
|
while (basep->extendsp() && basep->extendsp()->classp()) {
|
|
|
|
|
basep = basep->extendsp()->classp();
|
|
|
|
|
}
|
|
|
|
|
return basep;
|
|
|
|
|
}
|
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 {
|
2021-12-23 02:06:04 +01:00
|
|
|
this->AstNodeModule::dump(str);
|
2020-08-24 02:00:39 +02:00
|
|
|
if (isExtended()) str << " [EXT]";
|
2023-01-28 22:30:47 +01:00
|
|
|
if (isInterfaceClass()) str << " [IFCCLS]";
|
2020-08-24 02:00:39 +02:00
|
|
|
if (isVirtual()) str << " [VIRT]";
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstClass::broken() const {
|
|
|
|
|
BROKEN_BASE_RTN(AstNodeModule::broken());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstClass::cloneRelink() {
|
|
|
|
|
AstNodeModule::cloneRelink();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-28 22:30:47 +01:00
|
|
|
void AstClassExtends::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isImplements()) str << " [IMPLEMENTS]";
|
|
|
|
|
}
|
2023-05-16 01:50:04 +02:00
|
|
|
AstClass* AstClassExtends::classOrNullp() const {
|
|
|
|
|
const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep();
|
|
|
|
|
const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType);
|
|
|
|
|
if (refp && !refp->paramsp()) {
|
|
|
|
|
// Class already resolved
|
|
|
|
|
return refp->classp();
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
2020-11-26 17:06:59 +01:00
|
|
|
}
|
2023-05-16 01:50:04 +02:00
|
|
|
}
|
|
|
|
|
AstClass* AstClassExtends::classp() const {
|
|
|
|
|
AstClass* const clsp = classOrNullp();
|
|
|
|
|
UASSERT_OBJ(clsp, this, "Extended class is unresolved");
|
|
|
|
|
return clsp;
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
void AstClassRefDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::dump(str);
|
2021-12-23 02:06:04 +01:00
|
|
|
if (classOrPackagep()) str << " cpkg=" << nodeAddr(classOrPackagep());
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstClassRefDType::broken() const {
|
|
|
|
|
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstClassRefDType::cloneRelink() {
|
|
|
|
|
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
string AstClassRefDType::name() const { return classp() ? classp()->name() : "<unlinked>"; }
|
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
|
|
|
}
|
2023-01-28 18:22:23 +01:00
|
|
|
void AstClocking::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isDefault()) str << " [DEFAULT]";
|
|
|
|
|
if (isGlobal()) str << " [GLOBAL]";
|
|
|
|
|
}
|
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);
|
2021-09-09 01:31:26 +02:00
|
|
|
// str << " " << displayType().ascii();
|
2008-03-26 15:58:30 +01:00
|
|
|
}
|
2022-11-19 19:23:28 +01:00
|
|
|
void AstEnumDType::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dump(str);
|
|
|
|
|
str << " enum";
|
|
|
|
|
}
|
|
|
|
|
void AstEnumDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "enum";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstEnumItemRef::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstEnumItemRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_itemp && !m_itemp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstIfaceRefDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::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
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void AstIfaceRefDType::cloneRelink() {
|
|
|
|
|
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep();
|
|
|
|
|
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep();
|
|
|
|
|
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep();
|
|
|
|
|
}
|
2019-11-09 21:34:41 +01:00
|
|
|
void AstInitArray::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
int n = 0;
|
2021-12-11 17:22:04 +01:00
|
|
|
const auto& 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
|
|
|
}
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstInitArray::broken() const {
|
|
|
|
|
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
|
|
|
|
BROKEN_RTN(!it->second);
|
|
|
|
|
BROKEN_RTN(!it->second->brokeExists());
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstInitArray::cloneRelink() {
|
|
|
|
|
for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
|
|
|
|
if (it->second->clonep()) it->second = it->second->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
void AstInitArray::addIndexValuep(uint64_t index, AstNodeExpr* newp) {
|
2022-09-15 14:10:39 +02:00
|
|
|
const auto it = m_map.find(index);
|
|
|
|
|
if (it != m_map.end()) {
|
|
|
|
|
it->second->valuep(newp);
|
|
|
|
|
} else {
|
2022-11-20 21:06:49 +01:00
|
|
|
AstInitItem* const itemp = new AstInitItem{fileline(), newp};
|
2022-09-15 14:10:39 +02:00
|
|
|
m_map.emplace(index, itemp);
|
2022-09-15 20:43:56 +02:00
|
|
|
addInitsp(itemp);
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* AstInitArray::getIndexValuep(uint64_t index) const {
|
2022-09-15 14:10:39 +02:00
|
|
|
const auto it = m_map.find(index);
|
|
|
|
|
if (it == m_map.end()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
return it->second->valuep();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
|
|
|
|
|
AstNodeExpr* valuep = getIndexValuep(index);
|
2022-09-15 14:10:39 +02:00
|
|
|
if (!valuep) valuep = defaultp();
|
|
|
|
|
return valuep;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstJumpGo::broken() const {
|
|
|
|
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstJumpGo::cloneRelink() {
|
|
|
|
|
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
|
|
|
|
|
}
|
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";
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-12 00:38:23 +01:00
|
|
|
void AstLogOr::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::dump(str);
|
2021-12-12 00:38:23 +01:00
|
|
|
if (sideEffect()) str << " [SIDE]";
|
|
|
|
|
}
|
2023-05-07 03:41:17 +02:00
|
|
|
|
2023-01-29 22:50:10 +01:00
|
|
|
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "member";
|
|
|
|
|
}
|
2023-05-07 03:41:17 +02:00
|
|
|
AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
|
|
|
|
|
AstNodeDType* subdtp = skipRefp();
|
|
|
|
|
while (AstNodeArrayDType* const asubdtp = VN_CAST(subdtp, NodeArrayDType)) {
|
|
|
|
|
subdtp = asubdtp->subDTypep();
|
|
|
|
|
}
|
|
|
|
|
return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-30 09:12:22 +02:00
|
|
|
bool AstMemberSel::same(const AstNode* samep) const {
|
|
|
|
|
const AstMemberSel* const sp = static_cast<const AstMemberSel*>(samep);
|
|
|
|
|
return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
|
|
|
|
|
&& name() == sp->name() && varp()->same(sp->varp());
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-16 02:18:12 +01:00
|
|
|
void AstMemberSel::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
void AstMemberSel::cloneRelink() {
|
|
|
|
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
|
|
|
|
}
|
|
|
|
|
const char* AstMemberSel::broken() const {
|
|
|
|
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstModportFTaskRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstModportFTaskRef::cloneRelink() {
|
|
|
|
|
if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep();
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstModportVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstModportVarRef::cloneRelink() {
|
|
|
|
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
|
|
|
|
}
|
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";
|
|
|
|
|
}
|
2023-03-02 03:19:21 +01:00
|
|
|
if (svDotName()) str << " [.n]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (svImplicit()) str << " [.SV]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstPin::broken() const {
|
|
|
|
|
BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
string AstPin::prettyOperatorName() const {
|
|
|
|
|
return modVarp()
|
|
|
|
|
? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "")
|
|
|
|
|
+ "port connection " + modVarp()->prettyNameQ())
|
|
|
|
|
: "port connection";
|
|
|
|
|
}
|
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
|
|
|
|
2022-10-12 11:19:21 +02:00
|
|
|
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeExpr::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]";
|
2022-10-21 15:00:40 +02:00
|
|
|
if (subDTypep()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
subDTypep()->dump(str);
|
|
|
|
|
}
|
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);
|
2023-03-21 01:44:11 +01:00
|
|
|
if (ascending()) str << " [ASCENDING]";
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2022-10-21 15:00:40 +02:00
|
|
|
void AstParamTypeDType::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dump(str);
|
|
|
|
|
if (subDTypep()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
subDTypep()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-11-19 19:23:28 +01:00
|
|
|
void AstRefDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "ref";
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstRefDType::broken() const {
|
|
|
|
|
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstRefDType::cloneRelink() {
|
|
|
|
|
if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep();
|
|
|
|
|
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-17 00:48:56 +01:00
|
|
|
AstNodeDType* AstRefDType::subDTypep() const VL_MT_STABLE {
|
2022-09-15 14:10:39 +02:00
|
|
|
if (typedefp()) return typedefp()->subDTypep();
|
|
|
|
|
return refDTypep(); // Maybe nullptr
|
|
|
|
|
}
|
2019-12-17 04:46:09 +01:00
|
|
|
void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (packed()) str << " [PACKED]";
|
|
|
|
|
if (isFourstate()) str << " [4STATE]";
|
2023-05-07 03:41:17 +02:00
|
|
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
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]";
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const 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);
|
2021-11-26 23:55:36 +01:00
|
|
|
if (auto* const adtypep = VN_CAST(this, UnpackArrayDType)) {
|
2020-12-13 01:19:16 +01:00
|
|
|
// 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);
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const subp = unpackp->subDTypep()) {
|
2020-11-19 14:02:58 +01:00
|
|
|
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() << "]";
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstNetlist::broken() const {
|
|
|
|
|
BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_evalp && !m_evalp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
|
2022-09-15 14:17:00 +02:00
|
|
|
BROKEN_RTN(m_delaySchedulerp && !m_delaySchedulerp->brokeExists());
|
2022-09-15 14:10:39 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
AstPackage* AstNetlist::dollarUnitPkgAddp() {
|
|
|
|
|
if (!m_dollarUnitPkgp) {
|
2022-11-20 21:06:49 +01:00
|
|
|
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName()};
|
2022-09-15 14:10:39 +02:00
|
|
|
// packages are always libraries; don't want to make them a "top"
|
|
|
|
|
m_dollarUnitPkgp->inLibrary(true);
|
|
|
|
|
m_dollarUnitPkgp->modTrace(false); // may reconsider later
|
|
|
|
|
m_dollarUnitPkgp->internal(true);
|
2022-09-15 20:43:56 +02:00
|
|
|
addModulesp(m_dollarUnitPkgp);
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
|
|
|
|
return m_dollarUnitPkgp;
|
|
|
|
|
}
|
|
|
|
|
void AstNetlist::createTopScope(AstScope* scopep) {
|
|
|
|
|
UASSERT(scopep, "Must not be nullptr");
|
|
|
|
|
UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits");
|
|
|
|
|
m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep};
|
2022-09-15 20:43:56 +02:00
|
|
|
scopep->modp()->addStmtsp(v3Global.rootp()->topScopep());
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstPackageExport ::broken() const {
|
|
|
|
|
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstPackageExport::cloneRelink() {
|
|
|
|
|
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstPackageImport::broken() const {
|
|
|
|
|
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstPackageImport::cloneRelink() {
|
|
|
|
|
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
|
|
|
|
|
}
|
2020-11-07 17:56:24 +01:00
|
|
|
void AstPatMember::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::dump(str);
|
2020-11-07 17:56:24 +01:00
|
|
|
if (isDefault()) str << " [DEFAULT]";
|
|
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::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);
|
2022-01-02 19:56:40 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(VBasicDTypeKwd::_ENUM_MAX); ++i) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const subnodep = m_basicps[i]) {
|
2020-11-19 03:03:23 +01:00
|
|
|
str << '\n'; // Newline from caller, so newline first
|
2022-09-16 01:58:01 +02:00
|
|
|
str << "\t\t" << std::setw(8) << VBasicDTypeKwd{i}.ascii();
|
2020-04-15 13:58:34 +02:00
|
|
|
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) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const 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 + "]";
|
|
|
|
|
}
|
2022-07-20 15:01:36 +02:00
|
|
|
void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "[*]";
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
bool AstWildcardArrayDType::same(const AstNode* samep) const {
|
|
|
|
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
|
|
|
|
if (!asamep->subDTypep()) return false;
|
|
|
|
|
return (subDTypep() == asamep->subDTypep());
|
|
|
|
|
}
|
2022-12-02 00:47:09 +01:00
|
|
|
bool AstWildcardArrayDType::similarDType(const AstNodeDType* samep) const {
|
2022-09-15 14:10:39 +02:00
|
|
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
|
|
|
|
return type() == samep->type() && asamep->subDTypep()
|
|
|
|
|
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
|
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
void AstSampleQueueDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
bool AstUnsizedArrayDType::same(const AstNode* samep) const {
|
|
|
|
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
|
|
|
|
if (!asamep->subDTypep()) return false;
|
|
|
|
|
return (subDTypep() == asamep->subDTypep());
|
|
|
|
|
}
|
2022-12-02 00:47:09 +01:00
|
|
|
bool AstUnsizedArrayDType::similarDType(const AstNodeDType* samep) const {
|
2022-09-15 14:10:39 +02:00
|
|
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
|
|
|
|
return type() == samep->type() && asamep->subDTypep()
|
|
|
|
|
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
|
|
|
|
}
|
2021-08-28 23:23:35 +02:00
|
|
|
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "emptyq";
|
|
|
|
|
}
|
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
|
|
|
}
|
2023-06-14 04:46:42 +02:00
|
|
|
void AstStreamDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "stream";
|
|
|
|
|
}
|
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);
|
2022-01-02 21:03:57 +01:00
|
|
|
if (isTrace()) str << " [T]";
|
|
|
|
|
if (scopep()) str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-06-03 16:07:39 +02:00
|
|
|
bool AstVarScope::same(const AstNode* samep) const {
|
|
|
|
|
const AstVarScope* const asamep = static_cast<const AstVarScope*>(samep);
|
|
|
|
|
return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep());
|
|
|
|
|
}
|
2020-11-25 03:28:04 +01:00
|
|
|
void AstNodeVarRef::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::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
|
|
|
}
|
2023-08-03 08:52:52 +02:00
|
|
|
const char* AstVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(!varp());
|
|
|
|
|
return AstNodeVarRef::broken();
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
bool AstVarRef::same(const AstNode* samep) const {
|
|
|
|
|
return same(static_cast<const AstVarRef*>(samep));
|
|
|
|
|
}
|
2022-10-27 17:47:42 +02:00
|
|
|
int AstVarRef::instrCount() const {
|
|
|
|
|
// Account for the target of hard-coded method calls as just an address computation
|
|
|
|
|
if (const AstCMethodHard* const callp = VN_CAST(backp(), CMethodHard)) {
|
|
|
|
|
if (callp->fromp() == this) return 1;
|
|
|
|
|
}
|
|
|
|
|
// Otherwise as a load/store
|
|
|
|
|
return widthInstrs() * (access().isReadOrRW() ? INSTR_COUNT_LD : 1);
|
|
|
|
|
}
|
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]";
|
2022-12-23 16:51:52 +01:00
|
|
|
if (noReset()) str << " [!RST]";
|
2020-04-15 13:58:34 +02:00
|
|
|
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
|
|
|
}
|
2023-06-03 16:07:39 +02:00
|
|
|
bool AstVar::same(const AstNode* samep) const {
|
|
|
|
|
const AstVar* const asamep = static_cast<const AstVar*>(samep);
|
2023-06-03 16:11:23 +02:00
|
|
|
return name() == asamep->name() && varType() == asamep->varType();
|
2023-06-03 16:07:39 +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()) << "]";
|
|
|
|
|
}
|
2023-06-03 16:07:39 +02:00
|
|
|
bool AstScope::same(const AstNode* samep) const {
|
|
|
|
|
const AstScope* const asamep = static_cast<const AstScope*>(samep);
|
|
|
|
|
return name() == asamep->name()
|
|
|
|
|
&& ((!aboveScopep() && !asamep->aboveScopep())
|
|
|
|
|
|| (aboveScopep() && asamep->aboveScopep()
|
|
|
|
|
&& aboveScopep()->name() == asamep->aboveScopep()->name()));
|
|
|
|
|
}
|
2021-11-27 02:38:48 +01:00
|
|
|
void AstScopeName::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::dump(str);
|
2021-11-27 02:38:48 +01:00
|
|
|
if (dpiExport()) str << " [DPIEX]";
|
|
|
|
|
if (forFormat()) str << " [FMT]";
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-14 13:39:27 +02:00
|
|
|
void AstStrengthSpec::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")";
|
|
|
|
|
}
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
AstNodeModule* AstClassOrPackageRef::classOrPackagep() const {
|
|
|
|
|
AstNode* foundp = m_classOrPackageNodep;
|
2022-10-21 15:00:40 +02:00
|
|
|
if (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
|
|
|
|
if (auto* const anodep = VN_CAST(foundp, NodeDType)) foundp = anodep->skipRefp();
|
2022-09-15 14:10:39 +02:00
|
|
|
if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp();
|
|
|
|
|
return VN_CAST(foundp, NodeModule);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstActive::broken() const {
|
|
|
|
|
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstActive::cloneRelink() {
|
2022-09-15 14:17:00 +02:00
|
|
|
if (m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeExpr::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 (dpiExport()) str << " [DPIX]";
|
2022-01-04 00:50:41 +01:00
|
|
|
if (dpiImport()) str << " [DPII]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dpiOpenChild()) str << " [DPIOPENCHILD]";
|
|
|
|
|
if (dpiOpenParent()) str << " [DPIOPENPARENT]";
|
2022-01-04 00:50:41 +01:00
|
|
|
if (prototype()) str << " [PROTOTYPE]";
|
|
|
|
|
if (recursive()) str << " [RECURSIVE]";
|
|
|
|
|
if (taskPublic()) str << " [PUBLIC]";
|
2020-04-15 13:58:34 +02:00
|
|
|
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 {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeBlock::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 {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeBlock::dump(str);
|
2020-04-23 03:31:40 +02:00
|
|
|
if (!joinType().join()) str << " [" << joinType() << "]";
|
|
|
|
|
}
|
2022-04-11 01:40:27 +02:00
|
|
|
void AstTraceDecl::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (code()) str << " [code=" << code() << "]";
|
|
|
|
|
}
|
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]";
|
2023-09-08 08:51:19 +02:00
|
|
|
if (dpiPure()) str << " [DPIPURE]";
|
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]";
|
2021-08-12 22:43:32 +02:00
|
|
|
if (dpiContext()) str << " [DPICTX]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isConstructor()) str << " [CTOR]";
|
|
|
|
|
if (isDestructor()) str << " [DTOR]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
if (isCoroutine()) str << " [CORO]";
|
2023-06-01 16:02:08 +02:00
|
|
|
if (needProcess()) str << " [NPRC]";
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
const char* AstCAwait::broken() const {
|
|
|
|
|
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstCAwait::cloneRelink() {
|
|
|
|
|
if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
|
|
|
|
|
}
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
void AstCAwait::dump(std::ostream& str) const {
|
2022-10-12 11:19:21 +02:00
|
|
|
this->AstNodeUniop::dump(str);
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
if (sensesp()) {
|
|
|
|
|
str << " => ";
|
|
|
|
|
sensesp()->dump(str);
|
|
|
|
|
}
|
2008-08-06 23:09:33 +02:00
|
|
|
}
|
2022-10-27 17:47:42 +02:00
|
|
|
int AstCMethodHard::instrCount() const {
|
|
|
|
|
if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) {
|
|
|
|
|
// TODO: add a more structured description of library methods, rather than using string
|
2023-09-16 00:12:11 +02:00
|
|
|
// matching. See issue #3715.
|
2023-04-13 14:44:54 +02:00
|
|
|
if (basicp->isTriggerVec() && m_name == "word") {
|
2022-10-27 17:47:42 +02:00
|
|
|
// This is an important special case for scheduling so we compute it precisely,
|
|
|
|
|
// it is simply a load.
|
|
|
|
|
return INSTR_COUNT_LD;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
return 0;
|
2022-10-27 17:47:42 +02:00
|
|
|
}
|
2023-09-11 13:06:15 +02:00
|
|
|
void AstCMethodHard::setPurity() {
|
|
|
|
|
static const std::map<std::string, bool> isPureMethod{{"andNot", false},
|
|
|
|
|
{"any", true},
|
|
|
|
|
{"assign", false},
|
|
|
|
|
{"at", true},
|
|
|
|
|
{"atBack", true},
|
|
|
|
|
{"awaitingCurrentTime", true},
|
|
|
|
|
{"clear", false},
|
|
|
|
|
{"clearFired", false},
|
|
|
|
|
{"commit", false},
|
|
|
|
|
{"delay", false},
|
|
|
|
|
{"done", false},
|
|
|
|
|
{"erase", false},
|
|
|
|
|
{"evaluate", false},
|
|
|
|
|
{"evaluation", false},
|
|
|
|
|
{"exists", true},
|
|
|
|
|
{"find", true},
|
|
|
|
|
{"find_first", true},
|
|
|
|
|
{"find_first_index", true},
|
|
|
|
|
{"find_index", true},
|
|
|
|
|
{"find_last", true},
|
|
|
|
|
{"find_last_index", true},
|
|
|
|
|
{"fire", false},
|
|
|
|
|
{"first", false},
|
|
|
|
|
{"init", false},
|
|
|
|
|
{"insert", false},
|
|
|
|
|
{"isFired", true},
|
|
|
|
|
{"isTriggered", true},
|
|
|
|
|
{"join", false},
|
|
|
|
|
{"last", false},
|
|
|
|
|
{"max", true},
|
|
|
|
|
{"min", true},
|
|
|
|
|
{"neq", true},
|
|
|
|
|
{"next", false},
|
|
|
|
|
{"pop", false},
|
|
|
|
|
{"pop_back", false},
|
|
|
|
|
{"pop_front", false},
|
|
|
|
|
{"prev", false},
|
|
|
|
|
{"push", false},
|
|
|
|
|
{"push_back", false},
|
|
|
|
|
{"push_front", false},
|
|
|
|
|
{"r_and", true},
|
|
|
|
|
{"r_or", true},
|
|
|
|
|
{"r_product", true},
|
|
|
|
|
{"r_sum", true},
|
|
|
|
|
{"r_xor", true},
|
|
|
|
|
{"renew", false},
|
|
|
|
|
{"renew_copy", false},
|
|
|
|
|
{"resume", false},
|
|
|
|
|
{"reverse", false},
|
|
|
|
|
{"rsort", false},
|
|
|
|
|
{"set", false},
|
|
|
|
|
{"shuffle", false},
|
|
|
|
|
{"size", true},
|
|
|
|
|
{"slice", true},
|
|
|
|
|
{"sliceBackBack", true},
|
|
|
|
|
{"sliceFrontBack", true},
|
|
|
|
|
{"sort", false},
|
|
|
|
|
{"thisOr", false},
|
|
|
|
|
{"trigger", false},
|
|
|
|
|
{"unique", true},
|
|
|
|
|
{"unique_index", true},
|
|
|
|
|
{"word", true}};
|
|
|
|
|
|
|
|
|
|
auto isPureIt = isPureMethod.find(name());
|
|
|
|
|
UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name());
|
|
|
|
|
m_pure = isPureIt->second;
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstCFunc::broken() const {
|
|
|
|
|
BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
void AstCFunc::cloneRelink() {
|
|
|
|
|
if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-01 22:45:11 +01:00
|
|
|
void AstCUse::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << useType() << "]";
|
|
|
|
|
}
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
|
|
|
|
|
AstAlways* AstAssignW::convertToAlways() {
|
2022-10-14 09:35:26 +02:00
|
|
|
const bool hasTimingControl = isTimingControl();
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const lhs1p = lhsp()->unlinkFrBack();
|
|
|
|
|
AstNodeExpr* const rhs1p = rhsp()->unlinkFrBack();
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
AstNode* const controlp = timingControlp() ? timingControlp()->unlinkFrBack() : nullptr;
|
|
|
|
|
FileLine* const flp = fileline();
|
|
|
|
|
AstNode* bodysp = new AstAssign{flp, lhs1p, rhs1p, controlp};
|
2022-10-14 09:35:26 +02:00
|
|
|
if (hasTimingControl) {
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
// If there's a timing control, put the assignment in a fork..join_none. This process won't
|
|
|
|
|
// get marked as suspendable and thus will be scheduled normally
|
|
|
|
|
auto* forkp = new AstFork{flp, "", bodysp};
|
|
|
|
|
forkp->joinType(VJoinType::JOIN_NONE);
|
|
|
|
|
bodysp = forkp;
|
|
|
|
|
}
|
|
|
|
|
AstAlways* const newp = new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, bodysp};
|
|
|
|
|
replaceWith(newp); // User expected to then deleteTree();
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
2022-12-23 13:34:49 +01:00
|
|
|
|
|
|
|
|
void AstDelay::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (isCycleDelay()) str << " [CYCLE]";
|
|
|
|
|
}
|