verilator/src/V3AstNodeOther.h

4080 lines
178 KiB
C
Raw Normal View History

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: AstNode sub-types representing other constructs
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
2025-01-01 14:30:25 +01:00
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
//
// This files contains all 'AstNode' sub-types that relate to other constructs
// not covered by the more specific V3AstNode*.h files.
//
//*************************************************************************
#ifndef VERILATOR_V3ASTNODES_H_
#define VERILATOR_V3ASTNODES_H_
#ifndef VERILATOR_V3AST_H_
#error "Use V3Ast.h as the include"
#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
#endif
// === Abstract base node types (AstNode*) =====================================
class AstNodeBlock VL_NOT_FINAL : public AstNode {
// A Begin/fork block
// @astgen op2 := stmtsp : List[AstNode]
// Parents: statement
string m_name; // Name of block
bool m_unnamed; // Originally unnamed (name change does not affect this)
protected:
AstNodeBlock(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
: AstNode{t, fl}
, m_name{name} {
addStmtsp(stmtsp);
m_unnamed = (name == "");
}
public:
ASTGEN_MEMBERS_AstNodeBlock;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Block name
void name(const string& name) override { m_name = name; }
bool unnamed() const { return m_unnamed; }
bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); }
};
class AstNodeFTask VL_NOT_FINAL : public AstNode {
// Output variable in functions, nullptr in tasks
// @astgen op1 := fvarp : Optional[AstNode]
// Class/package scope
// @astgen op2 := classOrPackagep : Optional[AstNode]
// Statements/Ports/Vars
// @astgen op3 := stmtsp : List[AstNode]
// Scope name
// @astgen op4 := scopeNamep : Optional[AstScopeName]
string m_name; // Name of task
string m_cname; // Name of task if DPI import
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
bool m_taskPublic : 1; // Public task
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
bool m_classMethod : 1; // Class method
bool m_prototype : 1; // Just a prototype
bool m_dpiExport : 1; // DPI exported
bool m_dpiImport : 1; // DPI imported
bool m_dpiContext : 1; // DPI import context
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
bool m_dpiTask : 1; // DPI import task (vs. void function)
bool m_isConstructor : 1; // Class constructor
2024-12-12 14:16:19 +01:00
bool m_isExternProto : 1; // Extern prototype
bool m_isExternDef : 1; // Extern definition
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
bool m_dpiPure : 1; // DPI import pure (vs. virtual pure)
bool m_pureVirtual : 1; // Pure virtual
bool m_recursive : 1; // Recursive or part of recursion
bool m_static : 1; // Static method in class
bool m_underGenerate : 1; // Under generate (for warning)
bool m_virtual : 1; // Virtual method in class
2023-10-16 14:02:29 +02:00
bool m_needProcess : 1; // Needs access to VlProcess of the caller
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
VLifetime m_lifetime; // Default lifetime of local vars
VIsCached m_purity; // Pure state
protected:
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
: AstNode{t, fl}
, m_name{name}
, m_taskPublic{false}
, m_attrIsolateAssign{false}
, m_classMethod{false}
, m_prototype{false}
, m_dpiExport{false}
, m_dpiImport{false}
, m_dpiContext{false}
, m_dpiOpenChild{false}
, m_dpiTask{false}
, m_isConstructor{false}
2024-12-12 14:16:19 +01:00
, m_isExternProto{false}
, m_isExternDef{false}
, m_isHideLocal{false}
, m_isHideProtected{false}
, m_dpiPure{false}
, m_pureVirtual{false}
, m_recursive{false}
, m_static{false}
, m_underGenerate{false}
2023-06-01 16:02:08 +02:00
, m_virtual{false}
, m_needProcess{false} {
addStmtsp(stmtsp);
cname(name); // Might be overridden by dpi import/export
}
public:
ASTGEN_MEMBERS_AstNodeFTask;
virtual AstNodeFTask* cloneType(const string& name) = 0;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool isGateOptimizable() const override {
return !((m_dpiExport || m_dpiImport) && !m_dpiPure);
}
// {AstFunc only} op1 = Range output variable
void name(const string& name) override { m_name = name; }
string cname() const { return m_cname; }
void cname(const string& cname) { m_cname = cname; }
bool isFunction() const { return fvarp() != nullptr; }
// MORE ACCESSORS
void dpiOpenParentInc() { ++m_dpiOpenParent; }
void dpiOpenParentClear() { m_dpiOpenParent = 0; }
uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
bool taskPublic() const { return m_taskPublic; }
void taskPublic(bool flag) { m_taskPublic = flag; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
bool classMethod() const { return m_classMethod; }
void classMethod(bool flag) { m_classMethod = flag; }
2024-12-12 14:16:19 +01:00
bool isExternProto() const { return m_isExternProto; }
void isExternProto(bool flag) { m_isExternProto = flag; }
bool isExternDef() const { return m_isExternDef; }
void isExternDef(bool flag) { m_isExternDef = flag; }
bool prototype() const { return m_prototype; }
void prototype(bool flag) { m_prototype = flag; }
bool dpiExport() const { return m_dpiExport; }
void dpiExport(bool flag) { m_dpiExport = flag; }
bool dpiImport() const { return m_dpiImport; }
void dpiImport(bool flag) { m_dpiImport = flag; }
bool dpiContext() const { return m_dpiContext; }
void dpiContext(bool flag) { m_dpiContext = flag; }
bool dpiOpenChild() const { return m_dpiOpenChild; }
void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; }
bool dpiTask() const { return m_dpiTask; }
void dpiTask(bool flag) { m_dpiTask = flag; }
bool isConstructor() const { return m_isConstructor; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isHideLocal() const { return m_isHideLocal; }
void isHideLocal(bool flag) { m_isHideLocal = flag; }
bool isHideProtected() const { return m_isHideProtected; }
void isHideProtected(bool flag) { m_isHideProtected = flag; }
bool dpiPure() const { return m_dpiPure; }
void dpiPure(bool flag) { m_dpiPure = flag; }
bool pureVirtual() const { return m_pureVirtual; }
void pureVirtual(bool flag) { m_pureVirtual = flag; }
bool recursive() const { return m_recursive; }
void recursive(bool flag) { m_recursive = flag; }
bool isStatic() const { return m_static; }
void isStatic(bool flag) { m_static = flag; }
bool underGenerate() const { return m_underGenerate; }
void underGenerate(bool flag) { m_underGenerate = flag; }
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool needProcess() const { return m_needProcess; }
void setNeedProcess() { m_needProcess = true; }
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
VBaseOverride baseOverride() const { return m_baseOverride; }
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
bool isPure() override;
const char* broken() const override;
void propagateAttrFrom(const AstNodeFTask* fromp) {
// Creating a wrapper with e.g. cloneType(); preserve some attributes
classMethod(fromp->classMethod());
isHideLocal(fromp->isHideLocal());
isHideProtected(fromp->isHideProtected());
isVirtual(fromp->isVirtual());
isStatic(fromp->isStatic());
lifetime(fromp->lifetime());
underGenerate(fromp->underGenerate());
}
private:
bool getPurityRecurse() const;
};
class AstNodeFile VL_NOT_FINAL : public AstNode {
// Emitted Output file
// Parents: NETLIST
// @astgen op1 := tblockp : Optional[AstTextBlock]
string m_name; ///< Filename
public:
AstNodeFile(VNType t, FileLine* fl, const string& name)
: AstNode{t, fl}
, m_name{name} {}
ASTGEN_MEMBERS_AstNodeFile;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstNodeModule VL_NOT_FINAL : public AstNode {
// A module, package, program or interface declaration;
// something that can live directly under the TOP,
// excluding $unit package stuff
// @astgen op1 := inlinesp : List[AstNode]
// @astgen op2 := stmtsp : List[AstNode]
string m_name; // Name of the module
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module.
// Used for user messages only.
string m_libname; // Work library
int m_level = 0; // 1=top module, 2=cell off top module, ...
VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
bool m_modPublic : 1; // Module has public references
bool m_modTrace : 1; // Tracing this module
bool m_inLibrary : 1; // From a library, no error if not used, never top level
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
bool m_hasGParam : 1; // Has global parameter (for link)
bool m_hasParameterList : 1; // Has #() for parameter declaration
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
bool m_hierParams : 1; // Block containing params for parametrized hier blocks
bool m_internal : 1; // Internally created
bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
protected:
AstNodeModule(VNType t, FileLine* fl, const string& name, const string& libname)
: AstNode{t, fl}
, m_name{name}
, m_origName{name}
, m_libname{libname}
, m_modPublic{false}
, m_modTrace{false}
, m_inLibrary{false}
, m_dead{false}
, m_hasGParam{false}
, m_hasParameterList{false}
, m_hierBlock{false}
, m_hierParams{false}
, m_internal{false}
, m_recursive{false}
, m_recursiveClone{false} {}
public:
ASTGEN_MEMBERS_AstNodeModule;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
string name() const override VL_MT_STABLE { return m_name; }
virtual bool timescaleMatters() const = 0;
// ACCESSORS
void name(const string& name) override { m_name = name; }
string origName() const override { return m_origName; }
string someInstanceName() const VL_MT_SAFE { return m_someInstanceName; }
void someInstanceName(const string& name) { m_someInstanceName = name; }
bool inLibrary() const { return m_inLibrary; }
void inLibrary(bool flag) { m_inLibrary = flag; }
void level(int level) { m_level = level; }
int level() const VL_MT_SAFE { return m_level; }
string libname() const { return m_libname; }
string prettyLibnameQ() const { return "'" + prettyName(libname()) + "'"; }
bool isTop() const VL_MT_SAFE { return level() == 1; }
bool modPublic() const { return m_modPublic; }
void modPublic(bool flag) { m_modPublic = flag; }
bool modTrace() const { return m_modTrace; }
void modTrace(bool flag) { m_modTrace = flag; }
bool dead() const { return m_dead; }
void dead(bool flag) { m_dead = flag; }
bool hasGParam() const { return m_hasGParam; }
void hasGParam(bool flag) { m_hasGParam = flag; }
bool hasParameterList() const { return m_hasParameterList; }
void hasParameterList(bool flag) { m_hasParameterList = flag; }
bool hierBlock() const { return m_hierBlock; }
void hierBlock(bool flag) { m_hierBlock = flag; }
bool hierParams() const { return m_hierParams; }
void hierParams(bool flag) { m_hierParams = flag; }
bool internal() const { return m_internal; }
void internal(bool flag) { m_internal = flag; }
bool recursive() const { return m_recursive; }
void recursive(bool flag) { m_recursive = flag; }
void recursiveClone(bool flag) { m_recursiveClone = flag; }
bool recursiveClone() const { return m_recursiveClone; }
VLifetime lifetime() const { return m_lifetime; }
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
};
class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
2023-06-01 16:02:08 +02:00
bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc.
2023-10-16 14:02:29 +02:00
bool m_needProcess : 1; // Uses VlProcess
protected:
AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp)
: AstNode{t, fl} {
2023-06-01 16:02:08 +02:00
m_needProcess = false;
m_suspendable = false;
addStmtsp(stmtsp);
}
public:
ASTGEN_MEMBERS_AstNodeProcedure;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
2022-09-15 14:17:00 +02:00
bool isSuspendable() const { return m_suspendable; }
void setSuspendable() { m_suspendable = true; }
2023-06-01 16:02:08 +02:00
bool needProcess() const { return m_needProcess; }
void setNeedProcess() { m_needProcess = true; }
};
class AstNodeRange VL_NOT_FINAL : public AstNode {
// A range, sized or unsized
protected:
AstNodeRange(VNType t, FileLine* fl)
: AstNode{t, fl} {}
public:
ASTGEN_MEMBERS_AstNodeRange;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstNodeStmt VL_NOT_FINAL : public AstNode {
// Procedural statement
protected:
AstNodeStmt(VNType t, FileLine* fl)
: AstNode{t, fl} {}
public:
ASTGEN_MEMBERS_AstNodeStmt;
// METHODS
void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
// Iteration is in order, and we want rhsp to be visited first (which is the execution order)
// @astgen op1 := rhsp : AstNodeExpr
// @astgen op2 := lhsp : AstNodeExpr
// @astgen op3 := timingControlp : Optional[AstNode]
protected:
AstNodeAssign(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNode* timingControlp = nullptr)
: AstNodeStmt{t, fl} {
this->rhsp(rhsp);
this->lhsp(lhsp);
this->timingControlp(timingControlp);
dtypeFrom(lhsp);
}
public:
ASTGEN_MEMBERS_AstNodeAssign;
// Clone single node, just get same type back.
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
bool hasDType() const override VL_MT_SAFE { return true; }
virtual bool cleanRhs() const { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode*) const override { return true; }
string verilogKwd() const override { return "="; }
2022-09-16 17:15:10 +02:00
bool isTimingControl() const override { return timingControlp(); }
virtual bool brokeLhsMustBeLvalue() const = 0;
};
class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstCaseItem]
// @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's
protected:
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: AstNodeStmt{t, fl} {
this->exprp(exprp);
addItemsp(itemsp);
}
public:
ASTGEN_MEMBERS_AstNodeCase;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
};
class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt {
// Cover or Assert
// Parents: {statement list}
// @astgen op1 := propp : AstNode
// @astgen op2 := sentreep : Optional[AstSenTree]
// op3 used by some sub-types only
// @astgen op4 := passsp: List[AstNode] // Statements when propp is passing/truthly
string m_name; // Name to report
const VAssertType m_type; // Assertion/cover type
const VAssertDirectiveType m_directive; // Assertion directive type
public:
AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, VAssertType type,
VAssertDirectiveType directive, const string& name = "")
: AstNodeStmt{t, fl}
, m_name{name}
, m_type{type}
, m_directive{directive} {
this->propp(propp);
addPasssp(passsp);
}
ASTGEN_MEMBERS_AstNodeCoverOrAssert;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool sameNode(const AstNode* samep) const override { return samep->name() == name(); }
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
VAssertType type() const VL_MT_SAFE { return m_type; }
VAssertDirectiveType directive() const { return m_directive; }
bool immediate() const {
return this->type().containsAny(VAssertType::SIMPLE_IMMEDIATE
| VAssertType::OBSERVED_DEFERRED_IMMEDIATE
| VAssertType::FINAL_DEFERRED_IMMEDIATE)
|| this->type() == VAssertType::INTERNAL;
}
};
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := initsp : List[AstNode]
// @astgen op2 := condp : AstNodeExpr
// @astgen op3 := incsp : List[AstNode]
// @astgen op4 := stmtsp : List[AstNode]
protected:
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
AstNode* stmtsp)
: AstNodeStmt{t, fl} {
addInitsp(initsp);
this->condp(condp);
addIncsp(incsp);
addStmtsp(stmtsp);
}
public:
ASTGEN_MEMBERS_AstNodeFor;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := arrayp : AstNode
// @astgen op2 := stmtsp : List[AstNode]
public:
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: AstNodeStmt(t, fl) {
this->arrayp(arrayp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstNodeForeach;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := thensp : List[AstNode]
// @astgen op3 := elsesp : List[AstNode]
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
bool m_isBoundsCheck; // True if this if node is for assertion/bounds checking
protected:
AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: AstNodeStmt{t, fl} {
this->condp(condp);
addThensp(thensp);
addElsesp(elsesp);
isBoundsCheck(false);
}
public:
ASTGEN_MEMBERS_AstNodeIf;
bool isGateOptimizable() const override { return false; }
bool isGateDedupable() const override { return true; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
void branchPred(VBranchPred flag) { m_branchPred = flag; }
VBranchPred branchPred() const { return m_branchPred; }
void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; }
bool isBoundsCheck() const { return m_isBoundsCheck; }
bool isFirstInMyListOfStatements(AstNode* n) const override {
return n == thensp() || n == elsesp();
}
};
class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := filenamep : AstNodeExpr
// @astgen op2 := memp : AstNodeExpr
// @astgen op3 := lsbp : Optional[AstNodeExpr]
// @astgen op4 := msbp : Optional[AstNodeExpr]
const bool m_isHex; // readmemh, not readmemb
public:
AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNodeExpr* filenamep,
AstNodeExpr* memp, AstNodeExpr* lsbp, AstNodeExpr* msbp)
2022-11-20 21:06:49 +01:00
: AstNodeStmt{t, fl}
, m_isHex{hex} {
this->filenamep(filenamep);
this->memp(memp);
this->lsbp(lsbp);
this->msbp(msbp);
}
ASTGEN_MEMBERS_AstNodeReadWriteMem;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* samep) const override {
return isHex() == VN_DBG_AS(samep, NodeReadWriteMem)->isHex();
}
bool isHex() const { return m_isHex; }
virtual const char* cFuncPrefixp() const = 0;
};
class AstNodeText VL_NOT_FINAL : public AstNode {
string m_text;
// METHODS
string shortText() const;
protected:
// Node that puts text into the output stream
AstNodeText(VNType t, FileLine* fl, const string& text)
: AstNode{t, fl}
, m_text{text} {}
public:
ASTGEN_MEMBERS_AstNodeText;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool sameNode(const AstNode* samep) const override {
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
return text() == asamep->text();
}
const string& text() const VL_MT_SAFE { return m_text; }
2022-09-15 14:17:00 +02:00
void text(const string& value) { m_text = value; }
};
class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText {
bool m_tracking; // When emit, it's ok to parse the string to do indentation
public:
AstNodeSimpleText(VNType t, FileLine* fl, const string& textp, bool tracking = false)
2022-11-20 21:06:49 +01:00
: AstNodeText{t, fl, textp}
, m_tracking{tracking} {}
ASTGEN_MEMBERS_AstNodeSimpleText;
void tracking(bool flag) { m_tracking = flag; }
bool tracking() const { return m_tracking; }
};
// === Concrete node types =====================================================
// === AstNode ===
class AstActive final : public AstNode {
// Block of code with sensitivity activation
// Parents: MODULE | CFUNC
// @astgen op1 := sensesStorep : Optional[AstSenTree] // Moved into m_sensesp in V3Active
// @astgen op2 := stmtsp : List[AstNode] // Logic
//
// @astgen ptr := m_sensesp : Optional[AstSenTree] // Sensitivity list for this process
string m_name;
public:
AstActive(FileLine* fl, const string& name, AstSenTree* sensesp)
: ASTGEN_SUPER_Active(fl)
, m_name{name}
, m_sensesp{sensesp} {
UASSERT(sensesp, "Sensesp required arg");
}
ASTGEN_MEMBERS_AstActive;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; }
// Statements are broken into pieces, as some must come before others.
void sensesp(AstSenTree* nodep) { m_sensesp = nodep; }
AstSenTree* sensesp() const { return m_sensesp; }
// METHODS
inline bool hasClocked() const;
2022-09-15 14:17:00 +02:00
inline bool hasCombo() const;
};
class AstBind final : public AstNode {
// Parents: MODULE
// Children: CELL
// @astgen op1 := cellsp : List[AstNode]
string m_name; // Binding to name
public:
AstBind(FileLine* fl, const string& name, AstNode* cellsp)
: ASTGEN_SUPER_Bind(fl)
, m_name{name} {
UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound");
addCellsp(cellsp);
}
ASTGEN_MEMBERS_AstBind;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name
void name(const string& name) override { m_name = name; }
};
class AstCFunc final : public AstNode {
// C++ function
// Parents: MODULE/SCOPE
// If adding node accessors, see below emptyBody
// @astgen op1 := argsp : List[AstNode]
// @astgen op2 := initsp : List[AstNode]
// @astgen op3 := stmtsp : List[AstNode]
// @astgen op4 := finalsp : List[AstNode]
//
// @astgen ptr := m_scopep : Optional[AstScope] // Scope that function is under
string m_name;
string m_cname; // C name, for dpiExports
string m_rtnType; // void, bool, or other return type
string m_argTypes; // Argument types
string m_ifdef; // #ifdef symbol around this function
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
bool m_isTrace : 1; // Function is related to tracing
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
bool m_declPrivate : 1; // Declare it private
bool m_keepIfEmpty : 1; // Keep declaration and definition separate, even if empty
bool m_slow : 1; // Slow routine, called once or just at init time
bool m_funcPublic : 1; // From user public task/function
bool m_isConstructor : 1; // Is C class constructor
bool m_isDestructor : 1; // Is C class destructor
bool m_isMethod : 1; // Is inside a class definition
bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function with
// an explicitly passed 'self' pointer as the first argument. This can
// be slightly faster due to __restrict, and we do not declare in header
// so adding/removing loose functions doesn't recompile everything.
bool m_isInline : 1; // Inline function
bool m_isVirtual : 1; // Virtual function
bool m_entryPoint : 1; // User may call into this top level function
bool m_dpiPure : 1; // Pure DPI function
bool m_dpiContext : 1; // Declared as 'context' DPI import/export function
bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user)
bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup)
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
2023-10-16 14:02:29 +02:00
bool m_needProcess : 1; // Needs access to VlProcess of the caller
bool m_recursive : 1; // Recursive or part of recursion
int m_cost; // Function call cost
public:
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
: ASTGEN_SUPER_CFunc(fl) {
m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed
m_scopep = scopep;
m_name = name;
m_rtnType = rtnType;
m_isStatic = false;
m_isTrace = false;
m_dontCombine = false;
m_declPrivate = false;
m_keepIfEmpty = false;
m_slow = false;
m_funcPublic = false;
m_isConstructor = false;
m_isDestructor = false;
m_isMethod = true;
m_isLoose = false;
m_isInline = false;
m_isVirtual = false;
2023-06-01 16:02:08 +02:00
m_needProcess = false;
m_entryPoint = false;
m_dpiPure = false;
m_dpiContext = false;
m_dpiExportDispatcher = false;
m_dpiExportImpl = false;
m_dpiImportPrototype = false;
m_dpiImportWrapper = false;
m_recursive = false;
m_cost = v3Global.opt.instrCountDpi(); // As proxy for unknown general DPI cost
}
ASTGEN_MEMBERS_AstCFunc;
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool sameNode(const AstNode* samep) const override {
const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc);
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
&& (argTypes() == asamep->argTypes()) && isLoose() == asamep->isLoose()
&& (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name()));
}
//
void name(const string& name) override { m_name = name; }
int instrCount() const override { return m_cost; }
VBoolOrUnknown isConst() const { return m_isConst; }
void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); }
void isConst(VBoolOrUnknown flag) { m_isConst = flag; }
bool isStatic() const { return m_isStatic; }
void isStatic(bool flag) { m_isStatic = flag; }
bool isTrace() const VL_MT_SAFE { return m_isTrace; }
void isTrace(bool flag) { m_isTrace = flag; }
void cname(const string& name) { m_cname = name; }
string cname() const { return m_cname; }
AstScope* scopep() const { return m_scopep; }
void scopep(AstScope* nodep) { m_scopep = nodep; }
string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); }
2022-09-15 14:17:00 +02:00
void rtnType(const string& rtnType) { m_rtnType = rtnType; }
bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); }
void dontCombine(bool flag) { m_dontCombine = flag; }
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
bool declPrivate() const { return m_declPrivate; }
void declPrivate(bool flag) { m_declPrivate = flag; }
bool keepIfEmpty() const VL_MT_SAFE { return m_keepIfEmpty; }
void keepIfEmpty(bool flag) { m_keepIfEmpty = flag; }
bool slow() const VL_MT_SAFE { return m_slow; }
void slow(bool flag) { m_slow = flag; }
bool funcPublic() const { return m_funcPublic; }
void funcPublic(bool flag) { m_funcPublic = flag; }
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
void ifdef(const string& str) { m_ifdef = str; }
string ifdef() const { return m_ifdef; }
bool isConstructor() const { return m_isConstructor; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isDestructor() const { return m_isDestructor; }
void isDestructor(bool flag) { m_isDestructor = flag; }
bool isMethod() const { return m_isMethod; }
void isMethod(bool flag) { m_isMethod = flag; }
bool isLoose() const { return m_isLoose; }
void isLoose(bool flag) { m_isLoose = flag; }
bool isProperMethod() const { return isMethod() && !isLoose(); }
bool isInline() const { return m_isInline; }
void isInline(bool flag) { m_isInline = flag; }
bool isVirtual() const { return m_isVirtual; }
void isVirtual(bool flag) { m_isVirtual = flag; }
2023-06-01 16:02:08 +02:00
bool needProcess() const { return m_needProcess; }
void setNeedProcess() { m_needProcess = true; }
bool entryPoint() const { return m_entryPoint; }
void entryPoint(bool flag) { m_entryPoint = flag; }
bool dpiPure() const { return m_dpiPure; }
void dpiPure(bool flag) { m_dpiPure = flag; }
bool dpiContext() const { return m_dpiContext; }
void dpiContext(bool flag) { m_dpiContext = flag; }
bool dpiExportDispatcher() const VL_MT_SAFE { return m_dpiExportDispatcher; }
void dpiExportDispatcher(bool flag) { m_dpiExportDispatcher = flag; }
bool dpiExportImpl() const { return m_dpiExportImpl; }
void dpiExportImpl(bool flag) { m_dpiExportImpl = flag; }
bool dpiImportPrototype() const VL_MT_SAFE { return m_dpiImportPrototype; }
void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; }
bool dpiImportWrapper() const { return m_dpiImportWrapper; }
void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; }
2022-09-15 14:17:00 +02:00
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
void recursive(bool flag) { m_recursive = flag; }
bool recursive() const { return m_recursive; }
void cost(int cost) { m_cost = cost; }
// Special methods
bool emptyBody() const {
return !keepIfEmpty() && !argsp() && !initsp() && !stmtsp() && !finalsp();
}
};
class AstCLocalScope final : public AstNode {
// Pack statements into an unnamed scope when generating C++
// @astgen op1 := stmtsp : List[AstNode]
public:
AstCLocalScope(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_CLocalScope(fl) {
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCLocalScope;
};
class AstCUse final : public AstNode {
// C++ use of a class or #include; indicates need of forward declaration
// Parents: NODEMODULE
const string m_name;
const VUseType m_useType; // What sort of use this is
public:
AstCUse(FileLine* fl, VUseType useType, const string& name)
: ASTGEN_SUPER_CUse(fl)
, m_name{name}
, m_useType{useType} {}
ASTGEN_MEMBERS_AstCUse;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; }
VUseType useType() const { return m_useType; }
};
class AstCaseItem final : public AstNode {
// Single item of a case statement
// @astgen op1 := condsp : List[AstNodeExpr]
// @astgen op2 := stmtsp : List[AstNode]
public:
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
: ASTGEN_SUPER_CaseItem(fl) {
addCondsp(condsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCaseItem;
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
bool isDefault() const { return condsp() == nullptr; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstCell final : public AstNode {
// A instantiation cell or interface call (don't know which until link)
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
// @astgen op2 := paramsp : List[AstPin] // List of parameter assignments
// @astgen op3 := rangep : Optional[AstRange] // Range for arrayed instances
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references, for tracing
//
// @astgen ptr := m_modp : Optional[AstNodeModule] // [AfterLink] Pointer to module instanced
FileLine* m_modNameFileline; // Where module the cell instances token was
string m_name; // Cell name
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
bool m_hasIfaceVar : 1; // True if a Var has been created for this cell
bool m_recursive : 1; // Self-recursive module
bool m_trace : 1; // Trace this cell
public:
AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: ASTGEN_SUPER_Cell(fl)
, m_modNameFileline{mfl}
, m_name{instName}
, m_origName{instName}
, m_modName{modName}
, m_hasIfaceVar{false}
, m_recursive{false}
, m_trace{true} {
addPinsp(pinsp);
addParamsp(paramsp);
this->rangep(rangep);
}
ASTGEN_MEMBERS_AstCell;
// No cloneRelink, we presume cloneee's want the same module linkages
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
void name(const string& name) override { m_name = name; }
string origName() const override { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
string modName() const { return m_modName; } // * = Instance name
void modName(const string& name) { m_modName = name; }
FileLine* modNameFileline() const { return m_modNameFileline; }
AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated
void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
void trace(bool flag) { m_trace = flag; }
bool isTrace() const { return m_trace; }
void recursive(bool flag) { m_recursive = flag; }
bool recursive() const { return m_recursive; }
};
class AstCellInline final : public AstNode {
// A instantiation cell that was removed by inlining
// For communication between V3Inline and V3LinkDot,
// except for VPI runs where it exists until the end.
// It is augmented with the scope in V3Scope for VPI.
// Children: When 2 levels inlined, other CellInline under this
// @astgen ptr := m_scopep : Optional[AstScope] // The scope that the cell is inlined into
string m_name; // Cell name, possibly {a}__DOT__{b}...
const string m_origModName; // Original name of module, ignoring name() changes, for LinkDot
VTimescale m_timeunit; // Parent module time unit
public:
AstCellInline(FileLine* fl, const string& name, const string& origModName,
const VTimescale& timeunit)
: ASTGEN_SUPER_CellInline(fl)
, m_name{name}
, m_origModName{origModName}
, m_timeunit{timeunit} {}
ASTGEN_MEMBERS_AstCellInline;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Cell name
bool maybePointedTo() const override VL_MT_SAFE { return true; }
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
void name(const string& name) override { m_name = name; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
};
2024-04-02 05:11:15 +02:00
class AstCellInlineScope final : public AstNode {
// A particular scoped usage of a Cell Inline
// Parents: Scope
// Children: none
//
// @astgen ptr := m_scopep : Optional[AstScope] // Scope variable is underneath
// @astgen ptr := m_cellp : Optional[AstCellInline] // Cell ref
const string m_origModName; // Original name of module, ignoring name() changes, for LinkDot
public:
AstCellInlineScope(FileLine* fl, AstScope* scopep, AstCellInline* cellp)
: ASTGEN_SUPER_CellInlineScope(fl)
, m_scopep{scopep}
, m_cellp{cellp} {
UASSERT_OBJ(scopep, fl, "Scope must be non-null");
UASSERT_OBJ(cellp, fl, "CellInline must be non-null");
}
ASTGEN_MEMBERS_AstCellInlineScope;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_cellp->name(); }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
2024-04-02 05:11:15 +02:00
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
string origModName() const {
return m_cellp->origModName();
} // * = modp()->origName() before inlining
void scopep(AstScope* nodep) { m_scopep = nodep; }
};
class AstClassExtends final : public AstNode {
// class extends class name, or class implements class name
// Children: List of AstParseRef for packages/classes
// during early parse, then moves to dtype
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := classOrPkgsp : Optional[AstNode]
2025-04-09 04:09:40 +02:00
// @astgen op3 := argsp : List[AstNodeExpr]
const bool m_isImplements = false; // class implements
bool m_parameterized = false; // has parameters in its statement
public:
AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements)
: ASTGEN_SUPER_ClassExtends(fl)
, m_isImplements{isImplements} {
this->classOrPkgsp(classOrPkgsp); // Only for parser
}
ASTGEN_MEMBERS_AstClassExtends;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool hasDType() const override VL_MT_SAFE { return true; }
string verilogKwd() const override { return isImplements() ? "implements" : "extends"; }
// Class being extended (after link and instantiation if needed)
AstClass* classOrNullp() const;
AstClass* classp() const; // Like above, but throws error if nulll
bool isImplements() const { return m_isImplements; }
void parameterized(bool flag) { m_parameterized = flag; }
bool parameterized() const { return m_parameterized; }
};
class AstClocking final : public AstNode {
// Parents: MODULE
2022-12-23 13:34:49 +01:00
// Children: SENITEM, CLOCKING ITEMs, VARs
// @astgen op1 := sensesp : AstSenItem
// @astgen op2 := itemsp : List[AstClockingItem]
// @astgen op3 := eventp : Optional[AstVar]
2022-12-23 13:34:49 +01:00
std::string m_name; // Clocking block name
const bool m_isDefault = false; // True if default clocking
const bool m_isGlobal = false; // True if global clocking
2022-12-23 13:34:49 +01:00
public:
2022-12-23 13:34:49 +01:00
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
2022-12-23 13:34:49 +01:00
: ASTGEN_SUPER_Clocking(fl)
, m_name{name}
, m_isDefault{isDefault}
, m_isGlobal{isGlobal} {
2022-12-23 13:34:49 +01:00
this->sensesp(sensesp);
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstClocking;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
std::string name() const override VL_MT_STABLE { return m_name; }
2022-12-23 13:34:49 +01:00
bool isDefault() const { return m_isDefault; }
bool isGlobal() const { return m_isGlobal; }
AstVar* ensureEventp(bool childDType = false);
2022-12-23 13:34:49 +01:00
};
class AstClockingItem final : public AstNode {
// Parents: CLOCKING
// Children: EXPRs, ASSIGNs, VARs
// @astgen op1 := skewp : Optional[AstNodeExpr]
// @astgen op2 := exprp : Optional[AstNodeExpr]
// @astgen op3 := assignp : Optional[AstAssign]
// @astgen op4 := varp : Optional[AstVar]
2024-06-07 14:30:58 +02:00
// @astgen ptr := m_outputp : Optional[AstClockingItem]
2022-12-23 13:34:49 +01:00
VDirection m_direction;
public:
AstClockingItem(FileLine* fl, VDirection direction, AstNodeExpr* skewp, AstNode* clockingDeclp)
: ASTGEN_SUPER_ClockingItem(fl) {
m_direction = direction;
this->skewp(skewp);
if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) {
this->assignp(clkAssignp);
2022-12-23 13:34:49 +01:00
} else {
exprp(VN_AS(clockingDeclp, NodeExpr));
}
}
ASTGEN_MEMBERS_AstClockingItem;
VDirection direction() const { return m_direction; }
2024-06-07 14:30:58 +02:00
AstClockingItem* outputp() const { return m_outputp; }
void outputp(AstClockingItem* outputp) { m_outputp = outputp; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
};
class AstConfig final : public AstNode {
// Parents: NETLIST
// @astgen op1 := designp : List[AstConfigCell]
// @astgen op2 := itemsp : List[AstNode]
std::string m_name; // Config block name
public:
AstConfig(FileLine* fl, const std::string& name, AstNode* itemsp)
: ASTGEN_SUPER_Config(fl)
, m_name{name} {
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstConfig;
std::string name() const override VL_MT_STABLE { return m_name; }
};
class AstConfigCell final : public AstNode {
// Parents: CONFIGRULE
std::string m_libname; // Cell library, or ""
std::string m_cellname; // Cell name within library
public:
AstConfigCell(FileLine* fl, const std::string& libname, const std::string& cellname)
: ASTGEN_SUPER_ConfigCell(fl)
, m_libname{libname}
, m_cellname{cellname} {}
ASTGEN_MEMBERS_AstConfigCell;
std::string name() const override VL_MT_STABLE { return m_libname + "." + m_cellname; }
std::string libname() const VL_MT_STABLE { return m_libname; }
std::string cellname() const VL_MT_STABLE { return m_cellname; }
};
class AstConfigRule final : public AstNode {
// Parents: CONFIG
// @astgen op1 := cellp : Optional[AstNode] // Cells to apply to, or nullptr=default
// @astgen op2 := usep : List[AstNode] // Use or design to apply
const bool m_isCell; // Declared as "cell" versus "instance"
public:
AstConfigRule(FileLine* fl, AstNode* cellp, AstNode* usep, bool isCell)
: ASTGEN_SUPER_ConfigRule(fl)
, m_isCell{isCell} {
this->cellp(cellp);
addUsep(usep);
}
ASTGEN_MEMBERS_AstConfigRule;
bool isCell() const VL_MT_STABLE { return m_isCell; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstConfigUse final : public AstNode {
// Parents: CONFIGRULE
// @astgen op1 := paramsp : List[AstPin]
std::string m_libname; // Use library, or ""
std::string m_cellname; // Use name within library
const bool m_isConfig; // ":config"; Config, not module/primitive name
public:
AstConfigUse(FileLine* fl, const std::string& libname, const std::string& cellname,
AstPin* paramsp, bool isConfig)
: ASTGEN_SUPER_ConfigUse(fl)
, m_libname{libname}
, m_cellname{cellname}
, m_isConfig{isConfig} {
addParamsp(paramsp);
}
ASTGEN_MEMBERS_AstConfigUse;
std::string name() const override VL_MT_STABLE { return m_libname + "." + m_cellname; }
std::string libname() const VL_MT_STABLE { return m_libname; }
std::string cellname() const VL_MT_STABLE { return m_cellname; }
bool isConfig() const VL_MT_STABLE { return m_isConfig; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstConstPool final : public AstNode {
// Container for const static data
// @astgen op1 := modulep : AstModule // m_modp below TODO: fix this mess
//
// @astgen ptr := m_modp : AstModule // The Module holding the Scope below ...
// @astgen ptr := m_scopep : AstScope // Scope holding the constant variables
std::unordered_multimap<uint32_t, AstVarScope*> m_tables; // Constant tables (unpacked arrays)
std::unordered_multimap<uint32_t, AstVarScope*> m_consts; // Constant tables (scalars)
AstVarScope* createNewEntry(const string& name, AstNodeExpr* initp);
public:
explicit AstConstPool(FileLine* fl);
ASTGEN_MEMBERS_AstConstPool;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
void cloneRelink() override { V3ERROR_NA; }
AstModule* modp() const { return m_modp; }
// Find a table (unpacked array) within the constant pool which is initialized with the
// given value, or create one if one does not already exists. The returned VarScope *might*
// have a different dtype than the given initp->dtypep(), including a different element type,
// but it will always have the same size and element width. In contexts where this matters,
// the caller must handle the dtype difference as appropriate.
AstVarScope* findTable(AstInitArray* initp);
// Find a constant within the constant pool which is initialized with the given value, or
// create one if one does not already exists. If 'mergeDType' is true, then the returned
// VarScope *might* have a different type than the given initp->dtypep(). In contexts where
// this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
AstVarScope* findConst(AstConst* initp, bool mergeDType);
};
class AstConstraint final : public AstNode {
// Constraint
// @astgen op1 := itemsp : List[AstNode]
2024-12-12 14:16:19 +01:00
// @astgen op2 := classOrPackagep : Optional[AstNode]
string m_name; // Name of constraint
2024-12-12 14:16:19 +01:00
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
bool m_isExternDef = false; // Extern prototype definition
bool m_isExternExplicit = false; // Explicit prototype declaration (has extern)
bool m_isExternProto = false; // Prototype declaration (implicit or explicit)
2024-11-09 18:05:26 +01:00
bool m_isKwdPure = false; // Pure constraint
bool m_isStatic = false; // Static constraint
public:
AstConstraint(FileLine* fl, const string& name, AstNode* itemsp)
: ASTGEN_SUPER_Constraint(fl)
, m_name{name} {
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstConstraint;
2024-11-09 18:05:26 +01:00
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2024-12-12 14:16:19 +01:00
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
VBaseOverride baseOverride() const { return m_baseOverride; }
bool isExternDef() const { return m_isExternDef; }
void isExternDef(bool flag) { m_isExternDef = flag; }
void isExternExplicit(bool flag) { m_isExternExplicit = flag; }
bool isExternExplicit() const { return m_isExternExplicit; }
void isExternProto(bool flag) { m_isExternProto = flag; }
bool isExternProto() const { return m_isExternProto; }
2024-11-09 18:05:26 +01:00
void isKwdPure(bool flag) { m_isKwdPure = flag; }
bool isKwdPure() const { return m_isKwdPure; }
void isStatic(bool flag) { m_isStatic = flag; }
bool isStatic() const { return m_isStatic; }
};
class AstConstraintBefore final : public AstNode {
// Constraint solve before item
// @astgen op1 := lhssp : List[AstNodeExpr]
// @astgen op2 := rhssp : List[AstNodeExpr]
public:
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
: ASTGEN_SUPER_ConstraintBefore(fl) {
addLhssp(lhssp);
addRhssp(rhssp);
}
ASTGEN_MEMBERS_AstConstraintBefore;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstDefParam final : public AstNode {
// A defparam assignment
// Parents: MODULE
// @astgen op1 := rhsp : AstNodeExpr
string m_name; // Name of variable getting set
string m_path; // Dotted cellname to set parameter of
public:
AstDefParam(FileLine* fl, const string& path, const string& name, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DefParam(fl)
, m_name{name}
, m_path{path} {
this->rhsp(rhsp);
}
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
ASTGEN_MEMBERS_AstDefParam;
bool sameNode(const AstNode*) const override { return true; }
string path() const { return m_path; }
};
class AstDefaultDisable final : public AstNode {
// @astgen op1 := condp : AstNodeExpr
public:
AstDefaultDisable(FileLine* fl, AstNodeExpr* condp)
: ASTGEN_SUPER_DefaultDisable(fl) {
this->condp(condp);
}
ASTGEN_MEMBERS_AstDefaultDisable;
};
class AstDpiExport final : public AstNode {
// We could put an AstNodeFTaskRef instead of the verilog function name,
// however we're not *calling* it, so that seems somehow wrong.
// (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef)
string m_name; // Name of function
string m_cname; // Name of function on c side
public:
AstDpiExport(FileLine* fl, const string& vname, const string& cname)
: ASTGEN_SUPER_DpiExport(fl)
, m_name{vname}
, m_cname{cname} {}
ASTGEN_MEMBERS_AstDpiExport;
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
string cname() const { return m_cname; }
void cname(const string& cname) { m_cname = cname; }
};
class AstElabDisplay final : public AstNode {
// Parents: stmtlist
// @astgen op1 := fmtp : List[AstSFormatF]
VDisplayType m_displayType;
public:
inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* exprsp);
ASTGEN_MEMBERS_AstElabDisplay;
const char* broken() const override {
BROKEN_RTN(!fmtp());
return nullptr;
}
string verilogKwd() const override { return "$"s + string{displayType().ascii()}; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* samep) const override {
return displayType() == VN_DBG_AS(samep, ElabDisplay)->displayType();
}
int instrCount() const override { return INSTR_COUNT_PLI; }
VDisplayType displayType() const { return m_displayType; }
void displayType(VDisplayType type) { m_displayType = type; }
};
class AstEmpty final : public AstNode {
// Represents something missing, e.g. a missing argument in FOREACH
public:
explicit AstEmpty(FileLine* fl)
: ASTGEN_SUPER_Empty(fl) {}
ASTGEN_MEMBERS_AstEmpty;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstExecGraph final : public AstNode {
// For parallel execution, this node contains a dependency graph. Each
// vertex in the graph is an ExecMTask, which contains a body for the
// mtask (an AstMTaskBody), which contains sequentially executed statements.
//
// The AstMTaskBody nodes are also children of this node, so we can visit
// them without traversing the graph.
//
// @astgen op1 := mTaskBodiesp : List[AstMTaskBody]
// In later phases, the statements that start the parallel execution
// @astgen op2 := stmtsp : List[AstNode]
V3Graph* const m_depGraphp; // contains ExecMTask vertices
const string m_name; // Name of this AstExecGraph (for uniqueness at code generation)
public:
explicit AstExecGraph(FileLine* fl, const string& name) VL_MT_DISABLED;
~AstExecGraph() override;
ASTGEN_MEMBERS_AstExecGraph;
void cloneRelink() override { V3ERROR_NA; }
const char* broken() const override {
BROKEN_RTN(!m_depGraphp);
return nullptr;
}
string name() const override VL_MT_STABLE { return m_name; }
V3Graph* depGraphp() { return m_depGraphp; }
const V3Graph* depGraphp() const { return m_depGraphp; }
};
class AstImplicit final : public AstNode {
// Create implicit wires and do nothing else, for gates that are ignored
// Parents: MODULE
// @astgen op1 := exprsp : List[AstNode]
public:
AstImplicit(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_Implicit(fl) {
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstImplicit;
};
class AstInitItem final : public AstNode {
// Container for a item in an init array
// This container is present so that the value underneath may get replaced with a new nodep
// and the upper AstInitArray's map will remain correct (pointing to this InitItem)
// @astgen op1 := valuep : AstNodeExpr
public:
// Parents: INITARRAY
AstInitItem(FileLine* fl, AstNodeExpr* valuep)
: ASTGEN_SUPER_InitItem(fl) {
this->valuep(valuep);
}
ASTGEN_MEMBERS_AstInitItem;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool hasDType() const override VL_MT_SAFE { return false; } // See valuep()'s dtype instead
};
class AstIntfRef final : public AstNode {
// An interface reference
string m_name; // Name of the reference
public:
AstIntfRef(FileLine* fl, const string& name)
: ASTGEN_SUPER_IntfRef(fl)
, m_name{name} {}
string name() const override VL_MT_STABLE { return m_name; }
ASTGEN_MEMBERS_AstIntfRef;
};
class AstMTaskBody final : public AstNode {
// Hold statements for each MTask
// @astgen op1 := stmtsp : List[AstNode]
ExecMTask* m_execMTaskp = nullptr;
public:
explicit AstMTaskBody(FileLine* fl)
: ASTGEN_SUPER_MTaskBody(fl) {}
ASTGEN_MEMBERS_AstMTaskBody;
void cloneRelink() override { V3ERROR_NA; }
const char* broken() const override {
BROKEN_RTN(!m_execMTaskp);
return nullptr;
}
void addStmtsFirstp(AstNode* nodep) {
if (stmtsp()) {
stmtsp()->addHereThisAsNext(nodep);
} else {
addStmtsp(nodep);
}
}
ExecMTask* execMTaskp() const { return m_execMTaskp; }
void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstModport final : public AstNode {
// A modport in an interface
// @astgen op1 := varsp : List[AstNode]
string m_name; // Name of the modport
public:
AstModport(FileLine* fl, const string& name, AstNode* varsp)
: ASTGEN_SUPER_Modport(fl)
, m_name{name} {
addVarsp(varsp);
}
2025-02-21 22:49:14 +01:00
string verilogKwd() const override { return "modport"; }
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
ASTGEN_MEMBERS_AstModport;
};
class AstModportFTaskRef final : public AstNode {
// An import/export referenced under a modport
// The storage for the function itself is inside the
// interface/instantiator, thus this is a reference
// PARENT: AstModport
//
// @astgen ptr := m_ftaskp : Optional[AstNodeFTask] // Link to the function
string m_name; // Name of the variable referenced
bool m_export; // Type of the function (import/export)
public:
AstModportFTaskRef(FileLine* fl, const string& name, bool isExport)
: ASTGEN_SUPER_ModportFTaskRef(fl)
, m_name{name}
, m_export{isExport} {}
ASTGEN_MEMBERS_AstModportFTaskRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
bool isImport() const { return !m_export; }
bool isExport() const { return m_export; }
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp = ftaskp; }
};
class AstModportVarRef final : public AstNode {
// A input/output/etc variable referenced under a modport
// The storage for the variable itself is inside the interface, thus this is a reference
// PARENT: AstModport
//
// @astgen ptr := m_varp : Optional[AstVar] // Link to the actual Var
string m_name; // Name of the variable referenced
VDirection m_direction; // Direction of the variable (in/out)
public:
AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction)
: ASTGEN_SUPER_ModportVarRef(fl)
, m_name{name}
, m_direction{direction} {}
ASTGEN_MEMBERS_AstModportVarRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
void direction(const VDirection& flag) { m_direction = flag; }
VDirection direction() const { return m_direction; }
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp = varp; }
};
class AstNetlist final : public AstNode {
// All modules are under this single top node.
// Parents: none
// Children: MODULEs & CFILEs
// @astgen op1 := modulesp : List[AstNodeModule]
// @astgen op2 := filesp : List[AstNodeFile]
// @astgen op3 := miscsp : List[AstNode]
//
// @astgen ptr := m_typeTablep : AstTypeTable // Reference to type table, for faster lookup
// @astgen ptr := m_constPoolp : AstConstPool // Reference to constant pool, for faster lookup
// @astgen ptr := m_dollarUnitPkgp : Optional[AstPackage] // $unit
// @astgen ptr := m_stdPackagep : Optional[AstPackage] // SystemVerilog std package
// @astgen ptr := m_evalp : Optional[AstCFunc] // The '_eval' function
// @astgen ptr := m_evalNbap : Optional[AstCFunc] // The '_eval__nba' function
// @astgen ptr := m_dpiExportTriggerp : Optional[AstVarScope] // DPI export trigger variable
// @astgen ptr := m_delaySchedulerp : Optional[AstVar] // Delay scheduler variable
// @astgen ptr := m_nbaEventp : Optional[AstVarScope] // NBA event variable
// @astgen ptr := m_nbaEventTriggerp : Optional[AstVarScope] // NBA event trigger
// @astgen ptr := m_topScopep : Optional[AstTopScope] // Singleton AstTopScope
VTimescale m_timeunit; // Global time unit
VTimescale m_timeprecision; // Global time precision
bool m_timescaleSpecified = false; // Input HDL specified timescale
public:
AstNetlist();
ASTGEN_MEMBERS_AstNetlist;
void deleteContents();
void cloneRelink() override { V3ERROR_NA; }
string name() const override VL_MT_STABLE { return "$root"; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy
return modulesp(); // First one in the list, for now
}
AstTypeTable* typeTablep() { return m_typeTablep; }
AstConstPool* constPoolp() { return m_constPoolp; }
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
AstPackage* dollarUnitPkgAddp();
AstCFunc* evalp() const { return m_evalp; }
2022-09-15 14:17:00 +02:00
void evalp(AstCFunc* funcp) { m_evalp = funcp; }
AstCFunc* evalNbap() const { return m_evalNbap; }
void evalNbap(AstCFunc* funcp) { m_evalNbap = funcp; }
AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; }
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
2022-09-15 14:17:00 +02:00
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
AstVarScope* nbaEventp() const { return m_nbaEventp; }
void nbaEventp(AstVarScope* const varScopep) { m_nbaEventp = varScopep; }
AstVarScope* nbaEventTriggerp() const { return m_nbaEventTriggerp; }
void nbaEventTriggerp(AstVarScope* const varScopep) { m_nbaEventTriggerp = varScopep; }
void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
AstPackage* stdPackagep() const { return m_stdPackagep; }
AstTopScope* topScopep() const { return m_topScopep; }
void createTopScope(AstScope* scopep);
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& value) { m_timeunit = value; }
VTimescale timeprecision() const { return m_timeprecision; }
void timeInit() {
m_timeunit = v3Global.opt.timeDefaultUnit();
m_timeprecision = v3Global.opt.timeDefaultPrec();
}
void timeprecisionMerge(FileLine*, const VTimescale& value);
void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; }
bool timescaleSpecified() const { return m_timescaleSpecified; }
};
class AstPackageExport final : public AstNode {
// A package export declaration
//
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
string m_name; // What imported e.g. "*"
string m_pkgName; // Module the cell instances
public:
AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name)
: ASTGEN_SUPER_PackageExport(fl)
, m_name{name}
, m_packagep{packagep} {
pkgNameFrom();
}
AstPackageExport(FileLine* fl, const string& pkgName, const string& name)
: ASTGEN_SUPER_PackageExport(fl)
, m_name{name}
, m_pkgName{pkgName}
, m_packagep{nullptr} {}
ASTGEN_MEMBERS_AstPackageExport;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
string pkgName() const VL_MT_STABLE { return m_pkgName; }
string prettyPkgNameQ() const { return "'" + prettyName(pkgName()) + "'"; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
private:
void pkgNameFrom();
};
class AstPackageExportStarStar final : public AstNode {
// A package export *::* declaration
public:
// cppcheck-suppress noExplicitConstructor
AstPackageExportStarStar(FileLine* fl)
: ASTGEN_SUPER_PackageExportStarStar(fl) {}
ASTGEN_MEMBERS_AstPackageExportStarStar;
};
class AstPackageImport final : public AstNode {
// A package import declaration
//
// @astgen ptr := m_packagep : Optional[AstPackage] // Package hierarchy
string m_name; // What imported e.g. "*"
string m_pkgName; // Module the cell instances
public:
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
: ASTGEN_SUPER_PackageImport(fl)
, m_name{name}
, m_packagep{packagep} {
pkgNameFrom();
}
AstPackageImport(FileLine* fl, const string& pkgName, const string& name)
: ASTGEN_SUPER_PackageImport(fl)
, m_name{name}
, m_pkgName{pkgName}
, m_packagep{nullptr} {}
ASTGEN_MEMBERS_AstPackageImport;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
string pkgName() const VL_MT_STABLE { return m_pkgName; }
string prettyPkgNameQ() const { return "'" + prettyName(pkgName()) + "'"; }
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
private:
void pkgNameFrom();
};
class AstPin final : public AstNode {
// A port or parameter assignment on an instantiation
// @astgen op1 := exprp : Optional[AstNode<AstNodeExpr|AstNodeDType>] // nullptr=unconnected
//
// @astgen ptr := m_modVarp : Optional[AstVar] // Input/output connects to on submodule
// @astgen ptr := m_modPTypep : Optional[AstParamTypeDType] // Param type connects to on sub
int m_pinNum; // Pin number
string m_name; // Pin name, or "" for number based interconnect
bool m_param = false; // Pin connects to parameter
bool m_svDotName = false; // Pin is SystemVerilog .name'ed
bool m_svImplicit = false; // Pin is SystemVerilog .name'ed, allow implicit
public:
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
: ASTGEN_SUPER_Pin(fl)
, m_pinNum{pinNum}
, m_name{name} {
this->exprp(exprp);
}
inline AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp);
ASTGEN_MEMBERS_AstPin;
void cloneRelink() override {} // TODO V3Param shouldn't require avoiding cloneRelinkGen
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) override { m_name = name; }
string prettyOperatorName() const override;
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
int pinNum() const { return m_pinNum; }
AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable
void modVarp(AstVar* nodep) { m_modVarp = nodep; }
// [After Link] Pointer to variable
AstParamTypeDType* modPTypep() const { return m_modPTypep; }
void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; }
bool param() const { return m_param; }
void param(bool flag) { m_param = flag; }
bool svDotName() const { return m_svDotName; }
void svDotName(bool flag) { m_svDotName = flag; }
bool svImplicit() const { return m_svImplicit; }
void svImplicit(bool flag) { m_svImplicit = flag; }
};
class AstPort final : public AstNode {
// A port (in/out/inout) on a module
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression connected to port
const int m_pinNum; // Pin number
const string m_name; // Name of pin
public:
AstPort(FileLine* fl, int pinnum, const string& name)
: ASTGEN_SUPER_Port(fl)
, m_pinNum{pinnum}
, m_name{name} {}
ASTGEN_MEMBERS_AstPort;
string name() const override VL_MT_STABLE { return m_name; } // * = Port name
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
};
class AstPragma final : public AstNode {
const VPragmaType m_pragType; // Type of pragma
const VTimescale m_timescale; // For TIMEUNIT_SET
public:
// Pragmas don't result in any output code, they're just flags that affect
// other processing in verilator.
AstPragma(FileLine* fl, VPragmaType pragType)
: ASTGEN_SUPER_Pragma(fl)
, m_pragType{pragType} {}
AstPragma(FileLine* fl, VPragmaType pragType, const VTimescale& timescale)
: ASTGEN_SUPER_Pragma(fl)
, m_pragType{pragType}
, m_timescale{timescale} {}
ASTGEN_MEMBERS_AstPragma;
VPragmaType pragType() const { return m_pragType; } // *=type of the pragma
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* samep) const override {
return pragType() == VN_DBG_AS(samep, Pragma)->pragType();
}
VTimescale timescale() const { return m_timescale; }
};
2022-11-01 23:53:47 +01:00
class AstPropSpec final : public AstNode {
// A clocked property
// Parents: ASSERT|COVER (property)
// Children: SENITEM, Properties
// @astgen op1 := sensesp : Optional[AstSenItem]
// @astgen op2 := disablep : Optional[AstNodeExpr]
// @astgen op3 := propp : AstNode
public:
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* disablep, AstNode* propp)
2022-11-01 23:53:47 +01:00
: ASTGEN_SUPER_PropSpec(fl) {
this->sensesp(sensesp);
this->disablep(disablep);
this->propp(propp);
}
2022-11-01 23:53:47 +01:00
ASTGEN_MEMBERS_AstPropSpec;
bool hasDType() const override VL_MT_SAFE {
return true;
} // Used under Cover, which expects a bool child
};
class AstPull final : public AstNode {
// @astgen op1 := lhsp : AstNodeExpr
const bool m_direction;
public:
AstPull(FileLine* fl, AstNodeExpr* lhsp, bool direction)
: ASTGEN_SUPER_Pull(fl)
, m_direction{direction} {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstPull;
bool sameNode(const AstNode* samep) const override {
return direction() == VN_DBG_AS(samep, Pull)->direction();
}
uint32_t direction() const { return (uint32_t)m_direction; }
};
class AstScope final : public AstNode {
// A particular usage of a cell
// Parents: MODULE
// Children: NODEBLOCK
// @astgen op1 := varsp : List[AstVarScope]
// @astgen op2 := blocksp : List[AstNode] // Logic blocks/AstActive/AstCFunc
2024-04-02 05:11:15 +02:00
// @astgen op3 := inlinesp : List[AstCellInlineScope] // Cell Inlines
//
// Below scope and cell are nullptr if top scope
// @astgen ptr := m_aboveScopep : Optional[AstScope] // Scope above this one in the hierarchy
// @astgen ptr := m_aboveCellp : Optional[AstCell] // Cell above this in the hierarchy
// @astgen ptr := m_modp : AstNodeModule // Module scope corresponds to
// An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope
string m_name; // Name
public:
AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep,
AstCell* aboveCellp)
: ASTGEN_SUPER_Scope(fl)
, m_name{name}
, m_aboveScopep{aboveScopep}
, m_aboveCellp{aboveCellp}
, m_modp{modp} {}
ASTGEN_MEMBERS_AstScope;
const char* broken() const override {
BROKEN_RTN(!m_modp);
return nullptr;
}
bool maybePointedTo() const override VL_MT_SAFE { return true; }
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool sameNode(const AstNode* samep) const override;
string nameDotless() const;
AstNodeModule* modp() const { return m_modp; }
2022-09-15 14:17:00 +02:00
//
AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; }
AstCell* aboveCellp() const { return m_aboveCellp; }
bool isTop() const VL_MT_SAFE { return aboveScopep() == nullptr; } // At top of hierarchy
2022-09-15 14:17:00 +02:00
// Create new MODULETEMP variable under this scope
AstVarScope* createTemp(const string& name, unsigned width);
AstVarScope* createTemp(const string& name, AstNodeDType* dtypep);
AstVarScope* createTempLike(const string& name, AstVarScope* vscp);
};
class AstSenItem final : public AstNode {
// Parents: SENTREE
// @astgen op1 := sensp : Optional[AstNodeExpr] // Sensitivity expression
// @astgen op2 := condp : Optional[AstNodeExpr] // Sensitivity condition
VEdgeType m_edgeType; // Edge type
public:
2022-09-15 14:17:00 +02:00
class Combo {}; // for constructor type-overload selection
class Static {}; // for constructor type-overload selection
class Initial {}; // for constructor type-overload selection
class Final {}; // for constructor type-overload selection
class Never {}; // for constructor type-overload selection
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp, AstNodeExpr* condp = nullptr)
: ASTGEN_SUPER_SenItem(fl)
, m_edgeType{edgeType} {
this->sensp(senp);
this->condp(condp);
}
AstSenItem(FileLine* fl, Combo)
: ASTGEN_SUPER_SenItem(fl)
, m_edgeType{VEdgeType::ET_COMBO} {}
2022-09-15 14:17:00 +02:00
AstSenItem(FileLine* fl, Static)
: ASTGEN_SUPER_SenItem(fl)
, m_edgeType{VEdgeType::ET_STATIC} {}
AstSenItem(FileLine* fl, Initial)
: ASTGEN_SUPER_SenItem(fl)
, m_edgeType{VEdgeType::ET_INITIAL} {}
2022-09-15 14:17:00 +02:00
AstSenItem(FileLine* fl, Final)
: ASTGEN_SUPER_SenItem(fl)
2022-09-15 14:17:00 +02:00
, m_edgeType{VEdgeType::ET_FINAL} {}
AstSenItem(FileLine* fl, Never)
: ASTGEN_SUPER_SenItem(fl)
, m_edgeType{VEdgeType::ET_NEVER} {}
ASTGEN_MEMBERS_AstSenItem;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool sameNode(const AstNode* samep) const override {
return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType();
}
2022-09-15 14:17:00 +02:00
VEdgeType edgeType() const { return m_edgeType; }
void edgeType(VEdgeType type) {
m_edgeType = type;
editCountInc();
2022-09-15 14:17:00 +02:00
}
AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); }
//
bool isClocked() const { return edgeType().clockedStmt(); }
bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; }
2022-09-15 14:17:00 +02:00
bool isHybrid() const { return edgeType() == VEdgeType::ET_HYBRID; }
bool isStatic() const { return edgeType() == VEdgeType::ET_STATIC; }
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
2022-09-15 14:17:00 +02:00
bool isFinal() const { return edgeType() == VEdgeType::ET_FINAL; }
bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; }
};
class AstSenTree final : public AstNode {
// A sensitivity list
// @astgen op1 := sensesp : List[AstSenItem]
bool m_multi = false; // Created from combo logic by ORing multiple clock domains
public:
AstSenTree(FileLine* fl, AstSenItem* sensesp)
: ASTGEN_SUPER_SenTree(fl) {
addSensesp(sensesp);
}
ASTGEN_MEMBERS_AstSenTree;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool isMulti() const { return m_multi; }
void multi(bool flag) { m_multi = true; }
// METHODS
bool hasClocked() const; // Includes a clocked statement
2022-09-15 14:17:00 +02:00
bool hasStatic() const; // Includes a STATIC SenItem
bool hasInitial() const; // Includes a INITIAL SenItem
2022-09-15 14:17:00 +02:00
bool hasFinal() const; // Includes a FINAL SenItem
bool hasCombo() const; // Includes a COMBO SenItem
2022-09-15 14:17:00 +02:00
bool hasHybrid() const; // Includes a HYBRID SenItem
};
class AstSplitPlaceholder final : public AstNode {
public:
// Dummy node used within V3Split; never exists outside of V3Split.
explicit AstSplitPlaceholder(FileLine* fl)
: ASTGEN_SUPER_SplitPlaceholder(fl) {}
ASTGEN_MEMBERS_AstSplitPlaceholder;
};
class AstStrengthSpec final : public AstNode {
VStrength m_s0; // Drive 0 strength
VStrength m_s1; // Drive 1 strength
public:
AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1)
: ASTGEN_SUPER_StrengthSpec(fl)
, m_s0{s0}
, m_s1{s1} {}
ASTGEN_MEMBERS_AstStrengthSpec;
VStrength strength0() { return m_s0; }
VStrength strength1() { return m_s1; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstTopScope final : public AstNode {
// A singleton, held under the top level AstModule. Holds the top level
// AstScope, and after V3ActiveTop, the global list of AstSenTrees (list of
// unique sensitivity lists).
//
// @astgen op1 := senTreesp : List[AstSenTree] // Globally unique sensitivity lists
// @astgen op2 := scopep : AstScope // The AstScope of the top-leveL
friend class AstNetlist; // Only the AstNetlist can create one
AstTopScope(FileLine* fl, AstScope* ascopep)
: ASTGEN_SUPER_TopScope(fl) {
this->scopep(ascopep);
}
public:
ASTGEN_MEMBERS_AstTopScope;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
};
class AstTypeTable final : public AstNode {
// Container for hash of standard data types
// @astgen op1 := typesp : List[AstNodeDType]
//
// @astgen ptr := m_constraintRefp : Optional[AstConstraintRefDType]
// @astgen ptr := m_emptyQueuep : Optional[AstEmptyQueueDType]
// @astgen ptr := m_queueIndexp : Optional[AstQueueDType]
// @astgen ptr := m_streamp : Optional[AstStreamDType]
// @astgen ptr := m_voidp : Optional[AstVoidDType]
AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{};
//
using DetailedMap = std::map<VBasicTypeKey, AstBasicDType*>;
DetailedMap m_detailedMap;
public:
explicit AstTypeTable(FileLine* fl);
ASTGEN_MEMBERS_AstTypeTable;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
void cloneRelink() override { V3ERROR_NA; }
AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd);
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin,
VSigning numeric);
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range,
int widthMin, VSigning numeric);
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
AstConstraintRefDType* findConstraintRefDType(FileLine* fl);
AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl);
AstQueueDType* findQueueIndexDType(FileLine* fl);
AstStreamDType* findStreamDType(FileLine* fl);
AstVoidDType* findVoidDType(FileLine* fl);
void clearCache();
void repairCache();
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstTypedef final : public AstNode {
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
string m_name;
string m_tag; // Holds the string of the verilator tag -- used in XML output.
bool m_attrPublic = false;
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
2022-11-13 15:27:37 +01:00
public:
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType,
AstNodeDType* dtp)
: ASTGEN_SUPER_Typedef(fl)
, m_name{name}
, m_isHideLocal{false}
, m_isHideProtected{false} {
childDTypep(dtp); // Only for parser
addAttrsp(attrsp);
dtypep(nullptr); // V3Width will resolve
}
ASTGEN_MEMBERS_AstTypedef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
// METHODS
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool hasDType() const override VL_MT_SAFE { return true; }
void name(const string& flag) override { m_name = flag; }
bool attrPublic() const { return m_attrPublic; }
void attrPublic(bool flag) { m_attrPublic = flag; }
bool isHideLocal() const { return m_isHideLocal; }
void isHideLocal(bool flag) { m_isHideLocal = flag; }
bool isHideProtected() const { return m_isHideProtected; }
void isHideProtected(bool flag) { m_isHideProtected = flag; }
void tag(const string& text) override { m_tag = text; }
string tag() const override { return m_tag; }
};
class AstTypedefFwd final : public AstNode {
// Forward declaration of a type; stripped after netlist parsing is complete
string m_name;
public:
AstTypedefFwd(FileLine* fl, const string& name)
: ASTGEN_SUPER_TypedefFwd(fl)
, m_name{name} {}
ASTGEN_MEMBERS_AstTypedefFwd;
// METHODS
string name() const override VL_MT_STABLE { return m_name; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
};
class AstUdpTable final : public AstNode {
// @astgen op1 := linesp : List[AstUdpTableLine]
public:
AstUdpTable(FileLine* fl, AstUdpTableLine* linesp)
: ASTGEN_SUPER_UdpTable(fl) {
this->addLinesp(linesp);
if (!v3Global.hasTable()) v3Global.setHasTable();
}
ASTGEN_MEMBERS_AstUdpTable;
};
class AstUdpTableLine final : public AstNode {
// @astgen op1 := iFieldsp : List[AstUdpTableLineVal] // Input fields
// @astgen op2 := oFieldsp : List[AstUdpTableLineVal] // Output fields
private:
const bool m_udpIsCombo; // Combinational or sequential UDP
public:
class UdpCombo {};
AstUdpTableLine(UdpCombo, FileLine* fl, AstUdpTableLineVal* iFieldsp,
AstUdpTableLineVal* oFieldsp)
: ASTGEN_SUPER_UdpTableLine(fl)
, m_udpIsCombo{true} {
addIFieldsp(iFieldsp);
addOFieldsp(oFieldsp);
}
class UdpSequential {};
AstUdpTableLine(UdpSequential, FileLine* fl, AstUdpTableLineVal* iFieldsp,
AstUdpTableLineVal* oFieldsp1, AstUdpTableLineVal* oFieldsp2)
: ASTGEN_SUPER_UdpTableLine(fl)
, m_udpIsCombo{false} {
addIFieldsp(iFieldsp);
addOFieldsp(oFieldsp1);
addOFieldsp(oFieldsp2);
}
ASTGEN_MEMBERS_AstUdpTableLine;
int udpIsCombo() const { return m_udpIsCombo; }
};
class AstUdpTableLineVal final : public AstNode {
string m_text; // Value character
public:
AstUdpTableLineVal(FileLine* fl, const string& text)
: ASTGEN_SUPER_UdpTableLineVal(fl)
, m_text{text} {}
ASTGEN_MEMBERS_AstUdpTableLineVal;
string name() const override VL_MT_STABLE { return m_text; }
void name(std::string const& text) override VL_MT_STABLE { m_text = text; }
string text() const VL_MT_SAFE { return m_text; }
};
class AstVar final : public AstNode {
// A variable (in/out/wire/reg/param) inside a module
//
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := delayp : Optional[AstDelay] // Net delay
// Initial value that never changes (static const), or constructor argument for
// MTASKSTATE variables
// @astgen op3 := valuep : Optional[AstNode<AstNodeExpr|AstNodeDType>]
// Value is a DType for type parameter defaults
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
// @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this
// var are sensitive
string m_name; // Name of variable
string m_origName; // Original name before dot addition
string m_tag; // Holds the string of the verilator tag -- used in XML output.
VVarType m_varType; // Type of variable
VDirection m_direction; // Direction input/output etc
VDirection m_declDirection; // Declared direction input/output etc
VLifetime m_lifetime; // Lifetime
VVarAttrClocker m_attrClocker;
VRandAttr m_rand; // Randomizability of this variable (rand, randc, etc)
int m_pinNum = 0; // For XML, if non-zero the connection pin number
bool m_ansi : 1; // Params or pins declared in the module header, rather than the body
bool m_declTyped : 1; // Declared as type (for dedup check)
bool m_tristate : 1; // Inout or triwire or trireg
bool m_primaryIO : 1; // In/out to top level (or directly assigned from same)
bool m_sc : 1; // SystemC variable
bool m_scClocked : 1; // SystemC sc_clk<> needed
bool m_scSensitive : 1; // SystemC sensitive() needed
bool m_sigPublic : 1; // User C code accesses this signal or is top signal
bool m_sigModPublic : 1; // User C code accesses this signal and module
bool m_sigUserRdPublic : 1; // User C code accesses this signal, read only
bool m_sigUserRWPublic : 1; // User C code accesses this signal, read-write
bool m_usedClock : 1; // Signal used as a clock
bool m_usedParam : 1; // Parameter is referenced (on link; later signals not setup)
bool m_usedLoopIdx : 1; // Variable subject of for unrolling
bool m_funcLocal : 1; // Local variable for a function
bool m_funcLocalSticky : 1; // As m_funcLocal but remains set if var is moved to a static
bool m_funcReturn : 1; // Return variable for a function
bool m_attrScBv : 1; // User force bit vector attribute
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
bool m_attrSFormat : 1; // User sformat attribute
bool m_attrSplitVar : 1; // declared with split_var metacomment
bool m_fileDescr : 1; // File descriptor
bool m_isConst : 1; // Table contains constant data
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
bool m_isStatic : 1; // Static C variable (for Verilog see instead lifetime())
bool m_isPulldown : 1; // Tri0
bool m_isPullup : 1; // Tri1
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
2023-09-19 03:17:21 +02:00
bool m_isInternal : 1; // Internal state, don't add to method pinter
bool m_isDpiOpenArray : 1; // DPI import open array
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
bool m_noReset : 1; // Do not do automated reset/randomization
bool m_noSubst : 1; // Do not substitute out references
bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam
bool m_trace : 1; // Trace this variable
bool m_isLatched : 1; // Not assigned in all control paths of combo always
bool m_isForceable : 1; // May be forced/released externally from user C code
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
2022-09-15 14:17:00 +02:00
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
Safely support non-overlapping blocking/non-blocking assignments (#6137) The manual for the BLKANDNBLK warning describes that it is safe to disable that error if the updated ranges are non-overlapping. This however was not true (see the added t_nba_mixed_update* tests). In this patch we change V3Delayed to use a new ShadowVarMasked scheme for variables that have mixed blocking and non-blocking updates (or the FlagUnique scheme for unpacked variables), which is in fact safe to use when the updated parts are non-overlapping. Furthermore, mixed assignments are safe as far as scheduling is concerned if either: - They are to independent parts (bits/members/etc) (with this patch) - Or if the blocking assignment is in clocked (or suspendable) logic. The risk in scheduling is a race between the Post scheduled NBA commit, and blocking assignments in combinational logic, which might order incorrectly. The second point highlights that we can handle stuff like this safely, which is sometimes used in testbenches: ```systemverilog always @(posedge clk) begin if ($time == 0) a = 0; end always @(posedge clk) begin if ($time > 0) a <= 2; end ```` The only dangerous case is: ```systemverilog always @(posedge clk) foo[idx] <= val; assign foo[0] = bar; ``` Whit this patch, this will still resolve fine at run-time if 'idx' is never zero, but might resolve incorrectly if 'idx' is zero. With the above in mind, the BLKANDNBLK warning is now only issued if: - We can't prove that the assignments are to non-overlapping bits - And the blocking assignment is in combinational logic These are the cases that genuinely require user attention to resolve. With this patch, there are no more BLKANDNBLK warnings in the RTLMeter designs. Fixes #6122.
2025-06-28 21:45:45 +02:00
bool m_ignorePostRead : 1; // Ignore reads in 'Post' blocks during ordering
bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering
bool m_ignoreSchedWrite : 1; // Ignore writes in scheduling (for special optimizations)
void init() {
m_ansi = false;
m_declTyped = false;
m_tristate = false;
m_primaryIO = false;
m_sc = false;
m_scClocked = false;
m_scSensitive = false;
m_usedClock = false;
m_usedParam = false;
m_usedLoopIdx = false;
m_sigPublic = false;
m_sigModPublic = false;
m_sigUserRdPublic = false;
m_sigUserRWPublic = false;
m_funcLocal = false;
m_funcLocalSticky = false;
m_funcReturn = false;
m_attrScBv = false;
m_attrIsolateAssign = false;
m_attrSFormat = false;
m_attrSplitVar = false;
m_fileDescr = false;
m_isConst = false;
m_isContinuously = false;
m_hasStrengthAssignment = false;
m_isStatic = false;
m_isPulldown = false;
m_isPullup = false;
m_isIfaceParent = false;
2023-09-19 03:17:21 +02:00
m_isInternal = false;
m_isDpiOpenArray = false;
m_isHideLocal = false;
m_isHideProtected = false;
m_noReset = false;
m_noSubst = false;
m_overridenParam = false;
m_trace = false;
m_isLatched = false;
m_isForceable = false;
m_isForcedByCode = false;
2022-09-15 14:17:00 +02:00
m_isWrittenByDpi = false;
m_isWrittenBySuspendable = false;
Safely support non-overlapping blocking/non-blocking assignments (#6137) The manual for the BLKANDNBLK warning describes that it is safe to disable that error if the updated ranges are non-overlapping. This however was not true (see the added t_nba_mixed_update* tests). In this patch we change V3Delayed to use a new ShadowVarMasked scheme for variables that have mixed blocking and non-blocking updates (or the FlagUnique scheme for unpacked variables), which is in fact safe to use when the updated parts are non-overlapping. Furthermore, mixed assignments are safe as far as scheduling is concerned if either: - They are to independent parts (bits/members/etc) (with this patch) - Or if the blocking assignment is in clocked (or suspendable) logic. The risk in scheduling is a race between the Post scheduled NBA commit, and blocking assignments in combinational logic, which might order incorrectly. The second point highlights that we can handle stuff like this safely, which is sometimes used in testbenches: ```systemverilog always @(posedge clk) begin if ($time == 0) a = 0; end always @(posedge clk) begin if ($time > 0) a <= 2; end ```` The only dangerous case is: ```systemverilog always @(posedge clk) foo[idx] <= val; assign foo[0] = bar; ``` Whit this patch, this will still resolve fine at run-time if 'idx' is never zero, but might resolve incorrectly if 'idx' is zero. With the above in mind, the BLKANDNBLK warning is now only issued if: - We can't prove that the assignments are to non-overlapping bits - And the blocking assignment is in combinational logic These are the cases that genuinely require user attention to resolve. With this patch, there are no more BLKANDNBLK warnings in the RTLMeter designs. Fixes #6122.
2025-06-28 21:45:45 +02:00
m_ignorePostRead = false;
m_ignorePostWrite = false;
m_ignoreSchedWrite = false;
m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN;
}
public:
AstVar(FileLine* fl, VVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
: ASTGEN_SUPER_Var(fl)
, m_name{name}
, m_origName{name} {
init();
combineType(type);
childDTypep(dtp); // Only for parser
dtypep(nullptr); // V3Width will resolve
}
AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp)
: ASTGEN_SUPER_Var(fl)
, m_name{name}
, m_origName{name} {
init();
combineType(type);
UASSERT(dtp, "AstVar created with no dtype");
dtypep(dtp);
}
AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth)
: ASTGEN_SUPER_Var(fl)
, m_name{name}
, m_origName{name} {
init();
combineType(type);
dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED);
}
AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth)
: ASTGEN_SUPER_Var(fl)
, m_name{name}
, m_origName{name} {
init();
combineType(type);
dtypeSetBitSized(wantwidth, VSigning::UNSIGNED);
}
AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep)
: ASTGEN_SUPER_Var(fl)
, m_name{name}
, m_origName{name} {
init();
combineType(type);
if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true));
dtypeFrom(examplep);
}
ASTGEN_MEMBERS_AstVar;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool sameNode(const AstNode* samep) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool hasDType() const override VL_MT_SAFE { return true; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
string origName() const override { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
VVarType varType() const VL_MT_SAFE { return m_varType; } // * = Type of variable
void direction(const VDirection& flag) {
m_direction = flag;
if (m_direction == VDirection::INOUT) m_tristate = true;
}
VDirection direction() const VL_MT_SAFE { return m_direction; }
bool isIO() const VL_MT_SAFE { return m_direction != VDirection::NONE; }
void declDirection(const VDirection& flag) { m_declDirection = flag; }
VDirection declDirection() const { return m_declDirection; }
void varType(VVarType type) { m_varType = type; }
void varType2Out() {
m_tristate = false;
m_direction = VDirection::OUTPUT;
}
void varType2In() {
m_tristate = false;
m_direction = VDirection::INPUT;
}
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
// Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
string cPubArgType(bool named, bool forReturn) const;
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
string dpiTmpVarType(const string& varName) const;
// Return Verilator internal type for argument: CData, SData, IData, WData
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "",
bool asRef = false) const;
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration
void combineType(VVarType type);
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); }
// (Slow) recurse down to find basic data type (Note don't need virtual -
// AstVar isn't a NodeDType)
AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); }
virtual AstNodeDType* subDTypep() const VL_MT_STABLE {
return dtypep() ? dtypep() : childDTypep();
}
void ansi(bool flag) { m_ansi = flag; }
void declTyped(bool flag) { m_declTyped = flag; }
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
void attrClocker(VVarAttrClocker flag) { m_attrClocker = flag; }
void attrFileDescr(bool flag) { m_fileDescr = flag; }
void attrScClocked(bool flag) { m_scClocked = flag; }
void attrScBv(bool flag) { m_attrScBv = flag; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
void attrSFormat(bool flag) { m_attrSFormat = flag; }
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
void rand(const VRandAttr flag) { m_rand = flag; }
void usedClock(bool flag) { m_usedClock = flag; }
void usedParam(bool flag) { m_usedParam = flag; }
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
void sigPublic(bool flag) { m_sigPublic = flag; }
void sigModPublic(bool flag) { m_sigModPublic = flag; }
void sigUserRdPublic(bool flag) {
m_sigUserRdPublic = flag;
if (flag) sigPublic(true);
}
void sigUserRWPublic(bool flag) {
m_sigUserRWPublic = flag;
if (flag) sigUserRdPublic(true);
}
void sc(bool flag) { m_sc = flag; }
void scSensitive(bool flag) { m_scSensitive = flag; }
void primaryIO(bool flag) { m_primaryIO = flag; }
void isConst(bool flag) { m_isConst = flag; }
void isContinuously(bool flag) { m_isContinuously = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
2023-09-19 03:17:21 +02:00
void isInternal(bool flag) { m_isInternal = flag; }
void funcLocal(bool flag) {
m_funcLocal = flag;
if (flag) m_funcLocalSticky = true;
}
void funcReturn(bool flag) { m_funcReturn = flag; }
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
bool hasStrengthAssignment() { return m_hasStrengthAssignment; }
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
bool isDpiOpenArray() const VL_MT_SAFE { return m_isDpiOpenArray; }
bool isHideLocal() const { return m_isHideLocal; }
void isHideLocal(bool flag) { m_isHideLocal = flag; }
bool isHideProtected() const { return m_isHideProtected; }
void isHideProtected(bool flag) { m_isHideProtected = flag; }
void noReset(bool flag) { m_noReset = flag; }
bool noReset() const { return m_noReset; }
void noSubst(bool flag) { m_noSubst = flag; }
bool noSubst() const { return m_noSubst; }
void overriddenParam(bool flag) { m_overridenParam = flag; }
bool overriddenParam() const { return m_overridenParam; }
void trace(bool flag) { m_trace = flag; }
void isLatched(bool flag) { m_isLatched = flag; }
bool isForceable() const { return m_isForceable; }
void setForceable() { m_isForceable = true; }
void setForcedByCode() { m_isForcedByCode = true; }
bool isForced() const { return m_isForceable || m_isForcedByCode; }
2022-09-15 14:17:00 +02:00
bool isWrittenByDpi() const { return m_isWrittenByDpi; }
void setWrittenByDpi() { m_isWrittenByDpi = true; }
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }
void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; }
Safely support non-overlapping blocking/non-blocking assignments (#6137) The manual for the BLKANDNBLK warning describes that it is safe to disable that error if the updated ranges are non-overlapping. This however was not true (see the added t_nba_mixed_update* tests). In this patch we change V3Delayed to use a new ShadowVarMasked scheme for variables that have mixed blocking and non-blocking updates (or the FlagUnique scheme for unpacked variables), which is in fact safe to use when the updated parts are non-overlapping. Furthermore, mixed assignments are safe as far as scheduling is concerned if either: - They are to independent parts (bits/members/etc) (with this patch) - Or if the blocking assignment is in clocked (or suspendable) logic. The risk in scheduling is a race between the Post scheduled NBA commit, and blocking assignments in combinational logic, which might order incorrectly. The second point highlights that we can handle stuff like this safely, which is sometimes used in testbenches: ```systemverilog always @(posedge clk) begin if ($time == 0) a = 0; end always @(posedge clk) begin if ($time > 0) a <= 2; end ```` The only dangerous case is: ```systemverilog always @(posedge clk) foo[idx] <= val; assign foo[0] = bar; ``` Whit this patch, this will still resolve fine at run-time if 'idx' is never zero, but might resolve incorrectly if 'idx' is zero. With the above in mind, the BLKANDNBLK warning is now only issued if: - We can't prove that the assignments are to non-overlapping bits - And the blocking assignment is in combinational logic These are the cases that genuinely require user attention to resolve. With this patch, there are no more BLKANDNBLK warnings in the RTLMeter designs. Fixes #6122.
2025-06-28 21:45:45 +02:00
bool ignorePostRead() const { return m_ignorePostRead; }
void setIgnorePostRead() { m_ignorePostRead = true; }
bool ignorePostWrite() const { return m_ignorePostWrite; }
void setIgnorePostWrite() { m_ignorePostWrite = true; }
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
2022-09-15 14:17:00 +02:00
// METHODS
void name(const string& name) override { m_name = name; }
void tag(const string& text) override { m_tag = text; }
string tag() const override { return m_tag; }
bool isAnsi() const { return m_ansi; }
bool isContinuously() const { return m_isContinuously; }
bool isDeclTyped() const { return m_declTyped; }
2024-11-26 00:25:36 +01:00
bool isInout() const { return m_direction.isInout(); }
bool isInoutOrRef() const { return m_direction.isInoutOrRef(); }
bool isInput() const { return m_direction.isInput(); }
bool isNonOutput() const { return m_direction.isNonOutput(); }
bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); }
bool isConstRef() const VL_MT_SAFE { return m_direction.isConstRef(); }
bool isRef() const VL_MT_SAFE { return m_direction.isRef(); }
bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); }
bool isTristate() const { return m_tristate; }
bool isPrimaryIO() const VL_MT_SAFE { return m_primaryIO; }
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
bool isIfaceRef() const { return varType() == VVarType::IFACEREF; }
void setIfaceRef() {
m_direction = VDirection::NONE;
m_varType = VVarType::IFACEREF;
}
bool isIfaceParent() const { return m_isIfaceParent; }
2023-09-19 03:17:21 +02:00
bool isInternal() const { return m_isInternal; }
bool isSignal() const { return varType().isSignal(); }
bool isNet() const { return varType().isNet(); }
bool isWor() const { return varType().isWor(); }
bool isWand() const { return varType().isWand(); }
bool isWiredNet() const { return varType().isWiredNet(); }
bool isTemp() const { return varType().isTemp(); }
bool isToggleCoverable() const {
return ((isIO() || isSignal())
&& (isIO() || isBitLogic())
// Wrapper would otherwise duplicate wrapped module's coverage
&& !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString());
}
bool isClassMember() const { return varType() == VVarType::MEMBER; }
bool isStatementTemp() const { return varType() == VVarType::STMTTEMP; }
bool isXTemp() const { return varType() == VVarType::XTEMP; }
bool isParam() const { return varType().isParam(); }
bool isGParam() const { return varType() == VVarType::GPARAM; }
bool isGenVar() const { return varType() == VVarType::GENVAR; }
bool isBitLogic() const {
AstBasicDType* bdtypep = basicp();
return bdtypep && bdtypep->isBitLogic();
}
bool isUsedClock() const VL_MT_SAFE { return m_usedClock; }
bool isUsedParam() const { return m_usedParam; }
bool isUsedLoopIdx() const { return m_usedLoopIdx; }
bool isSc() const VL_MT_SAFE { return m_sc; }
bool isScQuad() const;
bool isScBv() const VL_MT_STABLE;
bool isScUint() const;
bool isScUintBool() const;
bool isScBigUint() const VL_MT_STABLE;
bool isScSensitive() const { return m_scSensitive; }
bool isSigPublic() const;
bool isSigModPublic() const { return m_sigModPublic && !isIfaceRef(); }
bool isSigUserRdPublic() const { return m_sigUserRdPublic && !isIfaceRef(); }
bool isSigUserRWPublic() const { return m_sigUserRWPublic && !isIfaceRef(); }
bool isTrace() const { return m_trace; }
bool isRand() const { return m_rand.isRand(); }
bool isRandC() const { return m_rand.isRandC(); }
bool isConst() const VL_MT_SAFE { return m_isConst; }
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
bool isLatched() const { return m_isLatched; }
bool isFuncLocal() const { return m_funcLocal; }
bool isFuncLocalSticky() const { return m_funcLocalSticky; }
bool isFuncReturn() const { return m_funcReturn; }
bool isPullup() const { return m_isPullup; }
bool isPulldown() const { return m_isPulldown; }
bool attrScBv() const { return m_attrScBv; }
bool attrFileDescr() const { return m_fileDescr; }
bool attrScClocked() const { return m_scClocked; }
bool attrSFormat() const { return m_attrSFormat; }
bool attrSplitVar() const { return m_attrSplitVar; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
AstIface* sensIfacep() const { return m_sensIfacep; }
VVarAttrClocker attrClocker() const { return m_attrClocker; }
VRandAttr rand() const { return m_rand; }
string verilogKwd() const override;
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
void pinNum(int id) { m_pinNum = id; }
int pinNum() const { return m_pinNum; }
void propagateAttrFrom(const AstVar* fromp) {
// This is getting connected to fromp; keep attributes
// Note the method below too
if (fromp->attrFileDescr()) attrFileDescr(true);
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
if (fromp->isContinuously()) isContinuously(true);
}
void propagateWrapAttrFrom(const AstVar* fromp) {
// Creating a function wrapper; keep attributes
propagateAttrFrom(fromp);
direction(fromp->direction());
declDirection(fromp->declDirection());
lifetime(fromp->lifetime());
}
void combineType(const AstVar* typevarp) {
// This is same as typevarp (for combining input & reg decls)
// "this" is the input var. typevarp is the reg var.
propagateAttrFrom(typevarp);
combineType(typevarp->varType());
if (typevarp->isSigPublic()) sigPublic(true);
if (typevarp->isSigModPublic()) sigModPublic(true);
if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
if (typevarp->attrScClocked()) attrScClocked(true);
}
void inlineAttrReset(const string& name) {
if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) {
m_varType = VVarType::TRIWIRE;
}
m_direction = VDirection::NONE;
m_name = name;
}
bool needsCReset() const {
return !isIfaceParent() && !isIfaceRef() && !noReset() && !isParam() && !isStatementTemp()
&& !(basicp() && (basicp()->isEvent() || basicp()->isTriggerVec()));
}
static AstVar* scVarRecurse(AstNode* nodep);
};
class AstVarScope final : public AstNode {
// A particular scoped usage of a variable
// That is, as a module is used under multiple cells, we get a different
// varscope for each var in the module
// Parents: MODULE
// Children: none
//
// @astgen ptr := m_scopep : Optional[AstScope] // Scope variable is underneath
// @astgen ptr := m_varp : Optional[AstVar] // [AfterLink] Pointer to variable itself
bool m_trace : 1; // Tracing is turned on for this scope
public:
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
: ASTGEN_SUPER_VarScope(fl)
, m_scopep{scopep}
, m_varp{varp} {
UASSERT_OBJ(scopep, fl, "Scope must be non-null");
UASSERT_OBJ(varp, fl, "Var must be non-null");
m_trace = true;
dtypeFrom(varp);
}
ASTGEN_MEMBERS_AstVarScope;
void cloneRelink() override {
if (m_varp && m_varp->clonep()) {
UASSERT(m_scopep->clonep(), "No clone cross link: " << this);
}
cloneRelinkGen();
}
bool maybePointedTo() const override VL_MT_SAFE { return true; }
string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool sameNode(const AstNode* samep) const override;
bool hasDType() const override VL_MT_SAFE { return true; }
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under
void scopep(AstScope* nodep) { m_scopep = nodep; }
bool isTrace() const { return m_trace; }
void trace(bool flag) { m_trace = flag; }
};
// === AstNodeBlock ===
class AstBegin final : public AstNodeBlock {
// A Begin/end named block, only exists shortly after parsing until linking
// Parents: statement
// @astgen op1 := genforp : Optional[AstNode]
2023-10-16 14:02:29 +02:00
bool m_generate : 1; // Underneath a generate
bool m_needProcess : 1; // Uses VlProcess
const bool m_implied : 1; // Not inserted by user
public:
// Node that puts name into the output stream
AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false,
bool implied = false)
: ASTGEN_SUPER_Begin(fl, name, stmtsp)
, m_generate{generate}
2023-10-16 14:02:29 +02:00
, m_needProcess{false}
, m_implied{implied} {}
ASTGEN_MEMBERS_AstBegin;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool generate() const { return m_generate; }
void generate(bool flag) { m_generate = flag; }
2023-10-16 14:02:29 +02:00
void setNeedProcess() { m_needProcess = true; }
bool needProcess() const { return m_needProcess; }
bool implied() const { return m_implied; }
};
class AstFork final : public AstNodeBlock {
// A fork named block
// @astgen op1 := initsp : List[AstNode]
// Parents: statement
// Children: statements
VJoinType m_joinType; // Join keyword type
public:
// Node that puts name into the output stream
AstFork(FileLine* fl, const string& name, AstNode* stmtsp)
: ASTGEN_SUPER_Fork(fl, name, stmtsp) {}
ASTGEN_MEMBERS_AstFork;
2022-09-16 17:15:10 +02:00
bool isTimingControl() const override { return !joinType().joinNone(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
VJoinType joinType() const { return m_joinType; }
void joinType(const VJoinType& flag) { m_joinType = flag; }
};
// === AstNodeFTask ===
class AstFunc final : public AstNodeFTask {
// A function inside a module
public:
AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarp)
: ASTGEN_SUPER_Func(fl, name, stmtp) {
this->fvarp(fvarp);
}
ASTGEN_MEMBERS_AstFunc;
bool hasDType() const override VL_MT_SAFE { return true; }
AstNodeFTask* cloneType(const string& name) override {
return new AstFunc{fileline(), name, nullptr, nullptr};
}
};
2023-09-08 03:45:51 +02:00
class AstLet final : public AstNodeFTask {
// Verilog "let" statement
// Parents: MODULE
// stmtp list first item is returned StmtExpr, as Let always returns AstNodeExpr
2023-09-08 03:45:51 +02:00
public:
AstLet(FileLine* fl, const string& name)
: ASTGEN_SUPER_Let(fl, name, nullptr) {}
ASTGEN_MEMBERS_AstLet;
bool hasDType() const override VL_MT_SAFE { return true; }
2023-09-08 03:45:51 +02:00
const char* broken() const override {
BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr));
return nullptr;
}
AstNodeFTask* cloneType(const string& name) override { return new AstLet{fileline(), name}; }
2023-09-08 03:45:51 +02:00
};
2022-11-01 23:53:47 +01:00
class AstProperty final : public AstNodeFTask {
// A property inside a module
public:
AstProperty(FileLine* fl, const string& name, AstNode* stmtp)
: ASTGEN_SUPER_Property(fl, name, stmtp) {}
ASTGEN_MEMBERS_AstProperty;
bool hasDType() const override VL_MT_SAFE { return true; }
AstNodeFTask* cloneType(const string& name) override {
return new AstProperty{fileline(), name, nullptr};
}
2022-11-01 23:53:47 +01:00
};
class AstTask final : public AstNodeFTask {
// A task inside a module
public:
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
: ASTGEN_SUPER_Task(fl, name, stmtp) {}
ASTGEN_MEMBERS_AstTask;
AstNodeFTask* cloneType(const string& name) override {
return new AstTask{fileline(), name, nullptr};
}
};
// === AstNodeFile ===
class AstCFile final : public AstNodeFile {
// C++ output file
// Parents: NETLIST
uint64_t m_complexityScore = 0;
bool m_slow : 1; ///< Compile w/o optimization
bool m_source : 1; ///< Source file (vs header file)
bool m_support : 1; ///< Support file (non systemc)
public:
AstCFile(FileLine* fl, const string& name)
: ASTGEN_SUPER_CFile(fl, name)
, m_slow{false}
, m_source{false}
, m_support{false} {}
ASTGEN_MEMBERS_AstCFile;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
uint64_t complexityScore() const { return m_complexityScore; }
void complexityScore(uint64_t newScore) { m_complexityScore = newScore; }
bool slow() const { return m_slow; }
void slow(bool flag) { m_slow = flag; }
bool source() const { return m_source; }
void source(bool flag) { m_source = flag; }
bool support() const { return m_support; }
void support(bool flag) VL_MT_SAFE { m_support = flag; }
};
class AstVFile final : public AstNodeFile {
// Verilog output file
// Parents: NETLIST
public:
AstVFile(FileLine* fl, const string& name)
: ASTGEN_SUPER_VFile(fl, name) {}
ASTGEN_MEMBERS_AstVFile;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
// === AstNodeModule ===
class AstClass final : public AstNodeModule {
// @astgen op4 := extendsp : List[AstClassExtends]
// MEMBERS
// @astgen ptr := m_classOrPackagep : Optional[AstClassPackage] // Package to be emitted with
VBaseOverride m_baseOverride; // BaseOverride (inital/final/extends)
bool m_extended = false; // Is extension or extended by other classes
bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
bool m_virtual = false; // Virtual class
public:
AstClass(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Class(fl, name, libname) {}
ASTGEN_MEMBERS_AstClass;
string verilogKwd() const override { return "class"; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool timescaleMatters() const override { return false; }
AstClassPackage* classOrPackagep() const VL_MT_STABLE { return m_classOrPackagep; }
void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; }
AstNode* membersp() const VL_MT_STABLE { return stmtsp(); }
void addMembersp(AstNode* nodep) { addStmtsp(nodep); }
bool isExtended() const { return m_extended; }
void isExtended(bool flag) { m_extended = flag; }
bool isInterfaceClass() const { return m_interfaceClass; }
void isInterfaceClass(bool flag) { m_interfaceClass = flag; }
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; }
void needRNG(bool flag) { m_needRNG = flag; }
bool useVirtualPublic() const { return m_useVirtualPublic; }
void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; }
// Return true if this class is an extension of base class (SLOW)
// Accepts nullptrs
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
void baseOverride(const VBaseOverride& flag) { m_baseOverride = flag; }
VBaseOverride baseOverride() const { return m_baseOverride; }
// Return the lowest class extended from, or this class
AstClass* baseMostClassp();
static bool isCacheableChild(const AstNode* nodep);
// Iterates top level members of the class, taking into account inheritance (starting from the
// root superclass). Note: after V3Scope, several children are moved under an AstScope and will
// not be found by this.
template <typename T_Callable>
void foreachMember(const T_Callable& f) {
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
static_assert(
vlstd::is_invocable<T_Callable, AstClass*, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value,
"T_Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const cextendsp = this->extendsp()) {
cextendsp->classp()->foreachMember(f);
}
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstNode::privateTypeTest<T_Node>(stmtp)) f(this, static_cast<T_Node*>(stmtp));
}
}
// Same as above, but stops after first match
template <typename T_Callable>
bool existsMember(const T_Callable& p) const {
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
static_assert(
vlstd::is_invocable_r<bool, T_Callable, const AstClass*, const T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const cextendsp = this->extendsp()) {
if (cextendsp->classp()->existsMember(p)) return true;
}
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstNode::privateTypeTest<T_Node>(stmtp)) {
if (p(this, static_cast<T_Node*>(stmtp))) return true;
}
}
return false;
}
};
class AstClassPackage final : public AstNodeModule {
// The static information portion of a class (treated similarly to a package)
//
// @astgen ptr := m_classp : Optional[AstClass] // Class package this is under
// // (weak pointer, hard link is other way)
public:
AstClassPackage(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_ClassPackage(fl, name, libname) {}
ASTGEN_MEMBERS_AstClassPackage;
string verilogKwd() const override { return "classpackage"; }
bool timescaleMatters() const override { return false; }
AstClass* classp() const VL_MT_SAFE { return m_classp; }
void classp(AstClass* classp) { m_classp = classp; }
};
class AstIface final : public AstNodeModule {
// A module declaration
public:
AstIface(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Iface(fl, name, libname) {}
ASTGEN_MEMBERS_AstIface;
// Interfaces have `timescale applicability but lots of code seems to
// get false warnings if we enable this
string verilogKwd() const override { return "interface"; }
bool timescaleMatters() const override { return false; }
};
class AstModule final : public AstNodeModule {
// A module declaration
const bool m_isChecker = false; // Module represents a checker
const bool m_isProgram = false; // Module represents a program
public:
class Checker {}; // for constructor type-overload selection
class Program {}; // for constructor type-overload selection
AstModule(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Module(fl, name, libname) {}
AstModule(FileLine* fl, const string& name, const string& libname, Checker)
: ASTGEN_SUPER_Module(fl, name, libname)
, m_isChecker{true} {}
AstModule(FileLine* fl, const string& name, const string& libname, Program)
: ASTGEN_SUPER_Module(fl, name, libname)
, m_isProgram{true} {}
ASTGEN_MEMBERS_AstModule;
string verilogKwd() const override {
return m_isChecker ? "checker" : m_isProgram ? "program" : "module";
}
bool timescaleMatters() const override { return true; }
bool isChecker() const { return m_isChecker; }
bool isProgram() const { return m_isProgram; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstNotFoundModule final : public AstNodeModule {
// A missing module declaration
public:
AstNotFoundModule(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_NotFoundModule(fl, name, libname) {}
ASTGEN_MEMBERS_AstNotFoundModule;
string verilogKwd() const override { return "/*not-found-*/ module"; }
bool timescaleMatters() const override { return false; }
};
class AstPackage final : public AstNodeModule {
// A package declaration
public:
AstPackage(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Package(fl, name, libname) {}
ASTGEN_MEMBERS_AstPackage;
string verilogKwd() const override { return "package"; }
bool timescaleMatters() const override { return !isDollarUnit(); }
static string dollarUnitName() { return AstNode::encodeName("$unit"); }
bool isDollarUnit() const { return name() == dollarUnitName(); }
};
class AstPrimitive final : public AstNodeModule {
// A primitive declaration
public:
AstPrimitive(FileLine* fl, const string& name, const string& libname)
: ASTGEN_SUPER_Primitive(fl, name, libname) {}
ASTGEN_MEMBERS_AstPrimitive;
string verilogKwd() const override { return "primitive"; }
bool timescaleMatters() const override { return false; }
};
// === AstNodeProcedure ===
class AstAlways final : public AstNodeProcedure {
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked
const VAlwaysKwd m_keyword;
public:
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_Always(fl, stmtsp)
, m_keyword{keyword} {
this->sensesp(sensesp);
}
ASTGEN_MEMBERS_AstAlways;
//
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
VAlwaysKwd keyword() const { return m_keyword; }
};
2022-12-23 13:34:49 +01:00
class AstAlwaysObserved final : public AstNodeProcedure {
// Like always but Observed scheduling region
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list, removed in V3Active
public:
AstAlwaysObserved(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
: ASTGEN_SUPER_AlwaysObserved(fl, bodysp) {
this->sensesp(sensesp);
}
ASTGEN_MEMBERS_AstAlwaysObserved;
};
class AstAlwaysPost final : public AstNodeProcedure {
// Like always but 'post' scheduled, e.g. for array NBA commits
public:
explicit AstAlwaysPost(FileLine* fl)
: ASTGEN_SUPER_AlwaysPost(fl, nullptr) {}
ASTGEN_MEMBERS_AstAlwaysPost;
};
class AstAlwaysPostponed final : public AstNodeProcedure {
// Like always but Postponed scheduling region
public:
AstAlwaysPostponed(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_AlwaysPostponed(fl, stmtsp) {}
ASTGEN_MEMBERS_AstAlwaysPostponed;
};
2022-12-23 13:34:49 +01:00
class AstAlwaysReactive final : public AstNodeProcedure {
// Like always but Reactive scheduling region
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list, removed in V3Active
public:
AstAlwaysReactive(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
: ASTGEN_SUPER_AlwaysReactive(fl, bodysp) {
this->sensesp(sensesp);
}
ASTGEN_MEMBERS_AstAlwaysReactive;
};
class AstFinal final : public AstNodeProcedure {
public:
AstFinal(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_Final(fl, stmtsp) {}
ASTGEN_MEMBERS_AstFinal;
};
class AstInitial final : public AstNodeProcedure {
public:
AstInitial(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_Initial(fl, stmtsp) {}
ASTGEN_MEMBERS_AstInitial;
};
class AstInitialAutomatic final : public AstNodeProcedure {
// Automatic variable initialization
// That is, it runs every function start, or class construction
public:
AstInitialAutomatic(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_InitialAutomatic(fl, stmtsp) {}
ASTGEN_MEMBERS_AstInitialAutomatic;
};
class AstInitialStatic final : public AstNodeProcedure {
// Static variable initialization
// That is, it runs at the beginning of simulation, before 'initial' blocks
public:
AstInitialStatic(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_InitialStatic(fl, stmtsp) {}
ASTGEN_MEMBERS_AstInitialStatic;
};
// === AstNodeRange ===
class AstBracketRange final : public AstNodeRange {
2022-12-10 03:06:27 +01:00
// Parser only concept "[lhsp]", an AstUnknownRange, QueueRange or Range,
// unknown until lhsp type is determined
// @astgen op1 := elementsp : AstNode<AstNodeExpr|AstNodeDType>
public:
AstBracketRange(FileLine* fl, AstNode* elementsp)
: ASTGEN_SUPER_BracketRange(fl) {
this->elementsp(elementsp);
}
ASTGEN_MEMBERS_AstBracketRange;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Will be removed in V3Width, which relies on this
// being a child not a dtype pointed node
bool maybePointedTo() const override VL_MT_SAFE { return false; }
};
class AstRange final : public AstNodeRange {
// Range specification, for use under variables and cells
// @astgen op1 := leftp : AstNodeExpr
// @astgen op2 := rightp : AstNodeExpr
public:
AstRange(FileLine* fl, AstNodeExpr* leftp, AstNodeExpr* rightp)
: ASTGEN_SUPER_Range(fl) {
this->leftp(leftp);
this->rightp(rightp);
}
inline AstRange(FileLine* fl, int left, int right);
inline AstRange(FileLine* fl, const VNumRange& range);
ASTGEN_MEMBERS_AstRange;
inline int leftConst() const VL_MT_STABLE;
inline int rightConst() const VL_MT_STABLE;
int hiConst() const VL_MT_STABLE {
const int l = leftConst();
const int r = rightConst();
return l > r ? l : r;
}
int loConst() const VL_MT_STABLE {
const int l = leftConst();
const int r = rightConst();
return l > r ? r : l;
}
int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; }
bool ascending() const { return leftConst() < rightConst(); }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstUnsizedRange final : public AstNodeRange {
// Unsized range specification, for open arrays
public:
explicit AstUnsizedRange(FileLine* fl)
: ASTGEN_SUPER_UnsizedRange(fl) {}
ASTGEN_MEMBERS_AstUnsizedRange;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { return "[]"; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstWildcardRange final : public AstNodeRange {
// Wildcard range specification, for wildcard index type associative arrays
public:
explicit AstWildcardRange(FileLine* fl)
: ASTGEN_SUPER_WildcardRange(fl) {}
ASTGEN_MEMBERS_AstWildcardRange;
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { return "[*]"; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
// === AstNodeStmt ===
class AstAlwaysPublic final : public AstNodeStmt {
// "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/
// Body statements are just AstVarRefs to the public signals
// @astgen op1 := sensesp : List[AstSenTree]
// @astgen op2 := stmtsp : List[AstNode]
public:
AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_AlwaysPublic(fl) {
addSensesp(sensesp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstAlwaysPublic;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Special accessors
bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstAssertCtl final : public AstNodeStmt {
// @astgen op1 := controlTypep : AstNodeExpr
// @astgen op2 := assertTypesp : Optional[AstNodeExpr]
// @astgen op3 := directiveTypesp : Optional[AstNodeExpr]
// Type of assertcontrol task; either known from parser or from evaluated
// controlTypep expression.
VAssertCtlType m_ctlType; // $assert keyword type (control_type)
VAssertType m_assertTypes; // Types of assertions affected
VAssertDirectiveType m_directiveTypes; // Types of directives affected
public:
AstAssertCtl(FileLine* fl, VAssertCtlType ctlType, AstNodeExpr* levelp = nullptr,
AstNodeExpr* itemsp = nullptr);
AstAssertCtl(FileLine* fl, AstNodeExpr* controlTypep, AstNodeExpr* assertTypesp = nullptr,
AstNodeExpr* directiveTypep = nullptr, AstNodeExpr* levelp = nullptr,
AstNodeExpr* itemsp = nullptr);
ASTGEN_MEMBERS_AstAssertCtl;
string verilogKwd() const override { return m_ctlType.ascii(); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
VAssertCtlType ctlType() const { return m_ctlType; }
void ctlType(int32_t type) { m_ctlType = VAssertCtlType{type}; }
VAssertType ctlAssertTypes() const { return m_assertTypes; }
void ctlAssertTypes(VAssertType types) { m_assertTypes = types; }
VAssertDirectiveType ctlDirectiveTypes() const { return m_directiveTypes; }
void ctlDirectiveTypes(VAssertDirectiveType types) { m_directiveTypes = types; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
};
class AstBreak final : public AstNodeStmt {
public:
explicit AstBreak(FileLine* fl)
: ASTGEN_SUPER_Break(fl) {}
ASTGEN_MEMBERS_AstBreak;
string verilogKwd() const override { return "break"; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
};
class AstCReset final : public AstNodeStmt {
// Reset variable at startup
// @astgen op1 := varrefp : AstVarRef
const bool m_constructing; // Previously cleared by constructor
public:
AstCReset(FileLine* fl, AstVarRef* varrefp, bool constructing)
: ASTGEN_SUPER_CReset(fl)
, m_constructing{constructing} {
this->varrefp(varrefp);
}
ASTGEN_MEMBERS_AstCReset;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* samep) const override {
return constructing() == VN_DBG_AS(samep, CReset)->constructing();
}
bool constructing() const { return m_constructing; }
};
class AstCReturn final : public AstNodeStmt {
// C++ return from a function
// @astgen op1 := lhsp : AstNodeExpr
public:
AstCReturn(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CReturn(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstCReturn;
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstCStmt final : public AstNodeStmt {
// Emit C statement
// @astgen op1 := exprsp : List[AstNode]
public:
AstCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_CStmt(fl) {
addExprsp(exprsp);
}
inline AstCStmt(FileLine* fl, const string& textStmt);
ASTGEN_MEMBERS_AstCStmt;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstComment final : public AstNodeStmt {
// Some comment to put into the output stream
const string m_name; // Text of comment
const bool m_showAt; // Show "at <fileline>"
public:
AstComment(FileLine* fl, const string& name, bool showAt = false)
: ASTGEN_SUPER_Comment(fl)
, m_name{name}
, m_showAt{showAt} {}
ASTGEN_MEMBERS_AstComment;
string name() const override VL_MT_STABLE { return m_name; } // * = Text
bool sameNode(const AstNode* samep) const override { return true; } // Ignore name in comments
virtual bool showAt() const { return m_showAt; }
};
class AstConstraintExpr final : public AstNodeStmt {
// Constraint expression
// @astgen op1 := exprp : AstNodeExpr
bool m_isDisableSoft = false; // Disable soft constraint expression
2024-11-09 18:45:55 +01:00
bool m_isSoft = false; // Soft constraint expression
public:
AstConstraintExpr(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_ConstraintExpr(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstConstraintExpr;
2024-11-09 18:45:55 +01:00
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isDisableSoft() const { return m_isDisableSoft; }
void isDisableSoft(bool flag) { m_isDisableSoft = flag; }
bool isSoft() const { return m_isSoft; }
void isSoft(bool flag) { m_isSoft = flag; }
};
class AstConstraintUnique final : public AstNodeStmt {
// Constraint unique statement
// @astgen op1 := rangesp : List[AstNode]
public:
AstConstraintUnique(FileLine* fl, AstNode* rangesp)
: ASTGEN_SUPER_ConstraintUnique(fl) {
addRangesp(rangesp);
}
ASTGEN_MEMBERS_AstConstraintUnique;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstContinue final : public AstNodeStmt {
public:
explicit AstContinue(FileLine* fl)
: ASTGEN_SUPER_Continue(fl) {}
ASTGEN_MEMBERS_AstContinue;
string verilogKwd() const override { return "continue"; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
};
class AstCoverDecl final : public AstNodeStmt {
// Coverage analysis point declaration
//
// [After V3CoverageJoin] Duplicate declaration to get data from instead
// @astgen ptr := m_dataDeclp : Optional[AstCoverDecl]
string m_page;
string m_text;
string m_hier;
string m_linescov;
int m_offset; // Offset column numbers to uniq-ify IFs
int m_binNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
public:
AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov,
int offset)
: ASTGEN_SUPER_CoverDecl(fl)
, m_page{page}
, m_text{comment}
, m_linescov{linescov}
, m_offset{offset} {}
ASTGEN_MEMBERS_AstCoverDecl;
const char* broken() const override {
if (m_dataDeclp
&& (m_dataDeclp == this || m_dataDeclp->m_dataDeclp)) { // Avoid O(n^2) accessing
v3fatalSrc("dataDeclp should point to real data, not be a list: " << cvtToHex(this));
}
return nullptr;
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
int binNum() const { return m_binNum; }
void binNum(int flag) { m_binNum = flag; }
int offset() const { return m_offset; }
const string& comment() const { return m_text; } // text to insert in code
const string& linescov() const { return m_linescov; }
const string& page() const { return m_page; }
const string& hier() const { return m_hier; }
void hier(const string& flag) { m_hier = flag; }
void comment(const string& flag) { m_text = flag; }
bool sameNode(const AstNode* samep) const override {
const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl);
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
&& hier() == asamep->hier() && comment() == asamep->comment());
}
bool isPredictOptimizable() const override { return false; }
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
// dataDecl nullptr means "use this one", but often you want "this" to
// indicate to get data from here
AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; }
AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; }
};
class AstCoverInc final : public AstNodeStmt {
// Coverage analysis point; increment coverage count
//
// @astgen ptr := m_declp : AstCoverDecl // [After V3CoverageJoin] Declaration
public:
AstCoverInc(FileLine* fl, AstCoverDecl* declp)
: ASTGEN_SUPER_CoverInc(fl)
, m_declp{declp} {}
ASTGEN_MEMBERS_AstCoverInc;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
bool sameNode(const AstNode* samep) const override {
return declp() == VN_DBG_AS(samep, CoverInc)->declp();
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() override { return true; }
bool isPure() override { return false; }
AstCoverDecl* declp() const { return m_declp; } // Where defined
};
class AstCoverToggle final : public AstNodeStmt {
// Toggle analysis of given signal
// Parents: MODULE
// @astgen op1 := incp : AstCoverInc
// @astgen op2 := origp : AstNodeExpr
// @astgen op3 := changep : AstNodeExpr
public:
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNodeExpr* origp, AstNodeExpr* changep)
: ASTGEN_SUPER_CoverToggle(fl) {
this->incp(incp);
this->origp(origp);
this->changep(changep);
}
ASTGEN_MEMBERS_AstCoverToggle;
int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return true; }
bool isOutputter() override {
return false; // Though the AstCoverInc under this is an outputter
}
// but isPure() true
};
class AstDelay final : public AstNodeStmt {
// Delay statement
// @astgen op1 := lhsp : AstNodeExpr // Delay value
// @astgen op2 := stmtsp : List[AstNode] // Statements under delay
VTimescale m_timeunit; // Delay's time unit
2022-12-23 13:34:49 +01:00
const bool m_isCycle; // True if it is a cycle delay
public:
2022-12-23 13:34:49 +01:00
AstDelay(FileLine* fl, AstNodeExpr* lhsp, bool isCycle)
: ASTGEN_SUPER_Delay(fl)
, m_isCycle{isCycle} {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstDelay;
2022-12-23 13:34:49 +01:00
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
2022-09-16 17:15:10 +02:00
bool isTimingControl() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
bool isCycleDelay() const { return m_isCycle; }
};
class AstDisable final : public AstNodeStmt {
// @astgen op1 := targetRefp : Optional[AstNodeExpr] // Reference to link in V3LinkDot
// @astgen ptr := m_targetp : Optional[AstNode] // Task or block after V3LinkDot
public:
AstDisable(FileLine* fl, AstNodeExpr* targetRefp)
: ASTGEN_SUPER_Disable(fl) {
this->targetRefp(targetRefp);
}
ASTGEN_MEMBERS_AstDisable;
const char* broken() const override;
void dump(std::ostream& str) const override;
void targetp(AstNode* nodep) { m_targetp = nodep; }
AstNode* targetp() const { return m_targetp; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
};
class AstDisableFork final : public AstNodeStmt {
// A "disable fork" statement
public:
explicit AstDisableFork(FileLine* fl)
: ASTGEN_SUPER_DisableFork(fl) {}
ASTGEN_MEMBERS_AstDisableFork;
};
class AstDisplay final : public AstNodeStmt {
// Parents: stmtlist
// @astgen op1 := fmtp : AstSFormatF
// @astgen op2 := filep : Optional[AstNodeExpr] // file (must resolve to a VarRef)
VDisplayType m_displayType;
public:
AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNodeExpr* filep,
AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} {
fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->filep(filep);
}
AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_Display(fl)
, m_displayType{dispType} {
fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->filep(filep);
}
ASTGEN_MEMBERS_AstDisplay;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override {
BROKEN_RTN(!fmtp());
return nullptr;
}
string verilogKwd() const override {
return (filep() ? "$f"s + string{displayType().ascii()}
: "$"s + string{displayType().ascii()});
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* samep) const override {
return displayType() == VN_DBG_AS(samep, Display)->displayType();
}
int instrCount() const override { return INSTR_COUNT_PLI; }
VDisplayType displayType() const { return m_displayType; }
void displayType(VDisplayType type) { m_displayType = type; }
// * = Add a newline for $display
bool addNewline() const { return displayType().addNewline(); }
};
class AstDoWhile final : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := stmtsp : List[AstNode]
public:
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr)
: ASTGEN_SUPER_DoWhile(fl) {
condp(conditionp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstDoWhile;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Stop statement searchback here
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstDumpCtl final : public AstNodeStmt {
// $dumpon etc
// Parents: expr
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression based on type of statement
const VDumpCtlType m_ctlType; // Type of operation
public:
AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNodeExpr* exprp = nullptr)
: ASTGEN_SUPER_DumpCtl(fl)
, m_ctlType{ctlType} {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstDumpCtl;
string verilogKwd() const override { return ctlType().ascii(); }
bool isGateOptimizable() const override { return false; }
bool isOutputter() override { return true; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
virtual bool cleanOut() const { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
VDumpCtlType ctlType() const { return m_ctlType; }
};
class AstEventControl final : public AstNodeStmt {
// Parents: stmtlist
// @astgen op1 := sensesp : Optional[AstSenTree]
// @astgen op2 := stmtsp : List[AstNode]
public:
AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER_EventControl(fl) {
this->sensesp(sensesp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstEventControl;
string verilogKwd() const override { return "@(%l) %r"; }
2022-09-16 17:15:10 +02:00
bool isTimingControl() const override { return true; }
int instrCount() const override { return 0; }
};
class AstFClose final : public AstNodeStmt {
// Parents: stmtlist
// @astgen op1 := filep : AstNodeExpr // file (must be a VarRef)
public:
AstFClose(FileLine* fl, AstNodeExpr* filep)
: ASTGEN_SUPER_FClose(fl) {
this->filep(filep);
}
ASTGEN_MEMBERS_AstFClose;
string verilogKwd() const override { return "$fclose"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstFFlush final : public AstNodeStmt {
// Parents: stmtlist
// @astgen op1 := filep : Optional[AstNodeExpr] // file (must be a VarRef)
public:
AstFFlush(FileLine* fl, AstNodeExpr* filep)
: ASTGEN_SUPER_FFlush(fl) {
this->filep(filep);
}
ASTGEN_MEMBERS_AstFFlush;
string verilogKwd() const override { return "$fflush"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstFinish final : public AstNodeStmt {
public:
explicit AstFinish(FileLine* fl)
: ASTGEN_SUPER_Finish(fl) {}
ASTGEN_MEMBERS_AstFinish;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
int instrCount() const override { return 0; } // Rarely executes
bool sameNode(const AstNode* samep) const override { return fileline() == samep->fileline(); }
};
2022-09-15 14:17:00 +02:00
class AstFireEvent final : public AstNodeStmt {
// '-> _' and '->> _' event trigger statements
// @astgen op1 := operandp : AstNodeExpr
const bool m_delayed; // Delayed (->>) vs non-delayed (->)
2022-09-15 14:17:00 +02:00
public:
AstFireEvent(FileLine* fl, AstNodeExpr* operandp, bool delayed)
2022-09-15 14:17:00 +02:00
: ASTGEN_SUPER_FireEvent(fl)
, m_delayed{delayed} {
this->operandp(operandp);
2022-09-15 14:17:00 +02:00
}
ASTGEN_MEMBERS_AstFireEvent;
2022-09-15 14:17:00 +02:00
bool isDelayed() const { return m_delayed; }
};
class AstJumpBlock final : public AstNodeStmt {
// Block of code that might contain AstJumpGo statements as children,
// which when exectued branch to right after the referenced AstJumpBlock.
// AstJumpBlocks can nest, and an AstJumpGo can reference any of the
// enclosing AstJumpBlocks (can break out of mulitple levels).
// Parents: {statement list}
// Children: {statement list, with JumpGo below}
// @astgen op1 := stmtsp : List[AstNode]
VIsCached m_purity; // Pure state
public:
// After construction must call ->labelp to associate with appropriate label
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER_JumpBlock(fl) {
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstJumpBlock;
int instrCount() const override { return 0; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool isPure() override;
private:
bool getPurityRecurse() const;
};
class AstJumpGo final : public AstNodeStmt {
// Branch to right after the referenced encloding AstJumpBlock
// Parents: statement, including the referenced AstJumpBlock
// Children: none
//
// @astgen ptr := m_blockp : AstJumpBlock // The AstJumpBlock we are branching after
public:
AstJumpGo(FileLine* fl, AstJumpBlock* blockp)
: ASTGEN_SUPER_JumpGo(fl)
, m_blockp{blockp} {}
ASTGEN_MEMBERS_AstJumpGo;
const char* broken() const override;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* samep) const override {
return blockp() == VN_DBG_AS(samep, JumpGo)->blockp();
}
bool isGateOptimizable() const override { return false; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
AstJumpBlock* blockp() const { return m_blockp; }
};
class AstMonitorOff final : public AstNodeStmt {
const bool m_off; // Monitor off. Using 0=on allows faster init and comparison
public:
AstMonitorOff(FileLine* fl, bool off)
: ASTGEN_SUPER_MonitorOff(fl)
, m_off{off} {}
ASTGEN_MEMBERS_AstMonitorOff;
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
bool isGateOptimizable() const override { return false; } // Though deleted before opt
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
bool isPure() override { return false; } // Though deleted before opt
bool isOutputter() override { return true; } // Though deleted before opt
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* samep) const override {
return m_off == VN_DBG_AS(samep, MonitorOff)->m_off;
}
bool off() const { return m_off; }
};
class AstPrintTimeScale final : public AstNodeStmt {
// Parents: stmtlist
string m_name; // Parent module name
VTimescale m_timeunit; // Parent module time unit
public:
explicit AstPrintTimeScale(FileLine* fl)
: ASTGEN_SUPER_PrintTimeScale(fl) {}
ASTGEN_MEMBERS_AstPrintTimeScale;
void name(const string& name) override { m_name = name; }
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string verilogKwd() const override { return "$printtimescale"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
VTimescale timeunit() const { return m_timeunit; }
};
2022-11-12 03:53:05 +01:00
class AstRandCase final : public AstNodeStmt {
// @astgen op2 := itemsp : List[AstCaseItem]
public:
AstRandCase(FileLine* fl, AstCaseItem* itemsp)
: ASTGEN_SUPER_RandCase(fl) {
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstRandCase;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
};
class AstRelease final : public AstNodeStmt {
// Procedural 'release' statement
// @astgen op1 := lhsp : AstNodeExpr
public:
AstRelease(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Release(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstRelease;
};
class AstRepeat final : public AstNodeStmt {
// @astgen op1 := countp : AstNodeExpr
// @astgen op2 := stmtsp : List[AstNode]
public:
AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp)
: ASTGEN_SUPER_Repeat(fl) {
this->countp(countp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstRepeat;
bool isGateOptimizable() const override { return false; } // Not relevant - converted to FOR
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstReturn final : public AstNodeStmt {
// @astgen op1 := lhsp : Optional[AstNodeExpr]
public:
explicit AstReturn(FileLine* fl, AstNodeExpr* lhsp = nullptr)
: ASTGEN_SUPER_Return(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstReturn;
string verilogKwd() const override { return "return"; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
};
class AstSFormat final : public AstNodeStmt {
// Parents: statement container
// @astgen op1 := fmtp : AstSFormatF
// @astgen op2 := lhsp : AstNodeExpr
public:
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, const string& text, AstNodeExpr* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) {
fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
this->lhsp(lhsp);
}
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER_SFormat(fl) {
fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp, missingArgChar});
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstSFormat;
const char* broken() const override {
BROKEN_RTN(!fmtp());
return nullptr;
}
string verilogKwd() const override { return "$sformat"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return true; }
bool isPure() override { return true; }
bool isOutputter() override { return false; }
virtual bool cleanOut() const { return false; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
2025-04-02 12:08:51 +02:00
class AstSetuphold final : public AstNodeStmt {
// Verilog $setuphold
// @astgen op1 := refevp : AstNodeExpr
// @astgen op2 := dataevp : AstNodeExpr
// @astgen op3 := delrefp : Optional[AstNodeExpr]
// @astgen op4 := deldatap : Optional[AstNodeExpr]
public:
AstSetuphold(FileLine* fl, AstNodeExpr* refevp, AstNodeExpr* dataevp,
AstNodeExpr* delrefp = nullptr, AstNodeExpr* deldatap = nullptr)
: ASTGEN_SUPER_Setuphold(fl) {
this->refevp(refevp);
this->dataevp(dataevp);
this->delrefp(delrefp);
this->deldatap(deldatap);
}
ASTGEN_MEMBERS_AstSetuphold;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
2022-11-18 01:12:54 +01:00
class AstStackTraceT final : public AstNodeStmt {
// $stacktrace used as task
public:
explicit AstStackTraceT(FileLine* fl)
2022-11-18 01:14:05 +01:00
: ASTGEN_SUPER_StackTraceT(fl) {}
2022-11-18 01:12:54 +01:00
ASTGEN_MEMBERS_AstStackTraceT;
string verilogKwd() const override { return "$stacktrace"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
2022-11-18 01:12:54 +01:00
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2022-11-18 01:12:54 +01:00
};
class AstStmtExpr final : public AstNodeStmt {
// Expression in statement position
// @astgen op1 := exprp : AstNodeExpr
public:
AstStmtExpr(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_StmtExpr(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstStmtExpr;
bool isPure() override { return exprp()->isPure(); }
};
class AstStop final : public AstNodeStmt {
const bool m_isFatal; // $fatal not $stop
public:
AstStop(FileLine* fl, bool isFatal)
2024-09-14 02:46:48 +02:00
: ASTGEN_SUPER_Stop(fl)
, m_isFatal{isFatal} {}
ASTGEN_MEMBERS_AstStop;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
int instrCount() const override { return 0; } // Rarely executes
bool sameNode(const AstNode* samep) const override { return fileline() == samep->fileline(); }
string emitVerilog() const { return m_isFatal ? "$fatal" : "$stop"; }
bool isFatal() const { return m_isFatal; }
};
class AstSysFuncAsTask final : public AstNodeStmt {
// TODO: This is superseded by AstStmtExpr, remove
// Call what is normally a system function (with a return) in a non-return context
// @astgen op1 := lhsp : AstNodeExpr
public:
AstSysFuncAsTask(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_SysFuncAsTask(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstSysFuncAsTask;
string verilogKwd() const override { return ""; }
bool isGateOptimizable() const override { return true; }
bool isPredictOptimizable() const override { return true; }
bool isPure() override { return true; }
bool isOutputter() override { return false; }
int instrCount() const override { return 0; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstSystemT final : public AstNodeStmt {
// $system used as task
// @astgen op1 := lhsp : AstNodeExpr
public:
AstSystemT(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_SystemT(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstSystemT;
string verilogKwd() const override { return "$system"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstTimeFormat final : public AstNodeStmt {
// Parents: stmtlist
// @astgen op1 := unitsp : Optional[AstNodeExpr]
// @astgen op2 := precisionp : Optional[AstNodeExpr]
// @astgen op3 := suffixp : Optional[AstNodeExpr]
// @astgen op4 := widthp : Optional[AstNodeExpr]
public:
AstTimeFormat(FileLine* fl, AstNodeExpr* unitsp, AstNodeExpr* precisionp, AstNodeExpr* suffixp,
AstNodeExpr* widthp)
: ASTGEN_SUPER_TimeFormat(fl) {
this->unitsp(unitsp);
this->precisionp(precisionp);
this->suffixp(suffixp);
this->widthp(widthp);
}
ASTGEN_MEMBERS_AstTimeFormat;
string verilogKwd() const override { return "$timeformat"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
};
class AstTraceDecl final : public AstNodeStmt {
// Trace point declaration
// Separate from AstTraceInc; as a declaration can't be deleted
// Parents: {statement list}
// Expression being traced - Moved to AstTraceInc by V3Trace
// @astgen op1 := valuep : Optional[AstNodeExpr]
uint32_t m_code{0}; // Trace identifier code
uint32_t m_fidx{0}; // Trace function index
const string m_showname; // Name of variable
const VNumRange m_bitRange; // Property of var the trace details
const VNumRange m_arrayRange; // Property of var the trace details
const VVarType m_varType; // Type of variable (for localparam vs. param)
const VDirection m_declDirection; // Declared direction input/output etc
public:
AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc
AstNodeExpr* valuep, const VNumRange& bitRange, const VNumRange& arrayRange)
: ASTGEN_SUPER_TraceDecl(fl)
, m_showname{showname}
, m_bitRange{bitRange}
, m_arrayRange{arrayRange}
, m_varType{varp->varType()}
, m_declDirection{varp->declDirection()} {
dtypeFrom(valuep);
this->valuep(valuep);
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 100; } // Large...
ASTGEN_MEMBERS_AstTraceDecl;
string name() const override VL_MT_STABLE { return m_showname; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool hasDType() const override VL_MT_SAFE { return true; }
bool sameNode(const AstNode* samep) const override { return false; }
string showname() const { return m_showname; } // * = Var name
// Details on what we're tracing
uint32_t code() const { return m_code; }
void code(uint32_t code) { m_code = code; }
uint32_t fidx() const { return m_fidx; }
void fidx(uint32_t fidx) { m_fidx = fidx; }
2023-12-12 20:30:18 +01:00
uint32_t codeInc() const {
return (m_arrayRange.ranged() ? m_arrayRange.elements() : 1)
* valuep()->dtypep()->widthWords()
* (VL_EDATASIZE / 32); // A code is always 32-bits
}
const VNumRange& bitRange() const { return m_bitRange; }
const VNumRange& arrayRange() const { return m_arrayRange; }
VVarType varType() const { return m_varType; }
VDirection declDirection() const { return m_declDirection; }
};
class AstTraceInc final : public AstNodeStmt {
// Trace point dump
// @astgen op1 := valuep : AstNodeExpr // Expression being traced (from decl)
//
// @astgen ptr := m_declp : AstTraceDecl // Pointer to declaration
const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc
const VTraceType m_traceType; // Is this a const/full/incremental dump
public:
AstTraceInc(FileLine* fl, AstTraceDecl* declp, VTraceType traceType, uint32_t baseCode = 0)
: ASTGEN_SUPER_TraceInc(fl)
, m_baseCode{baseCode}
, m_traceType{traceType}
, m_declp{declp} {
dtypeFrom(declp);
2023-12-12 20:30:18 +01:00
// Note: A clone is necessary (instead of using declp()->valuep()),
// for insertion of local temporaries in V3Premit
valuep(declp->valuep()->cloneTree(true));
}
ASTGEN_MEMBERS_AstTraceInc;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
bool hasDType() const override VL_MT_SAFE { return true; }
bool sameNode(const AstNode* samep) const override {
return declp() == VN_DBG_AS(samep, TraceInc)->declp();
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isOutputter() override { return true; }
bool isPure() override { return false; }
AstTraceDecl* declp() const { return m_declp; }
VTraceType traceType() const { return m_traceType; }
uint32_t baseCode() const { return m_baseCode; }
};
class AstTracePopPrefix final : public AstNodeStmt {
public:
explicit AstTracePopPrefix(FileLine* fl)
: ASTGEN_SUPER_TracePopPrefix(fl) {}
ASTGEN_MEMBERS_AstTracePopPrefix;
bool sameNode(const AstNode* samep) const override { return false; }
};
class AstTracePushPrefix final : public AstNodeStmt {
const string m_prefix; // Prefix to add to signal names
const VTracePrefixType m_prefixType; // Type of prefix being pushed
public:
AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType)
: ASTGEN_SUPER_TracePushPrefix(fl)
, m_prefix{prefix}
, m_prefixType{prefixType} {}
ASTGEN_MEMBERS_AstTracePushPrefix;
bool sameNode(const AstNode* samep) const override { return false; }
string prefix() const { return m_prefix; }
VTracePrefixType prefixType() const { return m_prefixType; }
};
class AstUCStmt final : public AstNodeStmt {
// User $c statement
// @astgen op1 := exprsp : List[AstNode] // (some are AstText)
public:
AstUCStmt(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_UCStmt(fl) {
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstUCStmt;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstWait final : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := stmtsp : List[AstNode]
public:
AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp)
: ASTGEN_SUPER_Wait(fl) {
this->condp(condp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstWait;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
2022-09-16 17:15:10 +02:00
bool isTimingControl() const override { return true; }
};
class AstWaitFork final : public AstNodeStmt {
// A "wait fork" statement
public:
explicit AstWaitFork(FileLine* fl)
: ASTGEN_SUPER_WaitFork(fl) {}
ASTGEN_MEMBERS_AstWaitFork;
2023-10-20 13:13:57 +02:00
bool isTimingControl() const override { return true; }
};
class AstWhile final : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := stmtsp : List[AstNode]
// @astgen op3 := incsp : List[AstNode]
VOptionBool m_unrollFull; // Full, disable, or default unrolling
public:
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
: ASTGEN_SUPER_While(fl) {
this->condp(condp);
addStmtsp(stmtsp);
addIncsp(incsp);
}
ASTGEN_MEMBERS_AstWhile;
void dump(std::ostream& str) const override;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Stop statement searchback here
void addNextStmt(AstNode* newp, AstNode* belowp) override;
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
VOptionBool unrollFull() const { return m_unrollFull; }
void unrollFull(const VOptionBool flag) { m_unrollFull = flag; }
};
// === AstNodeAssign ===
class AstAssign final : public AstNodeAssign {
public:
AstAssign(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNode* timingControlp = nullptr)
: ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstAssign;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-09-15 14:17:00 +02:00
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
return new AstAssign{fileline(), lhsp, rhsp, controlp};
}
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignAlias final : public AstNodeAssign {
// Like AstAssignW, but a true bidirect interconnection alias
// If both sides are wires, there's no LHS vs RHS,
public:
AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp)
: ASTGEN_SUPER_AssignAlias(fl, (AstNodeExpr*)lhsp, (AstNodeExpr*)rhsp) {}
ASTGEN_MEMBERS_AstAssignAlias;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
V3ERROR_NA_RETURN(nullptr);
}
bool brokeLhsMustBeLvalue() const override { return false; }
};
class AstAssignDly final : public AstNodeAssign {
public:
AstAssignDly(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNode* timingControlp = nullptr)
: ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {}
ASTGEN_MEMBERS_AstAssignDly;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-09-15 14:17:00 +02:00
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
return new AstAssignDly{fileline(), lhsp, rhsp, controlp};
}
bool isGateOptimizable() const override { return false; }
string verilogKwd() const override { return "<="; }
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignForce final : public AstNodeAssign {
// Procedural 'force' statement
public:
AstAssignForce(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstAssignForce;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-11-13 01:51:03 +01:00
return new AstAssignForce{fileline(), lhsp, rhsp};
}
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignPost final : public AstNodeAssign {
// Like Assign, but predelayed assignment requiring special order handling
public:
AstAssignPost(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstAssignPost;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-11-13 01:51:03 +01:00
return new AstAssignPost{fileline(), lhsp, rhsp};
}
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignPre final : public AstNodeAssign {
// Like Assign, but predelayed assignment requiring special order handling
public:
AstAssignPre(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstAssignPre;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-11-13 01:51:03 +01:00
return new AstAssignPre{fileline(), lhsp, rhsp};
}
bool brokeLhsMustBeLvalue() const override { return true; }
};
class AstAssignVarScope final : public AstNodeAssign {
// Assign two VarScopes to each other
public:
AstAssignVarScope(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) {
dtypeFrom(rhsp);
}
ASTGEN_MEMBERS_AstAssignVarScope;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-11-13 01:51:03 +01:00
return new AstAssignVarScope{fileline(), lhsp, rhsp};
}
bool brokeLhsMustBeLvalue() const override { return false; }
};
class AstAssignW final : public AstNodeAssign {
// Like assign, but wire/assign's in verilog, the only setting of the specified variable
// @astgen op4 := strengthSpecp : Optional[AstStrengthSpec]
public:
AstAssignW(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNode* timingControlp = nullptr)
2022-09-15 14:17:00 +02:00
: ASTGEN_SUPER_AssignW(fl, lhsp, rhsp, timingControlp) {}
ASTGEN_MEMBERS_AstAssignW;
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
2022-09-15 14:17:00 +02:00
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
return new AstAssignW{fileline(), lhsp, rhsp, controlp};
}
bool isTimingControl() const override {
return timingControlp() || lhsp()->exists([](const AstNodeVarRef* refp) {
return refp->access().isWriteOrRW() && refp->varp()->delayp();
});
}
bool brokeLhsMustBeLvalue() const override { return true; }
AstDelay* getLhsNetDelay() const;
2022-09-15 14:17:00 +02:00
AstAlways* convertToAlways();
};
// === AstNodeCase ===
class AstCase final : public AstNodeCase {
// Case statement
VCaseType m_casex; // 0=case, 1=casex, 2=casez
bool m_fullPragma = false; // Synthesis full_case
bool m_parallelPragma = false; // Synthesis parallel_case
bool m_uniquePragma = false; // unique case
bool m_unique0Pragma = false; // unique0 case
bool m_priorityPragma = false; // priority case
public:
AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp)
: ASTGEN_SUPER_Case(fl, exprp, itemsp)
, m_casex{casex} {}
ASTGEN_MEMBERS_AstCase;
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
bool sameNode(const AstNode* samep) const override {
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
}
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; }
bool caseSimple() const { return m_casex == VCaseType::CT_CASE; }
void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; }
bool fullPragma() const { return m_fullPragma; }
void fullPragma(bool flag) { m_fullPragma = flag; }
bool parallelPragma() const { return m_parallelPragma; }
void parallelPragma(bool flag) { m_parallelPragma = flag; }
bool uniquePragma() const { return m_uniquePragma; }
void uniquePragma(bool flag) { m_uniquePragma = flag; }
bool unique0Pragma() const { return m_unique0Pragma; }
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
bool priorityPragma() const { return m_priorityPragma; }
void priorityPragma(bool flag) { m_priorityPragma = flag; }
string pragmaString() const;
};
class AstGenCase final : public AstNodeCase {
// Generate Case statement
public:
AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {}
ASTGEN_MEMBERS_AstGenCase;
};
// === AstNodeCoverOrAssert ===
class AstAssert final : public AstNodeCoverOrAssert {
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
public:
ASTGEN_MEMBERS_AstAssert;
AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, VAssertType type,
VAssertDirectiveType directive, const string& name = "")
: ASTGEN_SUPER_Assert(fl, propp, passsp, type, directive, name) {
addFailsp(failsp);
}
};
class AstAssertIntrinsic final : public AstNodeCoverOrAssert {
// A $cast or other compiler inserted assert, that must run even without --assert option
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
public:
ASTGEN_MEMBERS_AstAssertIntrinsic;
AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp,
const string& name = "")
// Intrinsic asserts are always enabled thus 'type' field is set to INTERNAL.
: ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, VAssertType::INTERNAL,
VAssertDirectiveType::INTRINSIC, name) {
addFailsp(failsp);
}
};
class AstCover final : public AstNodeCoverOrAssert {
// @astgen op3 := coverincsp: List[AstNode] // Coverage node
public:
ASTGEN_MEMBERS_AstCover;
AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, VAssertType type,
const string& name = "")
: ASTGEN_SUPER_Cover(fl, propp, stmtsp, type, VAssertDirectiveType::COVER, name) {}
};
class AstRestrict final : public AstNodeCoverOrAssert {
public:
ASTGEN_MEMBERS_AstRestrict;
AstRestrict(FileLine* fl, AstNode* propp)
// Intrinsic asserts are always ignored thus 'type' field is set to INTERNAL.
: ASTGEN_SUPER_Restrict(fl, propp, nullptr, VAssertType::INTERNAL,
VAssertDirectiveType::RESTRICT) {}
};
// === AstNodeFor ===
class AstGenFor final : public AstNodeFor {
public:
AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* stmtsp)
: ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {}
ASTGEN_MEMBERS_AstGenFor;
};
// === AstNodeForeach ===
class AstConstraintForeach final : public AstNodeForeach {
// Constraint foreach statement
public:
AstConstraintForeach(FileLine* fl, AstNodeExpr* exprp, AstNode* bodysp)
: ASTGEN_SUPER_ConstraintForeach(fl, exprp, bodysp) {}
ASTGEN_MEMBERS_AstConstraintForeach;
};
class AstForeach final : public AstNodeForeach {
public:
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: ASTGEN_SUPER_Foreach(fl, arrayp, stmtsp) {}
ASTGEN_MEMBERS_AstForeach;
};
// === AstNodeIf ===
class AstConstraintIf final : public AstNodeIf {
public:
AstConstraintIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstConstraintIf;
};
class AstGenIf final : public AstNodeIf {
public:
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstGenIf;
};
class AstIf final : public AstNodeIf {
bool m_uniquePragma = false; // unique case
bool m_unique0Pragma = false; // unique0 case
bool m_priorityPragma = false; // priority case
public:
AstIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp = nullptr, AstNode* elsesp = nullptr)
: ASTGEN_SUPER_If(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstIf;
bool uniquePragma() const { return m_uniquePragma; }
void uniquePragma(bool flag) { m_uniquePragma = flag; }
bool unique0Pragma() const { return m_unique0Pragma; }
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
bool priorityPragma() const { return m_priorityPragma; }
void priorityPragma(bool flag) { m_priorityPragma = flag; }
};
// === AstNodeReadWriteMem ===
class AstReadMem final : public AstNodeReadWriteMem {
public:
AstReadMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
AstNodeExpr* lsbp, AstNodeExpr* msbp)
: ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {}
ASTGEN_MEMBERS_AstReadMem;
string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); }
const char* cFuncPrefixp() const override { return "VL_READMEM_"; }
};
class AstWriteMem final : public AstNodeReadWriteMem {
public:
AstWriteMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
AstNodeExpr* lsbp, AstNodeExpr* msbp)
: ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {}
ASTGEN_MEMBERS_AstWriteMem;
string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); }
const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; }
};
// === AstNodeText ===
class AstScCtor final : public AstNodeText {
public:
AstScCtor(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScCtor(fl, textp) {}
ASTGEN_MEMBERS_AstScCtor;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScDtor final : public AstNodeText {
public:
AstScDtor(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScDtor(fl, textp) {}
ASTGEN_MEMBERS_AstScDtor;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScHdr final : public AstNodeText {
public:
AstScHdr(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScHdr(fl, textp) {}
ASTGEN_MEMBERS_AstScHdr;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
2025-03-29 03:24:39 +01:00
class AstScHdrPost final : public AstNodeText {
public:
AstScHdrPost(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScHdrPost(fl, textp) {}
ASTGEN_MEMBERS_AstScHdrPost;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScImp final : public AstNodeText {
public:
AstScImp(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScImp(fl, textp) {}
ASTGEN_MEMBERS_AstScImp;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScImpHdr final : public AstNodeText {
public:
AstScImpHdr(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScImpHdr(fl, textp) {}
ASTGEN_MEMBERS_AstScImpHdr;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
class AstScInt final : public AstNodeText {
public:
AstScInt(FileLine* fl, const string& textp)
: ASTGEN_SUPER_ScInt(fl, textp) {}
ASTGEN_MEMBERS_AstScInt;
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
bool isOutputter() override { return true; }
};
// === AstNodeSimpleText ===
class AstText final : public AstNodeSimpleText {
public:
AstText(FileLine* fl, const string& textp, bool tracking = false)
: ASTGEN_SUPER_Text(fl, textp, tracking) {}
ASTGEN_MEMBERS_AstText;
};
class AstTextBlock final : public AstNodeSimpleText {
// @astgen op1 := nodesp : List[AstNode]
bool m_commas; // Comma separate emitted children
public:
explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false,
bool commas = false)
: ASTGEN_SUPER_TextBlock(fl, textp, tracking)
, m_commas{commas} {}
ASTGEN_MEMBERS_AstTextBlock;
bool commas() const { return m_commas; }
void commas(bool flag) { m_commas = flag; }
void addText(FileLine* fl, const string& textp, bool tracking = false) {
2022-11-20 21:06:49 +01:00
addNodesp(new AstText{fl, textp, tracking});
}
};
#endif // Guard