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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2024-01-01 09:19:59 +01:00
|
|
|
// Copyright 2003-2024 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
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3PchAstMT.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
#include "V3EmitCBase.h"
|
2024-03-16 15:02:17 +01:00
|
|
|
#include "V3ExecGraph.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3File.h"
|
2024-02-09 23:50:09 +01:00
|
|
|
#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"
|
2020-08-15 15:43:53 +02:00
|
|
|
#include "V3String.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2023-12-01 01:58:16 +01:00
|
|
|
#include "V3Ast__gen_impl.h" // Generated by 'astgen'
|
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>
|
2024-02-09 23:50:09 +01:00
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
2024-02-09 23:50:09 +01:00
|
|
|
// Routines for dumping dict fields (NOTE: due to leading ',' they can't be used for first field in
|
|
|
|
|
// dict)
|
|
|
|
|
void AstNode::dumpJsonNum(std::ostream& os, const std::string& name, int64_t val) {
|
|
|
|
|
os << ",\"" << name << "\":" << val;
|
|
|
|
|
}
|
|
|
|
|
void AstNode::dumpJsonBool(std::ostream& os, const std::string& name, bool val) {
|
|
|
|
|
os << ",\"" << name << "\":" << (val ? "true" : "false");
|
|
|
|
|
}
|
|
|
|
|
void AstNode::dumpJsonStr(std::ostream& os, const std::string& name, const std::string& val) {
|
|
|
|
|
os << ",\"" << name << "\":\"" << V3OutFormatter::quoteNameControls(val) << '"';
|
|
|
|
|
}
|
|
|
|
|
void AstNode::dumpJsonPtr(std::ostream& os, const std::string& name, const AstNode* const valp) {
|
|
|
|
|
v3Global.saveJsonPtrFieldName(name);
|
|
|
|
|
std::string addr = "UNLINKED";
|
|
|
|
|
if (valp) addr = (v3Global.opt.jsonIds() ? v3Global.ptrToId(valp) : cvtToHex(valp));
|
|
|
|
|
os << ",\"" << name << "\":\"" << addr << '"';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shorthands for dumping fields that use func name as key
|
|
|
|
|
#define dumpJsonNumFunc(os, func) dumpJsonNum(os, #func, func())
|
|
|
|
|
#define dumpJsonBoolFunc(os, func) dumpJsonBool(os, #func, func())
|
|
|
|
|
#define dumpJsonStrFunc(os, func) dumpJsonStr(os, #func, func())
|
|
|
|
|
#define dumpJsonPtrFunc(os, func) dumpJsonPtr(os, #func, func())
|
|
|
|
|
|
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
|
|
|
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 {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2021-12-13 00:10:52 +01:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-18 15:21:30 +02:00
|
|
|
bool AstNodeFTaskRef::isPure() {
|
|
|
|
|
if (!this->taskp()) {
|
|
|
|
|
// The task isn't linked yet, so it's assumed that it is impure, but the value shouldn't be
|
|
|
|
|
// cached.
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
2024-08-26 18:18:52 +02:00
|
|
|
if (!m_purity.isCached()) {
|
|
|
|
|
m_purity.set(true); // To prevent infinite recursion, set to true before getting
|
|
|
|
|
// the actual purity. If there are impure statements in the
|
|
|
|
|
// task/function, they'll taint this call anyway.
|
|
|
|
|
m_purity.set(this->getPurityRecurse());
|
|
|
|
|
}
|
2023-09-29 12:23:51 +02:00
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
2023-02-28 21:21:58 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-29 12:23:51 +02:00
|
|
|
bool AstNodeFTaskRef::getPurityRecurse() const {
|
2023-09-18 15:21:30 +02:00
|
|
|
AstNodeFTask* const taskp = this->taskp();
|
|
|
|
|
// Unlinked yet, so treat as impure
|
|
|
|
|
if (!taskp) return false;
|
|
|
|
|
|
|
|
|
|
// First compute the purity of arguments
|
|
|
|
|
for (AstNode* pinp = this->pinsp(); pinp; pinp = pinp->nextp()) {
|
|
|
|
|
if (!pinp->isPure()) return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return taskp->isPure();
|
|
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2020-09-17 03:52:24 +02:00
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeCCall::dumpJson(std::ostream& str) const {
|
|
|
|
|
if (funcp()) dumpJsonStr(str, "funcName", funcp()->name());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2023-09-18 15:21:30 +02:00
|
|
|
bool AstNodeCCall::isPure() { return funcp()->dpiPure(); }
|
|
|
|
|
bool AstNodeUniop::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(lhsp()->isPure());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodeUniop::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
bool AstNodeBiop::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodeBiop::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AstNodeTriop::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodeTriop::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AstNodePreSel::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodePreSel::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AstNodeQuadop::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodeQuadop::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
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.
|
2023-10-09 23:43:27 +02:00
|
|
|
AstNodeDType* const commonClassTypep = getCommonClassTypep(thenp, elsep);
|
2023-08-07 11:54:30 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstBasicDType::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstBasicDType* const sp = VN_DBG_AS(samep, BasicDType);
|
2023-10-15 21:15:46 +02:00
|
|
|
if (!(m == sp->m) || numeric() != sp->numeric()) return false;
|
|
|
|
|
if (!rangep() && !sp->rangep()) return true;
|
|
|
|
|
return rangep() && rangep()->sameTree(sp->rangep());
|
2023-04-14 12:51:33 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthTotalBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return widthWords() * (VL_EDATASIZE / 8);
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthAlignBytes() const {
|
2012-07-29 16:16:20 +02:00
|
|
|
// Could do max across members but that would be slow,
|
|
|
|
|
// instead intuit based on total structure size
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (width() <= 32) {
|
|
|
|
|
return 4;
|
|
|
|
|
} else {
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2023-09-25 04:12:23 +02:00
|
|
|
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name) VL_MT_DISABLED
|
|
|
|
|
: ASTGEN_SUPER_ExecGraph(fileline),
|
|
|
|
|
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) {
|
2023-09-17 04:50:54 +02:00
|
|
|
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTreePure(true), lhsp};
|
|
|
|
|
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTreePure(true), rhsp};
|
2020-03-31 00:12:50 +02:00
|
|
|
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
|
|
|
|
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
2024-03-08 14:17:41 +01:00
|
|
|
return new AstLogAnd{fileline(), ap, bp};
|
2020-03-31 00:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 10:05:15 +02:00
|
|
|
AstVar* AstClocking::ensureEventp(bool childDType) {
|
|
|
|
|
if (!eventp()) {
|
|
|
|
|
AstVar* const evp
|
|
|
|
|
= childDType ? new AstVar{fileline(), VVarType::MODULETEMP, m_name, VFlagChildDType{},
|
|
|
|
|
new AstBasicDType{fileline(), VBasicDTypeKwd::EVENT}}
|
|
|
|
|
: new AstVar{fileline(), VVarType::MODULETEMP, m_name,
|
|
|
|
|
findBasicDType(VBasicDTypeKwd::EVENT)};
|
|
|
|
|
evp->lifetime(VLifetime::STATIC);
|
|
|
|
|
eventp(evp);
|
|
|
|
|
// Trigger the clocking event in Observed (IEEE 1800-2023 14.13)
|
|
|
|
|
addNextHere(new AstAlwaysObserved{
|
|
|
|
|
fileline(), new AstSenTree{fileline(), sensesp()->cloneTree(false)},
|
|
|
|
|
new AstFireEvent{fileline(), new AstVarRef{fileline(), evp, VAccess::WRITE}, false}});
|
|
|
|
|
v3Global.setHasEvents();
|
|
|
|
|
}
|
|
|
|
|
return eventp();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-24 12:06:57 +02:00
|
|
|
void AstConsDynArray::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeExpr::dump(str);
|
|
|
|
|
if (lhsIsValue()) str << " [LVAL]";
|
|
|
|
|
if (rhsIsValue()) str << " [RVAL]";
|
|
|
|
|
}
|
|
|
|
|
void AstConsDynArray::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, lhsIsValue);
|
|
|
|
|
dumpJsonBoolFunc(str, rhsIsValue);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstConsQueue::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeExpr::dump(str);
|
|
|
|
|
if (lhsIsValue()) str << " [LVAL]";
|
|
|
|
|
if (rhsIsValue()) str << " [RVAL]";
|
|
|
|
|
}
|
|
|
|
|
void AstConsQueue::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, lhsIsValue);
|
|
|
|
|
dumpJsonBoolFunc(str, rhsIsValue);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-11-09 18:05:26 +01:00
|
|
|
void AstConstraint::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isKwdPure()) str << " [KWDPURE]";
|
|
|
|
|
if (isStatic()) str << " [STATIC]";
|
|
|
|
|
}
|
|
|
|
|
void AstConstraint::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isKwdPure);
|
|
|
|
|
dumpJsonBoolFunc(str, isStatic);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-11-09 18:45:55 +01:00
|
|
|
void AstConstraintExpr::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isDisableSoft()) str << " [DISSOFT]";
|
|
|
|
|
if (isSoft()) str << " [SOFT]";
|
|
|
|
|
}
|
|
|
|
|
void AstConstraintExpr::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isDisableSoft);
|
|
|
|
|
dumpJsonBoolFunc(str, isSoft);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
2024-08-21 12:16:44 +02:00
|
|
|
string AstConstraintRef::name() const { return constrp()->name(); }
|
|
|
|
|
|
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
|
|
|
}
|
2024-06-25 11:27:09 +02:00
|
|
|
bool AstVar::isScUintBool() const {
|
|
|
|
|
return (isSc() && v3Global.opt.pinsScUintBool() && width() == 1);
|
|
|
|
|
}
|
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()
|
2023-09-20 13:33:11 +02:00
|
|
|
|| (forFunc && (isWritable() || this->isRef() || this->isConstRef()))
|
|
|
|
|
|| 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";
|
2023-10-25 02:46:20 +02:00
|
|
|
} else if (isDouble()) {
|
|
|
|
|
arg += "VLVT_REAL";
|
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;
|
2024-11-26 00:25:36 +01:00
|
|
|
if (isInout()) {
|
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 ";
|
2023-09-20 13:33:11 +02:00
|
|
|
const bool isRef = !forReturn && (isWritable() || this->isRef() || this->isConstRef());
|
2022-03-05 22:19:53 +01:00
|
|
|
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()) {
|
2024-07-14 17:39:45 +02:00
|
|
|
return ("sc_dt::sc_biguint<"s + cvtToStr(widthMin())
|
2020-04-15 13:58:34 +02:00
|
|
|
+ "> "); // Keep the space so don't get >>
|
2024-06-25 11:27:09 +02:00
|
|
|
} else if (isScUint() || isScUintBool()) {
|
2024-07-14 17:39:45 +02:00
|
|
|
return ("sc_dt::sc_uint<"s + 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()) {
|
2024-07-14 17:39:45 +02:00
|
|
|
return ("sc_dt::sc_bv<"s + 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
|
|
|
}
|
|
|
|
|
|
2024-11-29 14:10:51 +01:00
|
|
|
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) const VL_MT_STABLE {
|
|
|
|
|
const AstNodeDType* nodep = this;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType)
|
|
|
|
|
|| VN_IS(nodep, RefDType) //
|
|
|
|
|
|| (VN_IS(nodep, ConstDType) && skipConst) //
|
|
|
|
|
|| (VN_IS(nodep, EnumDType) && skipEnum))) {
|
|
|
|
|
if (const AstNodeDType* subp = nodep->subDTypep()) {
|
|
|
|
|
nodep = subp;
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
v3fatalSrc("Typedef not linked");
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-03 16:23:04 +01:00
|
|
|
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef, bool packed) const {
|
|
|
|
|
const CTypeRecursed info = cTypeRecurse(false, packed);
|
2020-10-17 22:48:11 +02:00
|
|
|
return info.render(name, isRef);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-03 16:23:04 +01:00
|
|
|
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packed) 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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true, false);
|
|
|
|
|
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true, false);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
2023-09-19 03:17:21 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, CDType)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
2023-09-19 03:17:21 +02:00
|
|
|
info.m_type = adtypep->name();
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true, false);
|
2022-07-20 15:01:36 +02:00
|
|
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true, false);
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true, false);
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true, false);
|
2022-12-23 13:34:49 +01:00
|
|
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
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)) {
|
2024-03-03 16:23:04 +01:00
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
2020-12-13 01:19:16 +01:00
|
|
|
if (adtypep->isCompound()) compound = true;
|
2024-03-03 16:23:04 +01:00
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound, false);
|
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 += ">";
|
Support NBAs to arrays inside loops (#5092)
For NBAs that might execute a dynamic number of times in a single
evaluation (specifically: those that assign to array elements inside
loops), we introduce a new run-time VlNBACommitQueue data-structure
(currently a vector), which stores all pending updates and the necessary
info to reconstruct the LHS reference of the AstAssignDly at run-time.
All variables needing a commit queue has their corresponding unique
commit queue.
All NBAs to a variable that requires a commit queue go through the
commit queue. This is necessary to preserve update order in sequential
code, e.g.:
a[7] <= 10
for (int i = 1 ; i < 10; ++i) a[i] <= i;
a[2] <= 10
needs to end with array elements 1..9 being 1, 10, 3, 4, 5, 6, 7, 8, 9.
This enables supporting common forms of NBAs to arrays on the left hand
side of <= in non-suspendable/non-fork code. (Suspendable/fork
implementation is unclear to me so I left it unchanged, see #5084).
Any NBA that does not need a commit queue (i.e.: those that were
supported before), use the same scheme as before, and this patch should
have no effect on the generated code for those NBAs.
2024-05-03 13:45:49 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, NBACommitQueueDType)) {
|
|
|
|
|
UASSERT_OBJ(!packed, this, "Unsupported type for packed struct or union");
|
|
|
|
|
compound = true;
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound, false);
|
|
|
|
|
AstNodeDType* eDTypep = adtypep->subDTypep();
|
|
|
|
|
unsigned rank = 0;
|
|
|
|
|
while (AstUnpackArrayDType* const uaDTypep = VN_CAST(eDTypep, UnpackArrayDType)) {
|
|
|
|
|
eDTypep = uaDTypep->subDTypep()->skipRefp();
|
|
|
|
|
++rank;
|
|
|
|
|
}
|
|
|
|
|
info.m_type = "VlNBACommitQueue<";
|
|
|
|
|
info.m_type += sub.m_type;
|
|
|
|
|
info.m_type += adtypep->partial() ? ", true" : ", false";
|
|
|
|
|
info.m_type += ", " + eDTypep->cTypeRecurse(compound, false).m_type;
|
|
|
|
|
info.m_type += ", " + std::to_string(rank);
|
|
|
|
|
info.m_type += ">";
|
2024-03-03 16:23:04 +01:00
|
|
|
} else if (packed && (VN_IS(dtypep, PackArrayDType))) {
|
|
|
|
|
const AstPackArrayDType* const adtypep = VN_CAST(dtypep, PackArrayDType);
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, true);
|
|
|
|
|
info.m_type = std::move(sub.m_type);
|
|
|
|
|
info.m_dims = "[" + cvtToStr(adtypep->elementsConst()) + "]" + sub.m_dims;
|
|
|
|
|
} else if (VN_IS(dtypep, NodeUOrStructDType)
|
|
|
|
|
&& (!VN_AS(dtypep, NodeUOrStructDType)->packed() || packed)) {
|
|
|
|
|
const AstNodeUOrStructDType* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
|
|
|
|
UASSERT_OBJ(!packed || sdtypep->packed(), this,
|
|
|
|
|
"Unsupported type for packed struct or union");
|
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";
|
2024-05-17 16:38:34 +02:00
|
|
|
} else if (bdtypep->isRandomGenerator()) {
|
|
|
|
|
info.m_type = "VlRandomizer";
|
2022-05-15 17:03:32 +02:00
|
|
|
} else if (bdtypep->isEvent()) {
|
2023-10-26 16:38:47 +02:00
|
|
|
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "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
|
|
|
}
|
2024-03-03 16:23:04 +01:00
|
|
|
// CData, SData, IData, QData or VlWide are packed type.
|
|
|
|
|
const bool packedType = VString::startsWith(info.m_type, "CData")
|
|
|
|
|
|| VString::startsWith(info.m_type, "SData")
|
|
|
|
|
|| VString::startsWith(info.m_type, "IData")
|
|
|
|
|
|| VString::startsWith(info.m_type, "QData")
|
|
|
|
|
|| VString::startsWith(info.m_type, "VlWide");
|
|
|
|
|
UASSERT_OBJ(!packed || packedType, this, "Unsupported type for packed struct or union");
|
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;
|
2024-06-09 04:45:26 +02:00
|
|
|
} else if (VN_IS(dtypep, QueueDType) || VN_IS(dtypep, DynArrayDType)
|
|
|
|
|
|| VN_IS(dtypep, AssocArrayDType) || VN_IS(dtypep, WildcardArrayDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
unpacked++;
|
2024-06-09 04:44:45 +02:00
|
|
|
dtypep = dtypep->subDTypep();
|
2019-12-19 00:17:18 +01:00
|
|
|
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
|
|
|
}
|
2023-11-15 14:24:41 +01:00
|
|
|
// AstNodePreSel 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
|
|
|
}
|
2024-08-06 17:07:38 +02:00
|
|
|
bool AstJumpBlock::isPure() {
|
|
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
|
|
|
|
}
|
|
|
|
|
bool AstJumpBlock::getPurityRecurse() const {
|
|
|
|
|
for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
|
|
|
if (!stmtp->isPure()) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-05-07 03:33:05 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-12 02:20:37 +01:00
|
|
|
AstConstraintRefDType* AstTypeTable::findConstraintRefDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_constraintRefp)) {
|
|
|
|
|
AstConstraintRefDType* const newp = new AstConstraintRefDType{fl};
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
m_constraintRefp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_constraintRefp;
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
2023-11-12 02:20:37 +01:00
|
|
|
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_voidp)) {
|
|
|
|
|
AstVoidDType* const newp = new AstVoidDType{fl};
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
m_voidp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_voidp;
|
|
|
|
|
}
|
2020-11-01 16:56:07 +01:00
|
|
|
|
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()};
|
2023-10-28 14:38:02 +02:00
|
|
|
auto pair = m_detailedMap.emplace(key, nodep);
|
|
|
|
|
if (pair.second) nodep->generic(true);
|
2012-04-29 16:14:13 +02:00
|
|
|
// No addTypesp; the upper function that called new() is responsible for adding
|
2023-10-28 14:38:02 +02:00
|
|
|
return pair.first->second;
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
|
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-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
|
|
|
|
|
|
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());
|
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
|
|
|
|
2024-02-09 23:50:09 +01:00
|
|
|
void dumpNodeListJson(std::ostream& os, const AstNode* nodep, const std::string& listName,
|
|
|
|
|
const string& indent) {
|
|
|
|
|
os << ',';
|
|
|
|
|
if (!nodep) { // empty list, print inline
|
|
|
|
|
os << '"' << listName << "\": []";
|
|
|
|
|
} else {
|
|
|
|
|
os << '\n' << indent + " \"" << listName << "\": [\n";
|
|
|
|
|
for (; nodep; nodep = nodep->nextp()) {
|
|
|
|
|
nodep->dumpTreeJson(os, indent + " ");
|
|
|
|
|
if (nodep->nextp()) os << ',';
|
|
|
|
|
os << '\n';
|
|
|
|
|
}
|
|
|
|
|
os << indent << ']';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dumpFileInfo(std::ostream& os, const FileLine* fileinfop) {
|
|
|
|
|
const std::string filename
|
|
|
|
|
= v3Global.opt.jsonIds() ? fileinfop->filenameLetters() : fileinfop->filename();
|
|
|
|
|
os << ",\"loc\":\"" << filename << ',' << fileinfop->firstLineno() << ':'
|
|
|
|
|
<< fileinfop->firstColumn() << ',' << fileinfop->lastLineno() << ':'
|
|
|
|
|
<< fileinfop->lastColumn() << '"';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstNode::dumpTreeJson(std::ostream& os, const string& indent) const {
|
|
|
|
|
os << indent << "{\"type\":\"" << typeName() << '"';
|
|
|
|
|
dumpJsonStr(os, "name", V3OutFormatter::quoteNameControls(prettyName()));
|
|
|
|
|
dumpJsonPtr(os, "addr", this);
|
|
|
|
|
dumpFileInfo(os, fileline());
|
|
|
|
|
#ifdef VL_DEBUG
|
|
|
|
|
if (v3Global.opt.jsonEditNums()) dumpJsonNum(os, "editNum", editCount());
|
|
|
|
|
#endif
|
|
|
|
|
if (hasDType()) {
|
|
|
|
|
dumpJsonPtrFunc(os, dtypep);
|
|
|
|
|
} else { // V3Broken will throw an error
|
|
|
|
|
if (dtypep()) {
|
|
|
|
|
dumpJsonStr(os, "dtypep", " %Error-dtype-exp=null,got=" + nodeAddr(dtypep()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dumpJson(os);
|
|
|
|
|
dumpTreeJsonOpGen(os, indent);
|
|
|
|
|
os << "}";
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeProcedure::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isSuspendable);
|
|
|
|
|
dumpJsonBoolFunc(str, needProcess);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstAlways::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeProcedure::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
|
2013-05-01 04:55:28 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstAlways::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "keyword", keyword().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-08-05 23:54:13 +02:00
|
|
|
AstAssertCtl::AstAssertCtl(FileLine* fl, VAssertCtlType ctlType, AstNodeExpr*, AstNodeExpr*)
|
2024-05-08 14:31:34 +02:00
|
|
|
: ASTGEN_SUPER_AssertCtl(fl)
|
|
|
|
|
, m_ctlType{ctlType} {
|
|
|
|
|
controlTypep(new AstConst{fl, ctlType});
|
|
|
|
|
}
|
2024-07-10 11:06:13 +02:00
|
|
|
AstAssertCtl::AstAssertCtl(FileLine* fl, AstNodeExpr* controlTypep, AstNodeExpr* assertTypesp,
|
2024-08-05 23:54:13 +02:00
|
|
|
AstNodeExpr* directiveTypep, AstNodeExpr*, AstNodeExpr*)
|
2024-05-08 14:31:34 +02:00
|
|
|
: ASTGEN_SUPER_AssertCtl(fl)
|
2024-07-10 11:06:13 +02:00
|
|
|
, m_ctlType{VAssertCtlType::_TO_BE_EVALUATED}
|
2024-08-05 23:54:13 +02:00
|
|
|
, m_assertTypes{VAssertType::INTERNAL}
|
|
|
|
|
, m_directiveTypes{VAssertDirectiveType::INTERNAL} {
|
2024-05-08 14:31:34 +02:00
|
|
|
this->controlTypep(controlTypep);
|
2024-07-10 11:06:13 +02:00
|
|
|
this->assertTypesp(assertTypesp);
|
2024-08-05 23:54:13 +02:00
|
|
|
this->directiveTypesp(directiveTypep);
|
2024-05-08 14:31:34 +02:00
|
|
|
}
|
|
|
|
|
void AstAssertCtl::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << ctlType().ascii() << "]";
|
|
|
|
|
}
|
|
|
|
|
void AstAssertCtl::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "ctlType", ctlType().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstAttrOf::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "attrType", attrType().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstBasicDType::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "keyword", keyword().ascii());
|
|
|
|
|
if (isRanged() && !rangep()) {
|
|
|
|
|
dumpJsonStr(str, "range", std::to_string(left()) + ":" + std::to_string(right()));
|
|
|
|
|
}
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstBasicDType::prettyDTypeName(bool) const {
|
2020-01-26 19:21:25 +01:00
|
|
|
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); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeExpr::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2022-10-12 11:19:21 +02:00
|
|
|
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeUniop::dumpJson(std::ostream& str) const { dumpJsonGen(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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCCast::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonNumFunc(str, size);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCell::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, origName);
|
|
|
|
|
dumpJsonBoolFunc(str, recursive);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCellInline::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, origModName);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-04-02 05:11:15 +02:00
|
|
|
void AstCellInlineScope::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " -> " << origModName();
|
|
|
|
|
str << " [scopep=" << nodeAddr(scopep()) << "]";
|
|
|
|
|
}
|
|
|
|
|
void AstCellInlineScope::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, origModName);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2023-07-08 18:27:50 +02:00
|
|
|
bool AstClass::isCacheableChild(const AstNode* nodep) {
|
2023-11-12 02:20:37 +01:00
|
|
|
return (VN_IS(nodep, Var) || VN_IS(nodep, Constraint) || VN_IS(nodep, EnumItemRef)
|
2023-07-08 18:27:50 +02:00
|
|
|
|| (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]";
|
2024-01-24 01:36:11 +01:00
|
|
|
if (useVirtualPublic()) str << " [VIRPUB]";
|
2020-08-24 02:00:39 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstClass::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isExtended);
|
|
|
|
|
dumpJsonBoolFunc(str, isInterfaceClass);
|
|
|
|
|
dumpJsonBoolFunc(str, isVirtual);
|
2024-03-28 04:57:58 +01:00
|
|
|
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
2024-02-09 23:50:09 +01:00
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2023-01-28 22:30:47 +01:00
|
|
|
void AstClassExtends::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (isImplements()) str << " [IMPLEMENTS]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstClassExtends::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isImplements);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstClassRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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
|
|
|
}
|
2024-06-14 03:29:03 +02:00
|
|
|
string AstClassRefDType::prettyDTypeName(bool) const { return "class{}"s + prettyName(); }
|
2022-09-15 14:10:39 +02:00
|
|
|
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);
|
2024-07-10 11:06:13 +02:00
|
|
|
str << " ["s + this->type().ascii() + "]";
|
2019-12-17 03:43:52 +01:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeCoverOrAssert::dumpJson(std::ostream& str) const {
|
2024-07-10 11:06:13 +02:00
|
|
|
dumpJsonStr(str, "type", "["s + this->type().ascii() + "]");
|
2024-02-09 23:50:09 +01:00
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstClocking::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isDefault);
|
|
|
|
|
dumpJsonBoolFunc(str, isGlobal);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstDisplay::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2022-11-19 19:23:28 +01:00
|
|
|
void AstEnumDType::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dump(str);
|
|
|
|
|
str << " enum";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstEnumDType::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBool(str, "enum", 1);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2022-11-19 19:23:28 +01:00
|
|
|
void AstEnumDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "enum";
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstEnumDType::prettyDTypeName(bool full) const {
|
|
|
|
|
string result = "enum{";
|
|
|
|
|
if (full) { // else shorten for error messages
|
|
|
|
|
for (AstEnumItem* itemp = itemsp(); itemp; itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
|
|
|
|
result += itemp->prettyName() + "=";
|
|
|
|
|
if (AstConst* constp = VN_CAST(itemp->valuep(), Const)) {
|
|
|
|
|
result += constp->num().ascii(true, true);
|
|
|
|
|
} else {
|
|
|
|
|
result += "?";
|
|
|
|
|
}
|
|
|
|
|
result += ";";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result += "}" + prettyName();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
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
|
|
|
}
|
2023-11-06 13:13:31 +01:00
|
|
|
const char* AstEnumDType::broken() const {
|
2023-12-01 01:58:16 +01:00
|
|
|
BROKEN_RTN(!((m_refDTypep && !childDTypep()) || (!m_refDTypep && childDTypep())));
|
2023-11-06 13:13:31 +01:00
|
|
|
BROKEN_RTN(std::any_of(m_tableMap.begin(), m_tableMap.end(),
|
|
|
|
|
[](const auto& p) { return !p.second->brokeExists(); }));
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstEnumItemRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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);
|
2024-11-10 18:08:37 +01:00
|
|
|
if (isPortDecl()) str << " [PORTDECL]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstIfaceRefDType::dumpJson(std::ostream& str) const {
|
2024-11-10 18:08:37 +01:00
|
|
|
dumpJsonBoolFunc(str, isPortDecl);
|
|
|
|
|
dumpJsonBoolFunc(str, isVirtual);
|
2024-02-09 23:50:09 +01:00
|
|
|
dumpJsonStrFunc(str, cellName);
|
|
|
|
|
dumpJsonStrFunc(str, ifaceName);
|
|
|
|
|
dumpJsonStrFunc(str, modportName);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstInitArray::dumpInitList(std::ostream& str) const {
|
2019-11-09 21:34:41 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
const string addr
|
|
|
|
|
= (v3Global.opt.jsonIds() ? v3Global.ptrToId(itr.second) : nodeAddr(itr.second));
|
|
|
|
|
str << " [" << itr.first << "]=" << addr;
|
2019-11-09 21:34:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstInitArray::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
dumpInitList(str);
|
|
|
|
|
}
|
|
|
|
|
void AstInitArray::dumpJson(std::ostream& str) const {
|
|
|
|
|
str << ',' << '"' << "initList" << '"' << ':' << '"';
|
|
|
|
|
dumpInitList(str);
|
|
|
|
|
str << '"';
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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() {
|
2023-12-01 01:58:16 +01:00
|
|
|
cloneRelinkGen();
|
2022-09-15 14:10:39 +02:00
|
|
|
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) {
|
2023-10-28 14:38:02 +02:00
|
|
|
const auto pair = m_map.emplace(index, nullptr);
|
|
|
|
|
if (pair.second) {
|
2022-11-20 21:06:49 +01:00
|
|
|
AstInitItem* const itemp = new AstInitItem{fileline(), newp};
|
2023-10-28 14:38:02 +02:00
|
|
|
pair.first->second = itemp;
|
2022-09-15 20:43:56 +02:00
|
|
|
addInitsp(itemp);
|
2023-10-28 14:38:02 +02:00
|
|
|
} else {
|
|
|
|
|
pair.first->second->valuep(newp);
|
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 {
|
2024-03-27 14:00:34 +01:00
|
|
|
str << "%E:UNLINKED";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2013-02-18 18:15:50 +01:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2022-09-15 14:10:39 +02:00
|
|
|
const char* AstJumpGo::broken() const {
|
|
|
|
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2023-12-01 01:58:16 +01:00
|
|
|
|
2020-05-07 03:33:05 +02:00
|
|
|
void AstJumpLabel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-05-07 03:33:05 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (blockp()) {
|
|
|
|
|
blockp()->dump(str);
|
|
|
|
|
} else {
|
2024-03-27 14:00:34 +01:00
|
|
|
str << "%E:UNLINKED";
|
2020-05-07 03:33:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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";
|
|
|
|
|
}
|
2024-11-29 14:10:51 +01:00
|
|
|
AstNodeUOrStructDType* AstMemberDType::getChildStructp() {
|
2023-05-07 03:41:17 +02:00
|
|
|
AstNodeDType* subdtp = skipRefp();
|
|
|
|
|
while (AstNodeArrayDType* const asubdtp = VN_CAST(subdtp, NodeArrayDType)) {
|
|
|
|
|
subdtp = asubdtp->subDTypep();
|
|
|
|
|
}
|
2024-03-03 16:23:04 +01:00
|
|
|
// It's possible that `subdtp` is still a ref type, so skip it.
|
|
|
|
|
return VN_CAST(subdtp->skipRefp(), NodeUOrStructDType); // Maybe nullptr
|
2023-05-07 03:41:17 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-11 16:42:58 +02:00
|
|
|
AstMemberSel::AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp)
|
|
|
|
|
: ASTGEN_SUPER_MemberSel(fl)
|
|
|
|
|
, m_name{varp->name()} {
|
|
|
|
|
this->fromp(fromp);
|
|
|
|
|
this->varp(varp);
|
|
|
|
|
dtypep(varp->dtypep());
|
|
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstMemberSel::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
|
2023-10-18 23:36:09 +02:00
|
|
|
return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp())
|
2024-11-28 20:37:11 +01:00
|
|
|
&& name() == sp->name() && varp()->sameNode(sp->varp());
|
2023-06-30 09:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
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 {
|
2024-03-27 14:00:34 +01:00
|
|
|
str << "%E:UNLINKED";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2020-01-16 02:18:12 +01:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstMemberSel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstModportFTaskRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isExport);
|
|
|
|
|
dumpJsonBoolFunc(str, isImport);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstModportVarRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "direction", direction().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstPin::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, svDotName);
|
|
|
|
|
dumpJsonBoolFunc(str, svImplicit);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstPrintTimeScale::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeTermop::dumpJson(std::ostream& str) const { dumpJsonGen(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();
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTime::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTimeD::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTimeImport::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTypedef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, attrPublic);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeRange::dumpJson(std::ostream& str) const { dumpJsonGen(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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstRange::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, ascending);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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";
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstParamTypeDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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 << " -> ";
|
2024-10-07 00:08:40 +02:00
|
|
|
if (const auto subp = subDTypep()) {
|
2024-10-07 00:10:07 +02:00
|
|
|
if (typedefp()) str << "typedef=" << static_cast<void*>(typedefp()) << " -> ";
|
2021-07-08 01:42:49 +02:00
|
|
|
subp->dump(str);
|
2024-10-07 00:08:40 +02:00
|
|
|
} else if (const auto subp = typedefp()) {
|
2021-07-08 01:42:49 +02:00
|
|
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstRefDType::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2022-11-19 19:23:28 +01:00
|
|
|
void AstRefDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "ref";
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeUOrStructDType::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, packed);
|
|
|
|
|
dumpJsonBoolFunc(str, isFourstate);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstNodeUOrStructDType::prettyDTypeName(bool full) const {
|
|
|
|
|
string result = verilogKwd() + "{";
|
|
|
|
|
if (full) { // else shorten for errors
|
|
|
|
|
for (AstMemberDType* itemp = membersp(); itemp;
|
|
|
|
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
|
|
|
|
result += itemp->subDTypep()->prettyDTypeName(full);
|
|
|
|
|
result += " " + itemp->prettyName() + ";";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result += "}" + prettyName();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeDType::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, generic);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-03-02 14:57:26 +01:00
|
|
|
void AstNodeDType::dumpSmall(std::ostream& str) const VL_MT_STABLE {
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeArrayDType::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isCompound);
|
|
|
|
|
dumpJsonStr(str, "declRange", cvtToStr(declRange()));
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstPackArrayDType::prettyDTypeName(bool full) const {
|
2020-01-26 19:21:25 +01:00
|
|
|
std::ostringstream os;
|
2024-06-01 03:51:12 +02:00
|
|
|
if (const auto subp = subDTypep()) os << subp->prettyDTypeName(full);
|
2021-07-08 01:42:49 +02:00
|
|
|
os << declRange();
|
2020-01-26 19:21:25 +01:00
|
|
|
return os.str();
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstUnpackArrayDType::prettyDTypeName(bool full) const {
|
2020-01-26 19:21:25 +01:00
|
|
|
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();
|
|
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
os << subp->prettyDTypeName(full) << "$" << ranges;
|
2020-01-26 19:21:25 +01:00
|
|
|
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() << "]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNetlist::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonStr(str, "timeprecision", timeprecision().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeModule::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, origName);
|
|
|
|
|
dumpJsonNumFunc(str, level);
|
|
|
|
|
dumpJsonBoolFunc(str, modPublic);
|
|
|
|
|
dumpJsonBoolFunc(str, inLibrary);
|
|
|
|
|
dumpJsonBoolFunc(str, dead);
|
|
|
|
|
dumpJsonBoolFunc(str, recursiveClone);
|
|
|
|
|
dumpJsonBoolFunc(str, recursive);
|
|
|
|
|
dumpJsonStr(str, "timeunit", timeunit().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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);
|
2024-09-29 02:55:22 +02:00
|
|
|
if (packagep()) {
|
|
|
|
|
str << " -> " << packagep();
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED:" << pkgName();
|
|
|
|
|
}
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstPackageExport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2024-09-29 02:55:22 +02:00
|
|
|
void AstPackageExport::pkgNameFrom() {
|
|
|
|
|
if (packagep()) m_pkgName = packagep()->name();
|
|
|
|
|
}
|
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);
|
2024-09-29 02:55:22 +02:00
|
|
|
if (packagep()) {
|
|
|
|
|
str << " -> " << packagep();
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED:" << pkgName();
|
|
|
|
|
}
|
2009-11-10 01:07:59 +01:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstPackageImport::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2024-09-29 02:55:22 +02:00
|
|
|
void AstPackageImport::pkgNameFrom() {
|
|
|
|
|
if (packagep()) m_pkgName = packagep()->name();
|
|
|
|
|
}
|
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]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstPatMember::dumpJson(std::ostream& str) const {
|
|
|
|
|
if (isDefault()) dumpJsonBoolFunc(str, isDefault);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeTriop::dumpJson(std::ostream& str) const { dumpJsonGen(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
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstSel::dumpJson(std::ostream& str) const {
|
|
|
|
|
if (declRange().ranged()) {
|
|
|
|
|
dumpJsonStr(str, "declRange", cvtToStr(declRange()));
|
|
|
|
|
dumpJsonNumFunc(str, declElWidth);
|
|
|
|
|
}
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstSliceSel::dumpJson(std::ostream& str) const {
|
2024-03-27 22:57:49 +01:00
|
|
|
if (declRange().ranged()) dumpJsonStr(str, "declRange", cvtToStr(declRange()));
|
2024-02-09 23:50:09 +01:00
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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);
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstMTaskBody::dumpJson(std::ostream& str) const {
|
|
|
|
|
str << ',' << '"' << "execMTask" << '"' << ':' << '"';
|
|
|
|
|
m_execMTaskp->dump(str); // TODO: Consider dumping it as json object
|
|
|
|
|
str << '"';
|
|
|
|
|
dumpJsonGen(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.
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTypeTable::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2019-12-01 17:52:48 +01:00
|
|
|
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2023-10-25 17:50:22 +02:00
|
|
|
str << "[assoc-" << nodeAddr(keyDTypep()) << "]";
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstAssocArrayDType::prettyDTypeName(bool full) const {
|
|
|
|
|
return subDTypep()->prettyDTypeName(full) + "$[" + keyDTypep()->prettyDTypeName(full) + "]";
|
2020-01-26 19:21:25 +01:00
|
|
|
}
|
2020-03-07 16:24:27 +01:00
|
|
|
void AstDynArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2024-06-01 03:51:12 +02:00
|
|
|
str << "$[]";
|
|
|
|
|
}
|
|
|
|
|
string AstDynArrayDType::prettyDTypeName(bool full) const {
|
|
|
|
|
return subDTypep()->prettyDTypeName(full) + "$[]";
|
2020-03-07 16:24:27 +01:00
|
|
|
}
|
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
|
|
|
}
|
2024-06-01 03:51:12 +02:00
|
|
|
string AstQueueDType::prettyDTypeName(bool full) const {
|
|
|
|
|
string str = subDTypep()->prettyDTypeName(full) + "$[$";
|
2020-01-26 19:21:25 +01:00
|
|
|
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 << "[*]";
|
|
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstWildcardArrayDType::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
2022-09-15 14:10:39 +02:00
|
|
|
if (!asamep->subDTypep()) return false;
|
|
|
|
|
return (subDTypep() == asamep->subDTypep());
|
|
|
|
|
}
|
2024-11-29 15:20:02 +01:00
|
|
|
bool AstWildcardArrayDType::similarDTypeNode(const AstNodeDType* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
2024-11-29 15:20:02 +01:00
|
|
|
return asamep->subDTypep() && subDTypep()->similarDType(asamep->subDTypep());
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
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
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstUnsizedArrayDType::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
|
2022-09-15 14:10:39 +02:00
|
|
|
if (!asamep->subDTypep()) return false;
|
|
|
|
|
return (subDTypep() == asamep->subDTypep());
|
|
|
|
|
}
|
2024-11-29 15:20:02 +01:00
|
|
|
bool AstUnsizedArrayDType::similarDTypeNode(const AstNodeDType* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
|
2024-11-29 15:20:02 +01:00
|
|
|
return asamep->subDTypep() && subDTypep()->similarDType(asamep->subDTypep());
|
2022-09-15 14:10:39 +02:00
|
|
|
}
|
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]";
|
2023-10-25 17:50:22 +02:00
|
|
|
if (scopep()) str << " [scopep=" << nodeAddr(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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstVarScope::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isTrace);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstVarScope::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope);
|
2024-11-28 20:37:11 +01:00
|
|
|
return varp()->sameNode(asamep->varp()) && scopep()->sameNode(asamep->scopep());
|
2023-06-03 16:07:39 +02:00
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeVarRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "access", access().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstVarXRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, dotted);
|
|
|
|
|
dumpJsonStrFunc(str, inlinedDots);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstVarRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2023-08-03 08:52:52 +02:00
|
|
|
const char* AstVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(!varp());
|
2023-12-01 01:58:16 +01:00
|
|
|
return nullptr;
|
2023-08-03 08:52:52 +02:00
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstVarRef::sameNode(const AstNode* samep) const { return sameNode(VN_DBG_AS(samep, VarRef)); }
|
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]";
|
2024-11-26 00:25:36 +01:00
|
|
|
if (isPrimaryIO()) str << (isInout() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]"));
|
2020-04-15 13:58:34 +02:00
|
|
|
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]";
|
2023-09-19 03:17:21 +02:00
|
|
|
if (isInternal()) str << " [INTERNAL]";
|
2021-01-05 20:26:01 +01:00
|
|
|
if (isLatched()) str << " [LATCHED]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isUsedLoopIdx()) str << " [LOOP]";
|
2024-08-13 20:20:31 +02:00
|
|
|
if (rand().isRandomizable()) str << rand();
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstVar::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, origName);
|
|
|
|
|
dumpJsonBoolFunc(str, isSc);
|
|
|
|
|
dumpJsonBoolFunc(str, isPrimaryIO);
|
|
|
|
|
dumpJsonStr(str, "direction", direction().ascii());
|
|
|
|
|
dumpJsonBoolFunc(str, isConst);
|
|
|
|
|
dumpJsonBoolFunc(str, isPullup);
|
|
|
|
|
dumpJsonBoolFunc(str, isPulldown);
|
|
|
|
|
dumpJsonBoolFunc(str, isUsedClock);
|
|
|
|
|
dumpJsonBoolFunc(str, isSigPublic);
|
|
|
|
|
dumpJsonBoolFunc(str, isLatched);
|
|
|
|
|
dumpJsonBoolFunc(str, isUsedLoopIdx);
|
|
|
|
|
dumpJsonBoolFunc(str, noReset);
|
|
|
|
|
dumpJsonBoolFunc(str, attrIsolateAssign);
|
|
|
|
|
dumpJsonBoolFunc(str, attrFileDescr);
|
|
|
|
|
dumpJsonBoolFunc(str, isDpiOpenArray);
|
|
|
|
|
dumpJsonBoolFunc(str, isFuncReturn);
|
|
|
|
|
dumpJsonBoolFunc(str, isFuncLocal);
|
|
|
|
|
dumpJsonStr(str, "attrClocker", (attrClocker().unknown() ? "UNKNOWN" : attrClocker().ascii()));
|
|
|
|
|
dumpJsonStr(str, "lifetime", lifetime().ascii());
|
|
|
|
|
dumpJsonStr(str, "varType", varType().ascii());
|
|
|
|
|
if (dtypep()) dumpJsonStr(str, "dtypeName", dtypep()->name());
|
|
|
|
|
dumpJsonBoolFunc(str, isSigUserRdPublic);
|
|
|
|
|
dumpJsonBoolFunc(str, isSigUserRWPublic);
|
|
|
|
|
dumpJsonBoolFunc(str, isGParam);
|
|
|
|
|
dumpJsonBoolFunc(str, isParam);
|
|
|
|
|
dumpJsonBoolFunc(str, attrScBv);
|
|
|
|
|
dumpJsonBoolFunc(str, attrSFormat);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstVar::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstVar* const asamep = VN_DBG_AS(samep, Var);
|
2023-06-03 16:11:23 +02:00
|
|
|
return name() == asamep->name() && varType() == asamep->varType();
|
2023-06-03 16:07:39 +02:00
|
|
|
}
|
2024-01-26 13:49:07 +01:00
|
|
|
void AstWhile::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
if (unrollFull().isSetTrue())
|
|
|
|
|
str << " [unrollfull]";
|
|
|
|
|
else if (unrollFull().isSetFalse())
|
|
|
|
|
str << " [unrolldis]";
|
|
|
|
|
}
|
2020-11-12 01:00:10 +01:00
|
|
|
void AstScope::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
2023-10-25 17:50:22 +02:00
|
|
|
str << " [abovep=" << nodeAddr(aboveScopep()) << "]";
|
|
|
|
|
str << " [cellp=" << nodeAddr(aboveCellp()) << "]";
|
|
|
|
|
str << " [modp=" << nodeAddr(modp()) << "]";
|
2020-11-12 01:00:10 +01:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstScope::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2024-11-28 20:37:11 +01:00
|
|
|
bool AstScope::sameNode(const AstNode* samep) const {
|
2023-10-16 11:17:52 +02:00
|
|
|
const AstScope* const asamep = VN_DBG_AS(samep, Scope);
|
2023-06-03 16:07:39 +02:00
|
|
|
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]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstScopeName::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, dpiExport);
|
|
|
|
|
dumpJsonBoolFunc(str, forFormat);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstSenTree::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isMulti);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstSenItem::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "edgeType", edgeType().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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() << ")";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstStrengthSpec::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "strength0", m_s0.ascii());
|
|
|
|
|
dumpJsonStr(str, "strength1", m_s1.ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstParseRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "expect", expect().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstClassOrPackageRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstDot::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, colon);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstActive::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, dotted);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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]";
|
2024-03-11 23:56:30 +01:00
|
|
|
if (pureVirtual()) str << " [PUREVIRTUAL]";
|
2022-01-04 00:50:41 +01:00
|
|
|
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
|
|
|
}
|
2023-09-18 15:21:30 +02:00
|
|
|
bool AstNodeFTask::isPure() {
|
2023-09-29 12:23:51 +02:00
|
|
|
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
|
|
|
|
return m_purity.get();
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
const char* AstNodeFTask::broken() const {
|
2023-09-29 12:23:51 +02:00
|
|
|
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
2023-09-18 15:21:30 +02:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2023-09-29 12:23:51 +02:00
|
|
|
bool AstNodeFTask::getPurityRecurse() const {
|
2023-09-18 15:21:30 +02:00
|
|
|
if (this->dpiImport()) return this->dpiPure();
|
|
|
|
|
// Check the list of statements if it contains any impure statement
|
|
|
|
|
// or any write reference to a variable that isn't an automatic function local.
|
|
|
|
|
for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
|
|
|
if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
|
2024-11-26 00:25:36 +01:00
|
|
|
if (varp->isInoutOrRef()) return false;
|
2023-09-18 15:21:30 +02:00
|
|
|
}
|
|
|
|
|
if (!stmtp->isPure()) return false;
|
|
|
|
|
if (stmtp->exists([](const AstNodeVarRef* const varrefp) {
|
|
|
|
|
return (!varrefp->varp()->isFuncLocal() || varrefp->varp()->lifetime().isStatic())
|
|
|
|
|
&& varrefp->access().isWriteOrRW();
|
|
|
|
|
}))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeFTask::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBool(str, "method", classMethod());
|
|
|
|
|
dumpJsonBoolFunc(str, dpiExport);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiImport);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiOpenChild);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiOpenParent);
|
|
|
|
|
dumpJsonBoolFunc(str, prototype);
|
|
|
|
|
dumpJsonBoolFunc(str, recursive);
|
|
|
|
|
dumpJsonBoolFunc(str, taskPublic);
|
2024-03-28 04:57:58 +01:00
|
|
|
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
2024-02-09 23:50:09 +01:00
|
|
|
dumpJsonStrFunc(str, cname);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeBlock::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, unnamed);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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]";
|
2023-10-16 14:02:29 +02:00
|
|
|
if (needProcess()) str << " [NPRC]";
|
2009-10-12 02:50:31 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstBegin::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, generate);
|
|
|
|
|
dumpJsonBool(str, "genfor", bool(genforp()));
|
|
|
|
|
dumpJsonBoolFunc(str, implied);
|
|
|
|
|
dumpJsonBoolFunc(str, needProcess);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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()) {
|
2024-02-08 01:57:02 +01:00
|
|
|
static bool s_recursing = false;
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2024-02-08 01:57:02 +01:00
|
|
|
if (s_recursing) {
|
|
|
|
|
str << "%ErrorRECURSIVE";
|
|
|
|
|
} else {
|
|
|
|
|
s_recursing = true;
|
|
|
|
|
this->dataDeclNullp()->dump(str);
|
|
|
|
|
s_recursing = false;
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCoverDecl::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, page);
|
|
|
|
|
dumpJsonStrFunc(str, linescov);
|
|
|
|
|
dumpJsonNumFunc(str, binNum);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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 {
|
2024-03-27 14:00:34 +01:00
|
|
|
str << "%E:UNLINKED";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCoverInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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() << "]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstFork::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "joinType", joinType().ascii());
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-09-14 02:45:44 +02:00
|
|
|
void AstStop::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (isFatal()) str << " [FATAL]";
|
|
|
|
|
}
|
|
|
|
|
void AstStop::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isFatal);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2022-04-11 01:40:27 +02:00
|
|
|
void AstTraceDecl::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (code()) str << " [code=" << code() << "]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTraceDecl::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonNumFunc(str, code);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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 {
|
2024-03-27 14:00:34 +01:00
|
|
|
str << "%E:UNLINKED";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstTraceInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
|
|
|
|
string AstNodeText::shortText() const {
|
2009-12-05 16:38:49 +01:00
|
|
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
void AstNodeText::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " \"" << shortText() << "\"";
|
|
|
|
|
}
|
|
|
|
|
void AstNodeText::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStrFunc(str, shortText);
|
|
|
|
|
dumpJsonGen(str);
|
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); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstNodeFile::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstVFile::dumpJson(std::ostream& str) const { dumpJsonGen(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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
|
|
|
|
|
void AstCFile::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, source);
|
|
|
|
|
dumpJsonBoolFunc(str, slow);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
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]";
|
2023-11-12 02:34:51 +01:00
|
|
|
if (entryPoint()) str << " [ENTRY]";
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCFunc::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, slow);
|
|
|
|
|
dumpJsonBoolFunc(str, isStatic);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiExportDispatcher);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiExportImpl);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiImportPrototype);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiImportWrapper);
|
|
|
|
|
dumpJsonBoolFunc(str, dpiContext);
|
|
|
|
|
dumpJsonBoolFunc(str, isConstructor);
|
|
|
|
|
dumpJsonBoolFunc(str, isDestructor);
|
|
|
|
|
dumpJsonBoolFunc(str, isVirtual);
|
|
|
|
|
dumpJsonBoolFunc(str, isCoroutine);
|
|
|
|
|
dumpJsonBoolFunc(str, needProcess);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
// TODO: maybe try to shorten these flags somehow
|
|
|
|
|
}
|
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
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCAwait::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
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},
|
2023-10-16 17:06:41 +02:00
|
|
|
{"anyTriggered", false},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"assign", false},
|
|
|
|
|
{"at", true},
|
|
|
|
|
{"atBack", true},
|
2024-09-02 15:45:47 +02:00
|
|
|
{"atWrite", true},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"awaitingCurrentTime", true},
|
|
|
|
|
{"clear", false},
|
|
|
|
|
{"clearFired", false},
|
|
|
|
|
{"commit", false},
|
|
|
|
|
{"delay", false},
|
|
|
|
|
{"done", false},
|
Support NBAs to arrays inside loops (#5092)
For NBAs that might execute a dynamic number of times in a single
evaluation (specifically: those that assign to array elements inside
loops), we introduce a new run-time VlNBACommitQueue data-structure
(currently a vector), which stores all pending updates and the necessary
info to reconstruct the LHS reference of the AstAssignDly at run-time.
All variables needing a commit queue has their corresponding unique
commit queue.
All NBAs to a variable that requires a commit queue go through the
commit queue. This is necessary to preserve update order in sequential
code, e.g.:
a[7] <= 10
for (int i = 1 ; i < 10; ++i) a[i] <= i;
a[2] <= 10
needs to end with array elements 1..9 being 1, 10, 3, 4, 5, 6, 7, 8, 9.
This enables supporting common forms of NBAs to arrays on the left hand
side of <= in non-suspendable/non-fork code. (Suspendable/fork
implementation is unclear to me so I left it unchanged, see #5084).
Any NBA that does not need a commit queue (i.e.: those that were
supported before), use the same scheme as before, and this patch should
have no effect on the generated code for those NBAs.
2024-05-03 13:45:49 +02:00
|
|
|
{"enqueue", false},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"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},
|
2024-05-17 16:38:34 +02:00
|
|
|
{"hard", false},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"init", false},
|
|
|
|
|
{"insert", false},
|
2023-12-12 09:20:22 +01:00
|
|
|
{"inside", true},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"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},
|
2024-11-15 16:45:06 +01:00
|
|
|
{"resize", false},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"resume", false},
|
|
|
|
|
{"reverse", false},
|
|
|
|
|
{"rsort", false},
|
|
|
|
|
{"set", false},
|
2024-07-31 23:30:48 +02:00
|
|
|
{"set_randmode", false},
|
2023-09-11 13:06:15 +02:00
|
|
|
{"shuffle", false},
|
|
|
|
|
{"size", true},
|
|
|
|
|
{"slice", true},
|
|
|
|
|
{"sliceBackBack", true},
|
|
|
|
|
{"sliceFrontBack", true},
|
|
|
|
|
{"sort", false},
|
|
|
|
|
{"thisOr", false},
|
|
|
|
|
{"trigger", false},
|
|
|
|
|
{"unique", true},
|
|
|
|
|
{"unique_index", true},
|
2024-05-17 16:38:34 +02:00
|
|
|
{"word", true},
|
|
|
|
|
{"write_var", false}};
|
2023-09-11 13:06:15 +02:00
|
|
|
|
2024-09-02 15:45:47 +02:00
|
|
|
if (name() == "atWriteAppend" || name() == "atWriteAppendBack") {
|
|
|
|
|
m_pure = false;
|
|
|
|
|
// Treat atWriteAppend as pure if the argument is a loop iterator
|
|
|
|
|
if (AstNodeExpr* const argp = pinsp()) {
|
|
|
|
|
if (AstVarRef* const varrefp = VN_CAST(argp, VarRef)) {
|
|
|
|
|
if (varrefp->varp()->isUsedLoopIdx()) m_pure = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-09-11 13:06:15 +02:00
|
|
|
auto isPureIt = isPureMethod.find(name());
|
|
|
|
|
UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name());
|
|
|
|
|
m_pure = isPureIt->second;
|
2024-09-25 02:24:27 +02:00
|
|
|
if (!m_pure) return;
|
|
|
|
|
if (!fromp()->isPure()) m_pure = false;
|
|
|
|
|
if (!m_pure) return;
|
|
|
|
|
for (AstNodeExpr* argp = pinsp(); argp; argp = VN_AS(argp->nextp(), NodeExpr)) {
|
|
|
|
|
if (!argp->isPure()) {
|
|
|
|
|
m_pure = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-11 13:06:15 +02:00
|
|
|
}
|
2022-09-15 14:10:39 +02:00
|
|
|
|
2020-02-01 22:45:11 +01:00
|
|
|
void AstCUse::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << useType() << "]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstCUse::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonStr(str, "useType", useType().ascii());
|
|
|
|
|
dumpJsonGen(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
|
|
|
|
2024-09-07 00:13:52 +02:00
|
|
|
static AstDelay* getLhsNetDelayRecurse(const AstNodeExpr* const nodep) {
|
|
|
|
|
if (const AstNodeVarRef* const refp = VN_CAST(nodep, NodeVarRef)) {
|
|
|
|
|
if (refp->varp()->delayp()) return refp->varp()->delayp();
|
|
|
|
|
} else if (const AstNodeSel* const selp = VN_CAST(nodep, NodeSel)) {
|
|
|
|
|
return getLhsNetDelayRecurse(selp->fromp());
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
AstDelay* AstAssignW::getLhsNetDelay() const { return getLhsNetDelayRecurse(lhsp()); }
|
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
|
|
|
|
2024-02-13 13:53:32 +01:00
|
|
|
string AstCase::pragmaString() const {
|
|
|
|
|
if (fullPragma() && parallelPragma())
|
|
|
|
|
return "synthesis full_case parallel_case";
|
|
|
|
|
else if (fullPragma())
|
|
|
|
|
return "synthesis full_case";
|
|
|
|
|
else if (parallelPragma())
|
|
|
|
|
return "synthesis parallel_case";
|
|
|
|
|
else if (uniquePragma())
|
|
|
|
|
return "unique case";
|
|
|
|
|
else if (unique0Pragma())
|
|
|
|
|
return "unique0 case";
|
|
|
|
|
else if (priorityPragma())
|
|
|
|
|
return "priority case";
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 13:34:49 +01:00
|
|
|
void AstDelay::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (isCycleDelay()) str << " [CYCLE]";
|
|
|
|
|
}
|
2024-02-09 23:50:09 +01:00
|
|
|
void AstDelay::dumpJson(std::ostream& str) const {
|
|
|
|
|
dumpJsonBoolFunc(str, isCycleDelay);
|
|
|
|
|
dumpJsonGen(str);
|
|
|
|
|
}
|
2024-03-02 14:57:26 +01:00
|
|
|
const char* AstAnd::widthMismatch() const VL_MT_STABLE {
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
const char* AstOr::widthMismatch() const VL_MT_STABLE {
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
const char* AstXor::widthMismatch() const VL_MT_STABLE {
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
const char* AstNot::widthMismatch() const VL_MT_STABLE {
|
|
|
|
|
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|