verilator/src/V3AstNodeOther.h

2743 lines
121 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_didProto : 1; // Did prototype processing
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_didProto{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; }
bool didProto() const { return m_didProto; }
void didProto(bool flag) { m_didProto = 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 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 := senTreeStorep : Optional[AstSenTree] // Moved into m_sensesp in V3Active
// @astgen op2 := stmtsp : List[AstNode] // Logic
//
// @astgen ptr := m_sentreep : Optional[AstSenTree] // Sensitivity list for this process
string m_name;
public:
AstActive(FileLine* fl, const string& name, AstSenTree* sentreep)
: ASTGEN_SUPER_Active(fl)
, m_name{name}
, m_sentreep{sentreep} {
UASSERT(sentreep, "Sentreep 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 sentreep(AstSenTree* nodep) { m_sentreep = nodep; }
AstSenTree* sentreep() const { return m_sentreep; }
// 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 isComboOrStar() const {
return edgeType() == VEdgeType::ET_COMBO || edgeType() == VEdgeType::ET_COMBO_STAR;
}
bool isComboStar() const { return edgeType() == VEdgeType::ET_COMBO_STAR; }
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;
bool sameNode(const AstNode* samep) const override {
const AstSenTree* const asamep = VN_DBG_AS(samep, SenTree);
return m_multi == asamep->m_multi;
}
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.
uint32_t m_declTokenNum; // Declaration token number
bool m_attrPublic = false;
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
bool m_isUnderClass : 1; // Underneath class
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_declTokenNum{fl->tokenNum()}
, m_isHideLocal{false}
, m_isHideProtected{false}
, m_isUnderClass{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
uint32_t declTokenNum() const override { return m_declTokenNum; }
void declTokenNumSetMin(uint32_t tokenNum) override {
m_declTokenNum = std::min(m_declTokenNum, tokenNum);
}
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; }
bool isUnderClass() const { return m_isUnderClass; }
void isUnderClass(bool flag) { m_isUnderClass = 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;
const VFwdType m_fwdType; // Forward type for lint check
public:
AstTypedefFwd(FileLine* fl, const string& name, const VFwdType& fwdType)
: ASTGEN_SUPER_TypedefFwd(fl)
, m_name{name}
, m_fwdType{fwdType} {}
ASTGEN_MEMBERS_AstTypedefFwd;
// METHODS
string name() const override VL_MT_STABLE { return m_name; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
VFwdType fwdType() const { return m_fwdType; }
};
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_gotNansiType : 1; // Linker saw Non-ANSI type declaration
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_gotNansiType = 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 gotNansiType(bool flag) { m_gotNansiType = flag; }
bool gotNansiType() { return m_gotNansiType; }
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* otherp);
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};
}
2025-08-05 23:12:00 +02:00
string verilogKwd() const override { return "function"; }
};
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}; }
2025-08-05 23:12:00 +02:00
string verilogKwd() const override { return "let"; }
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};
}
2025-08-05 23:12:00 +02:00
string verilogKwd() const override { return "property"; }
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};
}
2025-08-05 23:12:00 +02:00
string verilogKwd() const override { return "task"; }
};
// === 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
uint32_t m_declTokenNum; // Declaration token number
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)
, m_declTokenNum{fl->tokenNum()} {}
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);
uint32_t declTokenNum() const override { return m_declTokenNum; }
void declTokenNumSetMin(uint32_t tokenNum) override {
m_declTokenNum = std::min(m_declTokenNum, tokenNum);
}
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 := sentreep : Optional[AstSenTree] // Sensitivity list iff clocked
const VAlwaysKwd m_keyword;
public:
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sentreep, AstNode* stmtsp)
: ASTGEN_SUPER_Always(fl, stmtsp)
, m_keyword{keyword} {
this->sentreep(sentreep);
}
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 := sentreep : Optional[AstSenTree] // Sensitivity list, removed in V3Active
2022-12-23 13:34:49 +01:00
public:
AstAlwaysObserved(FileLine* fl, AstSenTree* sentreep, AstNode* bodysp)
2022-12-23 13:34:49 +01:00
: ASTGEN_SUPER_AlwaysObserved(fl, bodysp) {
this->sentreep(sentreep);
2022-12-23 13:34:49 +01:00
}
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 := sentreep : Optional[AstSenTree] // Sensitivity list, removed in V3Active
2022-12-23 13:34:49 +01:00
public:
AstAlwaysReactive(FileLine* fl, AstSenTree* sentreep, AstNode* bodysp)
2022-12-23 13:34:49 +01:00
: ASTGEN_SUPER_AlwaysReactive(fl, bodysp) {
this->sentreep(sentreep);
2022-12-23 13:34:49 +01:00
}
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; }
};
// === 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