From 22b9dfb9c9c3a44fdb97b8b17f40f8a19abf7680 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 15 Sep 2022 13:10:39 +0100 Subject: [PATCH] Split and re-order AstNode definitions (#3622) - Move DType representations into V3AstNodeDType.h - Move AstNodeMath and subclasses into V3AstNodeMath.h - Move any other AstNode subtypes into V3AstNodeOther.h - Fix up out-of-order definitions via inline methods and implementations in V3Inlines.h and V3AstNodes.cpp - Enforce declaration order of AstNode subtypes via astgen, which will now fail when definitions are mis-ordered. --- docs/internals.rst | 5 +- src/Makefile_obj.in | 17 +- src/V3Ast.h | 1119 +---- src/V3AstInlines.h | 124 +- src/V3AstNodeDType.h | 1341 ++++++ src/V3AstNodeMath.h | 4426 +++++++++++++++++++ src/V3AstNodeOther.h | 4363 +++++++++++++++++++ src/V3AstNodes.cpp | 270 ++ src/V3AstNodes.h | 9592 ----------------------------------------- src/astgen | 92 +- src/cppcheck_filtered | 2 +- 11 files changed, 10651 insertions(+), 10700 deletions(-) create mode 100644 src/V3AstNodeDType.h create mode 100644 src/V3AstNodeMath.h create mode 100644 src/V3AstNodeOther.h delete mode 100644 src/V3AstNodes.h diff --git a/docs/internals.rst b/docs/internals.rst index 499e0fa12..c9e00d7dd 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1153,8 +1153,9 @@ Generally what would you do to add a new feature? language and has a lot of back-and-forth with Verilator's grammar. Copy the appropriate rules to src/verilog.y and modify the productions. -4. If a new Ast type is needed, add it to V3AstNodes.h. Follow the - convention described above about the AstNode type hierarchy. +4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h. + Follow the convention described above about the AstNode type hierarchy. + Ordering of definitions is enforced by ``astgen``. 5. Now you can run "test_regress/t/t_.pl --debug" and it'll probably fail but you'll see a diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 1496cc411..346521767 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -276,9 +276,16 @@ VLCOV_OBJS = \ NON_STANDALONE_HEADERS = \ V3AstInlines.h \ - V3AstNodes.h \ + V3AstNodeDType.h \ + V3AstNodeMath.h \ + V3AstNodeOther.h \ V3WidthCommit.h \ +AST_DEFS := \ + V3AstNodeDType.h \ + V3AstNodeMath.h \ + V3AstNodeOther.h \ + #### Linking ifeq ($(VL_VLCOV),) @@ -301,8 +308,8 @@ V3Number_test: V3Number_test.o #### Modules -%__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp +%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) + $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) $*.cpp %.o: %.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ @@ -332,8 +339,8 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h $(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir) touch $@ -V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I $(srcdir) --classes +V3Ast__gen_classes.h : $(ASTGEN) $(AST_DEFS) + $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) --classes V3ParseBison.h: V3ParseBison.c diff --git a/src/V3Ast.h b/src/V3Ast.h index bb945564c..3df21ffb4 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -36,8 +36,6 @@ #include #include #include -// Things like: -// class V3AstNode; // Forward declarations class V3Graph; @@ -2367,1084 +2365,6 @@ struct std::equal_to> final { } }; -//###################################################################### -//=== AstNode* : Derived generic node types - -#define ASTNODE_BASE_FUNCS(name) \ - virtual ~Ast##name() override = default; \ - static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ - } \ - Ast##name* cloneTree(bool cloneNext) { \ - return static_cast(AstNode::cloneTree(cloneNext)); \ - } \ - Ast##name* clonep() const { return static_cast(AstNode::clonep()); } - -class AstNodeMath VL_NOT_FINAL : public AstNode { - // Math -- anything that's part of an expression tree -protected: - AstNodeMath(VNType t, FileLine* fl) - : AstNode{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeMath) - // METHODS - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV - // For documentation on emitC format see EmitCFunc::emitOpName - virtual string emitC() = 0; - virtual string emitSimpleOperator() { return ""; } // "" means not ok to use - virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS - virtual bool cleanOut() const = 0; // True if output has extra upper bits zero - // Someday we will generically support data types on every math node - // Until then isOpaque indicates we shouldn't constant optimize this node type - bool isOpaque() const { return VN_IS(this, CvtPackString); } -}; - -class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { - // Terminal operator -- a operator with no "inputs" -protected: - AstNodeTermop(VNType t, FileLine* fl) - : AstNodeMath{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeTermop) - // Know no children, and hot function, so skip iterator for speed - // See checkTreeIter also that asserts no children - // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} - virtual void dump(std::ostream& str) const override; -}; - -class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { - // Unary math -protected: - AstNodeUniop(VNType t, FileLine* fl, AstNode* lhsp) - : AstNodeMath{t, fl} { - dtypeFrom(lhsp); - setOp1p(lhsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeUniop) - AstNode* lhsp() const { return op1p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - // METHODS - virtual void dump(std::ostream& str) const override; - // Set out to evaluation of a AstConst'ed lhs - virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; - virtual bool cleanLhs() const = 0; - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - // Signed flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } - virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { - // Binary math -protected: - AstNodeBiop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - } - -public: - ASTNODE_BASE_FUNCS(NodeBiop) - // Clone single node, just get same type back. - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; - // ACCESSORS - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - // METHODS - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - // Signed flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } - virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { - // Trinary math -protected: - AstNodeTriop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - setOp3p(ths); - } - -public: - ASTNODE_BASE_FUNCS(NodeTriop) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - // METHODS - virtual void dump(std::ostream& str) const override; - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) - = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { - // Quaternary math -protected: - AstNodeQuadop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - setOp3p(ths); - setOp4p(fhs); - } - -public: - ASTNODE_BASE_FUNCS(NodeQuadop) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - AstNode* fhsp() const { return op4p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - void fhsp(AstNode* nodep) { return setOp4p(nodep); } - // METHODS - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths, const V3Number& fhs) - = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero - virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size - virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { - // Binary math with commutative properties -protected: - AstNodeBiCom(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeBiop{t, fl, lhs, rhs} {} - -public: - ASTNODE_BASE_FUNCS(NodeBiCom) -}; - -class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { - // Binary math with commutative & associative properties -protected: - AstNodeBiComAsv(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeBiCom{t, fl, lhs, rhs} {} - -public: - ASTNODE_BASE_FUNCS(NodeBiComAsv) -}; - -class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { -protected: - AstNodeCond(VNType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : AstNodeTriop{t, fl, condp, expr1p, expr2p} { - if (expr1p) { - dtypeFrom(expr1p); - } else if (expr2p) { - dtypeFrom(expr2p); - } - } - -public: - ASTNODE_BASE_FUNCS(NodeCond) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override; - AstNode* condp() const { return op1p(); } // op1 = Condition - AstNode* expr1p() const { return op2p(); } // op2 = If true... - AstNode* expr2p() const { return op3p(); } // op3 = If false... - virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; } - virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; } - virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } // Propagates up - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; -}; - -class AstNodeBlock VL_NOT_FINAL : public AstNode { - // A Begin/fork block - // Parents: statement - // Children: statements -private: - 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} { - addNOp1p(stmtsp); - m_unnamed = (name == ""); - } - -public: - ASTNODE_BASE_FUNCS(NodeBlock) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Block name - virtual void name(const string& name) override { m_name = name; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } - bool unnamed() const { return m_unnamed; } - bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); } -}; - -class AstNodePreSel VL_NOT_FINAL : public AstNode { - // Something that becomes an AstSel -protected: - AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths) - : AstNode{t, fl} { - setOp1p(fromp); - setOp2p(rhs); - setNOp3p(ths); - } - -public: - ASTNODE_BASE_FUNCS(NodePreSel) - AstNode* fromp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); } - void fromp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - void attrp(AstAttrOf* nodep) { return setOp4p(reinterpret_cast(nodep)); } - // METHODS - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeProcedure VL_NOT_FINAL : public AstNode { - // IEEE procedure: initial, final, always -protected: - AstNodeProcedure(VNType t, FileLine* fl, AstNode* bodysp) - : AstNode{t, fl} { - addNOp2p(bodysp); - } - -public: - ASTNODE_BASE_FUNCS(NodeProcedure) - // METHODS - virtual void dump(std::ostream& str) const override; - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addStmtp(AstNode* nodep) { addOp2p(nodep); } - bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } -}; - -class AstNodeStmt VL_NOT_FINAL : public AstNode { - // Statement -- anything that's directly under a function - bool m_statement; // Really a statement (e.g. not a function with return) -protected: - AstNodeStmt(VNType t, FileLine* fl, bool statement = true) - : AstNode{t, fl} - , m_statement{statement} {} - -public: - ASTNODE_BASE_FUNCS(NodeStmt) - // METHODS - bool isStatement() const { return m_statement; } // Really a statement - void statement(bool flag) { m_statement = flag; } - virtual void addNextStmt(AstNode* newp, - AstNode* belowp) override; // Stop statement searchback here - virtual void addBeforeStmt(AstNode* newp, - AstNode* belowp) override; // Stop statement searchback here - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, - AstNode* timingControlp = nullptr) - : AstNodeStmt{t, fl} { - setOp1p(rhsp); - setOp2p(lhsp); - addNOp3p(timingControlp); - dtypeFrom(lhsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeAssign) - // Clone single node, just get same type back. - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; - // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 - AstNode* rhsp() const { return op1p(); } // op1 = Assign from - AstNode* lhsp() const { return op2p(); } // op2 = Assign to - // op3 = Timing controls (delays, event controls) - AstNode* timingControlp() const { return op3p(); } - void addTimingControlp(AstNode* const np) { addNOp3p(np); } - void rhsp(AstNode* np) { setOp1p(np); } - void lhsp(AstNode* np) { setOp2p(np); } - virtual bool hasDType() const override { return true; } - virtual bool cleanRhs() const { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } - virtual string verilogKwd() const override { return "="; } - virtual bool brokeLhsMustBeLvalue() const = 0; -}; - -class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, - AstNode* bodysp) - : AstNodeStmt{t, fl} { - addNOp1p(initsp); - setOp2p(condp); - addNOp3p(incsp); - addNOp4p(bodysp); - } - -public: - ASTNODE_BASE_FUNCS(NodeFor) - AstNode* initsp() const { return op1p(); } // op1 = initial statements - AstNode* condp() const { return op2p(); } // op2 = condition to continue - AstNode* incsp() const { return op3p(); } // op3 = increment statements - AstNode* bodysp() const { return op4p(); } // op4 = body of loop - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { -private: - VBranchPred m_branchPred; // Branch prediction as taken/untaken? - bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking -protected: - AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : AstNodeStmt{t, fl} { - setOp1p(condp); - addNOp2p(ifsp); - addNOp3p(elsesp); - isBoundsCheck(false); - } - -public: - ASTNODE_BASE_FUNCS(NodeIf) - AstNode* condp() const { return op1p(); } // op1 = condition - AstNode* ifsp() const { return op2p(); } // op2 = list of true statements - AstNode* elsesp() const { return op3p(); } // op3 = list of false statements - void condp(AstNode* newp) { setOp1p(newp); } - void addIfsp(AstNode* newp) { addOp2p(newp); } - void addElsesp(AstNode* newp) { addOp3p(newp); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isGateDedupable() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void branchPred(VBranchPred flag) { m_branchPred = flag; } - VBranchPred branchPred() const { return m_branchPred; } - void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } - bool isBoundsCheck() const { return m_isBoundsCheck; } - bool isFirstInMyListOfStatements(AstNode* n) const override { - return n == ifsp() || n == elsesp(); - } -}; - -class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeCase(VNType t, FileLine* fl, AstNode* exprp, AstNode* casesp) - : AstNodeStmt{t, fl} { - setOp1p(exprp); - addNOp2p(casesp); - } - -public: - ASTNODE_BASE_FUNCS(NodeCase) - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - AstNode* exprp() const { return op1p(); } // op1 = case condition - AstCaseItem* itemsp() const { - return VN_AS(op2p(), CaseItem); - } // op2 = list of case expressions - AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's - void addItemsp(AstNode* nodep) { addOp2p(nodep); } - void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } -}; - -class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { - // An AstVarRef or AstVarXRef -private: - VAccess m_access; // Left hand side assignment - AstVar* m_varp; // [AfterLink] Pointer to variable itself - AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable - string m_selfPointer; // Output code object pointer (e.g.: 'this') - -protected: - AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) - : AstNodeMath{t, fl} - , m_access{access} - , m_name{name} { - varp(nullptr); - } - AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) - : AstNodeMath{t, fl} - , m_access{access} - , m_name{name} { - // May have varp==nullptr - this->varp(varp); - } - -public: - ASTNODE_BASE_FUNCS(NodeVarRef) - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual const char* broken() const override; - virtual int instrCount() const override { return widthInstrs(); } - virtual void cloneRelink() override; - virtual string name() const override { return m_name; } // * = Var name - virtual void name(const string& name) override { m_name = name; } - VAccess access() const { return m_access; } - void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - void varp(AstVar* varp); - AstVarScope* varScopep() const { return m_varScopep; } - void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - // Know no children, and hot function, so skip iterator for speed - // See checkTreeIter also that asserts no children - // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} -}; - -class AstNodeText VL_NOT_FINAL : public AstNode { -private: - string m_text; - -protected: - // Node that puts text into the output stream - AstNodeText(VNType t, FileLine* fl, const string& textp) - : AstNode{t, fl} { - m_text = textp; // Copy it - } - -public: - ASTNODE_BASE_FUNCS(NodeText) - virtual void dump(std::ostream& str = std::cout) const override; - virtual bool same(const AstNode* samep) const override { - const AstNodeText* asamep = static_cast(samep); - return text() == asamep->text(); - } - const string& text() const { return m_text; } -}; - -class AstNodeDType VL_NOT_FINAL : public AstNode { - // Ideally width() would migrate to BasicDType as that's where it makes sense, - // but it's currently so prevalent in the code we leave it here. - // Note the below members are included in AstTypeTable::Key lookups -private: - int m_width; // (also in AstTypeTable::Key) Bit width of operation - int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation - VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed - // Other members - bool m_generic; // Simple globally referenced type, don't garbage collect - // Unique number assigned to each dtype during creation for IEEE matching - static int s_uniqueNum; - -protected: - // CONSTRUCTORS - AstNodeDType(VNType t, FileLine* fl) - : AstNode{t, fl} { - m_width = 0; - m_widthMin = 0; - m_generic = false; - } - -public: - ASTNODE_BASE_FUNCS(NodeDType) - // ACCESSORS - virtual void dump(std::ostream& str) const override; - virtual void dumpSmall(std::ostream& str) const; - virtual bool hasDType() const override { return true; } - /// Require VlUnpacked, instead of [] for POD elements. - /// A non-POD object is always compound, but some POD elements - /// are compound when methods calls operate on object, or when - /// under another compound-requiring object e.g. class - virtual bool isCompound() const = 0; - // (Slow) recurse down to find basic data type - virtual AstBasicDType* basicp() const = 0; - // recurses over typedefs/const/enum to next non-typeref type - virtual AstNodeDType* skipRefp() const = 0; - // recurses over typedefs to next non-typeref-or-const type - virtual AstNodeDType* skipRefToConstp() const = 0; - // recurses over typedefs/const to next non-typeref-or-enum/struct type - virtual AstNodeDType* skipRefToEnump() const = 0; - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const = 0; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const = 0; - virtual bool maybePointedTo() const override { return true; } - // Iff has a non-null refDTypep(), as generic node function - virtual AstNodeDType* virtRefDTypep() const { return nullptr; } - // Iff has refDTypep(), set as generic node function - virtual void virtRefDTypep(AstNodeDType* nodep) {} - // Iff has a non-null second dtypep, as generic node function - virtual AstNodeDType* virtRefDType2p() const { return nullptr; } - // Iff has second dtype, set as generic node function - virtual void virtRefDType2p(AstNodeDType* nodep) {} - // Assignable equivalence. Call skipRefp() on this and samep before calling - virtual bool similarDType(AstNodeDType* samep) const = 0; - // Iff has a non-null subDTypep(), as generic node function - virtual AstNodeDType* subDTypep() const { return nullptr; } - virtual bool isFourstate() const; - // Ideally an IEEE $typename - virtual string prettyDTypeName() const { return prettyTypeName(); } - string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } - // - // Changing the width may confuse the data type resolution, so must clear - // TypeTable cache after use. - void widthForce(int width, int widthMin) { - m_width = width; - m_widthMin = widthMin; - } - // For backward compatibility inherit width and signing from the subDType/base type - void widthFromSub(AstNodeDType* nodep) { - m_width = nodep->m_width; - m_widthMin = nodep->m_widthMin; - m_numeric = nodep->m_numeric; - } - // - int width() const { return m_width; } - void numeric(VSigning flag) { m_numeric = flag; } - bool isSigned() const { return m_numeric.isSigned(); } - bool isNosign() const { return m_numeric.isNosign(); } - VSigning numeric() const { return m_numeric; } - int widthWords() const { return VL_WORDS_I(width()); } - int widthMin() const { // If sized, the size, if unsized the min digits to represent it - return m_widthMin ? m_widthMin : m_width; - } - int widthPow2() const; - void widthMinFromWidth() { m_widthMin = m_width; } - bool widthSized() const { return !m_widthMin || m_widthMin == m_width; } - bool generic() const { return m_generic; } - void generic(bool flag) { m_generic = flag; } - std::pair dimensions(bool includeBasic); - uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions - static int uniqueNumInc() { return ++s_uniqueNum; } - const char* charIQWN() const { - return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); - } - string cType(const string& name, bool forFunc, bool isRef) const; - bool isLiteralType() const; // Does this represent a C++ LiteralType? (can be constexpr) - -private: - class CTypeRecursed; - CTypeRecursed cTypeRecurse(bool compound) const; -}; - -class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { - // A struct or union; common handling -private: - // TYPES - using MemberNameMap = std::map; - // MEMBERS - string m_name; // Name from upper typedef, if any - bool m_packed; - bool m_isFourstate; - MemberNameMap m_members; - const int m_uniqueNum; - -protected: - AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack) - : AstNodeDType{t, fl} - , m_uniqueNum{uniqueNumInc()} { - // VSigning::NOSIGN overloaded to indicate not packed - m_packed = (numericUnpack != VSigning::NOSIGN); - m_isFourstate = false; // V3Width computes - numeric(VSigning::fromBool(numericUnpack.isSigned())); - } - -public: - ASTNODE_BASE_FUNCS(NodeUOrStructDType) - int uniqueNum() const { return m_uniqueNum; } - virtual const char* broken() const override; - virtual void dump(std::ostream& str) const override; - virtual bool isCompound() const override { return false; } // Because don't support unpacked - // For basicp() we reuse the size to indicate a "fake" basic type of same size - virtual AstBasicDType* basicp() const override { - return (isFourstate() - ? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), - BasicDType) - : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), - BasicDType)); - } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override; - // op1 = members - virtual bool similarDType(AstNodeDType* samep) const override { - return this == samep; // We don't compare members, require exact equivalence - } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - AstMemberDType* membersp() const { - return VN_AS(op1p(), MemberDType); - } // op1 = AstMember list - void addMembersp(AstNode* nodep) { addNOp1p(nodep); } - bool packed() const { return m_packed; } - // packed() but as don't support unpacked, presently all structs - static bool packedUnsup() { return true; } - void isFourstate(bool flag) { m_isFourstate = flag; } - virtual bool isFourstate() const override { return m_isFourstate; } - void clearCache() { m_members.clear(); } - void repairMemberCache(); - AstMemberDType* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } - static int lo() { return 0; } - int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays - VNumRange declRange() const { return VNumRange{hi(), lo()}; } -}; - -class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { - // Array data type, ie "some_dtype var_name [2:0]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) - AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable -protected: - AstNodeArrayDType(VNType t, FileLine* fl) - : AstNodeDType{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeArrayDType) - virtual void dump(std::ostream& str) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep() - && rangenp()->sameTree(asamep->rangenp())); - } // HashedDT doesn't recurse, so need to check children - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return (asamep && type() == samep->type() && hi() == asamep->hi() - && rangenp()->sameTree(asamep->rangenp()) - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable - void rangep(AstRange* nodep); - // METHODS - virtual AstBasicDType* basicp() const override { - return subDTypep()->basicp(); - } // (Slow) recurse down to find basic data type - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { - return elementsConst() * subDTypep()->widthTotalBytes(); - } - int left() const; - int right() const; - int hi() const; - int lo() const; - int elementsConst() const; - VNumRange declRange() const; -}; - -class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { - // Single bit range extraction, perhaps with non-constant selection or array selection -protected: - AstNodeSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* bitp) - : AstNodeBiop{t, fl, fromp, bitp} {} - -public: - ASTNODE_BASE_FUNCS(NodeSel) - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* bitp() const { return op2p(); } // op2 = Msb selection expression - void bitp(AstNode* nodep) { setOp2p(nodep); } - int bitConst() const; - virtual bool hasDType() const override { return true; } -}; - -class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -protected: - AstNodeStream(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeBiop{t, fl, lhsp, rhsp} { - if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); - } - -public: - ASTNODE_BASE_FUNCS(NodeStream) -}; - -//###################################################################### -// Tasks/functions common handling - -class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { - // A call of a C++ function, perhaps a AstCFunc or perhaps globally named - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. - AstCFunc* m_funcp; - string m_argTypes; - -protected: - AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : AstNodeStmt{t, fl, true} - , m_funcp{funcp} { - addNOp2p(argsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeCCall) - virtual void dump(std::ostream& str = std::cout) const override; - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual int instrCount() const override { return INSTR_COUNT_CALL; } - virtual bool same(const AstNode* samep) const override { - const AstNodeCCall* const asamep = static_cast(samep); - return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); - } - AstNode* exprsp() const { return op2p(); } // op2 = expressions to print - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override; - virtual bool isOutputter() const override { return !isPure(); } - AstCFunc* funcp() const { return m_funcp; } - void funcp(AstCFunc* funcp) { m_funcp = funcp; } - void argTypes(const string& str) { m_argTypes = str; } - string argTypes() const { return m_argTypes; } - // op1p reserved for AstCMethodCall - AstNode* argsp() const { return op2p(); } - void addArgsp(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstNodeFTask VL_NOT_FINAL : public AstNode { -private: - 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_externProto : 1; // Extern prototype - bool m_externDef : 1; // Extern definition - 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_dpiTraceInit : 1; // DPI trace_init - bool m_isConstructor : 1; // Class constructor - bool m_isHideLocal : 1; // Verilog local - bool m_isHideProtected : 1; // Verilog protected - bool m_pure : 1; // DPI import pure (vs. virtual pure) - bool m_pureVirtual : 1; // Pure virtual - bool m_recursive : 1; // Recusive or part of recursion - bool m_underGenerate : 1; // Under generate (for warning) - bool m_virtual : 1; // Virtual method in class - VLifetime m_lifetime; // Lifetime -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_externProto{false} - , m_externDef{false} - , m_prototype{false} - , m_dpiExport{false} - , m_dpiImport{false} - , m_dpiContext{false} - , m_dpiOpenChild{false} - , m_dpiTask{false} - , m_dpiTraceInit{false} - , m_isConstructor{false} - , m_isHideLocal{false} - , m_isHideProtected{false} - , m_pure{false} - , m_pureVirtual{false} - , m_recursive{false} - , m_underGenerate{false} - , m_virtual{false} { - addNOp3p(stmtsp); - cname(name); // Might be overridden by dpi import/export - } - -public: - ASTNODE_BASE_FUNCS(NodeFTask) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool maybePointedTo() const override { return true; } - virtual bool isGateOptimizable() const override { - return !((m_dpiExport || m_dpiImport) && !m_pure); - } - // {AstFunc only} op1 = Range output variable - virtual void name(const string& name) override { m_name = name; } - string cname() const { return m_cname; } - void cname(const string& cname) { m_cname = cname; } - // op1 = Output variable (functions only, nullptr for tasks) - AstNode* fvarp() const { return op1p(); } - void addFvarp(AstNode* nodep) { addNOp1p(nodep); } - bool isFunction() const { return fvarp() != nullptr; } - // op2 = Class/package scope - AstNode* classOrPackagep() const { return op2p(); } - void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); } - // op3 = Statements/Ports/Vars - AstNode* stmtsp() const { return op3p(); } // op3 = List of statements - void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } - // op4 = scope name - AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } - // MORE ACCESSORS - void dpiOpenParentInc() { ++m_dpiOpenParent; } - void dpiOpenParentClear() { m_dpiOpenParent = 0; } - uint64_t dpiOpenParent() const { return m_dpiOpenParent; } - void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } - void taskPublic(bool flag) { m_taskPublic = flag; } - bool taskPublic() const { return m_taskPublic; } - void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } - bool attrIsolateAssign() const { return m_attrIsolateAssign; } - void classMethod(bool flag) { m_classMethod = flag; } - bool classMethod() const { return m_classMethod; } - void isExternProto(bool flag) { m_externProto = flag; } - bool isExternProto() const { return m_externProto; } - void isExternDef(bool flag) { m_externDef = flag; } - bool isExternDef() const { return m_externDef; } - void prototype(bool flag) { m_prototype = flag; } - bool prototype() const { return m_prototype; } - void dpiExport(bool flag) { m_dpiExport = flag; } - bool dpiExport() const { return m_dpiExport; } - void dpiImport(bool flag) { m_dpiImport = flag; } - bool dpiImport() const { return m_dpiImport; } - void dpiContext(bool flag) { m_dpiContext = flag; } - bool dpiContext() const { return m_dpiContext; } - void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; } - bool dpiOpenChild() const { return m_dpiOpenChild; } - void dpiTask(bool flag) { m_dpiTask = flag; } - bool dpiTask() const { return m_dpiTask; } - void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } - bool dpiTraceInit() const { return m_dpiTraceInit; } - void isConstructor(bool flag) { m_isConstructor = flag; } - bool isConstructor() const { return m_isConstructor; } - 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 pure(bool flag) { m_pure = flag; } - bool pure() const { return m_pure; } - void pureVirtual(bool flag) { m_pureVirtual = flag; } - bool pureVirtual() const { return m_pureVirtual; } - void recursive(bool flag) { m_recursive = flag; } - bool recursive() const { return m_recursive; } - void underGenerate(bool flag) { m_underGenerate = flag; } - bool underGenerate() const { return m_underGenerate; } - void isVirtual(bool flag) { m_virtual = flag; } - bool isVirtual() const { return m_virtual; } - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } -}; - -class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { - // A reference to a task (or function) - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. -private: - AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable - string m_dotted; // Dotted part of scope the name()ed task/func is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out - bool m_pli = false; // Pli system call ($name) -protected: - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} { - setOp1p(namep); - addNOp3p(pinsp); - } - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} - , m_name{name} { - addNOp3p(pinsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeFTaskRef) - virtual const char* broken() const override; - virtual void cloneRelink() override; - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool isGateOptimizable() const override { - return m_taskp && m_taskp->isGateOptimizable(); - } - string dotted() const { return m_dotted; } // * = Scope name or "" - string inlinedDots() const { return m_inlinedDots; } - void inlinedDots(const string& flag) { m_inlinedDots = flag; } - AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable - void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } - virtual void name(const string& name) override { m_name = name; } - void dotted(const string& name) { m_dotted = name; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - bool pli() const { return m_pli; } - void pli(bool flag) { m_pli = flag; } - // op1 = namep - AstNode* namep() const { return op1p(); } - // op2 = reserved for AstMethodCall - // op3 = Pin interconnection list - AstNode* pinsp() const { return op3p(); } - void addPinsp(AstNode* nodep) { addOp3p(nodep); } - // op4 = scope tracking - AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } - void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } -}; - -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 -private: - 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. - 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_hierBlock : 1; // Hiearchical Block marked by HIER_BLOCK pragma - bool m_internal : 1; // Internally created - bool m_recursive : 1; // Recursive module - bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr - 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 -protected: - AstNodeModule(VNType t, FileLine* fl, const string& name) - : AstNode{t, fl} - , m_name{name} - , m_origName{name} - , m_modPublic{false} - , m_modTrace{false} - , m_inLibrary{false} - , m_dead{false} - , m_hierBlock{false} - , m_internal{false} - , m_recursive{false} - , m_recursiveClone{false} {} - -public: - ASTNODE_BASE_FUNCS(NodeModule) - virtual void dump(std::ostream& str) const override; - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return m_name; } - virtual bool timescaleMatters() const = 0; - AstNode* stmtsp() const { return op2p(); } // op2 = List of statements - AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks - // METHODS - void addInlinesp(AstNode* nodep) { addOp1p(nodep); } - void addStmtp(AstNode* nodep) { addNOp2p(nodep); } - void addActivep(AstNode* nodep) { addOp3p(nodep); } - // ACCESSORS - virtual void name(const string& name) override { m_name = name; } - virtual string origName() const override { return m_origName; } - string someInstanceName() const { 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 { return m_level; } - bool isTop() const { return level() == 1; } - void modPublic(bool flag) { m_modPublic = flag; } - bool modPublic() const { return m_modPublic; } - void modTrace(bool flag) { m_modTrace = flag; } - bool modTrace() const { return m_modTrace; } - void dead(bool flag) { m_dead = flag; } - bool dead() const { return m_dead; } - void hierBlock(bool flag) { m_hierBlock = flag; } - bool hierBlock() const { return m_hierBlock; } - void internal(bool flag) { m_internal = flag; } - bool internal() const { return m_internal; } - void recursive(bool flag) { m_recursive = flag; } - bool recursive() const { return m_recursive; } - void recursiveClone(bool flag) { m_recursiveClone = flag; } - bool recursiveClone() const { return m_recursiveClone; } - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } - void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } - VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } -}; - -class AstNodeRange VL_NOT_FINAL : public AstNode { - // A range, sized or unsized -protected: - AstNodeRange(VNType t, FileLine* fl) - : AstNode{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeRange) - virtual void dump(std::ostream& str) const override; -}; - //###################################################################### // Inline VNVisitor METHODS @@ -3470,8 +2390,43 @@ inline AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { return nodep->iterateSubtreeReturnEdits(*this); } -//###################################################################### +// ###################################################################### +// Standard defines for all AstNode subclasses -#include "V3AstNodes.h" +#define ASTNODE_BASE_FUNCS(name) \ + virtual ~Ast##name() override = default; \ + static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ + return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ + } \ + Ast##name* cloneTree(bool cloneNext) { \ + return static_cast(AstNode::cloneTree(cloneNext)); \ + } \ + Ast##name* clonep() const { return static_cast(AstNode::clonep()); } + +#define ASTNODE_NODE_FUNCS_NO_DTOR(name) \ + virtual void accept(VNVisitor& v) override { v.visit(this); } \ + virtual AstNode* clone() override { return new Ast##name(*this); } \ + static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ + return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ + } \ + Ast##name* cloneTree(bool cloneNext) { \ + return static_cast(AstNode::cloneTree(cloneNext)); \ + } \ + Ast##name* clonep() const { return static_cast(AstNode::clonep()); } + +#define ASTNODE_NODE_FUNCS(name) \ + virtual ~Ast##name() override = default; \ + ASTNODE_NODE_FUNCS_NO_DTOR(name) + +// Macros generated by 'astgen' +#include "V3AstNodes__gen_macros.h" + +// AstNode subclasses +#include "V3AstNodeDType.h" +#include "V3AstNodeMath.h" +#include "V3AstNodeOther.h" + +// Inline function definitions need to go last +#include "V3AstInlines.h" #endif // Guard diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 9ad974a69..d532feb01 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -17,9 +17,9 @@ #ifndef VERILATOR_V3ASTINLINES_H_ #define VERILATOR_V3ASTINLINES_H_ -#ifndef VERILATOR_V3ASTNODES_H_ +#ifndef VERILATOR_V3AST_H_ #error "Use V3Ast.h as the include" -#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h and relaed #endif //###################################################################### @@ -91,4 +91,124 @@ inline void AstIfaceRefDType::cloneRelink() { if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); } +AstRange::AstRange(FileLine* fl, int left, int right) + : ASTGEN_SUPER_Range(fl) { + setOp2p(new AstConst{fl, static_cast(left)}); + setOp3p(new AstConst{fl, static_cast(right)}); +} +AstRange::AstRange(FileLine* fl, const VNumRange& range) + : ASTGEN_SUPER_Range(fl) { + setOp2p(new AstConst{fl, static_cast(range.left())}); + setOp3p(new AstConst{fl, static_cast(range.right())}); +} +int AstRange::leftConst() const { + AstConst* const constp = VN_CAST(leftp(), Const); + return (constp ? constp->toSInt() : 0); +} +int AstRange::rightConst() const { + AstConst* const constp = VN_CAST(rightp(), Const); + return (constp ? constp->toSInt() : 0); +} + +int AstQueueDType::boundConst() const { + AstConst* const constp = VN_CAST(boundp(), Const); + return (constp ? constp->toSInt() : 0); +} + +AstPin::AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) + : ASTGEN_SUPER_Pin(fl) + , m_pinNum{pinNum} + , m_name{varname->name()} { + setNOp1p(exprp); +} + +AstDpiExportUpdated::AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep) + : ASTGEN_SUPER_DpiExportUpdated(fl) { + addOp1p(new AstVarRef{fl, varScopep, VAccess::WRITE}); +} + +AstVarScope* AstDpiExportUpdated::varScopep() const { return VN_AS(op1p(), VarRef)->varScopep(); } + +AstPackArrayDType::AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, + AstRange* rangep) + : ASTGEN_SUPER_PackArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + setOp2p(rangep); + dtypep(nullptr); // V3Width will resolve + const int width = subDTypep()->width() * rangep->elementsConst(); + widthForce(width, width); +} +AstPackArrayDType::AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_PackArrayDType(fl) { + refDTypep(dtp); + setOp2p(rangep); + dtypep(this); + const int width = subDTypep()->width() * rangep->elementsConst(); + widthForce(width, width); +} + +int AstBasicDType::hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } +int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } +int AstBasicDType::elements() const { + return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); +} +bool AstBasicDType::littleEndian() const { + return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); +} + +bool AstActive::hasInitial() const { return m_sensesp->hasInitial(); } +bool AstActive::hasSettle() const { return m_sensesp->hasSettle(); } +bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); } + +AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp) + : ASTGEN_SUPER_ElabDisplay(fl) { + setOp1p(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp}); + m_displayType = dispType; +} + +AstCStmt::AstCStmt(FileLine* fl, const string& textStmt) + : ASTGEN_SUPER_CStmt(fl) { + addNOp1p(new AstText{fl, textStmt, true}); +} + +AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut) + : ASTGEN_SUPER_CMath(fl) + , m_cleanOut{cleanOut} + , m_pure{true} { + addNOp1p(new AstText{fl, textStmt, true}); + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); +} + +AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} +// This form only allowed post-link (see above) +AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { + varScopep(varscp); +} +bool AstVarRef::same(const AstVarRef* samep) const { + if (varScopep()) { + return (varScopep() == samep->varScopep() && access() == samep->access()); + } else { + return (selfPointer() == samep->selfPointer() && varp()->name() == samep->varp()->name() + && access() == samep->access()); + } +} +bool AstVarRef::sameNoLvalue(AstVarRef* samep) const { + if (varScopep()) { + return (varScopep() == samep->varScopep()); + } else { + return (selfPointer() == samep->selfPointer() + && (!selfPointer().empty() || !samep->selfPointer().empty()) + && varp()->name() == samep->varp()->name()); + } +} + +AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) + : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) + , m_dotted{dotted} { + dtypeFrom(varp); +} + #endif // Guard diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h new file mode 100644 index 000000000..4740ec685 --- /dev/null +++ b/src/V3AstNodeDType.h @@ -0,0 +1,1341 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing data types +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 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 the +// representation of data types. +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTNODEDTYPE_H_ +#define VERILATOR_V3ASTNODEDTYPE_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 AstNodeDType VL_NOT_FINAL : public AstNode { + // Ideally width() would migrate to BasicDType as that's where it makes sense, + // but it's currently so prevalent in the code we leave it here. + // Note the below members are included in AstTypeTable::Key lookups +private: + int m_width; // (also in AstTypeTable::Key) Bit width of operation + int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation + VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed + // Other members + bool m_generic; // Simple globally referenced type, don't garbage collect + // Unique number assigned to each dtype during creation for IEEE matching + static int s_uniqueNum; + +protected: + // CONSTRUCTORS + AstNodeDType(VNType t, FileLine* fl) + : AstNode{t, fl} { + m_width = 0; + m_widthMin = 0; + m_generic = false; + } + +public: + ASTNODE_BASE_FUNCS(NodeDType) + // ACCESSORS + virtual void dump(std::ostream& str) const override; + virtual void dumpSmall(std::ostream& str) const; + virtual bool hasDType() const override { return true; } + /// Require VlUnpacked, instead of [] for POD elements. + /// A non-POD object is always compound, but some POD elements + /// are compound when methods calls operate on object, or when + /// under another compound-requiring object e.g. class + virtual bool isCompound() const = 0; + // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const = 0; + // recurses over typedefs/const/enum to next non-typeref type + virtual AstNodeDType* skipRefp() const = 0; + // recurses over typedefs to next non-typeref-or-const type + virtual AstNodeDType* skipRefToConstp() const = 0; + // recurses over typedefs/const to next non-typeref-or-enum/struct type + virtual AstNodeDType* skipRefToEnump() const = 0; + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const = 0; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthTotalBytes() const = 0; + virtual bool maybePointedTo() const override { return true; } + // Iff has a non-null refDTypep(), as generic node function + virtual AstNodeDType* virtRefDTypep() const { return nullptr; } + // Iff has refDTypep(), set as generic node function + virtual void virtRefDTypep(AstNodeDType* nodep) {} + // Iff has a non-null second dtypep, as generic node function + virtual AstNodeDType* virtRefDType2p() const { return nullptr; } + // Iff has second dtype, set as generic node function + virtual void virtRefDType2p(AstNodeDType* nodep) {} + // Assignable equivalence. Call skipRefp() on this and samep before calling + virtual bool similarDType(AstNodeDType* samep) const = 0; + // Iff has a non-null subDTypep(), as generic node function + virtual AstNodeDType* subDTypep() const { return nullptr; } + virtual bool isFourstate() const; + // Ideally an IEEE $typename + virtual string prettyDTypeName() const { return prettyTypeName(); } + string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } + // + // Changing the width may confuse the data type resolution, so must clear + // TypeTable cache after use. + void widthForce(int width, int widthMin) { + m_width = width; + m_widthMin = widthMin; + } + // For backward compatibility inherit width and signing from the subDType/base type + void widthFromSub(AstNodeDType* nodep) { + m_width = nodep->m_width; + m_widthMin = nodep->m_widthMin; + m_numeric = nodep->m_numeric; + } + // + int width() const { return m_width; } + void numeric(VSigning flag) { m_numeric = flag; } + bool isSigned() const { return m_numeric.isSigned(); } + bool isNosign() const { return m_numeric.isNosign(); } + VSigning numeric() const { return m_numeric; } + int widthWords() const { return VL_WORDS_I(width()); } + int widthMin() const { // If sized, the size, if unsized the min digits to represent it + return m_widthMin ? m_widthMin : m_width; + } + int widthPow2() const; + void widthMinFromWidth() { m_widthMin = m_width; } + bool widthSized() const { return !m_widthMin || m_widthMin == m_width; } + bool generic() const { return m_generic; } + void generic(bool flag) { m_generic = flag; } + std::pair dimensions(bool includeBasic); + uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions + static int uniqueNumInc() { return ++s_uniqueNum; } + const char* charIQWN() const { + return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); + } + string cType(const string& name, bool forFunc, bool isRef) const; + bool isLiteralType() const; // Does this represent a C++ LiteralType? (can be constexpr) + +private: + class CTypeRecursed; + CTypeRecursed cTypeRecurse(bool compound) const; +}; +class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { + // Array data type, ie "some_dtype var_name [2:0]" + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: RANGE (array bounds) +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) + AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable +protected: + AstNodeArrayDType(VNType t, FileLine* fl) + : AstNodeDType{t, fl} {} + +public: + ASTNODE_BASE_FUNCS(NodeArrayDType) + virtual void dump(std::ostream& str) const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstNodeArrayDType* const asamep = static_cast(samep); + return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep() + && rangenp()->sameTree(asamep->rangenp())); + } // HashedDT doesn't recurse, so need to check children + virtual bool similarDType(AstNodeDType* samep) const override { + const AstNodeArrayDType* const asamep = static_cast(samep); + return (asamep && type() == samep->type() && hi() == asamep->hi() + && rangenp()->sameTree(asamep->rangenp()) + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable + void rangep(AstRange* nodep); + // METHODS + virtual AstBasicDType* basicp() const override { + return subDTypep()->basicp(); + } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { + return elementsConst() * subDTypep()->widthTotalBytes(); + } + int left() const; + int right() const; + int hi() const; + int lo() const; + int elementsConst() const; + VNumRange declRange() const; +}; +class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { + // A struct or union; common handling +private: + // TYPES + using MemberNameMap = std::map; + // MEMBERS + string m_name; // Name from upper typedef, if any + bool m_packed; + bool m_isFourstate; + MemberNameMap m_members; + const int m_uniqueNum; + +protected: + AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack) + : AstNodeDType{t, fl} + , m_uniqueNum{uniqueNumInc()} { + // VSigning::NOSIGN overloaded to indicate not packed + m_packed = (numericUnpack != VSigning::NOSIGN); + m_isFourstate = false; // V3Width computes + numeric(VSigning::fromBool(numericUnpack.isSigned())); + } + +public: + ASTNODE_BASE_FUNCS(NodeUOrStructDType) + int uniqueNum() const { return m_uniqueNum; } + virtual const char* broken() const override; + virtual void dump(std::ostream& str) const override; + virtual bool isCompound() const override { return false; } // Because don't support unpacked + // For basicp() we reuse the size to indicate a "fake" basic type of same size + virtual AstBasicDType* basicp() const override { + return (isFourstate() + ? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), + BasicDType) + : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), + BasicDType)); + } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const override; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthTotalBytes() const override; + // op1 = members + virtual bool similarDType(AstNodeDType* samep) const override { + return this == samep; // We don't compare members, require exact equivalence + } + virtual string name() const override { return m_name; } + virtual void name(const string& flag) override { m_name = flag; } + AstMemberDType* membersp() const { + return VN_AS(op1p(), MemberDType); + } // op1 = AstMember list + void addMembersp(AstNode* nodep) { addNOp1p(nodep); } + bool packed() const { return m_packed; } + // packed() but as don't support unpacked, presently all structs + static bool packedUnsup() { return true; } + void isFourstate(bool flag) { m_isFourstate = flag; } + virtual bool isFourstate() const override { return m_isFourstate; } + void clearCache() { m_members.clear(); } + void repairMemberCache(); + AstMemberDType* findMember(const string& name) const { + const auto it = m_members.find(name); + return (it == m_members.end()) ? nullptr : it->second; + } + static int lo() { return 0; } + int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays + VNumRange declRange() const { return VNumRange{hi(), lo()}; } +}; + +// === Concrete node types ===================================================== + +// === AstNode === +class AstEnumItem final : public AstNode { +private: + string m_name; + +public: + // Parents: ENUM + AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) + : ASTGEN_SUPER_EnumItem(fl) + , m_name{name} { + addNOp1p(rangep); + addNOp2p(initp); + } + ASTNODE_NODE_FUNCS(EnumItem) + virtual string name() const override { return m_name; } + virtual bool maybePointedTo() const override { return true; } + virtual bool hasDType() const override { return true; } + virtual void name(const string& flag) override { m_name = flag; } + AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range for name appending + void rangep(AstRange* nodep) { addOp1p((AstNode*)nodep); } + AstNode* valuep() const { return op2p(); } // op2 = Value + void valuep(AstNode* nodep) { addOp2p(nodep); } +}; + +// === AstNodeDType === +class AstAssocArrayDType final : public AstNodeDType { + // Associative array data type, ie "[some_dtype]" + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: DTYPE (the key, which remains here as a pointer) +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) + AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) +public: + AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) + : ASTGEN_SUPER_AssocArrayDType(fl) { + childDTypep(dtp); // Only for parser + keyChildDTypep(keyDtp); // Only for parser + refDTypep(nullptr); + keyDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstAssocArrayDType(FileLine* fl, AstNodeDType* dtp, AstNodeDType* keyDtp) + : ASTGEN_SUPER_AssocArrayDType(fl) { + refDTypep(dtp); + keyDTypep(keyDtp); + dtypep(dtp); + } + ASTNODE_NODE_FUNCS(AssocArrayDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + BROKEN_RTN(!((m_keyDTypep && !childDTypep() && m_keyDTypep->brokeExists()) + || (!m_keyDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + if (!asamep->keyDTypep()) return false; + return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); + } + virtual bool similarDType(AstNodeDType* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + virtual string prettyDTypeName() const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + virtual AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + virtual AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; } + virtual void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); } + // + AstNodeDType* keyDTypep() const { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } + void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } + // op1 = Range of variable + AstNodeDType* keyChildDTypep() const { return VN_AS(op2p(), NodeDType); } + void keyChildDTypep(AstNodeDType* nodep) { setOp2p(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + virtual bool isCompound() const override { return true; } +}; +class AstBasicDType final : public AstNodeDType { + // Builtin atomic/vectored data type + // Children: RANGE (converted to constant in V3Width) +private: + struct Members { + VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type + VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) + bool operator==(const Members& rhs) const { + return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; + } + } m; + // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) +public: + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, signst, 0, -1, nullptr); + } + AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) + : ASTGEN_SUPER_BasicDType(fl) { + init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); + } + AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) + : ASTGEN_SUPER_BasicDType(fl) { + init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); + } + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, numer, wantwidth, widthmin, nullptr); + } + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, numer, range.elements(), widthmin, nullptr); + m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be + } + // See also addRange in verilog.y +private: + void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, + AstRange* rangep); + +public: + ASTNODE_NODE_FUNCS(BasicDType) + virtual void dump(std::ostream& str) const override; + // width/widthMin/numeric compared elsewhere + virtual bool same(const AstNode* samep) const override { + const AstBasicDType* const sp = static_cast(samep); + return m == sp->m; + } + virtual bool similarDType(AstNodeDType* samep) const override { + return type() == samep->type() && same(samep); + } + virtual string name() const override { return m.m_keyword.ascii(); } + virtual string prettyDTypeName() const override; + virtual const char* broken() const override { + BROKEN_RTN(dtypep() != this); + return nullptr; + } + AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range of variable + void rangep(AstRange* nodep) { setNOp1p((AstNode*)nodep); } + void setSignedState(const VSigning& signst) { + // Note NOSIGN does NOT change the state; this is required by the parser + if (signst == VSigning::UNSIGNED) { + numeric(signst); + } else if (signst == VSigning::SIGNED) { + numeric(signst); + } + } + // METHODS + virtual AstBasicDType* basicp() const override { return (AstBasicDType*)this; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const override; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthTotalBytes() const override; + virtual bool isFourstate() const override { return keyword().isFourstate(); } + VBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead + return m.m_keyword; + } + bool isBitLogic() const { return keyword().isBitLogic(); } + bool isDouble() const { return keyword().isDouble(); } + bool isEventValue() const { return keyword().isEventValue(); } + bool isOpaque() const { return keyword().isOpaque(); } + bool isString() const { return keyword().isString(); } + bool isZeroInit() const { return keyword().isZeroInit(); } + bool isRanged() const { return rangep() || m.m_nrange.ranged(); } + bool isDpiBitVec() const { // DPI uses svBitVecVal + return keyword() == VBasicDTypeKwd::BIT && isRanged(); + } + bool isDpiLogicVec() const { // DPI uses svLogicVecVal + return keyword().isFourstate() && !(keyword() == VBasicDTypeKwd::LOGIC && !isRanged()); + } + bool isDpiPrimitive() const { // DPI uses a primitive type + return !isDpiBitVec() && !isDpiLogicVec(); + } + // Generally the lo/hi/left/right funcs should be used instead of nrange() + const VNumRange& nrange() const { return m.m_nrange; } + inline int hi() const; + inline int lo() const; + inline int elements() const; + int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration + int right() const { return littleEndian() ? hi() : lo(); } + inline bool littleEndian() const; + bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; } + VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } + void cvtRangeConst(); // Convert to smaller representation + virtual bool isCompound() const override { return isString(); } +}; +class AstBracketArrayDType final : public AstNodeDType { + // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" + // only for early parsing then becomes another data type + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: DTYPE (the key) +public: + AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) + : ASTGEN_SUPER_BracketArrayDType(fl) { + setOp1p(dtp); // Only for parser + setOp2p(elementsp); // Only for parser + } + ASTNODE_NODE_FUNCS(BracketArrayDType) + virtual bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + virtual AstNodeDType* subDTypep() const override { return childDTypep(); } + // op2 = Range of variable + AstNode* elementsp() const { return op2p(); } + // METHODS + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + virtual bool maybePointedTo() const override { return false; } + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); } + virtual int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } + virtual bool isCompound() const override { return true; } +}; +class AstClassRefDType final : public AstNodeDType { + // Reference to a class + // Children: PINs (for parameter settings) +private: + AstClass* m_classp; // data type pointed to, BELOW the AstTypedef + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy +public: + AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) + : ASTGEN_SUPER_ClassRefDType(fl) + , m_classp{classp} { + dtypep(this); + addNOp4p(paramsp); + } + ASTNODE_NODE_FUNCS(ClassRefDType) + // METHODS + const char* broken() const override; + void cloneRelink() override; + virtual bool same(const AstNode* samep) const override { + const AstClassRefDType* const asamep = static_cast(samep); + return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); + } + virtual bool similarDType(AstNodeDType* samep) const override { + return this == samep || (type() == samep->type() && same(samep)); + } + virtual void dump(std::ostream& str = std::cout) const override; + virtual void dumpSmall(std::ostream& str) const override; + string name() const override; + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return 0; } + virtual int widthTotalBytes() const override { return 0; } + virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } + virtual void virtRefDTypep(AstNodeDType* nodep) override {} + virtual AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + AstClass* classp() const { return m_classp; } + void classp(AstClass* nodep) { m_classp = nodep; } + AstPin* paramsp() const { return VN_AS(op4p(), Pin); } + virtual bool isCompound() const override { return true; } +}; +class AstConstDType final : public AstNodeDType { + // const data type, ie "const some_dtype var_name [2:0]" + // ConstDType are removed in V3LinkLValue and become AstVar::isConst. + // When more generic types are supported AstConstDType will be propagated further. +private: + AstNodeDType* m_refDTypep = nullptr; // Inherit from this base data type +public: + AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_ConstDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); // V3Width will resolve + dtypep(nullptr); // V3Width will resolve + widthFromSub(subDTypep()); + } + ASTNODE_NODE_FUNCS(ConstDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstConstDType* const sp = static_cast(samep); + return (m_refDTypep == sp->m_refDTypep); + } + virtual bool similarDType(AstNodeDType* samep) const override { + return skipRefp()->similarDType(samep->skipRefp()); + } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + virtual bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstDefImplicitDType final : public AstNodeDType { + // For parsing enum/struct/unions that are declared with a variable rather than typedef + // This allows "var enum {...} a,b" to share the enum definition for both variables + // After link, these become typedefs +private: + string m_name; + void* m_containerp; // In what scope is the name unique, so we can know what are duplicate + // definitions (arbitrary value) + const int m_uniqueNum; + +public: + AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_DefImplicitDType(fl) + , m_name{name} + , m_containerp{containerp} + , m_uniqueNum{uniqueNumInc()} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(DefImplicitDType) + int uniqueNum() const { return m_uniqueNum; } + virtual bool same(const AstNode* samep) const override { + const AstDefImplicitDType* const sp = static_cast(samep); + return uniqueNum() == sp->uniqueNum(); + } + virtual bool similarDType(AstNodeDType* samep) const override { + return type() == samep->type() && same(samep); + } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return dtypep() ? dtypep() : childDTypep(); + } + void* containerp() const { return m_containerp; } + // METHODS + // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } + virtual string name() const override { return m_name; } + virtual void name(const string& flag) override { m_name = flag; } + virtual bool isCompound() const override { return false; } +}; +class AstDynArrayDType final : public AstNodeDType { + // Dynamic array data type, ie "[]" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) +public: + AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_DynArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER_DynArrayDType(fl) { + refDTypep(dtp); + dtypep(nullptr); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(DynArrayDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return subDTypep() == asamep->subDTypep(); + } + virtual bool similarDType(AstNodeDType* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + virtual string prettyDTypeName() const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + virtual bool isCompound() const override { return true; } +}; +class AstEmptyQueueDType final : public AstNodeDType { + // For EmptyQueue +public: + explicit AstEmptyQueueDType(FileLine* fl) + : ASTGEN_SUPER_EmptyQueueDType(fl) { + dtypep(this); + } + ASTNODE_NODE_FUNCS(EmptyQueueDType) + virtual void dumpSmall(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + virtual bool maybePointedTo() const override { return true; } + virtual bool undead() const override { return true; } + virtual AstNodeDType* subDTypep() const override { return nullptr; } + virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } + virtual void virtRefDTypep(AstNodeDType* nodep) override {} + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + virtual AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return 1; } + virtual int widthTotalBytes() const override { return 1; } + virtual bool isCompound() const override { return false; } +}; +class AstEnumDType final : public AstNodeDType { + // Parents: TYPEDEF/MODULE + // Children: ENUMVALUEs +private: + string m_name; // Name from upper typedef, if any + AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width + const int m_uniqueNum = 0; + +public: + AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) + : ASTGEN_SUPER_EnumDType(fl) + , m_uniqueNum{uniqueNumInc()} { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + addNOp2p(itemsp); + dtypep(nullptr); // V3Width will resolve + widthFromSub(subDTypep()); + } + ASTNODE_NODE_FUNCS(EnumDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + int uniqueNum() const { return m_uniqueNum; } + virtual bool same(const AstNode* samep) const override { + const AstEnumDType* const sp = static_cast(samep); + return uniqueNum() == sp->uniqueNum(); + } + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } // op1 = Data type + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + // op1 = Range of variable + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + virtual string name() const override { return m_name; } + virtual void name(const string& flag) override { m_name = flag; } + AstEnumItem* itemsp() const { return VN_AS(op2p(), EnumItem); } // op2 = AstEnumItem's + // METHODS + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefToConstp() const override { + return subDTypep()->skipRefToConstp(); + } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + int itemCount() const { + size_t count = 0; + for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++; + return count; + } + virtual bool isCompound() const override { return false; } +}; +class AstIfaceRefDType final : public AstNodeDType { + // Reference to an interface, either for a port, or inside parent cell +private: + FileLine* m_modportFileline; // Where modport token was + string m_cellName; // "" = no cell, such as when connects to 'input' iface + string m_ifaceName; // Interface name + string m_modportName; // "" = no modport + AstIface* m_ifacep = nullptr; // Pointer to interface; note cellp() should override + AstCell* m_cellp = nullptr; // When exact parent cell known; not a guess + AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport +public: + AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) + : ASTGEN_SUPER_IfaceRefDType(fl) + , m_modportFileline{nullptr} + , m_cellName{cellName} + , m_ifaceName{ifaceName} + , m_modportName{""} {} + AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, + const string& ifaceName, const string& modport) + : ASTGEN_SUPER_IfaceRefDType(fl) + , m_modportFileline{modportFl} + , m_cellName{cellName} + , m_ifaceName{ifaceName} + , m_modportName{modport} {} + ASTNODE_NODE_FUNCS(IfaceRefDType) + // METHODS + virtual const char* broken() const override; + virtual void dump(std::ostream& str = std::cout) const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual void cloneRelink() override; + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + virtual int widthAlignBytes() const override { return 1; } + virtual int widthTotalBytes() const override { return 1; } + FileLine* modportFileline() const { return m_modportFileline; } + string cellName() const { return m_cellName; } + void cellName(const string& name) { m_cellName = name; } + string ifaceName() const { return m_ifaceName; } + void ifaceName(const string& name) { m_ifaceName = name; } + string modportName() const { return m_modportName; } + AstIface* ifaceViaCellp() const; // Use cellp or ifacep + AstIface* ifacep() const { return m_ifacep; } + void ifacep(AstIface* nodep) { m_ifacep = nodep; } + AstCell* cellp() const { return m_cellp; } + void cellp(AstCell* nodep) { m_cellp = nodep; } + AstModport* modportp() const { return m_modportp; } + void modportp(AstModport* modportp) { m_modportp = modportp; } + bool isModport() { return !m_modportName.empty(); } + virtual bool isCompound() const override { return true; } // But not relevant +}; +class AstMemberDType final : public AstNodeDType { + // A member of a struct/union + // PARENT: AstNodeUOrStructDType +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) + string m_name; // Name of variable + string m_tag; // Holds the string of the verilator tag -- used in XML output. + int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member + // UNSUP: int m_randType; // Randomization type (IEEE) +public: + AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberDType(fl) + , m_name{name} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + refDTypep(nullptr); + } + AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberDType(fl) + , m_name{name} { + UASSERT(dtp, "AstMember created with no dtype"); + refDTypep(dtp); + dtypep(this); + widthFromSub(subDTypep()); + } + ASTNODE_NODE_FUNCS(MemberDType) + virtual string name() const override { return m_name; } // * = Var name + virtual bool hasDType() const override { return true; } + virtual bool maybePointedTo() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + // + // (Slow) recurse down to find basic data type (Note don't need virtual - + // AstVar isn't a NodeDType) + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefToConstp() const override { + return subDTypep()->skipRefToConstp(); + } + virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + // METHODS + virtual void name(const string& name) override { m_name = name; } + virtual void tag(const string& text) override { m_tag = text; } + virtual string tag() const override { return m_tag; } + int lsb() const { return m_lsb; } + void lsb(int lsb) { m_lsb = lsb; } + virtual bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstParamTypeDType final : public AstNodeDType { + // Parents: MODULE + // A parameter type statement; much like a var or typedef +private: + const VVarType m_varType; // Type of variable (for localparam vs. param) + string m_name; // Name of variable +public: + AstParamTypeDType(FileLine* fl, VVarType type, const string& name, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_ParamTypeDType(fl) + , m_varType{type} + , m_name{name} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(ParamTypeDType) + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return dtypep() ? dtypep() : childDTypep(); + } + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + virtual AstNodeDType* skipRefToConstp() const override { + return subDTypep()->skipRefToConstp(); + } + virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + virtual bool similarDType(AstNodeDType* samep) const override { + const AstParamTypeDType* const sp = static_cast(samep); + return type() == samep->type() && sp + && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); + } + virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } + // METHODS + virtual string name() const override { return m_name; } + virtual bool maybePointedTo() const override { return true; } + virtual bool hasDType() const override { return true; } + virtual void name(const string& flag) override { m_name = flag; } + VVarType varType() const { return m_varType; } // * = Type of variable + bool isParam() const { return true; } + bool isGParam() const { return (varType() == VVarType::GPARAM); } + virtual bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstParseTypeDType final : public AstNodeDType { + // Parents: VAR + // During parsing, this indicates the type of a parameter is a "parameter type" + // e.g. the data type is a container of any data type +public: + explicit AstParseTypeDType(FileLine* fl) + : ASTGEN_SUPER_ParseTypeDType(fl) {} + ASTNODE_NODE_FUNCS(ParseTypeDType) + AstNodeDType* dtypep() const { return nullptr; } + // METHODS + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + virtual AstBasicDType* basicp() const override { return nullptr; } + virtual AstNodeDType* skipRefp() const override { return nullptr; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return 0; } + virtual int widthTotalBytes() const override { return 0; } + virtual bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstQueueDType final : public AstNodeDType { + // Queue array data type, ie "[ $ ]" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) +public: + AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) + : ASTGEN_SUPER_QueueDType(fl) { + setNOp2p(boundp); + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) + : ASTGEN_SUPER_QueueDType(fl) { + setNOp2p(boundp); + refDTypep(dtp); + dtypep(dtp); + } + ASTNODE_NODE_FUNCS(QueueDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstQueueDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); + } + virtual bool similarDType(AstNodeDType* samep) const override { + const AstQueueDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + virtual void dumpSmall(std::ostream& str) const override; + virtual string prettyDTypeName() const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNode* boundp() const { return op2p(); } // op2 = Bound, nullptr = none + void boundp(AstNode* nodep) { setNOp2p(nodep); } + inline int boundConst() const; + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + virtual bool isCompound() const override { return true; } +}; +class AstRefDType final : public AstNodeDType { +private: + // Pre-Width must reference the Typeref, not what it points to, as some child + // types like AstBracketArrayType will disappear and can't lose the handle + AstTypedef* m_typedefp = nullptr; // referenced type + // Post-width typedefs are removed and point to type directly + AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef + string m_name; // Name of an AstTypedef + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy +public: + AstRefDType(FileLine* fl, const string& name) + : ASTGEN_SUPER_RefDType(fl) + , m_name{name} {} + AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) + : ASTGEN_SUPER_RefDType(fl) + , m_name{name} { + setNOp3p(classOrPackagep); + addNOp4p(paramsp); + } + class FlagTypeOfExpr {}; // type(expr) for parser only + AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) + : ASTGEN_SUPER_RefDType(fl) { + setOp2p(typeofp); + } + ASTNODE_NODE_FUNCS(RefDType) + // METHODS + const char* broken() const override; + void cloneRelink() override; + virtual bool same(const AstNode* samep) const override { + const AstRefDType* const asamep = static_cast(samep); + return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep + && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); + } + virtual bool similarDType(AstNodeDType* samep) const override { + return skipRefp()->similarDType(samep->skipRefp()); + } + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } + virtual string prettyDTypeName() const override { + return subDTypep() ? subDTypep()->name() : prettyName(); + } + virtual AstBasicDType* basicp() const override { + return subDTypep() ? subDTypep()->basicp() : nullptr; + } + AstNodeDType* subDTypep() const override; + virtual AstNodeDType* skipRefp() const override { + // Skip past both the Ref and the Typedef + if (subDTypep()) { + return subDTypep()->skipRefp(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + virtual AstNodeDType* skipRefToConstp() const override { + if (subDTypep()) { + return subDTypep()->skipRefToConstp(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + virtual AstNodeDType* skipRefToEnump() const override { + if (subDTypep()) { + return subDTypep()->skipRefToEnump(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + virtual int widthAlignBytes() const override { return dtypeSkipRefp()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); } + virtual void name(const string& flag) override { m_name = flag; } + // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + AstTypedef* typedefp() const { return m_typedefp; } + void typedefp(AstTypedef* nodep) { m_typedefp = nodep; } + AstNodeDType* refDTypep() const { return m_refDTypep; } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return refDTypep(); } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + AstNode* typeofp() const { return op2p(); } + AstNode* classOrPackageOpp() const { return op3p(); } + AstPin* paramsp() const { return VN_AS(op4p(), Pin); } + virtual bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstUnsizedArrayDType final : public AstNodeDType { + // Unsized/open-range Array data type, ie "some_dtype var_name []" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_UnsizedArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(UnsizedArrayDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override; + bool similarDType(AstNodeDType* samep) const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + virtual bool isCompound() const override { return true; } +}; +class AstVoidDType final : public AstNodeDType { + // For e.g. a function returning void +public: + explicit AstVoidDType(FileLine* fl) + : ASTGEN_SUPER_VoidDType(fl) { + dtypep(this); + } + ASTNODE_NODE_FUNCS(VoidDType) + virtual void dumpSmall(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + virtual bool maybePointedTo() const override { return true; } + virtual bool undead() const override { return true; } + virtual AstNodeDType* subDTypep() const override { return nullptr; } + virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } + virtual void virtRefDTypep(AstNodeDType* nodep) override {} + virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } + virtual AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { return 1; } + virtual int widthTotalBytes() const override { return 1; } + virtual bool isCompound() const override { return false; } +}; +class AstWildcardArrayDType final : public AstNodeDType { + // Wildcard index type associative array data type, ie "some_dtype var_name [*]" + // Children: DTYPE (moved to refDTypep() in V3Width) +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstWildcardArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_WildcardArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + ASTNODE_NODE_FUNCS(WildcardArrayDType) + virtual const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + virtual void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override; + bool similarDType(AstNodeDType* samep) const override; + virtual void dumpSmall(std::ostream& str) const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const override { + return m_refDTypep ? m_refDTypep : childDTypep(); + } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const override { + return sizeof(std::map); + } + virtual int widthTotalBytes() const override { + return sizeof(std::map); + } + virtual bool isCompound() const override { return true; } +}; + +// === AstNodeArrayDType === +class AstPackArrayDType final : public AstNodeArrayDType { + // Packed array data type, ie "some_dtype [2:0] var_name" + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: RANGE (array bounds) +public: + inline AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep); + inline AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep); + ASTNODE_NODE_FUNCS(PackArrayDType) + virtual string prettyDTypeName() const override; + virtual bool isCompound() const override { return false; } +}; +class AstUnpackArrayDType final : public AstNodeArrayDType { + // Array data type, ie "some_dtype var_name [2:0]" + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: RANGE (array bounds) + bool m_isCompound = false; // Non-POD subDType, or parent requires compound +public: + AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_UnpackArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + setOp2p((AstNode*)rangep); + dtypep(nullptr); // V3Width will resolve + // For backward compatibility AstNodeArrayDType and others inherit + // width and signing from the subDType/base type + widthFromSub(subDTypep()); + } + AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_UnpackArrayDType(fl) { + refDTypep(dtp); + setOp2p((AstNode*)rangep); + dtypep(this); + // For backward compatibility AstNodeArrayDType and others inherit + // width and signing from the subDType/base type + widthFromSub(subDTypep()); + } + ASTNODE_NODE_FUNCS(UnpackArrayDType) + virtual string prettyDTypeName() const override; + virtual bool same(const AstNode* samep) const override { + const AstUnpackArrayDType* const sp = static_cast(samep); + return m_isCompound == sp->m_isCompound; + } + // Outer dimension comes first. The first element is this node. + std::vector unpackDimensions(); + void isCompound(bool flag) { m_isCompound = flag; } + virtual bool isCompound() const override { return m_isCompound; } +}; + +// === AstNodeUOrStructDType === +class AstStructDType final : public AstNodeUOrStructDType { +public: + // VSigning below is mispurposed to indicate if packed or not + AstStructDType(FileLine* fl, VSigning numericUnpack) + : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} + ASTNODE_NODE_FUNCS(StructDType) + virtual string verilogKwd() const override { return "struct"; } +}; +class AstUnionDType final : public AstNodeUOrStructDType { +public: + // UNSUP: bool isTagged; + // VSigning below is mispurposed to indicate if packed or not + AstUnionDType(FileLine* fl, VSigning numericUnpack) + : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} + ASTNODE_NODE_FUNCS(UnionDType) + virtual string verilogKwd() const override { return "union"; } +}; + +#endif // Guard diff --git a/src/V3AstNodeMath.h b/src/V3AstNodeMath.h new file mode 100644 index 000000000..ce1ca2338 --- /dev/null +++ b/src/V3AstNodeMath.h @@ -0,0 +1,4426 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing expressions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 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 representing expressions, +// i.e.: those constructs that evaluate to [a possible void/unit] value. The +// root of the hierarchy is 'AstNodeMath', which could also be called +// 'AstNodeExpr'. +// +// Warning: Although the above is what we are aiming for, currently there are +// some 'AstNode' sub-types defined elsewhere, that represent expressions but +// are not part of the `AstNodeMath` hierarchy (e.g.: 'AstNodeCall' and its +// sub-types). These should eventually be fixed and moved under 'AstNodeMath'. +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTNODEMATH_H_ +#define VERILATOR_V3ASTNODEMATH_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 AstNodeMath VL_NOT_FINAL : public AstNode { + // Math -- anything that's part of an expression tree +protected: + AstNodeMath(VNType t, FileLine* fl) + : AstNode{t, fl} {} + +public: + ASTNODE_BASE_FUNCS(NodeMath) + // METHODS + virtual void dump(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV + // For documentation on emitC format see EmitCFunc::emitOpName + virtual string emitC() = 0; + virtual string emitSimpleOperator() { return ""; } // "" means not ok to use + virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS + virtual bool cleanOut() const = 0; // True if output has extra upper bits zero + // Someday we will generically support data types on every math node + // Until then isOpaque indicates we shouldn't constant optimize this node type + bool isOpaque() const { return VN_IS(this, CvtPackString); } +}; +class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { + // Binary math +protected: + AstNodeBiop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) + : AstNodeMath{t, fl} { + setOp1p(lhs); + setOp2p(rhs); + } + +public: + ASTNODE_BASE_FUNCS(NodeBiop) + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; + // ACCESSORS + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + // METHODS + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } + virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode*) const override { return true; } +}; +class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { + // Binary math with commutative properties +protected: + AstNodeBiCom(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) + : AstNodeBiop{t, fl, lhs, rhs} {} + +public: + ASTNODE_BASE_FUNCS(NodeBiCom) +}; +class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { + // Binary math with commutative & associative properties +protected: + AstNodeBiComAsv(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) + : AstNodeBiCom{t, fl, lhs, rhs} {} + +public: + ASTNODE_BASE_FUNCS(NodeBiComAsv) +}; +class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { + // Single bit range extraction, perhaps with non-constant selection or array selection +protected: + AstNodeSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* bitp) + : AstNodeBiop{t, fl, fromp, bitp} {} + +public: + ASTNODE_BASE_FUNCS(NodeSel) + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + void fromp(AstNode* nodep) { setOp1p(nodep); } + AstNode* bitp() const { return op2p(); } // op2 = Msb selection expression + void bitp(AstNode* nodep) { setOp2p(nodep); } + int bitConst() const; + virtual bool hasDType() const override { return true; } +}; +class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +protected: + AstNodeStream(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeBiop{t, fl, lhsp, rhsp} { + if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); + } + +public: + ASTNODE_BASE_FUNCS(NodeStream) +}; +class AstNodeSystemBiop VL_NOT_FINAL : public AstNodeBiop { +public: + AstNodeSystemBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeBiop(t, fl, lhsp, rhsp) { + dtypeSetDouble(); + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { + // Quaternary math +protected: + AstNodeQuadop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) + : AstNodeMath{t, fl} { + setOp1p(lhs); + setOp2p(rhs); + setOp3p(ths); + setOp4p(fhs); + } + +public: + ASTNODE_BASE_FUNCS(NodeQuadop) + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + AstNode* thsp() const { return op3p(); } + AstNode* fhsp() const { return op4p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + void thsp(AstNode* nodep) { return setOp3p(nodep); } + void fhsp(AstNode* nodep) { return setOp4p(nodep); } + // METHODS + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths, const V3Number& fhs) + = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero + virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size + virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode*) const override { return true; } +}; +class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { + // Terminal operator -- a operator with no "inputs" +protected: + AstNodeTermop(VNType t, FileLine* fl) + : AstNodeMath{t, fl} {} + +public: + ASTNODE_BASE_FUNCS(NodeTermop) + // Know no children, and hot function, so skip iterator for speed + // See checkTreeIter also that asserts no children + // cppcheck-suppress functionConst + void iterateChildren(VNVisitor& v) {} + virtual void dump(std::ostream& str) const override; +}; +class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { + // Trinary math +protected: + AstNodeTriop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) + : AstNodeMath{t, fl} { + setOp1p(lhs); + setOp2p(rhs); + setOp3p(ths); + } + +public: + ASTNODE_BASE_FUNCS(NodeTriop) + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + AstNode* thsp() const { return op3p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + void thsp(AstNode* nodep) { return setOp3p(nodep); } + // METHODS + virtual void dump(std::ostream& str) const override; + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) + = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode*) const override { return true; } +}; +class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { +protected: + AstNodeCond(VNType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) + : AstNodeTriop{t, fl, condp, expr1p, expr2p} { + if (expr1p) { + dtypeFrom(expr1p); + } else if (expr2p) { + dtypeFrom(expr2p); + } + } + +public: + ASTNODE_BASE_FUNCS(NodeCond) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override; + AstNode* condp() const { return op1p(); } // op1 = Condition + AstNode* expr1p() const { return op2p(); } // op2 = If true... + AstNode* expr2p() const { return op3p(); } // op3 = If false... + virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; } + virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; } + virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return false; } + virtual bool cleanThs() const override { return false; } // Propagates up + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; +}; +class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { + // Unary math +protected: + AstNodeUniop(VNType t, FileLine* fl, AstNode* lhsp) + : AstNodeMath{t, fl} { + dtypeFrom(lhsp); + setOp1p(lhsp); + } + +public: + ASTNODE_BASE_FUNCS(NodeUniop) + AstNode* lhsp() const { return op1p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + // METHODS + virtual void dump(std::ostream& str) const override; + // Set out to evaluation of a AstConst'ed lhs + virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; + virtual bool cleanLhs() const = 0; + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } + virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode*) const override { return true; } +}; +class AstNodeSystemUniop VL_NOT_FINAL : public AstNodeUniop { +public: + AstNodeSystemUniop(VNType t, FileLine* fl, AstNode* lhsp) + : AstNodeUniop(t, fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_BASE_FUNCS(NodeSystemUniop) + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { + // An AstVarRef or AstVarXRef +private: + VAccess m_access; // Left hand side assignment + AstVar* m_varp; // [AfterLink] Pointer to variable itself + AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + string m_name; // Name of variable + string m_selfPointer; // Output code object pointer (e.g.: 'this') + +protected: + AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) + : AstNodeMath{t, fl} + , m_access{access} + , m_name{name} { + varp(nullptr); + } + AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) + : AstNodeMath{t, fl} + , m_access{access} + , m_name{name} { + // May have varp==nullptr + this->varp(varp); + } + +public: + ASTNODE_BASE_FUNCS(NodeVarRef) + virtual void dump(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + virtual const char* broken() const override; + virtual int instrCount() const override { return widthInstrs(); } + virtual void cloneRelink() override; + virtual string name() const override { return m_name; } // * = Var name + virtual void name(const string& name) override { m_name = name; } + VAccess access() const { return m_access; } + void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor + AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable + void varp(AstVar* varp); + AstVarScope* varScopep() const { return m_varScopep; } + void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } + string selfPointer() const { return m_selfPointer; } + void selfPointer(const string& value) { m_selfPointer = value; } + string selfPointerProtect(bool useSelfForThis) const; + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + // Know no children, and hot function, so skip iterator for speed + // See checkTreeIter also that asserts no children + // cppcheck-suppress functionConst + void iterateChildren(VNVisitor& v) {} +}; + +// === Concrete node types ===================================================== + +// === AstNodeMath === +class AstAddrOfCFunc final : public AstNodeMath { + // Get address of CFunc +private: + AstCFunc* m_funcp; // Pointer to function itself + +public: + AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp) + : ASTGEN_SUPER_AddrOfCFunc(fl) + , m_funcp{funcp} { + dtypep(findCHandleDType()); + } + +public: + ASTNODE_NODE_FUNCS(AddrOfCFunc) + virtual void cloneRelink() override; + virtual const char* broken() const override; + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + AstCFunc* funcp() const { return m_funcp; } +}; +class AstCMath final : public AstNodeMath { +private: + const bool m_cleanOut; + bool m_pure; // Pure optimizable +public: + // Emit C textual math function (like AstUCFunc) + AstCMath(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_CMath(fl) + , m_cleanOut{true} + , m_pure{false} { + addOp1p(exprsp); + dtypeFrom(exprsp); + } + inline AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true); + ASTNODE_NODE_FUNCS(CMath) + virtual bool isGateOptimizable() const override { return m_pure; } + virtual bool isPredictOptimizable() const override { return m_pure; } + virtual bool cleanOut() const override { return m_cleanOut; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + void addBodysp(AstNode* nodep) { addNOp1p(nodep); } + AstNode* bodysp() const { return op1p(); } // op1 = expressions to print + bool pure() const { return m_pure; } + void pure(bool flag) { m_pure = flag; } +}; +class AstConsAssoc final : public AstNodeMath { + // Construct an assoc array and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsAssoc(FileLine* fl, AstNode* defaultp) + : ASTGEN_SUPER_ConsAssoc(fl) { + setNOp1p(defaultp); + } + ASTNODE_NODE_FUNCS(ConsAssoc) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* defaultp() const { return op1p(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsDynArray final : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // Parents: math + // Children: expression (elements or other queues) +public: + explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER_ConsDynArray(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ConsDynArray) + virtual string emitVerilog() override { return "'{%l, %r}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } // op1 = expression + AstNode* rhsp() const { return op2p(); } // op2 = expression + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsQueue final : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // Parents: math + // Children: expression (elements or other queues) +public: + explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER_ConsQueue(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ConsQueue) + virtual string emitVerilog() override { return "'{%l, %r}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } // op1 = expression + AstNode* rhsp() const { return op2p(); } // op2 = expression + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsWildcard final : public AstNodeMath { + // Construct a wildcard assoc array and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsWildcard(FileLine* fl, AstNode* defaultp) + : ASTGEN_SUPER_ConsWildcard(fl) { + setNOp1p(defaultp); + } + ASTNODE_NODE_FUNCS(ConsWildcard) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* defaultp() const { return op1p(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConst final : public AstNodeMath { + // A constant +private: + V3Number m_num; // Constant value + void initWithNumber() { + if (m_num.isDouble()) { + dtypeSetDouble(); + } else if (m_num.isString()) { + dtypeSetString(); + } else { + dtypeSetLogicUnsized(m_num.width(), (m_num.sized() ? 0 : m_num.widthMin()), + VSigning::fromBool(m_num.isSigned())); + } + m_num.nodep(this); + } + +public: + AstConst(FileLine* fl, const V3Number& num) + : ASTGEN_SUPER_Const(fl) + , m_num(num) { + initWithNumber(); + } + class WidthedValue {}; // for creator type-overload selection + AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) + : ASTGEN_SUPER_Const(fl) + , m_num(this, width, value) { + initWithNumber(); + } + class DTyped {}; // for creator type-overload selection + // Zero/empty constant with a type matching nodetypep + AstConst(FileLine* fl, DTyped, const AstNodeDType* nodedtypep) + : ASTGEN_SUPER_Const(fl) + , m_num(this, nodedtypep) { + initWithNumber(); + } + class StringToParse {}; // for creator type-overload selection + AstConst(FileLine* fl, StringToParse, const char* sourcep) + : ASTGEN_SUPER_Const(fl) + , m_num(this, sourcep) { + initWithNumber(); + } + class VerilogStringLiteral {}; // for creator type-overload selection + AstConst(FileLine* fl, VerilogStringLiteral, const string& str) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::VerilogStringLiteral(), this, str) { + initWithNumber(); + } + AstConst(FileLine* fl, uint32_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); + } + class Unsized32 {}; // for creator type-overload selection + AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + m_num.width(32, false); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); + } + class Signed32 {}; // for creator type-overload selection + AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + m_num.width(32, true); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); + } + class Unsized64 {}; // for creator type-overload selection + AstConst(FileLine* fl, Unsized64, uint64_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 64, 0) { + m_num.setQuad(num); + dtypeSetLogicSized(64, VSigning::UNSIGNED); + } + class SizedEData {}; // for creator type-overload selection + AstConst(FileLine* fl, SizedEData, uint64_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, VL_EDATASIZE, 0) { + m_num.setQuad(num); + dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); + } + class RealDouble {}; // for creator type-overload selection + AstConst(FileLine* fl, RealDouble, double num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 64) { + m_num.setDouble(num); + dtypeSetDouble(); + } + class String {}; // for creator type-overload selection + AstConst(FileLine* fl, String, const string& num) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::String(), this, num) { + dtypeSetString(); + } + class BitFalse {}; + AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 + : ASTGEN_SUPER_Const(fl) + , m_num(this, 1, 0) { + dtypeSetBit(); + } + // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 + class BitTrue {}; + AstConst(FileLine* fl, BitTrue, bool on = true) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 1, on) { + dtypeSetBit(); + } + class Null {}; + AstConst(FileLine* fl, Null) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::Null{}, this) { + dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here + initWithNumber(); + } + ASTNODE_NODE_FUNCS(Const) + virtual string name() const override { return num().ascii(); } // * = Value + const V3Number& num() const { return m_num; } // * = Value + V3Number& num() { return m_num; } // * = Value + uint32_t toUInt() const { return num().toUInt(); } + int32_t toSInt() const { return num().toSInt(); } + uint64_t toUQuad() const { return num().toUQuad(); } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* samep) const override { + const AstConst* const sp = static_cast(samep); + return num().isCaseEq(sp->num()); + } + virtual int instrCount() const override { return widthInstrs(); } + bool isEqAllOnes() const { return num().isEqAllOnes(width()); } + bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } + // Parse string and create appropriate type of AstConst. + // May return nullptr on parse failure. + static AstConst* parseParamLiteral(FileLine* fl, const string& literal); +}; +class AstEmptyQueue final : public AstNodeMath { +public: + explicit AstEmptyQueue(FileLine* fl) + : ASTGEN_SUPER_EmptyQueue(fl) {} + ASTNODE_NODE_FUNCS(EmptyQueue) + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() override { return "{}"; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual bool cleanOut() const override { return true; } +}; +class AstEnumItemRef final : public AstNodeMath { +private: + AstEnumItem* m_itemp; // [AfterLink] Pointer to item + AstNodeModule* m_classOrPackagep; // Package hierarchy +public: + AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) + : ASTGEN_SUPER_EnumItemRef(fl) + , m_itemp{itemp} + , m_classOrPackagep{classOrPackagep} { + dtypeFrom(m_itemp); + } + ASTNODE_NODE_FUNCS(EnumItemRef) + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return itemp()->name(); } + virtual int instrCount() const override { return 0; } + const char* broken() const override; + virtual void cloneRelink() override { + if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); + } + virtual bool same(const AstNode* samep) const override { + const AstEnumItemRef* const sp = static_cast(samep); + return itemp() == sp->itemp(); + } + AstEnumItem* itemp() const { return m_itemp; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } +}; +class AstExprStmt final : public AstNodeMath { + // Perform a statement, often assignment inside an expression/math node, + // the parent gets passed the 'resultp()'. + // resultp is evaluated AFTER the statement(s). +public: + AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) + : ASTGEN_SUPER_ExprStmt(fl) { + addOp1p(stmtsp); + setOp2p(resultp); // Possibly in future nullptr could mean return rhsp() + dtypeFrom(resultp); + } + ASTNODE_NODE_FUNCS(ExprStmt) + // ACCESSORS + AstNode* stmtsp() const { return op1p(); } + void addStmtsp(AstNode* nodep) { addOp1p(nodep); } + AstNode* resultp() const { return op2p(); } + // METHODS + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode*) const override { return true; } +}; +class AstFError final : public AstNodeMath { +public: + AstFError(FileLine* fl, AstNode* filep, AstNode* strp) + : ASTGEN_SUPER_FError(fl) { + setOp1p(filep); + setOp2p(strp); + } + ASTNODE_NODE_FUNCS(FError) + virtual string emitVerilog() override { return "%f$ferror(%l, %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual int instrCount() const override { return widthInstrs() * 64; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + void filep(AstNode* nodep) { setOp1p(nodep); } + AstNode* filep() const { return op1p(); } + void strp(AstNode* nodep) { setOp2p(nodep); } + AstNode* strp() const { return op2p(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFRead final : public AstNodeMath { + // Parents: expr + // Children: varrefs to load + // Children: file which must be a varref + // Children: low index + // Children: count +public: + AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) + : ASTGEN_SUPER_FRead(fl) { + setOp1p(memp); + setOp2p(filep); + setNOp3p(startp); + setNOp4p(countp); + } + ASTNODE_NODE_FUNCS(FRead) + virtual string verilogKwd() const override { return "$fread"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: makes output + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* memp() const { return op1p(); } + void memp(AstNode* nodep) { setOp1p(nodep); } + AstNode* filep() const { return op2p(); } + void filep(AstNode* nodep) { setOp2p(nodep); } + AstNode* startp() const { return op3p(); } + void startp(AstNode* nodep) { setNOp3p(nodep); } + AstNode* countp() const { return op4p(); } + void countp(AstNode* nodep) { setNOp4p(nodep); } +}; +class AstFRewind final : public AstNodeMath { + // Parents: stmtlist + // Children: file which must be a varref +public: + AstFRewind(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FRewind(fl) { + setNOp2p(filep); + } + ASTNODE_NODE_FUNCS(FRewind) + virtual string verilogKwd() const override { return "$frewind"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op2p(); } + void filep(AstNodeVarRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstFScanF final : public AstNodeMath { + // Parents: expr + // Children: file which must be a varref + // Children: varrefs to load +private: + string m_text; + +public: + AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) + : ASTGEN_SUPER_FScanF(fl) + , m_text{text} { + addNOp1p(exprsp); + setNOp2p(filep); + } + ASTNODE_NODE_FUNCS(FScanF) + virtual string name() const override { return m_text; } + virtual string verilogKwd() const override { return "$fscanf"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: makes output + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output + void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } + AstNode* filep() const { return op2p(); } + void filep(AstNodeVarRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstFSeek final : public AstNodeMath { + // Parents: expr + // Children: file which must be a varref + // Children: offset + // Children: operation +public: + AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) + : ASTGEN_SUPER_FSeek(fl) { + setOp2p(filep); + setNOp3p(offset); + setNOp4p(operation); + } + ASTNODE_NODE_FUNCS(FSeek) + virtual string verilogKwd() const override { return "$fseek"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: makes output + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op2p(); } + void filep(AstNode* nodep) { setOp2p(nodep); } + AstNode* offset() const { return op3p(); } + void offset(AstNode* nodep) { setNOp3p(nodep); } + AstNode* operation() const { return op4p(); } + void operation(AstNode* nodep) { setNOp4p(nodep); } +}; +class AstFTell final : public AstNodeMath { + // Parents: stmtlist + // Children: file which must be a varref +public: + AstFTell(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FTell(fl) { + setNOp2p(filep); + } + ASTNODE_NODE_FUNCS(FTell) + virtual string verilogKwd() const override { return "$ftell"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op2p(); } + void filep(AstNodeVarRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstFell final : public AstNodeMath { + // Verilog $fell + // Parents: math + // Children: expression +public: + AstFell(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Fell(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Fell) + virtual string emitVerilog() override { return "$fell(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p((AstNode*)sentreep); } // op2 = clock domain + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstGatePin final : public AstNodeMath { + // Possibly expand a gate primitive input pin value to match the range of the gate primitive +public: + AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) + : ASTGEN_SUPER_GatePin(fl) { + setOp1p(lhsp); + setOp2p((AstNode*)rangep); + } + ASTNODE_NODE_FUNCS(GatePin) + virtual string emitVerilog() override { return "%l"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + AstNode* exprp() const { return op1p(); } // op1 = Pin expression + AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Range of pin +}; +class AstImplication final : public AstNodeMath { + // Verilog |-> |=> + // Parents: math + // Children: expression +public: + AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) + : ASTGEN_SUPER_Implication(fl) { + setOp1p(lhs); + setOp2p(rhs); + } + ASTNODE_NODE_FUNCS(Implication) + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain + void sentreep(AstSenTree* sentreep) { addOp4p((AstNode*)sentreep); } // op4 = clock domain + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstInside final : public AstNodeMath { +public: + AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) + : ASTGEN_SUPER_Inside(fl) { + addOp1p(exprp); + addOp2p(itemsp); + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Inside) + AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with + // op2 = RHS, possibly a list of expr or AstInsideRange + AstNode* itemsp() const { return op2p(); } + virtual string emitVerilog() override { return "%l inside { %r }"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } // NA +}; +class AstInsideRange final : public AstNodeMath { +public: + AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_InsideRange(fl) { + addOp1p(lhsp); + addOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(InsideRange) + AstNode* lhsp() const { return op1p(); } // op1 = LHS + AstNode* rhsp() const { return op2p(); } // op2 = RHS + virtual string emitVerilog() override { return "[%l:%r]"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } // NA + // Create AstAnd(AstGte(...), AstLte(...)) + AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); +}; +class AstLambdaArgRef final : public AstNodeMath { + // Lambda argument usage + // These are not AstVarRefs because we need to be able to delete/clone lambdas during + // optimizations and AstVar's are painful to remove. +private: + string m_name; // Name of variable + bool m_index; // Index, not value + +public: + AstLambdaArgRef(FileLine* fl, const string& name, bool index) + : ASTGEN_SUPER_LambdaArgRef(fl) + , m_name{name} + , m_index(index) {} + ASTNODE_NODE_FUNCS(LambdaArgRef) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual string emitVerilog() override { return name(); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool hasDType() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + virtual string name() const override { return m_name; } // * = Var name + virtual void name(const string& name) override { m_name = name; } + bool index() const { return m_index; } +}; +class AstMemberSel final : public AstNodeMath { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + string m_name; + AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection +public: + AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) + : ASTGEN_SUPER_MemberSel(fl) + , m_name{name} { + setOp1p(fromp); + dtypep(nullptr); // V3Width will resolve + } + AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberSel(fl) + , m_name{dtp->name()} { + setOp1p(fromp); + dtypep(dtp); + } + ASTNODE_NODE_FUNCS(MemberSel) + void cloneRelink() override; + const char* broken() const override; + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* samep) const override { + return true; + } // dtype comparison does it + virtual int instrCount() const override { return widthInstrs(); } + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + void fromp(AstNode* nodep) { setOp1p(nodep); } + AstVar* varp() const { return m_varp; } + void varp(AstVar* nodep) { m_varp = nodep; } +}; +class AstNewCopy final : public AstNodeMath { + // New as shallow copy + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNewCopy(FileLine* fl, AstNode* rhsp) + : ASTGEN_SUPER_NewCopy(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + setNOp1p(rhsp); + } + ASTNODE_NODE_FUNCS(NewCopy) + virtual string emitVerilog() override { return "new"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* rhsp() const { return op1p(); } +}; +class AstNewDynamic final : public AstNodeMath { + // New for dynamic array + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) + : ASTGEN_SUPER_NewDynamic(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + setNOp1p(sizep); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(NewDynamic) + virtual string emitVerilog() override { return "new"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* sizep() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } +}; +class AstPast final : public AstNodeMath { + // Verilog $past + // Parents: math + // Children: expression +public: + AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) + : ASTGEN_SUPER_Past(fl) { + addOp1p(exprp); + addNOp2p(ticksp); + } + ASTNODE_NODE_FUNCS(Past) + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstNode* ticksp() const { return op2p(); } // op2 = ticks or nullptr means 1 + AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain + void sentreep(AstSenTree* sentreep) { addOp4p((AstNode*)sentreep); } // op4 = clock domain + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstPatMember final : public AstNodeMath { + // Verilog '{a} or '{a{b}} + // Parents: AstPattern + // Children: expression, AstPattern, replication count +private: + bool m_default = false; + +public: + AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) + : ASTGEN_SUPER_PatMember(fl) { + addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); + } + ASTNODE_NODE_FUNCS(PatMember) + virtual string emitVerilog() override { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs() * 2; } + virtual void dump(std::ostream& str = std::cout) const override; + // op1 = expression to assign or another AstPattern (list if replicated) + AstNode* lhssp() const { return op1p(); } + AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) + AstNode* repp() const { return op3p(); } // op3 = replication count, or nullptr for count 1 + bool isDefault() const { return m_default; } + void isDefault(bool flag) { m_default = flag; } +}; +class AstPattern final : public AstNodeMath { + // Verilog '{a,b,c,d...} + // Parents: AstNodeAssign, AstPattern, ... + // Children: expression, AstPattern, AstPatReplicate +public: + AstPattern(FileLine* fl, AstNode* itemsp) + : ASTGEN_SUPER_Pattern(fl) { + addNOp2p(itemsp); + } + ASTNODE_NODE_FUNCS(Pattern) + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc + void addItemsp(AstNode* nodep) { addOp2p(nodep); } +}; +class AstRand final : public AstNodeMath { + // $random/$random(seed) or $urandom/$urandom(seed) + // Return a random number, based upon width() +private: + const bool m_urandom = false; // $urandom vs $random + const bool m_reset = false; // Random reset, versus always random +public: + class Reset {}; + AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) + : ASTGEN_SUPER_Rand(fl) + , m_reset{reset} { + dtypep(dtp); + } + AstRand(FileLine* fl, AstNode* seedp, bool urandom) + : ASTGEN_SUPER_Rand(fl) + , m_urandom(urandom) { + setNOp1p(seedp); + } + ASTNODE_NODE_FUNCS(Rand) + virtual string emitVerilog() override { + return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)") + : (m_urandom ? "%f$urandom()" : "%f$random()"); + } + virtual string emitC() override { + return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() + ? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" : "VL_RANDOM_SEEDED_%nq%lq(%li)") + : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // + : "VL_RANDOM_%nq()"; + } + virtual bool cleanOut() const override { return false; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + bool combinable(const AstRand* samep) const { + return !seedp() && !samep->seedp() && reset() == samep->reset() + && urandom() == samep->urandom(); + } + AstNode* seedp() const { return op1p(); } + bool reset() const { return m_reset; } + bool urandom() const { return m_urandom; } +}; +class AstRose final : public AstNodeMath { + // Verilog $rose + // Parents: math + // Children: expression +public: + AstRose(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Rose(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Rose) + virtual string emitVerilog() override { return "$rose(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p((AstNode*)sentreep); } // op2 = clock domain + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSScanF final : public AstNodeMath { + // Parents: expr + // Children: file which must be a varref + // Children: varrefs to load +private: + string m_text; + +public: + AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) + : ASTGEN_SUPER_SScanF(fl) + , m_text{text} { + addNOp1p(exprsp); + setOp2p(fromp); + } + ASTNODE_NODE_FUNCS(SScanF) + virtual string name() const override { return m_text; } + virtual string verilogKwd() const override { return "$sscanf"; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: makes output + virtual bool cleanOut() const override { return false; } + virtual bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output + void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } + AstNode* fromp() const { return op2p(); } + void fromp(AstNode* nodep) { setOp2p(nodep); } +}; +class AstSampled final : public AstNodeMath { + // Verilog $sampled + // Parents: math + // Children: expression +public: + AstSampled(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Sampled(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Sampled) + virtual string emitVerilog() override { return "$sampled(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return 0; } + AstNode* exprp() const { return op1p(); } // op1 = expression + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstScopeName final : public AstNodeMath { + // For display %m and DPI context imports + // Parents: DISPLAY + // Children: TEXT +private: + bool m_dpiExport = false; // Is for dpiExport + const bool m_forFormat = false; // Is for a format %m + string scopeNameFormatter(AstText* scopeTextp) const; + string scopePrettyNameFormatter(AstText* scopeTextp) const; + +public: + class ForFormat {}; + AstScopeName(FileLine* fl, bool forFormat) + : ASTGEN_SUPER_ScopeName(fl) + , m_forFormat{forFormat} { + dtypeSetUInt64(); + } + ASTNODE_NODE_FUNCS(ScopeName) + virtual bool same(const AstNode* samep) const override { + return (m_dpiExport == static_cast(samep)->m_dpiExport + && m_forFormat == static_cast(samep)->m_forFormat); + } + virtual string emitVerilog() override { return ""; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual void dump(std::ostream& str = std::cout) const override; + AstText* scopeAttrp() const { return VN_AS(op1p(), Text); } + void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } + AstText* scopeEntrp() const { return VN_AS(op2p(), Text); } + void scopeEntrp(AstNode* nodep) { addOp2p(nodep); } + string scopeSymName() const { // Name for __Vscope variable including children + return scopeNameFormatter(scopeAttrp()); + } + string scopeDpiName() const { // Name for DPI import scope + return scopeNameFormatter(scopeEntrp()); + } + string scopePrettySymName() const { // Name for __Vscope variable including children + return scopePrettyNameFormatter(scopeAttrp()); + } + string scopePrettyDpiName() const { // Name for __Vscope variable including children + return scopePrettyNameFormatter(scopeEntrp()); + } + bool dpiExport() const { return m_dpiExport; } + void dpiExport(bool flag) { m_dpiExport = flag; } + bool forFormat() const { return m_forFormat; } +}; +class AstSetAssoc final : public AstNodeMath { + // Set an assoc array element and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) + : ASTGEN_SUPER_SetAssoc(fl) { + setOp1p(lhsp); + setNOp2p(keyp); + setOp3p(valuep); + } + ASTNODE_NODE_FUNCS(SetAssoc) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } + AstNode* keyp() const { return op2p(); } + AstNode* valuep() const { return op3p(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSetWildcard final : public AstNodeMath { + // Set a wildcard assoc array element and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) + : ASTGEN_SUPER_SetWildcard(fl) { + setOp1p(lhsp); + setNOp2p(keyp); + setOp3p(valuep); + } + ASTNODE_NODE_FUNCS(SetWildcard) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } + AstNode* keyp() const { return op2p(); } + AstNode* valuep() const { return op3p(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstStable final : public AstNodeMath { + // Verilog $stable + // Parents: math + // Children: expression +public: + AstStable(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Stable(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Stable) + virtual string emitVerilog() override { return "$stable(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p((AstNode*)sentreep); } // op2 = clock domain + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSystemF final : public AstNodeMath { + // $system used as function +public: + AstSystemF(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SystemF(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(SystemF) + virtual string verilogKwd() const override { return "$system"; } + virtual string emitVerilog() override { return verilogKwd(); } + virtual string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* lhsp() const { return op1p(); } +}; +class AstTestPlusArgs final : public AstNodeMath { + // Parents: expr + // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs +public: + AstTestPlusArgs(FileLine* fl, AstNode* searchp) + : ASTGEN_SUPER_TestPlusArgs(fl) { + setOp1p(searchp); + } + ASTNODE_NODE_FUNCS(TestPlusArgs) + virtual string verilogKwd() const override { return "$test$plusargs"; } + virtual string emitVerilog() override { return verilogKwd(); } + virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* searchp() const { return op1p(); } // op1 = Search expression + void searchp(AstNode* nodep) { setOp1p(nodep); } +}; +class AstUCFunc final : public AstNodeMath { + // User's $c function + // Perhaps this should be an AstNodeListop; but there's only one list math right now +public: + AstUCFunc(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_UCFunc(fl) { + addNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(UCFunc) + virtual bool cleanOut() const override { return false; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + AstNode* bodysp() const { return op1p(); } // op1 = expressions to print + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isSubstOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstUnbounded final : public AstNodeMath { + // A $ in the parser, used for unbounded and queues + // Due to where is used, treated as Signed32 +public: + explicit AstUnbounded(FileLine* fl) + : ASTGEN_SUPER_Unbounded(fl) { + dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(Unbounded) + virtual string emitVerilog() override { return "$"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } +}; +class AstValuePlusArgs final : public AstNodeMath { + // Parents: expr + // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs +public: + AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) + : ASTGEN_SUPER_ValuePlusArgs(fl) { + setOp1p(searchp); + setOp2p(outp); + } + ASTNODE_NODE_FUNCS(ValuePlusArgs) + virtual string verilogKwd() const override { return "$value$plusargs"; } + virtual string emitVerilog() override { return "%f$value$plusargs(%l, %k%r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return !outp(); } + virtual bool cleanOut() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* searchp() const { return op1p(); } // op1 = Search expression + void searchp(AstNode* nodep) { setOp1p(nodep); } + AstNode* outp() const { return op2p(); } // op2 = Expressions to output + void outp(AstNode* nodep) { setOp2p(nodep); } +}; + +// === AstNodeBiop === +class AstBufIf1 final : public AstNodeBiop { + // lhs is enable, rhs is data to drive + // Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp + // bit enables respective rhsp bit +public: + AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(BufIf1) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstBufIf1(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opBufIf1(lhs, rhs); + } + virtual string emitVerilog() override { return "bufif(%r,%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstCastDynamic final : public AstNodeBiop { + // Verilog $cast used as a function + // Task usage of $cast is converted during parse to assert($cast(...)) + // Parents: MATH + // Children: MATH + // lhsp() is value (we are converting FROM) to match AstCCast etc, this + // is opposite of $cast's order, because the first access is to the + // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). +public: + AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(CastDynamic) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstCastDynamic(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f$cast(%r, %l)"; } + virtual string emitC() override { return "VL_DYNAMIC_CAST(%r, %l)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 20; } + virtual bool isPure() const override { return true; } + AstNode* fromp() const { return lhsp(); } + AstNode* top() const { return rhsp(); } +}; +class AstCompareNN final : public AstNodeBiop { + // Verilog str.compare() and str.icompare() +private: + const bool m_ignoreCase; // True for str.icompare() +public: + AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) + : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) + , m_ignoreCase{ignoreCase} { + dtypeSetUInt32(); + } + ASTNODE_NODE_FUNCS(CompareNN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstCompareNN(this->fileline(), lhsp, rhsp, m_ignoreCase); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCompareNN(lhs, rhs, m_ignoreCase); + } + virtual string name() const override { return m_ignoreCase ? "icompare" : "compare"; } + virtual string emitVerilog() override { + return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))"; + } + virtual string emitC() override { + return m_ignoreCase ? "VL_CMP_NN(%li,%ri,true)" : "VL_CMP_NN(%li,%ri,false)"; + } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstConcat final : public AstNodeBiop { + // If you're looking for {#{}}, see AstReplicate +public: + AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { + if (lhsp->dtypep() && rhsp->dtypep()) { + dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), + VSigning::UNSIGNED); + } + } + ASTNODE_NODE_FUNCS(Concat) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstConcat(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f{%l, %k%r}"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opConcat(lhs, rhs); + } + virtual string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } +}; +class AstConcatN final : public AstNodeBiop { + // String concatenate +public: + AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(ConcatN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstConcatN(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f{%l, %k%r}"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opConcatN(lhs, rhs); + } + virtual string emitC() override { return "VL_CONCATN_NNN(%li, %ri)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstDiv final : public AstNodeBiop { +public: + AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Div) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDiv(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDiv(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } + virtual string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } +}; +class AstDivD final : public AstNodeBiop { +public: + AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(DivD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDivD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDivD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "/"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstDivS final : public AstNodeBiop { +public: + AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(DivS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDivS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDivS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } + virtual string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } + virtual bool signedFlavor() const override { return true; } +}; +class AstEqWild final : public AstNodeBiop { + // Note wildcard operator rhs differs from lhs +public: + AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(EqWild) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqWild(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEqWild/AstEqD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opWildEq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f==? %r)"; } + virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "=="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstFGetS final : public AstNodeBiop { +public: + AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(FGetS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstFGetS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; } + virtual string emitC() override { + return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)" + : "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 64; } + AstNode* strgp() const { return lhsp(); } + AstNode* filep() const { return rhsp(); } +}; +class AstFUngetC final : public AstNodeBiop { +public: + AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(FUngetC) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstFUngetC(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f$ungetc(%r, %l)"; } + // Non-existent filehandle returns EOF + virtual string emitC() override { + return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 64; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } + AstNode* charp() const { return rhsp(); } +}; +class AstGetcN final : public AstNodeBiop { + // Verilog string.getc() +public: + AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { + dtypeSetBitSized(8, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(GetcN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGetcN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGetcN(lhs, rhs); + } + virtual string name() const override { return "getc"; } + virtual string emitVerilog() override { return "%k(%l.getc(%r))"; } + virtual string emitC() override { return "VL_GETC_N(%li,%ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstGetcRefN final : public AstNodeBiop { + // Verilog string[#] on the left-hand-side of assignment + // Spec says is of type byte (not string of single character) +public: + AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { + dtypeSetBitSized(8, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(GetcRefN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGetcRefN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%k%l[%r]"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstGt final : public AstNodeBiop { +public: + AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Gt) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGt(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGt(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f> %r)"; } + virtual string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ">"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstGtD final : public AstNodeBiop { +public: + AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GtD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f> %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return ">"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstGtN final : public AstNodeBiop { +public: + AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GtN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f> %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return ">"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstGtS final : public AstNodeBiop { +public: + AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GtS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f> %r)"; } + virtual string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool signedFlavor() const override { return true; } +}; +class AstGte final : public AstNodeBiop { +public: + AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Gte) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGte(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGte(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } + virtual string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ">="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstGteD final : public AstNodeBiop { +public: + AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GteD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return ">="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstGteN final : public AstNodeBiop { +public: + AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GteN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return ">="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstGteS final : public AstNodeBiop { +public: + AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(GteS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } + virtual string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool signedFlavor() const override { return true; } +}; +class AstLogAnd final : public AstNodeBiop { +public: + AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LogAnd) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogAnd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogAnd(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f&& %r)"; } + virtual string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "&&"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstLogIf final : public AstNodeBiop { +public: + AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LogIf) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogIf(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogIf(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f-> %r)"; } + virtual string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "->"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstLogOr final : public AstNodeBiop { + // LOGOR with optional side effects + // Side effects currently used in some V3Width code + // TBD if this concept is generally adopted for side-effect tracking + // versus V3Const tracking it itself + bool m_sideEffect = false; // Has side effect, relies on short-circuiting +public: + AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LogOr) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogOr(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogOr(lhs, rhs); + } + virtual bool same(const AstNode* samep) const override { + const AstLogOr* const sp = static_cast(samep); + return m_sideEffect == sp->m_sideEffect; + } + virtual void dump(std::ostream& str = std::cout) const override; + virtual string emitVerilog() override { return "%k(%l %f|| %r)"; } + virtual string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "||"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } + virtual bool isPure() const override { return !m_sideEffect; } + void sideEffect(bool flag) { m_sideEffect = flag; } + bool sideEffect() const { return m_sideEffect; } +}; +class AstLt final : public AstNodeBiop { +public: + AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Lt) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLt(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLt(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f< %r)"; } + virtual string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "<"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstLtD final : public AstNodeBiop { +public: + AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LtD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f< %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "<"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstLtN final : public AstNodeBiop { +public: + AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LtN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f< %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "<"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstLtS final : public AstNodeBiop { +public: + AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LtS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f< %r)"; } + virtual string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool signedFlavor() const override { return true; } +}; +class AstLte final : public AstNodeBiop { +public: + AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Lte) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLte(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLte(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } + virtual string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "<="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstLteD final : public AstNodeBiop { +public: + AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LteD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "<="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstLteN final : public AstNodeBiop { +public: + AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LteN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "<="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstLteS final : public AstNodeBiop { +public: + AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LteS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } + virtual string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool signedFlavor() const override { return true; } +}; +class AstModDiv final : public AstNodeBiop { +public: + AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(ModDiv) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstModDiv(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opModDiv(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } + virtual string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } +}; +class AstModDivS final : public AstNodeBiop { +public: + AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(ModDivS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstModDivS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opModDivS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } + virtual string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } + virtual bool signedFlavor() const override { return true; } +}; +class AstNeqWild final : public AstNodeBiop { +public: + AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(NeqWild) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqWild(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opWildNeq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f!=? %r)"; } + virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "!="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstPow final : public AstNodeBiop { +public: + AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Pow) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPow(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPow(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f** %r)"; } + virtual string emitC() override { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } +}; +class AstPowD final : public AstNodeBiop { +public: + AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(PowD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f** %r)"; } + virtual string emitC() override { return "pow(%li,%ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV * 5; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstPowSS final : public AstNodeBiop { +public: + AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(PowSS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowSS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowSS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f** %r)"; } + virtual string emitC() override { + return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; + } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + virtual bool signedFlavor() const override { return true; } +}; +class AstPowSU final : public AstNodeBiop { +public: + AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(PowSU) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowSU(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowSU(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f** %r)"; } + virtual string emitC() override { + return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; + } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + virtual bool signedFlavor() const override { return true; } +}; +class AstPowUS final : public AstNodeBiop { +public: + AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(PowUS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowUS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowUS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f** %r)"; } + virtual string emitC() override { + return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; + } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + virtual bool signedFlavor() const override { return true; } +}; +class AstReplicate final : public AstNodeBiop { + // Also used as a "Uniop" flavor of Concat, e.g. "{a}" + // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() +public: + AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { + if (lhsp) { + if (const AstConst* const constp = VN_CAST(rhsp, Const)) { + dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); + } + } + } + AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) + : AstReplicate(fl, lhsp, new AstConst(fl, repCount)) {} + ASTNODE_NODE_FUNCS(Replicate) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstReplicate(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opRepl(lhs, rhs); + } + virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } + virtual string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } +}; +class AstReplicateN final : public AstNodeBiop { + // String replicate +public: + AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { + dtypeSetString(); + } + AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) + : AstReplicateN(fl, lhsp, new AstConst(fl, repCount)) {} + ASTNODE_NODE_FUNCS(ReplicateN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstReplicateN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opReplN(lhs, rhs); + } + virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } + virtual string emitC() override { return "VL_REPLICATEN_NN%rq(%li, %ri)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } + virtual bool stringFlavor() const override { return true; } +}; +class AstShiftL final : public AstNodeBiop { +public: + AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(ShiftL) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftL(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftL(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<< %r)"; } + virtual string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstShiftR final : public AstNodeBiop { +public: + AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(ShiftR) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftR(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftR(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f>> %r)"; } + virtual string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + // LHS size might be > output size, so don't want to force size + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstShiftRS final : public AstNodeBiop { + // Shift right with sign extension, >>> operator + // Output data type's width determines which bit is used for sign extension +public: + AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { + // Important that widthMin be correct, as opExtend requires it after V3Expand + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); + } + ASTNODE_NODE_FUNCS(ShiftRS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftRS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); + } + virtual string emitVerilog() override { return "%k(%l %f>>> %r)"; } + virtual string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool signedFlavor() const override { return true; } +}; +class AstSub final : public AstNodeBiop { +public: + AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Sub) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstSub(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opSub(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f- %r)"; } + virtual string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "-"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } +}; +class AstSubD final : public AstNodeBiop { +public: + AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(SubD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstSubD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opSubD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f- %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "-"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstURandomRange final : public AstNodeBiop { + // $urandom_range +public: + explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { + dtypeSetUInt32(); // Says IEEE + } + ASTNODE_NODE_FUNCS(URandomRange) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstURandomRange(fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%f$urandom_range(%l, %r)"; } + virtual string emitC() override { return "VL_URANDOM_RANGE_%nq(%li, %ri)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } +}; + +// === AstNodeBiCom === +class AstEq final : public AstNodeBiCom { +public: + AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Eq) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEq(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEq/AstEqD + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f== %r)"; } + virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "=="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstEqCase final : public AstNodeBiCom { +public: + AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(EqCase) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqCase(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCaseEq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f=== %r)"; } + virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "=="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstEqD final : public AstNodeBiCom { +public: + AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(EqD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEqD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f== %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "=="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstEqN final : public AstNodeBiCom { +public: + AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(EqN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEqN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f== %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "=="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; +class AstLogEq final : public AstNodeBiCom { +public: + AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LogEq) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogEq(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogEq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f<-> %r)"; } + virtual string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "<->"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstNeq final : public AstNodeBiCom { +public: + AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(Neq) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeq(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } + virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "!="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstNeqCase final : public AstNodeBiCom { +public: + AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(NeqCase) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqCase(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCaseNeq(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f!== %r)"; } + virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "!="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstNeqD final : public AstNodeBiCom { +public: + AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(NeqD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeqD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "!="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstNeqN final : public AstNodeBiCom { +public: + AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(NeqN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeqN(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "!="; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_STR; } + virtual bool stringFlavor() const override { return true; } +}; + +// === AstNodeBiComAsv === +class AstAdd final : public AstNodeBiComAsv { +public: + AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Add) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAdd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAdd(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } + virtual string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "+"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } +}; +class AstAddD final : public AstNodeBiComAsv { +public: + AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(AddD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAddD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAddD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "+"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstAnd final : public AstNodeBiComAsv { +public: + AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_And(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(And) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAnd(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAnd(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f& %r)"; } + virtual string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "&"; } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstMul final : public AstNodeBiComAsv { +public: + AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Mul) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMul(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMul(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f* %r)"; } + virtual string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "*"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } +}; +class AstMulD final : public AstNodeBiComAsv { +public: + AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(MulD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMulD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMulD(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f* %r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "*"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstMulS final : public AstNodeBiComAsv { +public: + AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(MulS) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMulS(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMulS(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f* %r)"; } + virtual string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } + virtual bool signedFlavor() const override { return true; } +}; +class AstOr final : public AstNodeBiComAsv { +public: + AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Or) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstOr(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opOr(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f| %r)"; } + virtual string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "|"; } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; +class AstXor final : public AstNodeBiComAsv { +public: + AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Xor) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstXor(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opXor(lhs, rhs); + } + virtual string emitVerilog() override { return "%k(%l %f^ %r)"; } + virtual string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } + virtual string emitSimpleOperator() override { return "^"; } + virtual bool cleanOut() const override { return false; } // Lclean && Rclean + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } +}; + +// === AstNodeSel === +class AstArraySel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); + } + } + +public: + AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { + init(fromp); + } + AstArraySel(FileLine* fl, AstNode* fromp, int bit) + : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { + init(fromp); + } + ASTNODE_NODE_FUNCS(ArraySel) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstArraySel(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; /* How can from be a const? */ + } + virtual string emitVerilog() override { return "%k(%l%f[%r])"; } + virtual string emitC() override { return "%li%k[%ri]"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool isGateOptimizable() const override { + return true; + } // esp for V3Const::ifSameAssign + virtual bool isPredictOptimizable() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + // Special operators + // Return base var (or const) nodep dereferences + static AstNode* baseFromp(AstNode* nodep, bool overMembers); +}; +class AstAssocSel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), AssocArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), AssocArrayDType)->subDTypep()); + } + } + +public: + AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { + init(fromp); + } + ASTNODE_NODE_FUNCS(AssocSel) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssocSel(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%k(%l%f[%r])"; } + virtual string emitC() override { return "%li%k[%ri]"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool isGateOptimizable() const override { + return true; + } // esp for V3Const::ifSameAssign + virtual bool isPredictOptimizable() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } +}; +class AstWildcardSel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep()); + } + } + +public: + AstWildcardSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) { + init(fromp); + } + ASTNODE_NODE_FUNCS(WildcardSel) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstWildcardSel{this->fileline(), lhsp, rhsp}; + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%k(%l%f[%r])"; } + virtual string emitC() override { return "%li%k[%ri]"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool isGateOptimizable() const override { + return true; + } // esp for V3Const::ifSameAssign + virtual bool isPredictOptimizable() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } +}; +class AstWordSel final : public AstNodeSel { + // Select a single word from a multi-word wide value +public: + AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { + dtypeSetUInt32(); // Always used on WData arrays so returns edata size + } + ASTNODE_NODE_FUNCS(WordSel) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstWordSel(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { return "%k(%l%f[%r])"; } + virtual string emitC() override { + return "%li[%ri]"; + } // Not %k, as usually it's a small constant rhsp + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeStream === +class AstStreamL final : public AstNodeStream { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +public: + AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(StreamL) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstStreamL(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f{ << %r %k{%l} }"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opStreamL(lhs, rhs); + } + virtual string emitC() override { return "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } +}; +class AstStreamR final : public AstNodeStream { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +public: + AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(StreamR) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstStreamR(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() override { return "%f{ >> %r %k{%l} }"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAssign(lhs); + } + virtual string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } +}; + +// === AstNodeSystemBiop === +class AstAtan2D final : public AstNodeSystemBiop { +public: + AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(Atan2D) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAtan2D(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.setDouble(std::atan2(lhs.toDouble(), rhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$atan2(%l,%r)"; } + virtual string emitC() override { return "atan2(%li,%ri)"; } +}; +class AstHypotD final : public AstNodeSystemBiop { +public: + AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(HypotD) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstHypotD(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.setDouble(std::hypot(lhs.toDouble(), rhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$hypot(%l,%r)"; } + virtual string emitC() override { return "hypot(%li,%ri)"; } +}; + +// === AstNodeQuadop === +class AstCountBits final : public AstNodeQuadop { + // Number of bits set in vector +public: + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), + ctrl1p->cloneTree(false)) {} + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} + ASTNODE_NODE_FUNCS(CountBits) + virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, + const V3Number& ctrl2, const V3Number& ctrl3) override { + out.opCountBits(expr, ctrl1, ctrl2, ctrl3); + } + virtual string emitVerilog() override { return "%f$countbits(%l, %r, %f, %o)"; } + virtual string emitC() override { return ""; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool cleanThs() const override { return true; } + virtual bool cleanFhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } + virtual bool sizeMattersFhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 16; } +}; + +// === AstNodeTermop === +class AstTime final : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit +public: + AstTime(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER_Time(fl) + , m_timeunit{timeunit} { + dtypeSetUInt64(); + } + ASTNODE_NODE_FUNCS(Time) + virtual string emitVerilog() override { return "%f$time"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_TIME; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstTimeD final : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit +public: + AstTimeD(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER_TimeD(fl) + , m_timeunit{timeunit} { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(TimeD) + virtual string emitVerilog() override { return "%f$realtime"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_TIME; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; + +// === AstNodeTriop === +class AstPostAdd final : public AstNodeTriop { + // Post-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} + ASTNODE_NODE_FUNCS(PostAdd) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() override { return "%k(%r++)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool cleanThs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual bool sizeMattersThs() const override { return true; } +}; +class AstPostSub final : public AstNodeTriop { + // Post-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} + ASTNODE_NODE_FUNCS(PostSub) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() override { return "%k(%r--)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool cleanThs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual bool sizeMattersThs() const override { return true; } +}; +class AstPreAdd final : public AstNodeTriop { + // Pre-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} + ASTNODE_NODE_FUNCS(PreAdd) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() override { return "%k(++%r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool cleanThs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual bool sizeMattersThs() const override { return true; } +}; +class AstPreSub final : public AstNodeTriop { + // Pre-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} + ASTNODE_NODE_FUNCS(PreSub) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() override { return "%k(--%r)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return false; } + virtual bool cleanThs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } + virtual bool sizeMattersRhs() const override { return true; } + virtual bool sizeMattersThs() const override { return true; } +}; +class AstPutcN final : public AstNodeTriop { + // Verilog string.putc() +public: + AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) + : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(PutcN) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + out.opPutcN(lhs, rhs, ths); + } + virtual string name() const override { return "putc"; } + virtual string emitVerilog() override { return "%k(%l.putc(%r,%t))"; } + virtual string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool cleanThs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } +}; +class AstSel final : public AstNodeTriop { + // Multiple bit range extraction + // Parents: math|stmt + // Children: varref|arraysel, math, constant math + // Tempting to have an access() style method here as LHS selects are quite + // different, but that doesn't play well with V3Inst and bidirects which don't know direction +private: + VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid + int m_declElWidth; // If a packed array, the number of bits per element +public: + AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) + : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) + , m_declElWidth{1} { + if (VN_IS(widthp, Const)) { + dtypeSetLogicSized(VN_AS(widthp, Const)->toUInt(), VSigning::UNSIGNED); + } + } + AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) + : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) + , m_declElWidth{1} { + dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(Sel) + virtual void dump(std::ostream& str) const override; + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, + const V3Number& width) override { + out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); + } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { + return widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%lw, %P, %li, %ri)" + : isWide() ? "VL_SEL_%nq%lq%rq%tq(%nw,%lw, %P, %li, %ri, %ti)" + : "VL_SEL_%nq%lq%rq%tq(%lw, %P, %li, %ri, %ti)"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool cleanThs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } + virtual bool same(const AstNode*) const override { return true; } + virtual int instrCount() const override { + return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); + } + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression + AstNode* widthp() const { return op3p(); } // op3 = Width + int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); } + int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); } + int msbConst() const { return lsbConst() + widthConst() - 1; } + VNumRange& declRange() { return m_declRange; } + const VNumRange& declRange() const { return m_declRange; } + void declRange(const VNumRange& flag) { m_declRange = flag; } + int declElWidth() const { return m_declElWidth; } + void declElWidth(int flag) { m_declElWidth = flag; } +}; +class AstSliceSel final : public AstNodeTriop { + // Multiple array element extraction + // Parents: math|stmt + // Children: varref|arraysel, math, constant math +private: + VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid +public: + AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) + : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), + new AstConst(fl, declRange.elements())) + , m_declRange{declRange} {} + ASTNODE_NODE_FUNCS(SliceSel) + virtual void dump(std::ostream& str) const override; + virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, + const V3Number& width) override { + V3ERROR_NA; + } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Removed before EmitC + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool cleanRhs() const override { return true; } + virtual bool cleanThs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } + virtual bool same(const AstNode*) const override { return true; } + virtual int instrCount() const override { return 10; } // Removed before matters + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + // For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods + VNumRange& declRange() { return m_declRange; } + const VNumRange& declRange() const { return m_declRange; } + void declRange(const VNumRange& flag) { m_declRange = flag; } +}; +class AstSubstrN final : public AstNodeTriop { + // Verilog string.substr() +public: + AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) + : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(SubstrN) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + out.opSubstrN(lhs, rhs, ths); + } + virtual string name() const override { return "substr"; } + virtual string emitVerilog() override { return "%k(%l.substr(%r,%t))"; } + virtual string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; } + virtual string emitSimpleOperator() override { return ""; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool cleanRhs() const override { return true; } + virtual bool cleanThs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool sizeMattersRhs() const override { return false; } + virtual bool sizeMattersThs() const override { return false; } +}; + +// === AstNodeCond === +class AstCond final : public AstNodeCond { + // Conditional ?: statement + // Parents: MATH + // Children: MATH +public: + AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) + : ASTGEN_SUPER_Cond(fl, condp, expr1p, expr2p) {} + ASTNODE_NODE_FUNCS(Cond) + virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { + return new AstCond(this->fileline(), condp, expr1p, expr2p); + } +}; +class AstCondBound final : public AstNodeCond { + // Conditional ?: statement, specially made for safety checking of array bounds + // Parents: MATH + // Children: MATH +public: + AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) + : ASTGEN_SUPER_CondBound(fl, condp, expr1p, expr2p) {} + ASTNODE_NODE_FUNCS(CondBound) + virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { + return new AstCondBound(this->fileline(), condp, expr1p, expr2p); + } +}; + +// === AstNodeUniop === +class AstAtoN final : public AstNodeUniop { + // string.atoi(), atobin(), atohex(), atooct(), atoireal() +public: + enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; + +private: + const FmtType m_fmt; // Operation type +public: + AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) + : ASTGEN_SUPER_AtoN(fl, lhsp) + , m_fmt{fmt} { + fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(AtoN) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opAtoN(lhs, m_fmt); + } + virtual string name() const override { + switch (m_fmt) { + case ATOI: return "atoi"; + case ATOHEX: return "atohex"; + case ATOOCT: return "atooct"; + case ATOBIN: return "atobin"; + case ATOREAL: return "atoreal"; + default: V3ERROR_NA; + } + } + virtual string emitVerilog() override { return "%l." + name() + "()"; } + virtual string emitC() override { + switch (m_fmt) { + case ATOI: return "VL_ATOI_N(%li, 10)"; + case ATOHEX: return "VL_ATOI_N(%li, 16)"; + case ATOOCT: return "VL_ATOI_N(%li, 8)"; + case ATOBIN: return "VL_ATOI_N(%li, 2)"; + case ATOREAL: return "std::atof(%li.c_str())"; + default: V3ERROR_NA; + } + } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + FmtType format() const { return m_fmt; } +}; +class AstBitsToRealD final : public AstNodeUniop { +public: + AstBitsToRealD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(BitsToRealD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opBitsToRealD(lhs); + } + virtual string emitVerilog() override { return "%f$bitstoreal(%l)"; } + virtual string emitC() override { return "VL_CVT_D_Q(%li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } // Eliminated before matters + virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstCCast final : public AstNodeUniop { + // Cast to C-based data type +private: + int m_size; + +public: + AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) + : ASTGEN_SUPER_CCast(fl, lhsp) { + m_size = setwidth; + if (setwidth) { + if (minwidth == -1) minwidth = setwidth; + dtypeSetLogicUnsized(setwidth, minwidth, VSigning::UNSIGNED); + } + } + AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) + : ASTGEN_SUPER_CCast(fl, lhsp) { + dtypeFrom(typeFromp); + m_size = width(); + } + ASTNODE_NODE_FUNCS(CCast) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } + virtual string emitVerilog() override { return "%f$_CAST(%l)"; } + virtual string emitC() override { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast + virtual bool same(const AstNode* samep) const override { + return size() == static_cast(samep)->size(); + } + virtual void dump(std::ostream& str = std::cout) const override; + // + int size() const { return m_size; } +}; +class AstCLog2 final : public AstNodeUniop { +public: + AstCLog2(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CLog2(fl, lhsp) { + dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(CLog2) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } + virtual string emitVerilog() override { return "%f$clog2(%l)"; } + virtual string emitC() override { return "VL_CLOG2_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 16; } +}; +class AstCountOnes final : public AstNodeUniop { + // Number of bits set in vector +public: + AstCountOnes(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CountOnes(fl, lhsp) {} + ASTNODE_NODE_FUNCS(CountOnes) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opCountOnes(lhs); + } + virtual string emitVerilog() override { return "%f$countones(%l)"; } + virtual string emitC() override { return "VL_COUNTONES_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 16; } +}; +class AstCvtPackString final : public AstNodeUniop { + // Convert to Verilator Packed String (aka verilog "string") +public: + AstCvtPackString(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CvtPackString(fl, lhsp) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(CvtPackString) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + virtual string emitVerilog() override { return "%f$_CAST(%l)"; } + virtual string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstExtend final : public AstNodeUniop { + // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() +public: + AstExtend(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Extend(fl, lhsp) {} + AstExtend(FileLine* fl, AstNode* lhsp, int width) + : ASTGEN_SUPER_Extend(fl, lhsp) { + dtypeSetLogicSized(width, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(Extend) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } + virtual string emitVerilog() override { return "%l"; } + virtual string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { + return false; // Because the EXTEND operator self-casts + } + virtual int instrCount() const override { return 0; } +}; +class AstExtendS final : public AstNodeUniop { + // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() +public: + AstExtendS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ExtendS(fl, lhsp) {} + AstExtendS(FileLine* fl, AstNode* lhsp, int width) + // Important that widthMin be correct, as opExtend requires it after V3Expand + : ASTGEN_SUPER_ExtendS(fl, lhsp) { + dtypeSetLogicSized(width, VSigning::UNSIGNED); + } + ASTNODE_NODE_FUNCS(ExtendS) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opExtendS(lhs, lhsp()->widthMinV()); + } + virtual string emitVerilog() override { return "%l"; } + virtual string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { + return false; // Because the EXTEND operator self-casts + } + virtual int instrCount() const override { return 0; } + virtual bool signedFlavor() const override { return true; } +}; +class AstFEof final : public AstNodeUniop { +public: + AstFEof(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FEof(fl, lhsp) {} + ASTNODE_NODE_FUNCS(FEof) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + virtual string emitVerilog() override { return "%f$feof(%l)"; } + virtual string emitC() override { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 16; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } +}; +class AstFGetC final : public AstNodeUniop { +public: + AstFGetC(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FGetC(fl, lhsp) {} + ASTNODE_NODE_FUNCS(FGetC) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + virtual string emitVerilog() override { return "%f$fgetc(%l)"; } + // Non-existent filehandle returns EOF + virtual string emitC() override { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 64; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } +}; +class AstISToRD final : public AstNodeUniop { + // $itor where lhs is signed +public: + AstISToRD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ISToRD(fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(ISToRD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opISToRD(lhs); } + virtual string emitVerilog() override { return "%f$itor($signed(%l))"; } + virtual string emitC() override { return "VL_ISTOR_D_%lq(%lw, %li)"; } + virtual bool emitCheckMaxWords() override { return true; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstIToRD final : public AstNodeUniop { + // $itor where lhs is unsigned +public: + AstIToRD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IToRD(fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(IToRD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIToRD(lhs); } + virtual string emitVerilog() override { return "%f$itor(%l)"; } + virtual string emitC() override { return "VL_ITOR_D_%lq(%lw, %li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstIsUnbounded final : public AstNodeUniop { + // True if is unmbounded ($) +public: + AstIsUnbounded(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(IsUnbounded) + virtual void numberOperate(V3Number& out, const V3Number&) override { + // Any constant isn't unbounded + out.setZero(); + } + virtual string emitVerilog() override { return "%f$isunbounded(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstIsUnknown final : public AstNodeUniop { + // True if any unknown bits +public: + AstIsUnknown(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IsUnknown(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(IsUnknown) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opIsUnknown(lhs); + } + virtual string emitVerilog() override { return "%f$isunknown(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstLenN final : public AstNodeUniop { + // Length of a string +public: + AstLenN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LenN(fl, lhsp) { + dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(LenN) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); } + virtual string emitVerilog() override { return "%f(%l)"; } + virtual string emitC() override { return "VL_LEN_IN(%li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstLogNot final : public AstNodeUniop { +public: + AstLogNot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LogNot(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(LogNot) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } + virtual string emitVerilog() override { return "%f(! %l)"; } + virtual string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; } + virtual string emitSimpleOperator() override { return "!"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstNegate final : public AstNodeUniop { +public: + AstNegate(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Negate(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Negate) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); } + virtual string emitVerilog() override { return "%f(- %l)"; } + virtual string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; } + virtual string emitSimpleOperator() override { return "-"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } +}; +class AstNegateD final : public AstNodeUniop { +public: + AstNegateD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_NegateD(fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(NegateD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegateD(lhs); } + virtual string emitVerilog() override { return "%f(- %l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { return "-"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } + virtual bool doubleFlavor() const override { return true; } +}; +class AstNot final : public AstNodeUniop { +public: + AstNot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Not(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Not) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); } + virtual string emitVerilog() override { return "%f(~ %l)"; } + virtual string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; } + virtual string emitSimpleOperator() override { return "~"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return true; } +}; +class AstNullCheck final : public AstNodeUniop { + // Return LHS after checking that LHS is non-null + // Children: VarRef or something returning pointer +public: + AstNullCheck(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_NullCheck(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(NullCheck) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + virtual int instrCount() const override { return 1; } // Rarely executes + virtual string emitVerilog() override { return "%l"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual bool same(const AstNode* samep) const override { + return fileline() == samep->fileline(); + } +}; +class AstOneHot final : public AstNodeUniop { + // True if only single bit set in vector +public: + AstOneHot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_OneHot(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(OneHot) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); } + virtual string emitVerilog() override { return "%f$onehot(%l)"; } + virtual string emitC() override { return "VL_ONEHOT_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 4; } +}; +class AstOneHot0 final : public AstNodeUniop { + // True if only single bit, or no bits set in vector +public: + AstOneHot0(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_OneHot0(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(OneHot0) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); } + virtual string emitVerilog() override { return "%f$onehot0(%l)"; } + virtual string emitC() override { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 3; } +}; +class AstRToIRoundS final : public AstNodeUniop { + // Convert real to integer, with arbitrary sized output (not just "integer" format) +public: + AstRToIRoundS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { + dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(RToIRoundS) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opRToIRoundS(lhs); + } + virtual string emitVerilog() override { return "%f$rtoi_rounded(%l)"; } + virtual string emitC() override { + return isWide() ? "VL_RTOIROUND_%nq_D(%nw, %P, %li)" : "VL_RTOIROUND_%nq_D(%li)"; + } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRToIS final : public AstNodeUniop { + // $rtoi(lhs) +public: + AstRToIS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RToIS(fl, lhsp) { + dtypeSetSigned32(); + } + ASTNODE_NODE_FUNCS(RToIS) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); } + virtual string emitVerilog() override { return "%f$rtoi(%l)"; } + virtual string emitC() override { return "VL_RTOI_I_D(%li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } // Eliminated before matters + virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRealToBits final : public AstNodeUniop { +public: + AstRealToBits(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RealToBits(fl, lhsp) { + dtypeSetUInt64(); + } + ASTNODE_NODE_FUNCS(RealToBits) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opRealToBits(lhs); + } + virtual string emitVerilog() override { return "%f$realtobits(%l)"; } + virtual string emitC() override { return "VL_CVT_Q_D(%li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } // Eliminated before matters + virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters + virtual int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRedAnd final : public AstNodeUniop { +public: + AstRedAnd(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedAnd(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(RedAnd) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } + virtual string emitVerilog() override { return "%f(& %l)"; } + virtual string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstRedOr final : public AstNodeUniop { +public: + AstRedOr(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedOr(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(RedOr) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } + virtual string emitVerilog() override { return "%f(| %l)"; } + virtual string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstRedXor final : public AstNodeUniop { +public: + AstRedXor(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedXor(fl, lhsp) { + dtypeSetBit(); + } + ASTNODE_NODE_FUNCS(RedXor) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } + virtual string emitVerilog() override { return "%f(^ %l)"; } + virtual string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { + const int w = lhsp()->width(); + return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16); + } + virtual bool sizeMattersLhs() const override { return false; } + virtual int instrCount() const override { return 1 + V3Number::log2b(width()); } +}; +class AstSigned final : public AstNodeUniop { + // $signed(lhs) +public: + AstSigned(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Signed(fl, lhsp) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTNODE_NODE_FUNCS(Signed) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opAssign(lhs); + out.isSigned(false); + } + virtual string emitVerilog() override { return "%f$signed(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } // Eliminated before matters + virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters + virtual int instrCount() const override { return 0; } +}; +class AstTimeImport final : public AstNodeUniop { + // Take a constant that represents a time and needs conversion based on time units + VTimescale m_timeunit; // Parent module time unit +public: + AstTimeImport(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TimeImport(fl, lhsp) {} + ASTNODE_NODE_FUNCS(TimeImport) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + virtual string emitVerilog() override { return "%l"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } + virtual bool sizeMattersLhs() const override { return false; } + virtual void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstToLowerN final : public AstNodeUniop { + // string.tolower() +public: + AstToLowerN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ToLowerN(fl, lhsp) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(ToLowerN) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opToLowerN(lhs); + } + virtual string emitVerilog() override { return "%l.tolower()"; } + virtual string emitC() override { return "VL_TOLOWER_NN(%li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstToUpperN final : public AstNodeUniop { + // string.toupper() +public: + AstToUpperN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ToUpperN(fl, lhsp) { + dtypeSetString(); + } + ASTNODE_NODE_FUNCS(ToUpperN) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opToUpperN(lhs); + } + virtual string emitVerilog() override { return "%l.toupper()"; } + virtual string emitC() override { return "VL_TOUPPER_NN(%li)"; } + virtual bool cleanOut() const override { return true; } + virtual bool cleanLhs() const override { return true; } + virtual bool sizeMattersLhs() const override { return false; } +}; +class AstUnsigned final : public AstNodeUniop { + // $unsigned(lhs) +public: + AstUnsigned(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Unsigned(fl, lhsp) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTNODE_NODE_FUNCS(Unsigned) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opAssign(lhs); + out.isSigned(false); + } + virtual string emitVerilog() override { return "%f$unsigned(%l)"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return false; } + virtual bool cleanLhs() const override { return false; } // Eliminated before matters + virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters + virtual int instrCount() const override { return 0; } +}; + +// === AstNodeSystemUniop === +class AstAcosD final : public AstNodeSystemUniop { +public: + AstAcosD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AcosD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AcosD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::acos(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$acos(%l)"; } + virtual string emitC() override { return "acos(%li)"; } +}; +class AstAcoshD final : public AstNodeSystemUniop { +public: + AstAcoshD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AcoshD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AcoshD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::acosh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$acosh(%l)"; } + virtual string emitC() override { return "acosh(%li)"; } +}; +class AstAsinD final : public AstNodeSystemUniop { +public: + AstAsinD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AsinD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AsinD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::asin(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$asin(%l)"; } + virtual string emitC() override { return "asin(%li)"; } +}; +class AstAsinhD final : public AstNodeSystemUniop { +public: + AstAsinhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AsinhD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AsinhD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::asinh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$asinh(%l)"; } + virtual string emitC() override { return "asinh(%li)"; } +}; +class AstAtanD final : public AstNodeSystemUniop { +public: + AstAtanD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AtanD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AtanD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::atan(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$atan(%l)"; } + virtual string emitC() override { return "atan(%li)"; } +}; +class AstAtanhD final : public AstNodeSystemUniop { +public: + AstAtanhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AtanhD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(AtanhD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::atanh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$atanh(%l)"; } + virtual string emitC() override { return "atanh(%li)"; } +}; +class AstCeilD final : public AstNodeSystemUniop { +public: + AstCeilD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CeilD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(CeilD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::ceil(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$ceil(%l)"; } + virtual string emitC() override { return "ceil(%li)"; } +}; +class AstCosD final : public AstNodeSystemUniop { +public: + AstCosD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CosD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(CosD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::cos(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$cos(%l)"; } + virtual string emitC() override { return "cos(%li)"; } +}; +class AstCoshD final : public AstNodeSystemUniop { +public: + AstCoshD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CoshD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(CoshD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::cosh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$cosh(%l)"; } + virtual string emitC() override { return "cosh(%li)"; } +}; +class AstExpD final : public AstNodeSystemUniop { +public: + AstExpD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ExpD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(ExpD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::exp(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$exp(%l)"; } + virtual string emitC() override { return "exp(%li)"; } +}; +class AstFloorD final : public AstNodeSystemUniop { +public: + AstFloorD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FloorD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(FloorD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::floor(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$floor(%l)"; } + virtual string emitC() override { return "floor(%li)"; } +}; +class AstLog10D final : public AstNodeSystemUniop { +public: + AstLog10D(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Log10D(fl, lhsp) {} + ASTNODE_NODE_FUNCS(Log10D) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::log10(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$log10(%l)"; } + virtual string emitC() override { return "log10(%li)"; } +}; +class AstLogD final : public AstNodeSystemUniop { +public: + AstLogD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LogD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(LogD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::log(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$ln(%l)"; } + virtual string emitC() override { return "log(%li)"; } +}; +class AstSinD final : public AstNodeSystemUniop { +public: + AstSinD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SinD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(SinD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sin(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$sin(%l)"; } + virtual string emitC() override { return "sin(%li)"; } +}; +class AstSinhD final : public AstNodeSystemUniop { +public: + AstSinhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SinhD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(SinhD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sinh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$sinh(%l)"; } + virtual string emitC() override { return "sinh(%li)"; } +}; +class AstSqrtD final : public AstNodeSystemUniop { +public: + AstSqrtD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SqrtD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(SqrtD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sqrt(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$sqrt(%l)"; } + virtual string emitC() override { return "sqrt(%li)"; } +}; +class AstTanD final : public AstNodeSystemUniop { +public: + AstTanD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TanD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(TanD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::tan(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$tan(%l)"; } + virtual string emitC() override { return "tan(%li)"; } +}; +class AstTanhD final : public AstNodeSystemUniop { +public: + AstTanhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TanhD(fl, lhsp) {} + ASTNODE_NODE_FUNCS(TanhD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::tanh(lhs.toDouble())); + } + virtual string emitVerilog() override { return "%f$tanh(%l)"; } + virtual string emitC() override { return "tanh(%li)"; } +}; + +// === AstNodeVarRef === +class AstVarRef final : public AstNodeVarRef { + // A reference to a variable (lvalue or rvalue) +public: + AstVarRef(FileLine* fl, const string& name, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} + // This form only allowed post-link because output/wire compression may + // lead to deletion of AstVar's + inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access); + // This form only allowed post-link (see above) + inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access); + ASTNODE_NODE_FUNCS(VarRef) + virtual void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override; + inline bool same(const AstVarRef* samep) const; + inline bool sameNoLvalue(AstVarRef* samep) const; + virtual int instrCount() const override { + return widthInstrs() * (access().isReadOrRW() ? INSTR_COUNT_LD : 1); + } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } +}; +class AstVarXRef final : public AstNodeVarRef { + // A VarRef to something in another module before AstScope. + // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope +private: + string m_dotted; // Dotted part of scope the name()'ed reference is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out +public: + AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) + : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) + , m_dotted{dotted} {} + inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access); + ASTNODE_NODE_FUNCS(VarXRef) + virtual void dump(std::ostream& str) const override; + string dotted() const { return m_dotted; } + void dotted(const string& dotted) { m_dotted = dotted; } + string inlinedDots() const { return m_inlinedDots; } + void inlinedDots(const string& flag) { m_inlinedDots = flag; } + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode* samep) const override { + const AstVarXRef* asamep = static_cast(samep); + return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp() + && name() == asamep->name() && dotted() == asamep->dotted()); + } +}; + +#endif // Guard diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h new file mode 100644 index 000000000..b197e18bd --- /dev/null +++ b/src/V3AstNodeOther.h @@ -0,0 +1,4363 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing other constructs +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 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 speficic 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 + // Parents: statement + // Children: statements +private: + 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} { + addNOp1p(stmtsp); + m_unnamed = (name == ""); + } + +public: + ASTNODE_BASE_FUNCS(NodeBlock) + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } // * = Block name + virtual void name(const string& name) override { m_name = name; } + // op1 = Statements + AstNode* stmtsp() const { return op1p(); } // op1 = List of statements + void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + bool unnamed() const { return m_unnamed; } + bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); } +}; +class AstNodeFTask VL_NOT_FINAL : public AstNode { +private: + 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_externProto : 1; // Extern prototype + bool m_externDef : 1; // Extern definition + 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_dpiTraceInit : 1; // DPI trace_init + bool m_isConstructor : 1; // Class constructor + bool m_isHideLocal : 1; // Verilog local + bool m_isHideProtected : 1; // Verilog protected + bool m_pure : 1; // DPI import pure (vs. virtual pure) + bool m_pureVirtual : 1; // Pure virtual + bool m_recursive : 1; // Recusive or part of recursion + bool m_underGenerate : 1; // Under generate (for warning) + bool m_virtual : 1; // Virtual method in class + VLifetime m_lifetime; // Lifetime +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_externProto{false} + , m_externDef{false} + , m_prototype{false} + , m_dpiExport{false} + , m_dpiImport{false} + , m_dpiContext{false} + , m_dpiOpenChild{false} + , m_dpiTask{false} + , m_dpiTraceInit{false} + , m_isConstructor{false} + , m_isHideLocal{false} + , m_isHideProtected{false} + , m_pure{false} + , m_pureVirtual{false} + , m_recursive{false} + , m_underGenerate{false} + , m_virtual{false} { + addNOp3p(stmtsp); + cname(name); // Might be overridden by dpi import/export + } + +public: + ASTNODE_BASE_FUNCS(NodeFTask) + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } // * = Var name + virtual bool maybePointedTo() const override { return true; } + virtual bool isGateOptimizable() const override { + return !((m_dpiExport || m_dpiImport) && !m_pure); + } + // {AstFunc only} op1 = Range output variable + virtual void name(const string& name) override { m_name = name; } + string cname() const { return m_cname; } + void cname(const string& cname) { m_cname = cname; } + // op1 = Output variable (functions only, nullptr for tasks) + AstNode* fvarp() const { return op1p(); } + void addFvarp(AstNode* nodep) { addNOp1p(nodep); } + bool isFunction() const { return fvarp() != nullptr; } + // op2 = Class/package scope + AstNode* classOrPackagep() const { return op2p(); } + void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); } + // op3 = Statements/Ports/Vars + AstNode* stmtsp() const { return op3p(); } // op3 = List of statements + void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } + // op4 = scope name + AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } + // MORE ACCESSORS + void dpiOpenParentInc() { ++m_dpiOpenParent; } + void dpiOpenParentClear() { m_dpiOpenParent = 0; } + uint64_t dpiOpenParent() const { return m_dpiOpenParent; } + void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } + void taskPublic(bool flag) { m_taskPublic = flag; } + bool taskPublic() const { return m_taskPublic; } + void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } + bool attrIsolateAssign() const { return m_attrIsolateAssign; } + void classMethod(bool flag) { m_classMethod = flag; } + bool classMethod() const { return m_classMethod; } + void isExternProto(bool flag) { m_externProto = flag; } + bool isExternProto() const { return m_externProto; } + void isExternDef(bool flag) { m_externDef = flag; } + bool isExternDef() const { return m_externDef; } + void prototype(bool flag) { m_prototype = flag; } + bool prototype() const { return m_prototype; } + void dpiExport(bool flag) { m_dpiExport = flag; } + bool dpiExport() const { return m_dpiExport; } + void dpiImport(bool flag) { m_dpiImport = flag; } + bool dpiImport() const { return m_dpiImport; } + void dpiContext(bool flag) { m_dpiContext = flag; } + bool dpiContext() const { return m_dpiContext; } + void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; } + bool dpiOpenChild() const { return m_dpiOpenChild; } + void dpiTask(bool flag) { m_dpiTask = flag; } + bool dpiTask() const { return m_dpiTask; } + void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } + bool dpiTraceInit() const { return m_dpiTraceInit; } + void isConstructor(bool flag) { m_isConstructor = flag; } + bool isConstructor() const { return m_isConstructor; } + 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 pure(bool flag) { m_pure = flag; } + bool pure() const { return m_pure; } + void pureVirtual(bool flag) { m_pureVirtual = flag; } + bool pureVirtual() const { return m_pureVirtual; } + void recursive(bool flag) { m_recursive = flag; } + bool recursive() const { return m_recursive; } + void underGenerate(bool flag) { m_underGenerate = flag; } + bool underGenerate() const { return m_underGenerate; } + void isVirtual(bool flag) { m_virtual = flag; } + bool isVirtual() const { return m_virtual; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstNodeFile VL_NOT_FINAL : public AstNode { + // Emitted Otput file + // Parents: NETLIST + // Children: AstTextBlock +private: + string m_name; ///< Filename +public: + AstNodeFile(VNType t, FileLine* fl, const string& name) + : AstNode(t, fl) { + m_name = name; + } + ASTNODE_BASE_FUNCS(NodeFile) + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + void tblockp(AstTextBlock* tblockp) { setOp1p((AstNode*)tblockp); } + AstTextBlock* tblockp() { return VN_AS(op1p(), TextBlock); } +}; +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 +private: + 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. + 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_hierBlock : 1; // Hiearchical Block marked by HIER_BLOCK pragma + bool m_internal : 1; // Internally created + bool m_recursive : 1; // Recursive module + bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr + 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 +protected: + AstNodeModule(VNType t, FileLine* fl, const string& name) + : AstNode{t, fl} + , m_name{name} + , m_origName{name} + , m_modPublic{false} + , m_modTrace{false} + , m_inLibrary{false} + , m_dead{false} + , m_hierBlock{false} + , m_internal{false} + , m_recursive{false} + , m_recursiveClone{false} {} + +public: + ASTNODE_BASE_FUNCS(NodeModule) + virtual void dump(std::ostream& str) const override; + virtual bool maybePointedTo() const override { return true; } + virtual string name() const override { return m_name; } + virtual bool timescaleMatters() const = 0; + AstNode* stmtsp() const { return op2p(); } // op2 = List of statements + AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks + // METHODS + void addInlinesp(AstNode* nodep) { addOp1p(nodep); } + void addStmtp(AstNode* nodep) { addNOp2p(nodep); } + void addActivep(AstNode* nodep) { addOp3p(nodep); } + // ACCESSORS + virtual void name(const string& name) override { m_name = name; } + virtual string origName() const override { return m_origName; } + string someInstanceName() const { 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 { return m_level; } + bool isTop() const { return level() == 1; } + void modPublic(bool flag) { m_modPublic = flag; } + bool modPublic() const { return m_modPublic; } + void modTrace(bool flag) { m_modTrace = flag; } + bool modTrace() const { return m_modTrace; } + void dead(bool flag) { m_dead = flag; } + bool dead() const { return m_dead; } + void hierBlock(bool flag) { m_hierBlock = flag; } + bool hierBlock() const { return m_hierBlock; } + void internal(bool flag) { m_internal = flag; } + bool internal() const { return m_internal; } + void recursive(bool flag) { m_recursive = flag; } + bool recursive() const { return m_recursive; } + void recursiveClone(bool flag) { m_recursiveClone = flag; } + bool recursiveClone() const { return m_recursiveClone; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } + void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } + VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } +}; +class AstNodePreSel VL_NOT_FINAL : public AstNode { + // Something that becomes an AstSel +protected: + AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths) + : AstNode{t, fl} { + setOp1p(fromp); + setOp2p(rhs); + setNOp3p(ths); + } + +public: + ASTNODE_BASE_FUNCS(NodePreSel) + AstNode* fromp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + AstNode* thsp() const { return op3p(); } + AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); } + void fromp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + void thsp(AstNode* nodep) { return setOp3p(nodep); } + void attrp(AstAttrOf* nodep) { return setOp4p(reinterpret_cast(nodep)); } + // METHODS + virtual bool same(const AstNode*) const override { return true; } +}; +class AstNodeProcedure VL_NOT_FINAL : public AstNode { + // IEEE procedure: initial, final, always +protected: + AstNodeProcedure(VNType t, FileLine* fl, AstNode* bodysp) + : AstNode{t, fl} { + addNOp2p(bodysp); + } + +public: + ASTNODE_BASE_FUNCS(NodeProcedure) + // METHODS + virtual void dump(std::ostream& str) const override; + AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate + void addStmtp(AstNode* nodep) { addOp2p(nodep); } + bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } +}; +class AstNodeRange VL_NOT_FINAL : public AstNode { + // A range, sized or unsized +protected: + AstNodeRange(VNType t, FileLine* fl) + : AstNode{t, fl} {} + +public: + ASTNODE_BASE_FUNCS(NodeRange) + virtual void dump(std::ostream& str) const override; +}; +class AstNodeStmt VL_NOT_FINAL : public AstNode { + // Statement -- anything that's directly under a function + bool m_statement; // Really a statement (e.g. not a function with return) +protected: + AstNodeStmt(VNType t, FileLine* fl, bool statement = true) + : AstNode{t, fl} + , m_statement{statement} {} + +public: + ASTNODE_BASE_FUNCS(NodeStmt) + // METHODS + bool isStatement() const { return m_statement; } // Really a statement + void statement(bool flag) { m_statement = flag; } + virtual void addNextStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + virtual void addBeforeStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + virtual void dump(std::ostream& str = std::cout) const override; +}; +class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { +protected: + AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, + AstNode* timingControlp = nullptr) + : AstNodeStmt{t, fl} { + setOp1p(rhsp); + setOp2p(lhsp); + addNOp3p(timingControlp); + dtypeFrom(lhsp); + } + +public: + ASTNODE_BASE_FUNCS(NodeAssign) + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; + // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 + AstNode* rhsp() const { return op1p(); } // op1 = Assign from + AstNode* lhsp() const { return op2p(); } // op2 = Assign to + // op3 = Timing controls (delays, event controls) + AstNode* timingControlp() const { return op3p(); } + void addTimingControlp(AstNode* const np) { addNOp3p(np); } + void rhsp(AstNode* np) { setOp1p(np); } + void lhsp(AstNode* np) { setOp2p(np); } + virtual bool hasDType() const override { return true; } + virtual bool cleanRhs() const { return true; } + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode*) const override { return true; } + virtual string verilogKwd() const override { return "="; } + virtual bool brokeLhsMustBeLvalue() const = 0; +}; +class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { + // A call of a C++ function, perhaps a AstCFunc or perhaps globally named + // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. + AstCFunc* m_funcp; + string m_argTypes; + +protected: + AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : AstNodeStmt{t, fl, true} + , m_funcp{funcp} { + addNOp2p(argsp); + } + +public: + ASTNODE_BASE_FUNCS(NodeCCall) + virtual void dump(std::ostream& str = std::cout) const override; + virtual void cloneRelink() override; + virtual const char* broken() const override; + virtual int instrCount() const override { return INSTR_COUNT_CALL; } + virtual bool same(const AstNode* samep) const override { + const AstNodeCCall* const asamep = static_cast(samep); + return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); + } + AstNode* exprsp() const { return op2p(); } // op2 = expressions to print + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override; + virtual bool isOutputter() const override { return !isPure(); } + AstCFunc* funcp() const { return m_funcp; } + void funcp(AstCFunc* funcp) { m_funcp = funcp; } + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } + // op1p reserved for AstCMethodCall + AstNode* argsp() const { return op2p(); } + void addArgsp(AstNode* nodep) { addOp2p(nodep); } +}; +class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { +protected: + AstNodeCase(VNType t, FileLine* fl, AstNode* exprp, AstNode* casesp) + : AstNodeStmt{t, fl} { + setOp1p(exprp); + addNOp2p(casesp); + } + +public: + ASTNODE_BASE_FUNCS(NodeCase) + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + AstNode* exprp() const { return op1p(); } // op1 = case condition + AstCaseItem* itemsp() const { + return VN_AS(op2p(), CaseItem); + } // op2 = list of case expressions + AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's + void addItemsp(AstNode* nodep) { addOp2p(nodep); } + void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } +}; +class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { + // Cover or Assert + // Parents: {statement list} + // Children: expression, report string +private: + const bool m_immediate; // Immediate assertion/cover + string m_name; // Name to report +public: + AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, bool immediate, + const string& name = "") + : AstNodeStmt{t, fl} + , m_immediate{immediate} + , m_name{name} { + addOp1p(propp); + addNOp4p(passsp); + } + ASTNODE_BASE_FUNCS(NodeCoverOrAssert) + virtual string name() const override { return m_name; } // * = Var name + virtual bool same(const AstNode* samep) const override { return samep->name() == name(); } + virtual void name(const string& name) override { m_name = name; } + virtual void dump(std::ostream& str = std::cout) const override; + AstNode* propp() const { return op1p(); } // op1 = property + AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p((AstNode*)sentreep); } // op2 = clock domain + AstNode* passsp() const { return op4p(); } // op4 = statements (assert/cover passes) + bool immediate() const { return m_immediate; } +}; +class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { + // A reference to a task (or function) + // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. +private: + AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + string m_name; // Name of variable + string m_dotted; // Dotted part of scope the name()ed task/func is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out + bool m_pli = false; // Pli system call ($name) +protected: + AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) + : AstNodeStmt{t, fl, statement} { + setOp1p(namep); + addNOp3p(pinsp); + } + AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) + : AstNodeStmt{t, fl, statement} + , m_name{name} { + addNOp3p(pinsp); + } + +public: + ASTNODE_BASE_FUNCS(NodeFTaskRef) + virtual const char* broken() const override; + virtual void cloneRelink() override; + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } // * = Var name + virtual bool isGateOptimizable() const override { + return m_taskp && m_taskp->isGateOptimizable(); + } + string dotted() const { return m_dotted; } // * = Scope name or "" + string inlinedDots() const { return m_inlinedDots; } + void inlinedDots(const string& flag) { m_inlinedDots = flag; } + AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable + void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } + virtual void name(const string& name) override { m_name = name; } + void dotted(const string& name) { m_dotted = name; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + bool pli() const { return m_pli; } + void pli(bool flag) { m_pli = flag; } + // op1 = namep + AstNode* namep() const { return op1p(); } + // op2 = reserved for AstMethodCall + // op3 = Pin interconnection list + AstNode* pinsp() const { return op3p(); } + void addPinsp(AstNode* nodep) { addOp3p(nodep); } + // op4 = scope tracking + AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } + void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } +}; +class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { +protected: + AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, + AstNode* bodysp) + : AstNodeStmt{t, fl} { + addNOp1p(initsp); + setOp2p(condp); + addNOp3p(incsp); + addNOp4p(bodysp); + } + +public: + ASTNODE_BASE_FUNCS(NodeFor) + AstNode* initsp() const { return op1p(); } // op1 = initial statements + AstNode* condp() const { return op2p(); } // op2 = condition to continue + AstNode* incsp() const { return op3p(); } // op3 = increment statements + AstNode* bodysp() const { return op4p(); } // op4 = body of loop + virtual bool isGateOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { +private: + VBranchPred m_branchPred; // Branch prediction as taken/untaken? + bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking +protected: + AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) + : AstNodeStmt{t, fl} { + setOp1p(condp); + addNOp2p(ifsp); + addNOp3p(elsesp); + isBoundsCheck(false); + } + +public: + ASTNODE_BASE_FUNCS(NodeIf) + AstNode* condp() const { return op1p(); } // op1 = condition + AstNode* ifsp() const { return op2p(); } // op2 = list of true statements + AstNode* elsesp() const { return op3p(); } // op3 = list of false statements + void condp(AstNode* newp) { setOp1p(newp); } + void addIfsp(AstNode* newp) { addOp2p(newp); } + void addElsesp(AstNode* newp) { addOp3p(newp); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isGateDedupable() const override { return true; } + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + void branchPred(VBranchPred flag) { m_branchPred = flag; } + VBranchPred branchPred() const { return m_branchPred; } + void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } + bool isBoundsCheck() const { return m_isBoundsCheck; } + bool isFirstInMyListOfStatements(AstNode* n) const override { + return n == ifsp() || n == elsesp(); + } +}; +class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { +private: + const bool m_isHex; // readmemh, not readmemb +public: + AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, + AstNode* lsbp, AstNode* msbp) + : AstNodeStmt(t, fl) + , m_isHex(hex) { + setOp1p(filenamep); + setOp2p(memp); + setNOp3p(lsbp); + setNOp4p(msbp); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* samep) const override { + return isHex() == static_cast(samep)->isHex(); + } + bool isHex() const { return m_isHex; } + AstNode* filenamep() const { return op1p(); } + AstNode* memp() const { return op2p(); } + AstNode* lsbp() const { return op3p(); } + AstNode* msbp() const { return op4p(); } + virtual const char* cFuncPrefixp() const = 0; +}; +class AstNodeText VL_NOT_FINAL : public AstNode { +private: + string m_text; + +protected: + // Node that puts text into the output stream + AstNodeText(VNType t, FileLine* fl, const string& textp) + : AstNode{t, fl} { + m_text = textp; // Copy it + } + +public: + ASTNODE_BASE_FUNCS(NodeText) + virtual void dump(std::ostream& str = std::cout) const override; + virtual bool same(const AstNode* samep) const override { + const AstNodeText* asamep = static_cast(samep); + return text() == asamep->text(); + } + const string& text() const { return m_text; } +}; +class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText { +private: + 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) + : AstNodeText(t, fl, textp) + , m_tracking(tracking) {} + ASTNODE_BASE_FUNCS(NodeSimpleText) + 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 + // Children: SENTREE, statements +private: + string m_name; + AstSenTree* m_sensesp; + +public: + AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) + : ASTGEN_SUPER_Active(fl) { + m_name = name; // Copy it + UASSERT(sensesp, "Sensesp required arg"); + m_sensesp = sensesp; + } + ASTNODE_NODE_FUNCS(Active) + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } + const char* broken() const override; + void cloneRelink() override; + // Statements are broken into pieces, as some must come before others. + void sensesp(AstSenTree* nodep) { m_sensesp = nodep; } + AstSenTree* sensesp() const { return m_sensesp; } + // op1 = Sensitivity tree, if a clocked block in early stages + void sensesStorep(AstSenTree* nodep) { addOp1p((AstNode*)nodep); } + AstSenTree* sensesStorep() const { return VN_AS(op1p(), SenTree); } + // op2 = Combo logic + AstNode* stmtsp() const { return op2p(); } + void addStmtsp(AstNode* nodep) { addOp2p(nodep); } + // METHODS + inline bool hasInitial() const; + inline bool hasSettle() const; + inline bool hasClocked() const; +}; +class AstArg final : public AstNode { + // An argument to a function/task +private: + string m_name; // Pin name, or "" for number based interconnect +public: + AstArg(FileLine* fl, const string& name, AstNode* exprp) + : ASTGEN_SUPER_Arg(fl) + , m_name{name} { + setNOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Arg) + virtual string name() const override { return m_name; } // * = Pin name, ""=go by number + virtual void name(const string& name) override { m_name = name; } + void exprp(AstNode* nodep) { addOp1p(nodep); } + // op1 = Expression connected to pin, nullptr if unconnected + AstNode* exprp() const { return op1p(); } + bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } +}; +class AstAttrOf final : public AstNode { +private: + // Return a value of a attribute, for example a LSB or array LSB of a signal + VAttrType m_attrType; // What sort of extraction +public: + AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) + : ASTGEN_SUPER_AttrOf(fl) { + setNOp1p(fromp); + setNOp2p(dimp); + m_attrType = attrtype; + } + ASTNODE_NODE_FUNCS(AttrOf) + AstNode* fromp() const { return op1p(); } + AstNode* dimp() const { return op2p(); } + VAttrType attrType() const { return m_attrType; } + virtual void dump(std::ostream& str = std::cout) const override; +}; +class AstBind final : public AstNode { + // Parents: MODULE + // Children: CELL +private: + 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"); + addNOp1p(cellsp); + } + ASTNODE_NODE_FUNCS(Bind) + // ACCESSORS + virtual string name() const override { return m_name; } // * = Bind Target name + virtual void name(const string& name) override { m_name = name; } + AstNode* cellsp() const { return op1p(); } // op1 = cells +}; +class AstCFunc final : public AstNode { + // C++ function + // Parents: MODULE/SCOPE + // Children: VAR/statements +private: + AstScope* m_scopep; + 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_ctorInits; // Constructor sub-class inits + 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_isFinal : 1; // This is a function corresponding to a SystemVerilog 'final' block + 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 + 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_pure : 1; // Pure 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 + bool m_dpiTraceInit : 1; // DPI trace_init +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_isFinal = 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; + m_entryPoint = false; + m_pure = false; + m_dpiContext = false; + m_dpiExportDispatcher = false; + m_dpiExportImpl = false; + m_dpiImportPrototype = false; + m_dpiImportWrapper = false; + m_dpiTraceInit = false; + } + ASTNODE_NODE_FUNCS(CFunc) + virtual string name() const override { return m_name; } + const char* broken() const override; + void cloneRelink() override; + virtual bool maybePointedTo() const override { return true; } + virtual void dump(std::ostream& str = std::cout) const override; + virtual bool same(const AstNode* samep) const override { + const AstCFunc* const asamep = static_cast(samep); + return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) + && (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits()) + && isLoose() == asamep->isLoose() + && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); + } + // + virtual void name(const string& name) override { m_name = name; } + virtual int instrCount() const override { + return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0; + } + 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 { 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); } + 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 isFinal() const { return m_isFinal; } + void isFinal(bool flag) { m_isFinal = flag; } + bool slow() const { 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 ctorInits(const string& str) { m_ctorInits = str; } + string ctorInits() const { return m_ctorInits; } + 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; } + bool entryPoint() const { return m_entryPoint; } + void entryPoint(bool flag) { m_entryPoint = flag; } + bool pure() const { return m_pure; } + void pure(bool flag) { m_pure = flag; } + bool dpiContext() const { return m_dpiContext; } + void dpiContext(bool flag) { m_dpiContext = flag; } + bool dpiExportDispatcher() const { 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 { return m_dpiImportPrototype; } + void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; } + bool dpiImportWrapper() const { return m_dpiImportWrapper; } + void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; } + void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } + bool dpiTraceInit() const { return m_dpiTraceInit; } + // + // If adding node accessors, see below emptyBody + AstNode* argsp() const { return op1p(); } + void addArgsp(AstNode* nodep) { addOp1p(nodep); } + AstNode* initsp() const { return op2p(); } + void addInitsp(AstNode* nodep) { addOp2p(nodep); } + AstNode* stmtsp() const { return op3p(); } + void addStmtsp(AstNode* nodep) { addOp3p(nodep); } + AstNode* finalsp() const { return op4p(); } + void addFinalsp(AstNode* nodep) { addOp4p(nodep); } + // Special methods + bool emptyBody() const { + return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr + && finalsp() == nullptr; + } +}; +class AstCUse final : public AstNode { + // C++ use of a class or #include; indicates need of forward declaration + // Parents: NODEMODULE +private: + const VUseType m_useType; // What sort of use this is + const string m_name; + +public: + AstCUse(FileLine* fl, VUseType useType, const string& name) + : ASTGEN_SUPER_CUse(fl) + , m_useType{useType} + , m_name{name} {} + ASTNODE_NODE_FUNCS(CUse) + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } + VUseType useType() const { return m_useType; } +}; +class AstCaseItem final : public AstNode { + // Single item of a case statement + // Parents: CASE + // condsp Children: MATH (Null condition used for default block) + // bodysp Children: Statements +public: + AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) + : ASTGEN_SUPER_CaseItem(fl) { + addNOp1p(condsp); + addNOp2p(bodysp); + } + ASTNODE_NODE_FUNCS(CaseItem) + virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } + AstNode* condsp() const { return op1p(); } // op1 = list of possible matching expressions + AstNode* bodysp() const { return op2p(); } // op2 = what to do + void condsp(AstNode* nodep) { setOp1p(nodep); } + void addBodysp(AstNode* newp) { addOp2p(newp); } + bool isDefault() const { return condsp() == nullptr; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstCast final : public AstNode { + // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc +public: + AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + setOp1p(lhsp); + setOp2p(dtp); + dtypeFrom(dtp); + } + AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + setOp1p(lhsp); + dtypeFrom(dtp); + } + ASTNODE_NODE_FUNCS(Cast) + virtual bool hasDType() const override { return true; } + virtual string emitVerilog() { return "((%d)'(%l))"; } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + AstNode* lhsp() const { return op1p(); } + AstNode* fromp() const { return lhsp(); } + void lhsp(AstNode* nodep) { setOp1p(nodep); } + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* childDTypep() const { return VN_AS(op2p(), NodeDType); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } +}; +class AstCastParse final : public AstNode { + // Cast to appropriate type, where we haven't determined yet what the data type is +public: + AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) + : ASTGEN_SUPER_CastParse(fl) { + setOp1p(lhsp); + setOp2p(dtp); + } + ASTNODE_NODE_FUNCS(CastParse) + virtual string emitVerilog() { return "((%d)'(%l))"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + AstNode* lhsp() const { return op1p(); } + AstNode* dtp() const { return op2p(); } +}; +class AstCastSize final : public AstNode { + // Cast to specific size; signed/twostate inherited from lower element per IEEE +public: + AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) + : ASTGEN_SUPER_CastSize(fl) { + setOp1p(lhsp); + setOp2p((AstNode*)rhsp); + } + ASTNODE_NODE_FUNCS(CastSize) + // No hasDType because widthing removes this node before the hasDType check + virtual string emitVerilog() { return "((%r)'(%l))"; } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } +}; +class AstCell final : public AstNode { + // A instantiation cell or interface call (don't know which until link) +private: + 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 + AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced + 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} { + addNOp1p((AstNode*)pinsp); + addNOp2p((AstNode*)paramsp); + setNOp3p((AstNode*)rangep); + } + ASTNODE_NODE_FUNCS(Cell) + // No cloneRelink, we presume cloneee's want the same module linkages + virtual void dump(std::ostream& str) const override; + const char* broken() const override; + virtual bool maybePointedTo() const override { return true; } + // ACCESSORS + virtual string name() const override { return m_name; } // * = Cell name + virtual void name(const string& name) override { m_name = name; } + virtual 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; } + AstPin* pinsp() const { return VN_AS(op1p(), Pin); } // op1 = List of cell ports + // op2 = List of parameter #(##) values + AstPin* paramsp() const { return VN_AS(op2p(), Pin); } + // op3 = Range of arrayed instants (nullptr=not ranged) + AstRange* rangep() const { return VN_AS(op3p(), Range); } + // op4 = List of interface references + AstIntfRef* intfRefp() const { return VN_AS(op4p(), IntfRef); } + AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated + void addPinsp(AstPin* nodep) { addOp1p((AstNode*)nodep); } + void addParamsp(AstPin* nodep) { addOp2p((AstNode*)nodep); } + void addIntfRefp(AstIntfRef* nodep) { addOp4p((AstNode*)nodep); } + 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 AstCellArrayRef final : public AstNode { + // As-of-yet unlinkable reference into an array of cells +private: + string m_name; // Array name +public: + AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) + : ASTGEN_SUPER_CellArrayRef(fl) + , m_name{name} { + addNOp1p(selectExprp); + } + ASTNODE_NODE_FUNCS(CellArrayRef) + // ACCESSORS + virtual string name() const override { return m_name; } // * = Array name + AstNode* selp() const { return op1p(); } // op1 = Select expression +}; +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 +private: + string m_name; // Cell name, possibly {a}__DOT__{b}... + const string + m_origModName; // Original name of the module, ignoring name() changes, for dot lookup + AstScope* m_scopep = nullptr; // The scope that the cell is inlined into + 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} {} + ASTNODE_NODE_FUNCS(CellInline) + virtual void dump(std::ostream& str) const override; + const char* broken() const override; + // ACCESSORS + virtual string name() const override { return m_name; } // * = Cell name + string origModName() const { return m_origModName; } // * = modp()->origName() before inlining + virtual void name(const string& name) override { m_name = name; } + void scopep(AstScope* scp) { m_scopep = scp; } + AstScope* scopep() const { return m_scopep; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstCellRef final : public AstNode { + // As-of-yet unlinkable reference into a cell +private: + string m_name; // Cell name +public: + AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) + : ASTGEN_SUPER_CellRef(fl) + , m_name{name} { + addNOp1p(cellp); + addNOp2p(exprp); + } + ASTNODE_NODE_FUNCS(CellRef) + // ACCESSORS + virtual string name() const override { return m_name; } // * = Array name + AstNode* cellp() const { return op1p(); } // op1 = Cell + AstNode* exprp() const { return op2p(); } // op2 = Expression +}; +class AstClassExtends final : public AstNode { + // Children: List of AstParseRef for packages/classes + // during early parse, then moves to dtype +public: + AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) + : ASTGEN_SUPER_ClassExtends(fl) { + setNOp2p(classOrPkgsp); // Only for parser + } + ASTNODE_NODE_FUNCS(ClassExtends) + virtual bool hasDType() const override { return true; } + virtual string verilogKwd() const override { return "extends"; } + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + AstNode* classOrPkgsp() const { return op2p(); } + AstClass* classp() const; // Class being extended (after link) +}; +class AstClassOrPackageRef final : public AstNode { +private: + string m_name; + // Node not NodeModule to appease some early parser usage + AstNode* m_classOrPackageNodep; // Package hierarchy +public: + AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, + AstNode* paramsp) + : ASTGEN_SUPER_ClassOrPackageRef(fl) + , m_name{name} + , m_classOrPackageNodep{classOrPackageNodep} { + addNOp4p(paramsp); + } + ASTNODE_NODE_FUNCS(ClassOrPackageRef) + // METHODS + virtual const char* broken() const override { + BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { + if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) { + m_classOrPackageNodep = m_classOrPackageNodep->clonep(); + } + } + virtual bool same(const AstNode* samep) const override { + return (m_classOrPackageNodep + == static_cast(samep)->m_classOrPackageNodep); + } + virtual void dump(std::ostream& str = std::cout) const override; + virtual string name() const override { return m_name; } // * = Var name + AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } + void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } + AstNodeModule* classOrPackagep() const; + AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = (AstNode*)nodep; } + AstPin* paramsp() const { return VN_AS(op4p(), Pin); } +}; +class AstClocking final : public AstNode { + // Set default clock region + // Parents: MODULE + // Children: Assertions +public: + AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_Clocking(fl) { + addOp1p((AstNode*)sensesp); + addNOp2p(bodysp); + } + ASTNODE_NODE_FUNCS(Clocking) + // op1 = Sensitivity list + AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } + AstNode* bodysp() const { return op2p(); } // op2 = Body +}; +class AstConstPool final : public AstNode { + // Container for const static data + std::unordered_multimap m_tables; // Constant tables (unpacked arrays) + std::unordered_multimap m_consts; // Constant tables (scalars) + AstModule* const m_modp; // The Module holding the Scope below ... + AstScope* const m_scopep; // Scope holding the constant variables + + AstVarScope* createNewEntry(const string& name, AstNode* initp); + +public: + explicit AstConstPool(FileLine* fl); + ASTNODE_NODE_FUNCS(ConstPool) + virtual bool maybePointedTo() const override { return true; } + const char* broken() const override; + virtual 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 AstDefParam final : public AstNode { + // A defparam assignment + // Parents: MODULE + // Children: math +private: + 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, AstNode* rhsp) + : ASTGEN_SUPER_DefParam(fl) { + setOp1p(rhsp); + m_name = name; + m_path = path; + } + virtual string name() const override { return m_name; } // * = Scope name + ASTNODE_NODE_FUNCS(DefParam) + virtual bool same(const AstNode*) const override { return true; } + AstNode* rhsp() const { return op1p(); } // op1 = Assign from + string path() const { return m_path; } +}; +class AstDot final : public AstNode { + // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef + // These are eliminated in the link stage + const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) +public: + AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Dot(fl) + , m_colon{colon} { + setOp1p(lhsp); + setOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(Dot) + // For parser, make only if non-null package + static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { + if (!packageOrClassp) return rhsp; + return new AstDot(fl, true, packageOrClassp, rhsp); + } + virtual void dump(std::ostream& str) const override; + AstNode* lhsp() const { return op1p(); } + void rhsp(AstNode* nodep) { setOp2p(nodep); } + AstNode* rhsp() const { return op2p(); } + bool colon() const { return m_colon; } +}; +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) +private: + 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} {} + ASTNODE_NODE_FUNCS(DpiExport) + virtual string name() const override { return m_name; } + virtual 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 + // Children: SFORMATF to generate print string +private: + VDisplayType m_displayType; + +public: + inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp); + ASTNODE_NODE_FUNCS(ElabDisplay) + virtual const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + virtual string verilogKwd() const override { + return (string("$") + string(displayType().ascii())); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* samep) const override { + return displayType() == static_cast(samep)->displayType(); + } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + VDisplayType displayType() const { return m_displayType; } + void displayType(VDisplayType type) { m_displayType = type; } + void fmtp(AstSFormatF* nodep) { addOp1p((AstNode*)nodep); } // op1 = To-String formatter + AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } +}; +class AstEmpty final : public AstNode { + // Represents something missing, e.g. a missing argument in FOREACH +public: + explicit AstEmpty(FileLine* fl) + : ASTGEN_SUPER_Empty(fl) {} + ASTNODE_NODE_FUNCS(Empty) + virtual bool same(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. +private: + 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); + ASTNODE_NODE_FUNCS_NO_DTOR(ExecGraph) + virtual ~AstExecGraph() override; + virtual const char* broken() const override { + BROKEN_RTN(!m_depGraphp); + return nullptr; + } + virtual string name() const override { return m_name; } + V3Graph* depGraphp() { return m_depGraphp; } + const V3Graph* depGraphp() const { return m_depGraphp; } + // op1: The mtask bodies + AstMTaskBody* mTaskBodiesp() const { return VN_AS(op1p(), MTaskBody); } + void addMTaskBodyp(AstMTaskBody* bodyp) { addOp1p((AstNode*)bodyp); } + // op2: In later phases, the statements that start the parallel execution + void addStmtsp(AstNode* stmtp) { addOp2p(stmtp); } +}; +class AstImplicit final : public AstNode { + // Create implicit wires and do nothing else, for gates that are ignored + // Parents: MODULE +public: + AstImplicit(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_Implicit(fl) { + addNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(Implicit) + AstNode* exprsp() const { return op1p(); } // op1 = Assign from +}; +class AstInitArray final : public AstNode { + // Set a var to a map of values + // The list of initsp() is not relevant + // If default is specified, the vector may be sparse, and not provide each value. + // Key values are C++ array style, with lo() at index 0 + // Parents: ASTVAR::init() + // Children: AstInitItem +public: + using KeyItemMap = std::map; + +private: + KeyItemMap m_map; // Node value for each array index +public: + AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp) + : ASTGEN_SUPER_InitArray(fl) { + dtypep(newDTypep); + addNOp1p(defaultp); + } + ASTNODE_NODE_FUNCS(InitArray) + virtual void dump(std::ostream& str) const override; + const char* broken() const override; + void cloneRelink() override; + virtual bool hasDType() const override { return true; } + virtual bool same(const AstNode* samep) const override { + // Only works if exact same children, instead should override comparison + // of children list, and instead use map-vs-map key/value compare + return m_map == static_cast(samep)->m_map; + } + AstNode* defaultp() const { return op1p(); } // op1 = Default if sparse + void defaultp(AstNode* newp) { setOp1p(newp); } + AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions + void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); } + const KeyItemMap& map() const { return m_map; } + AstNode* addIndexValuep(uint64_t index, AstNode* newp); + AstNode* getIndexValuep(uint64_t index) const; + AstNode* getIndexDefaultedValuep(uint64_t index) const; +}; +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) +public: + // Parents: INITARRAY + AstInitItem(FileLine* fl, AstNode* valuep) + : ASTGEN_SUPER_InitItem(fl) { + addOp1p(valuep); + } + ASTNODE_NODE_FUNCS(InitItem) + virtual bool maybePointedTo() const override { return true; } + virtual bool hasDType() const override { return false; } // See valuep()'s dtype instead + AstNode* valuep() const { return op1p(); } // op1 = Value + void valuep(AstNode* nodep) { addOp1p(nodep); } +}; +class AstIntfRef final : public AstNode { + // An interface reference +private: + string m_name; // Name of the reference +public: + AstIntfRef(FileLine* fl, const string& name) + : ASTGEN_SUPER_IntfRef(fl) + , m_name{name} {} + virtual string name() const override { return m_name; } + ASTNODE_NODE_FUNCS(IntfRef) +}; +class AstMTaskBody final : public AstNode { + // Hold statements for each MTask +private: + ExecMTask* m_execMTaskp = nullptr; + +public: + explicit AstMTaskBody(FileLine* fl) + : ASTGEN_SUPER_MTaskBody(fl) {} + ASTNODE_NODE_FUNCS(MTaskBody); + virtual const char* broken() const override { + BROKEN_RTN(!m_execMTaskp); + return nullptr; + } + AstNode* stmtsp() const { return op1p(); } + void addStmtsp(AstNode* nodep) { addOp1p(nodep); } + 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; } + virtual void dump(std::ostream& str = std::cout) const override; +}; +class AstModport final : public AstNode { + // A modport in an interface +private: + string m_name; // Name of the modport +public: + AstModport(FileLine* fl, const string& name, AstNode* varsp) + : ASTGEN_SUPER_Modport(fl) + , m_name{name} { + addNOp1p(varsp); + } + virtual string name() const override { return m_name; } + virtual bool maybePointedTo() const override { return true; } + ASTNODE_NODE_FUNCS(Modport) + AstNode* varsp() const { return op1p(); } // op1 = List of Vars +}; +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 +private: + string m_name; // Name of the variable referenced + bool m_export; // Type of the function (import/export) + AstNodeFTask* m_ftaskp = nullptr; // Link to the function +public: + AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) + : ASTGEN_SUPER_ModportFTaskRef(fl) + , m_name{name} + , m_export{isExport} {} + ASTNODE_NODE_FUNCS(ModportFTaskRef) + const char* broken() const override; + void cloneRelink() override; + virtual void dump(std::ostream& str) const override; + virtual string name() const override { 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 +private: + string m_name; // Name of the variable referenced + VDirection m_direction; // Direction of the variable (in/out) + AstVar* m_varp = nullptr; // Link to the actual Var +public: + AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) + : ASTGEN_SUPER_ModportVarRef(fl) + , m_name{name} + , m_direction{direction} {} + ASTNODE_NODE_FUNCS(ModportVarRef) + const char* broken() const override; + void cloneRelink() override; + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } + void direction(const VDirection& flag) { m_direction = flag; } + VDirection direction() const { return m_direction; } + AstVar* varp() const { 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 +private: + AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup + AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup + AstPackage* m_dollarUnitPkgp = nullptr; // $unit + AstCFunc* m_evalp = nullptr; // The '_eval' function + AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable + AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module + VTimescale m_timeunit; // Global time unit + VTimescale m_timeprecision; // Global time precision + bool m_changeRequest = false; // Have _change_request method + bool m_timescaleSpecified = false; // Input HDL specified timescale + uint32_t m_nextFreeMTaskID = 1; // Next unique MTask ID within netlist + // starts at 1 so 0 means no MTask ID + uint32_t m_nextFreeMTaskProfilingID = 0; // Next unique ID to use for PGO +public: + AstNetlist(); + ASTNODE_NODE_FUNCS(Netlist) + const char* broken() const override; + virtual void cloneRelink() override { V3ERROR_NA; } + virtual string name() const override { return "$root"; } + virtual void dump(std::ostream& str) const override; + AstNodeModule* modulesp() const { // op1 = List of modules + return VN_AS(op1p(), NodeModule); + } + AstNodeModule* topModulep() const { // Top module in hierarchy + return modulesp(); // First one in the list, for now + } + void addModulep(AstNodeModule* modulep) { addOp1p((AstNode*)modulep); } + AstNodeFile* filesp() const { return VN_AS(op2p(), NodeFile); } // op2 = List of files + void addFilesp(AstNodeFile* filep) { addOp2p((AstNode*)filep); } + void addMiscsp(AstNode* nodep) { addOp3p(nodep); } + AstTypeTable* typeTablep() { return m_typeTablep; } + void changeRequest(bool specified) { m_changeRequest = specified; } + bool changeRequest() const { return m_changeRequest; } + AstConstPool* constPoolp() { return m_constPoolp; } + AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; } + AstPackage* dollarUnitPkgAddp(); + AstCFunc* evalp() const { return m_evalp; } + void evalp(AstCFunc* evalp) { m_evalp = evalp; } + AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; } + void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } + 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; } + uint32_t allocNextMTaskID() { return m_nextFreeMTaskID++; } + uint32_t allocNextMTaskProfilingID() { return m_nextFreeMTaskProfilingID++; } + uint32_t usedMTaskProfilingIDs() const { return m_nextFreeMTaskProfilingID; } +}; +class AstPackageExport final : public AstNode { +private: + // A package export declaration + string m_name; + AstPackage* m_packagep; // Package hierarchy +public: + AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) + : ASTGEN_SUPER_PackageExport(fl) + , m_name{name} + , m_packagep{packagep} {} + ASTNODE_NODE_FUNCS(PackageExport) + const char* broken() const override; + void cloneRelink() override; + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep = nodep; } +}; +class AstPackageExportStarStar final : public AstNode { + // A package export *::* declaration +public: + // cppcheck-suppress noExplicitConstructor + AstPackageExportStarStar(FileLine* fl) + : ASTGEN_SUPER_PackageExportStarStar(fl) {} + ASTNODE_NODE_FUNCS(PackageExportStarStar) +}; +class AstPackageImport final : public AstNode { +private: + // A package import declaration + string m_name; + AstPackage* m_packagep; // Package hierarchy +public: + AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) + : ASTGEN_SUPER_PackageImport(fl) + , m_name{name} + , m_packagep{packagep} {} + ASTNODE_NODE_FUNCS(PackageImport) + const char* broken() const override; + void cloneRelink() override; + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep = nodep; } +}; +class AstParseRef final : public AstNode { + // A reference to a variable, function or task + // We don't know which at parse time due to bison constraints + // The link stages will replace this with AstVarRef, or AstTaskRef, etc. + // Parents: math|stmt + // Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel) +private: + VParseRefExp m_expect; // Type we think it should resolve to + string m_name; + +public: + AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, + AstNodeFTaskRef* ftaskrefp = nullptr) + : ASTGEN_SUPER_ParseRef(fl) + , m_expect{expect} + , m_name{name} { + setNOp1p(lhsp); + setNOp2p((AstNode*)ftaskrefp); + } + ASTNODE_NODE_FUNCS(ParseRef) + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } // * = Var name + virtual bool same(const AstNode* samep) const override { + const AstParseRef* const asamep = static_cast(samep); + return (expect() == asamep->expect() && m_name == asamep->m_name); + } + virtual void name(const string& name) override { m_name = name; } + VParseRefExp expect() const { return m_expect; } + void expect(VParseRefExp exp) { m_expect = exp; } + // op1 = Components + AstNode* lhsp() const { return op1p(); } // op1 = List of statements + AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference + // op2 = Function/task reference + void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstPin final : public AstNode { + // A pin on a cell +private: + int m_pinNum; // Pin number + string m_name; // Pin name, or "" for number based interconnect + AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule. + AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule. + bool m_param = false; // Pin connects to parameter + bool m_svImplicit = false; // Pin is SystemVerilog .name'ed +public: + AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) + : ASTGEN_SUPER_Pin(fl) + , m_pinNum{pinNum} + , m_name{name} { + setNOp1p(exprp); + } + inline AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp); + ASTNODE_NODE_FUNCS(Pin) + virtual void dump(std::ostream& str) const override; + const char* broken() const override; + virtual string name() const override { return m_name; } // * = Pin name, ""=go by number + virtual 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; } + void exprp(AstNode* nodep) { addOp1p(nodep); } + // op1 = Expression connected to pin, nullptr if unconnected + AstNode* exprp() const { return op1p(); } + 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 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 +private: + int m_pinNum; // Pin number + 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} {} + ASTNODE_NODE_FUNCS(Port) + virtual string name() const override { return m_name; } // * = Port name + int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation + AstNode* exprp() const { return op1p(); } // op1 = Expression connected to port +}; +class AstPragma final : public AstNode { +private: + const VPragmaType m_pragType; // Type of pragma +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} {} + ASTNODE_NODE_FUNCS(Pragma) + VPragmaType pragType() const { return m_pragType; } // *=type of the pragma + virtual bool isPredictOptimizable() const override { return false; } + virtual bool same(const AstNode* samep) const override { + return pragType() == static_cast(samep)->pragType(); + } +}; +class AstPropClocked final : public AstNode { + // A clocked property + // Parents: ASSERT|COVER (property) + // Children: SENITEM, Properties +public: + AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) + : ASTGEN_SUPER_PropClocked(fl) { + addNOp1p((AstNode*)sensesp); + addNOp2p(disablep); + addOp3p(propp); + } + ASTNODE_NODE_FUNCS(PropClocked) + virtual bool hasDType() const override { + return true; + } // Used under Cover, which expects a bool child + AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } // op1 = Sensitivity list + AstNode* disablep() const { return op2p(); } // op2 = disable + AstNode* propp() const { return op3p(); } // op3 = property +}; +class AstPull final : public AstNode { +private: + bool m_direction; + +public: + AstPull(FileLine* fl, AstNode* lhsp, bool direction) + : ASTGEN_SUPER_Pull(fl) { + setOp1p(lhsp); + m_direction = direction; + } + ASTNODE_NODE_FUNCS(Pull) + virtual bool same(const AstNode* samep) const override { + return direction() == static_cast(samep)->direction(); + } + void lhsp(AstNode* np) { setOp1p(np); } + AstNode* lhsp() const { return op1p(); } // op1 = Assign to + uint32_t direction() const { return (uint32_t)m_direction; } +}; +class AstSFormatF final : public AstNode { + // Convert format to string, generally under an AstDisplay or AstSFormat + // Also used as "real" function for /*verilator sformat*/ functions + string m_text; + const bool m_hidden; // Under display, etc + bool m_hasFormat; // Has format code + const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' + VTimescale m_timeunit; // Parent module time unit +public: + class NoFormat {}; + AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_SFormatF(fl) + , m_text{text} + , m_hidden{hidden} + , m_hasFormat{true} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addNOp1p(exprsp); + addNOp2p(nullptr); + } + AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', + bool hidden = true) + : ASTGEN_SUPER_SFormatF(fl) + , m_text{""} + , m_hidden{hidden} + , m_hasFormat{false} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addNOp1p(exprsp); + addNOp2p(nullptr); + } + ASTNODE_NODE_FUNCS(SFormatF) + virtual string name() const override { return m_text; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool hasDType() const override { return true; } + virtual bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + virtual string verilogKwd() const override { return "$sformatf"; } + void addExprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output + AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } + AstScopeName* scopeNamep() const { return VN_AS(op2p(), ScopeName); } + void scopeNamep(AstNode* nodep) { setNOp2p(nodep); } + bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive + return (name().find("%m") != string::npos || name().find("%M") != string::npos); + } + bool hidden() const { return m_hidden; } + void hasFormat(bool flag) { m_hasFormat = flag; } + bool hasFormat() const { return m_hasFormat; } + char missingArgChar() const { return m_missingArgChar; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstScope final : public AstNode { + // A particular usage of a cell + // Parents: MODULE + // Children: NODEBLOCK +private: + // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope + string m_name; // Name + AstScope* const m_aboveScopep; // Scope above this one in the hierarchy (nullptr if top) + AstCell* const m_aboveCellp; // Cell above this in the hierarchy (nullptr if top) + AstNodeModule* const m_modp; // Module scope corresponds to +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} {} + ASTNODE_NODE_FUNCS(Scope) + virtual void cloneRelink() override; + virtual const char* broken() const override; + virtual bool maybePointedTo() const override { return true; } + virtual string name() const override { return m_name; } // * = Scope name + virtual void name(const string& name) override { m_name = name; } + virtual void dump(std::ostream& str) const override; + string nameDotless() const; + string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } + AstNodeModule* modp() const { return m_modp; } + void addVarp(AstVarScope* nodep) { addOp1p((AstNode*)nodep); } + AstVarScope* varsp() const { return VN_AS(op1p(), VarScope); } // op1 = AstVarScope's + void addActivep(AstNode* nodep) { addOp2p(nodep); } + AstNode* blocksp() const { return op2p(); } // op2 = Block names + void addFinalClkp(AstNode* nodep) { addOp3p(nodep); } + AstNode* finalClksp() const { return op3p(); } // op3 = Final assigns for clock correction + AstScope* aboveScopep() const { return m_aboveScopep; } + AstCell* aboveCellp() const { return m_aboveCellp; } + bool isTop() const { return aboveScopep() == nullptr; } // At top of hierarchy +}; +class AstSelLoopVars final : public AstNode { + // Parser only concept "[id, id, id]" for a foreach statement + // Unlike normal selects elements is a list +public: + AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) + : ASTGEN_SUPER_SelLoopVars(fl) { + setOp1p(fromp); + addNOp2p(elementsp); + } + ASTNODE_NODE_FUNCS(SelLoopVars) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual bool maybePointedTo() const override { return false; } + AstNode* fromp() const { return op1p(); } + void fromp(AstNode* nodep) { setOp1p(nodep); } + AstNode* elementsp() const { return op2p(); } +}; +class AstSenItem final : public AstNode { + // Parents: SENTREE + // Children: (optional) VARREF +private: + VEdgeType m_edgeType; // Edge type +public: + class Combo {}; // for creator type-overload selection + class Illegal {}; // for creator type-overload selection + class Initial {}; // for creator type-overload selection + class Settle {}; // for creator type-overload selection + class Never {}; // for creator type-overload selection + AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{edgeType} { + setOp1p(varrefp); + } + AstSenItem(FileLine* fl, Combo) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_COMBO} {} + AstSenItem(FileLine* fl, Illegal) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_ILLEGAL} {} + AstSenItem(FileLine* fl, Initial) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_INITIAL} {} + AstSenItem(FileLine* fl, Settle) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_SETTLE} {} + AstSenItem(FileLine* fl, Never) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_NEVER} {} + ASTNODE_NODE_FUNCS(SenItem) + virtual void dump(std::ostream& str) const override; + virtual bool same(const AstNode* samep) const override { + return edgeType() == static_cast(samep)->edgeType(); + } + VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge + void edgeType(VEdgeType type) { + m_edgeType = type; + editCountInc(); + } // * = Posedge/negedge + AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized + AstNodeVarRef* varrefp() const { + return VN_CAST(op1p(), NodeVarRef); + } // op1 = Signal sensitized + // + bool isClocked() const { return edgeType().clockedStmt(); } + bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } + bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } + bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } + bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } + bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } + bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } +}; +class AstSenTree final : public AstNode { + // A list of senitems + // Parents: MODULE | SBLOCK + // Children: SENITEM list +private: + bool m_multi = false; // Created from combo logic by ORing multiple clock domains +public: + AstSenTree(FileLine* fl, AstSenItem* sensesp) + : ASTGEN_SUPER_SenTree(fl) { + addNOp1p(sensesp); + } + ASTNODE_NODE_FUNCS(SenTree) + virtual void dump(std::ostream& str) const override; + virtual bool maybePointedTo() const override { return true; } + bool isMulti() const { return m_multi; } + // op1 = Sensitivity list + AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } + void addSensesp(AstSenItem* nodep) { addOp1p(nodep); } + void multi(bool flag) { m_multi = true; } + // METHODS + bool hasClocked() const; // Includes a clocked statement + bool hasSettle() const; // Includes a SETTLE SenItem + bool hasInitial() const; // Includes a INITIAL SenItem + bool hasCombo() const; // Includes a COMBO 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) {} + ASTNODE_NODE_FUNCS(SplitPlaceholder) +}; +class AstStrengthSpec final : public AstNode { +private: + 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} {} + + ASTNODE_NODE_FUNCS(StrengthSpec) + VStrength strength0() { return m_s0; } + VStrength strength1() { return m_s1; } + virtual void dump(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). + // Parent: Top level AstModule + // Children: AstSenTree, AstScope + friend class AstNetlist; // Only the AstNetlist can create one + AstTopScope(FileLine* fl, AstScope* ascopep) + : ASTGEN_SUPER_TopScope(fl) { + addOp2p(ascopep); + } + +public: + ASTNODE_NODE_FUNCS(TopScope) + virtual bool maybePointedTo() const override { return true; } + AstSenTree* senTreesp() const { return VN_AS(op1p(), SenTree); } + void addSenTreep(AstSenTree* nodep) { addOp1p((AstNode*)nodep); } + AstScope* scopep() const { return VN_AS(op2p(), Scope); } +}; +class AstTypeTable final : public AstNode { + // Container for hash of standard data types + // Children: NODEDTYPEs + AstEmptyQueueDType* m_emptyQueuep = nullptr; + AstQueueDType* m_queueIndexp = nullptr; + AstVoidDType* m_voidp = nullptr; + AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{}; + // + using DetailedMap = std::map; + DetailedMap m_detailedMap; + +public: + explicit AstTypeTable(FileLine* fl); + ASTNODE_NODE_FUNCS(TypeTable) + virtual bool maybePointedTo() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(m_emptyQueuep && !m_emptyQueuep->brokeExists()); + BROKEN_RTN(m_queueIndexp && !m_queueIndexp->brokeExists()); + BROKEN_RTN(m_voidp && !m_voidp->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { V3ERROR_NA; } + AstNodeDType* typesp() const { return VN_AS(op1p(), NodeDType); } // op1 = List of dtypes + void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); } + 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); + AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl); + AstQueueDType* findQueueIndexDType(FileLine* fl); + AstVoidDType* findVoidDType(FileLine* fl); + void clearCache(); + void repairCache(); + virtual void dump(std::ostream& str = std::cout) const override; +}; +class AstTypedef final : public AstNode { +private: + string m_name; + bool m_attrPublic; + string m_tag; // Holds the string of the verilator tag -- used in XML output. +public: + AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_Typedef(fl) + , m_name{name} { + childDTypep(dtp); // Only for parser + addAttrsp(attrsp); + dtypep(nullptr); // V3Width will resolve + m_attrPublic = false; + } + ASTNODE_NODE_FUNCS(Typedef) + virtual void dump(std::ostream& str) const override; + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Type assigning to + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } + AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse + // METHODS + virtual string name() const override { return m_name; } + virtual bool maybePointedTo() const override { return true; } + virtual bool hasDType() const override { return true; } + virtual void name(const string& flag) override { m_name = flag; } + bool attrPublic() const { return m_attrPublic; } + void attrPublic(bool flag) { m_attrPublic = flag; } + virtual void tag(const string& text) override { m_tag = text; } + virtual string tag() const override { return m_tag; } +}; +class AstTypedefFwd final : public AstNode { + // Forward declaration of a type; stripped after netlist parsing is complete +private: + string m_name; + +public: + AstTypedefFwd(FileLine* fl, const string& name) + : ASTGEN_SUPER_TypedefFwd(fl) + , m_name{name} {} + ASTNODE_NODE_FUNCS(TypedefFwd) + // METHODS + virtual string name() const override { return m_name; } + virtual bool maybePointedTo() const override { return true; } +}; +class AstUdpTable final : public AstNode { +public: + AstUdpTable(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_UdpTable(fl) { + addNOp1p(bodysp); + } + ASTNODE_NODE_FUNCS(UdpTable) + // op1 = List of UdpTableLines + AstUdpTableLine* bodysp() const { return VN_AS(op1p(), UdpTableLine); } +}; +class AstUdpTableLine final : public AstNode { + string m_text; + +public: + AstUdpTableLine(FileLine* fl, const string& text) + : ASTGEN_SUPER_UdpTableLine(fl) + , m_text{text} {} + ASTNODE_NODE_FUNCS(UdpTableLine) + virtual string name() const override { return m_text; } + string text() const { return m_text; } +}; +class AstUnlinkedRef final : public AstNode { + // As-of-yet unlinkable Ref +private: + string m_name; // Var name +public: + AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) + : ASTGEN_SUPER_UnlinkedRef(fl) + , m_name{name} { + addNOp1p(refp); + addNOp2p(crp); + } + ASTNODE_NODE_FUNCS(UnlinkedRef) + // ACCESSORS + virtual string name() const override { return m_name; } // * = Var name + AstNode* refp() const { return op1p(); } // op1 = VarXRef or AstNodeFTaskRef + AstNode* cellrefp() const { return op2p(); } // op2 = CellArrayRef or CellRef +}; +class AstVar final : public AstNode { + // A variable (in/out/wire/reg/param) inside a module +private: + 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 + VBasicDTypeKwd m_declKwd; // Keyword at declaration time + VLifetime m_lifetime; // Lifetime + VVarAttrClocker m_attrClocker; + MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var + int m_pinNum = 0; // For XML, if non-zero the connection pin number + bool m_ansi : 1; // ANSI port list variable (for dedup check) + 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_funcReturn : 1; // Return variable for a function + bool m_attrClockEn : 1; // User clock enable attribute + 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_isRand : 1; // Random variable + 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 isAutomatic) + bool m_isPulldown : 1; // Tri0 + bool m_isPullup : 1; // Tri1 + bool m_isIfaceParent : 1; // dtype is reference to interface present in this module + 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 + + 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_funcReturn = false; + m_attrClockEn = false; + m_attrScBv = false; + m_attrIsolateAssign = false; + m_attrSFormat = false; + m_attrSplitVar = false; + m_fileDescr = false; + m_isRand = false; + m_isConst = false; + m_isContinuously = false; + m_hasStrengthAssignment = false; + m_isStatic = false; + m_isPulldown = false; + m_isPullup = false; + m_isIfaceParent = 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_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 + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = VBasicDTypeKwd::LOGIC; + } + } + 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); + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = VBasicDTypeKwd::LOGIC; + } + } + 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); + m_declKwd = VBasicDTypeKwd::LOGIC; + } + 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); + m_declKwd = VBasicDTypeKwd::BIT; + } + 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); + m_declKwd = examplep->declKwd(); + } + ASTNODE_NODE_FUNCS(Var) + virtual void dump(std::ostream& str) const override; + virtual string name() const override { return m_name; } // * = Var name + virtual bool hasDType() const override { return true; } + virtual bool maybePointedTo() const override { return true; } + virtual string origName() const override { return m_origName; } // * = Original name + void origName(const string& name) { m_origName = name; } + VVarType varType() const { 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 { return m_direction; } + bool isIO() const { 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; + } + VBasicDTypeKwd declKwd() const { return m_declKwd; } + 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); + virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + // op2 = Net delay + AstNode* delayp() const { return op2p(); } + void delayp(AstNode* const nodep) { setNOp2p(nodep); } + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + // (Slow) recurse down to find basic data type (Note don't need virtual - + // AstVar isn't a NodeDType) + AstBasicDType* basicp() const { return subDTypep()->basicp(); } + // op3 = Initial value that never changes (static const), or constructor argument for + // MTASKSTATE variables + AstNode* valuep() const { return op3p(); } + // It's valuep(), not constp(), as may be more complicated than an AstConst + void valuep(AstNode* nodep) { setOp3p(nodep); } + void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } + AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse + void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + void ansi(bool flag) { m_ansi = flag; } + void declTyped(bool flag) { m_declTyped = flag; } + void attrClockEn(bool flag) { m_attrClockEn = flag; } + 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 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 isRand(bool flag) { m_isRand = 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; } + void funcLocal(bool flag) { m_funcLocal = flag; } + void funcReturn(bool flag) { m_funcReturn = flag; } + void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } + bool hasStrengthAssignment() { return m_hasStrengthAssignment; } + void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } + bool isDpiOpenArray() const { 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; } + // METHODS + virtual void name(const string& name) override { m_name = name; } + virtual void tag(const string& text) override { m_tag = text; } + virtual 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; } + bool isInoutish() const { return m_direction.isInoutish(); } + bool isNonOutput() const { return m_direction.isNonOutput(); } + bool isReadOnly() const { return m_direction.isReadOnly(); } + bool isWritable() const { return m_direction.isWritable(); } + bool isTristate() const { return m_tristate; } + bool isPrimaryIO() const { return m_primaryIO; } + bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } + bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } + bool isIfaceParent() const { return m_isIfaceParent; } + bool isSignal() const { return varType().isSignal(); } + bool isNet() const { return varType().isNet(); } + 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() == VVarType::LPARAM || varType() == VVarType::GPARAM); + } + 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 { return m_usedClock; } + bool isUsedParam() const { return m_usedParam; } + bool isUsedLoopIdx() const { return m_usedLoopIdx; } + bool isSc() const { return m_sc; } + bool isScQuad() const; + bool isScBv() const; + bool isScUint() const; + bool isScBigUint() const; + bool isScSensitive() const { return m_scSensitive; } + bool isSigPublic() const; + bool isSigModPublic() const { return m_sigModPublic; } + bool isSigUserRdPublic() const { return m_sigUserRdPublic; } + bool isSigUserRWPublic() const { return m_sigUserRWPublic; } + bool isTrace() const { return m_trace; } + bool isRand() const { return m_isRand; } + bool isConst() const { return m_isConst; } + bool isStatic() const { return m_isStatic; } + bool isLatched() const { return m_isLatched; } + bool isFuncLocal() const { return m_funcLocal; } + bool isFuncReturn() const { return m_funcReturn; } + bool isPullup() const { return m_isPullup; } + bool isPulldown() const { return m_isPulldown; } + bool attrClockEn() const { return m_attrClockEn; } + 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; } + VVarAttrClocker attrClocker() const { return m_attrClocker; } + virtual string verilogKwd() const override; + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + void propagateAttrFrom(AstVar* fromp) { + // This is getting connected to fromp; keep attributes + // Note the method below too + if (fromp->attrClockEn()) attrClockEn(true); + if (fromp->attrFileDescr()) attrFileDescr(true); + if (fromp->attrIsolateAssign()) attrIsolateAssign(true); + if (fromp->isContinuously()) isContinuously(true); + } + bool gateMultiInputOptimizable() const { + // Ok to gate optimize; must return false if propagateAttrFrom would do anything + return (!attrClockEn() && !isUsedClock()); + } + void combineType(AstVar* typevarp) { + // This is same as typevarp (for combining input & reg decls) + // "this" is the input var. typevarp is the reg var. + propagateAttrFrom(typevarp); + combineType(typevarp->varType()); + if (typevarp->isSigPublic()) sigPublic(true); + if (typevarp->isSigModPublic()) sigModPublic(true); + if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true); + if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true); + if (typevarp->attrScClocked()) attrScClocked(true); + } + void inlineAttrReset(const string& name) { + if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) { + m_varType = VVarType::TRIWIRE; + } + m_direction = VDirection::NONE; + m_name = name; + } + static AstVar* scVarRecurse(AstNode* nodep); + void addProducingMTaskId(int id) { m_mtaskIds.insert(id); } + void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } + const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } + void pinNum(int id) { m_pinNum = id; } + int pinNum() const { return m_pinNum; } +}; +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 +private: + AstScope* m_scopep; // Scope variable is underneath + AstVar* m_varp; // [AfterLink] Pointer to variable itself + bool m_circular : 1; // Used in circular ordering dependency, need change detect + 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_circular = false; + m_trace = true; + dtypeFrom(varp); + } + ASTNODE_NODE_FUNCS(VarScope) + virtual void cloneRelink() override { + if (m_varp && m_varp->clonep()) { + m_varp = m_varp->clonep(); + UASSERT(m_scopep->clonep(), "No clone cross link: " << this); + m_scopep = m_scopep->clonep(); + } + } + virtual const char* broken() const override { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; + } + virtual bool maybePointedTo() const override { return true; } + virtual string name() const override { return scopep()->name() + "->" + varp()->name(); } + virtual void dump(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable + AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under + void scopep(AstScope* nodep) { m_scopep = nodep; } + bool isCircular() const { return m_circular; } + void circular(bool flag) { m_circular = flag; } + 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 + // Children: statements +private: + bool m_generate; // Underneath a generate + const bool m_implied; // 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} + , m_implied{implied} {} + ASTNODE_NODE_FUNCS(Begin) + virtual void dump(std::ostream& str) const override; + // op1p is statements in NodeBlock + AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, + // might NOT be a GenFor, as loop unrolling replaces with Begin + void addGenforp(AstGenFor* nodep) { addOp2p((AstNode*)nodep); } + void generate(bool flag) { m_generate = flag; } + bool generate() const { return m_generate; } + bool implied() const { return m_implied; } +}; +class AstFork final : public AstNodeBlock { + // A fork named block + // Parents: statement + // Children: statements +private: + 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) {} + ASTNODE_NODE_FUNCS(Fork) + virtual void dump(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* fvarsp) + : ASTGEN_SUPER_Func(fl, name, stmtp) { + addNOp1p(fvarsp); + } + ASTNODE_NODE_FUNCS(Func) + virtual bool hasDType() const override { return true; } +}; +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) {} + ASTNODE_NODE_FUNCS(Task) +}; + +// === AstNodeFile === +class AstCFile final : public AstNodeFile { + // C++ output file + // Parents: NETLIST +private: + 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} {} + ASTNODE_NODE_FUNCS(CFile) + virtual void dump(std::ostream& str = std::cout) const override; + 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) { 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) {} + ASTNODE_NODE_FUNCS(VFile) + virtual void dump(std::ostream& str = std::cout) const override; +}; + +// === AstNodeModule === +class AstClass final : public AstNodeModule { + // TYPES + using MemberNameMap = std::map; + // MEMBERS + MemberNameMap m_members; // Members or method children + AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under + bool m_virtual = false; // Virtual class + bool m_extended = false; // Is extension or extended by other classes + void insertCache(AstNode* nodep); + +public: + AstClass(FileLine* fl, const string& name) + : ASTGEN_SUPER_Class(fl, name) {} + ASTNODE_NODE_FUNCS(Class) + virtual string verilogKwd() const override { return "class"; } + virtual bool maybePointedTo() const override { return true; } + virtual void dump(std::ostream& str) const override; + const char* broken() const override; + void cloneRelink() override; + virtual bool timescaleMatters() const override { return false; } + // op1/op2/op3 in AstNodeModule + AstClassPackage* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } + AstNode* membersp() const { return stmtsp(); } // op2 = List of statements + void addMembersp(AstNode* nodep) { + insertCache(nodep); + addStmtp(nodep); + } + AstClassExtends* extendsp() const { return VN_AS(op4p(), ClassExtends); } + void extendsp(AstNode* nodep) { addNOp4p(nodep); } + void clearCache() { m_members.clear(); } + void repairCache(); + AstNode* findMember(const string& name) const { + const auto it = m_members.find(name); + return (it == m_members.end()) ? nullptr : it->second; + } + bool isExtended() const { return m_extended; } + void isExtended(bool flag) { m_extended = flag; } + bool isVirtual() const { return m_virtual; } + void isVirtual(bool flag) { m_virtual = flag; } + // Return true if this class is an extension of base class (SLOW) + // Accepts nullptrs + static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); +}; +class AstClassPackage final : public AstNodeModule { + // The static information portion of a class (treated similarly to a package) + AstClass* m_classp + = nullptr; // Class package this is under (weak pointer, hard link is other way) +public: + AstClassPackage(FileLine* fl, const string& name) + : ASTGEN_SUPER_ClassPackage(fl, name) {} + ASTNODE_NODE_FUNCS(ClassPackage) + virtual string verilogKwd() const override { return "classpackage"; } + virtual const char* broken() const override; + virtual void cloneRelink() override; + virtual bool timescaleMatters() const override { return false; } + AstClass* classp() const { 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) + : ASTGEN_SUPER_Iface(fl, name) {} + ASTNODE_NODE_FUNCS(Iface) + // Interfaces have `timescale applicability but lots of code seems to + // get false warnings if we enable this + virtual string verilogKwd() const override { return "interface"; } + virtual bool timescaleMatters() const override { return false; } +}; +class AstModule final : public AstNodeModule { + // A module declaration +private: + const bool m_isProgram; // Module represents a program +public: + AstModule(FileLine* fl, const string& name, bool program = false) + : ASTGEN_SUPER_Module(fl, name) + , m_isProgram{program} {} + ASTNODE_NODE_FUNCS(Module) + virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } + virtual bool timescaleMatters() const override { return true; } +}; +class AstNotFoundModule final : public AstNodeModule { + // A missing module declaration +public: + AstNotFoundModule(FileLine* fl, const string& name) + : ASTGEN_SUPER_NotFoundModule(fl, name) {} + ASTNODE_NODE_FUNCS(NotFoundModule) + virtual string verilogKwd() const override { return "/*not-found-*/ module"; } + virtual bool timescaleMatters() const override { return false; } +}; +class AstPackage final : public AstNodeModule { + // A package declaration +public: + AstPackage(FileLine* fl, const string& name) + : ASTGEN_SUPER_Package(fl, name) {} + ASTNODE_NODE_FUNCS(Package) + virtual string verilogKwd() const override { return "package"; } + virtual 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) + : ASTGEN_SUPER_Primitive(fl, name) {} + ASTNODE_NODE_FUNCS(Primitive) + virtual string verilogKwd() const override { return "primitive"; } + virtual bool timescaleMatters() const override { return false; } +}; + +// === AstNodePreSel === +class AstSelBit final : public AstNodePreSel { + // Single bit range extraction, perhaps with non-constant selection or array selection + // Gets replaced during link with AstArraySel or AstSel +public: + AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTNODE_NODE_FUNCS(SelBit) + AstNode* bitp() const { return rhsp(); } +}; +class AstSelExtract final : public AstNodePreSel { + // Range extraction, gets replaced with AstSel +public: + AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) + : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} + ASTNODE_NODE_FUNCS(SelExtract) + AstNode* leftp() const { return rhsp(); } + AstNode* rightp() const { return thsp(); } +}; +class AstSelMinus final : public AstNodePreSel { + // -: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} + ASTNODE_NODE_FUNCS(SelMinus) + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; +class AstSelPlus final : public AstNodePreSel { + // +: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} + ASTNODE_NODE_FUNCS(SelPlus) + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; + +// === AstNodeProcedure === +class AstAlways final : public AstNodeProcedure { + const VAlwaysKwd m_keyword; + +public: + AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_Always(fl, bodysp) + , m_keyword{keyword} { + addNOp1p(sensesp); + } + ASTNODE_NODE_FUNCS(Always) + // + virtual void dump(std::ostream& str) const override; + AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list + void sensesp(AstSenTree* nodep) { setOp1p(nodep); } + VAlwaysKwd keyword() const { return m_keyword; } +}; +class AstAlwaysPost final : public AstNodeProcedure { + // Like always but post assignments for memory assignment IFs +public: + AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_AlwaysPost(fl, bodysp) { + addNOp1p(sensesp); + } + ASTNODE_NODE_FUNCS(AlwaysPost) +}; +class AstAlwaysPostponed final : public AstNodeProcedure { + // Like always but postponement scheduling region + +public: + AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_AlwaysPostponed(fl, bodysp) {} + ASTNODE_NODE_FUNCS(AlwaysPostponed) +}; +class AstFinal final : public AstNodeProcedure { +public: + AstFinal(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_Final(fl, bodysp) {} + ASTNODE_NODE_FUNCS(Final) +}; +class AstInitial final : public AstNodeProcedure { +public: + AstInitial(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_Initial(fl, bodysp) {} + ASTNODE_NODE_FUNCS(Initial) +}; +class AstInitialAutomatic final : public AstNodeProcedure { + // Automatic variable initialization + // That is, it runs every function start, or class construction +public: + AstInitialAutomatic(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER_InitialAutomatic(fl, bodysp) {} + ASTNODE_NODE_FUNCS(InitialAutomatic) +}; +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* bodysp) + : ASTGEN_SUPER_InitialStatic(fl, bodysp) {} + ASTNODE_NODE_FUNCS(InitialStatic) +}; + +// === AstNodeRange === +class AstBracketRange final : public AstNodeRange { + // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, + // unknown until lhsp type is determined +public: + AstBracketRange(FileLine* fl, AstNode* elementsp) + : ASTGEN_SUPER_BracketRange(fl) { + setOp1p(elementsp); + } + ASTNODE_NODE_FUNCS(BracketRange) + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + virtual bool maybePointedTo() const override { return false; } + AstNode* elementsp() const { return op1p(); } +}; +class AstRange final : public AstNodeRange { + // Range specification, for use under variables and cells +public: + AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) + : ASTGEN_SUPER_Range(fl) { + setOp2p(leftp); + setOp3p(rightp); + } + inline AstRange(FileLine* fl, int left, int right); + inline AstRange(FileLine* fl, const VNumRange& range); + ASTNODE_NODE_FUNCS(Range) + AstNode* leftp() const { return op2p(); } + AstNode* rightp() const { return op3p(); } + inline int leftConst() const; + inline int rightConst() const; + int hiConst() const { + const int l = leftConst(); + const int r = rightConst(); + return l > r ? l : r; + } + int loConst() const { + const int l = leftConst(); + const int r = rightConst(); + return l > r ? r : l; + } + int elementsConst() const { return hiConst() - loConst() + 1; } + bool littleEndian() const { return leftConst() < rightConst(); } + virtual void dump(std::ostream& str) const override; + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool same(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) {} + ASTNODE_NODE_FUNCS(UnsizedRange) + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { return "[]"; } + virtual bool same(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) {} + ASTNODE_NODE_FUNCS(WildcardRange) + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { return "[*]"; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeStmt === +class AstAlwaysPublic final : public AstNodeStmt { + // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ + // Body statements are just AstVarRefs to the public signals +public: + AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_AlwaysPublic(fl) { + addNOp1p(sensesp); + addNOp2p(bodysp); + } + ASTNODE_NODE_FUNCS(AlwaysPublic) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // + AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list + AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate + void addStmtp(AstNode* nodep) { addOp2p(nodep); } + // Special accessors + bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstBreak final : public AstNodeStmt { +public: + explicit AstBreak(FileLine* fl) + : ASTGEN_SUPER_Break(fl) {} + ASTNODE_NODE_FUNCS(Break) + virtual string verilogKwd() const override { return "break"; } + virtual bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstCMethodHard final : public AstNodeStmt { + // A reference to a "C" hardcoded member task (or function) + // PARENTS: stmt/math + // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. +private: + string m_name; // Name of method + bool m_pure = false; // Pure optimizable +public: + AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl, false) + , m_name{name} { + setOp1p(fromp); + dtypep(nullptr); // V3Width will resolve + addNOp2p(pinsp); + } + AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl, false) + , m_name{name} { + setOp1p(fromp); + addNOp2p(pinsp); + } + ASTNODE_NODE_FUNCS(CMethodHard) + virtual string name() const override { return m_name; } // * = Var name + virtual bool hasDType() const override { return true; } + virtual void name(const string& name) override { m_name = name; } + virtual bool same(const AstNode* samep) const override { + const AstCMethodHard* asamep = static_cast(samep); + return (m_name == asamep->m_name); + } + virtual bool isPure() const override { return m_pure; } + void pure(bool flag) { m_pure = flag; } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + void fromp(AstNode* nodep) { setOp1p(nodep); } + AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list + void addPinsp(AstNode* nodep) { addOp2p(nodep); } +}; +class AstCReset final : public AstNodeStmt { + // Reset variable at startup +public: + AstCReset(FileLine* fl, AstVarRef* exprsp) + : ASTGEN_SUPER_CReset(fl) { + addNOp1p((AstNode*)exprsp); + } + ASTNODE_NODE_FUNCS(CReset) + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstVarRef* varrefp() const { return VN_AS(op1p(), VarRef); } // op1 = varref to reset +}; +class AstCReturn final : public AstNodeStmt { + // C++ return from a function + // Parents: CFUNC/statement + // Children: Math +public: + AstCReturn(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CReturn(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(CReturn) + virtual int instrCount() const override { return widthInstrs(); } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // + AstNode* lhsp() const { return op1p(); } +}; +class AstCStmt final : public AstNodeStmt { + // Emit C statement +public: + AstCStmt(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_CStmt(fl) { + addNOp1p(exprsp); + } + inline AstCStmt(FileLine* fl, const string& textStmt); + ASTNODE_NODE_FUNCS(CStmt) + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + void addBodysp(AstNode* nodep) { addNOp1p(nodep); } + AstNode* bodysp() const { return op1p(); } // op1 = expressions to print +}; +class AstChangeDet final : public AstNodeStmt { + // A comparison to determine change detection, common & must be fast. +public: + // Null lhs+rhs used to indicate change needed with no spec vars + AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ChangeDet(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ChangeDet) + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual int instrCount() const override { return widthInstrs() * 2; } // xor, or/logor + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstComment final : public AstNodeStmt { + // Some comment to put into the output stream + // Parents: {statement list} + // Children: none +private: + const bool m_showAt; // Show "at " + const string m_name; // Text of comment +public: + AstComment(FileLine* fl, const string& name, bool showAt = false) + : ASTGEN_SUPER_Comment(fl) + , m_showAt{showAt} + , m_name{name} {} + ASTNODE_NODE_FUNCS(Comment) + virtual string name() const override { return m_name; } // * = Text + virtual bool same(const AstNode* samep) const override { + return true; + } // Ignore name in comments + virtual bool showAt() const { return m_showAt; } +}; +class AstContinue final : public AstNodeStmt { +public: + explicit AstContinue(FileLine* fl) + : ASTGEN_SUPER_Continue(fl) {} + ASTNODE_NODE_FUNCS(Continue) + virtual string verilogKwd() const override { return "continue"; } + virtual bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstCoverDecl final : public AstNodeStmt { + // Coverage analysis point declaration + // Parents: {statement list} + // Children: none +private: + AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get + // data from instead + string m_page; + string m_text; + string m_hier; + string m_linescov; + int m_offset; // Offset column numbers to uniq-ify IFs + int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment +public: + AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, + int offset) + : ASTGEN_SUPER_CoverDecl(fl) { + m_page = page; + m_text = comment; + m_linescov = linescov; + m_offset = offset; + m_binNum = 0; + m_dataDeclp = nullptr; + } + ASTNODE_NODE_FUNCS(CoverDecl) + virtual const char* broken() const override { + BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists()); + if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing + v3fatalSrc("dataDeclp should point to real data, not be a list"); + } + return nullptr; + } + virtual void cloneRelink() override { + if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); + } + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } + virtual bool maybePointedTo() const override { return true; } + void binNum(int flag) { m_binNum = flag; } + int binNum() const { return m_binNum; } + int offset() const { return m_offset; } + const string& comment() const { return m_text; } // text to insert in code + const string& linescov() const { return m_linescov; } + const string& page() const { return m_page; } + const string& hier() const { return m_hier; } + void hier(const string& flag) { m_hier = flag; } + void comment(const string& flag) { m_text = flag; } + virtual bool same(const AstNode* samep) const override { + const AstCoverDecl* const asamep = static_cast(samep); + return (fileline() == asamep->fileline() && linescov() == asamep->linescov() + && hier() == asamep->hier() && comment() == asamep->comment()); + } + virtual bool isPredictOptimizable() const override { return false; } + void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } + // dataDecl nullptr means "use this one", but often you want "this" to + // indicate to get data from here + AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } + AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } +}; +class AstCoverInc final : public AstNodeStmt { + // Coverage analysis point; increment coverage count + // Parents: {statement list} + // Children: none +private: + AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration +public: + AstCoverInc(FileLine* fl, AstCoverDecl* declp) + : ASTGEN_SUPER_CoverInc(fl) + , m_declp{declp} {} + ASTNODE_NODE_FUNCS(CoverInc) + virtual const char* broken() const override { + BROKEN_RTN(!declp()->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } + virtual bool same(const AstNode* samep) const override { + return declp() == static_cast(samep)->declp(); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isOutputter() const override { return true; } + // but isPure() true + AstCoverDecl* declp() const { return m_declp; } // Where defined +}; +class AstCoverToggle final : public AstNodeStmt { + // Toggle analysis of given signal + // Parents: MODULE + // Children: AstCoverInc, orig var, change det var +public: + AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) + : ASTGEN_SUPER_CoverToggle(fl) { + setOp1p(incp); + setOp2p(origp); + setOp3p(changep); + } + ASTNODE_NODE_FUNCS(CoverToggle) + virtual int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return true; } + virtual bool isOutputter() const override { + return false; // Though the AstCoverInc under this is an outputter + } + // but isPure() true + AstCoverInc* incp() const { return VN_AS(op1p(), CoverInc); } + void incp(AstCoverInc* nodep) { setOp1p(nodep); } + AstNode* origp() const { return op2p(); } + AstNode* changep() const { return op3p(); } +}; +class AstDelay final : public AstNodeStmt { + // Delay statement +public: + AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp) + : ASTGEN_SUPER_Delay(fl) { + setOp1p(lhsp); + setNOp2p(stmtsp); + } + ASTNODE_NODE_FUNCS(Delay) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // + AstNode* lhsp() const { return op1p(); } // op1 = delay value + void lhsp(AstNode* nodep) { setOp1p(nodep); } + void stmtsp(AstNode* nodep) { setOp2p(nodep); } // op2 = statements under delay + AstNode* stmtsp() const { return op2p(); } +}; +class AstDisable final : public AstNodeStmt { +private: + string m_name; // Name of block +public: + AstDisable(FileLine* fl, const string& name) + : ASTGEN_SUPER_Disable(fl) + , m_name{name} {} + ASTNODE_NODE_FUNCS(Disable) + virtual string name() const override { return m_name; } // * = Block name + virtual void name(const string& flag) override { m_name = flag; } + virtual bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstDisableFork final : public AstNodeStmt { + // A "disable fork" statement +public: + explicit AstDisableFork(FileLine* fl) + : ASTGEN_SUPER_DisableFork(fl) {} + ASTNODE_NODE_FUNCS(DisableFork) +}; +class AstDisplay final : public AstNodeStmt { + // Parents: stmtlist + // Children: file which must be a varref + // Children: SFORMATF to generate print string +private: + VDisplayType m_displayType; + +public: + AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNode* filep, + AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER_Display(fl) { + setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); + setNOp3p(filep); + m_displayType = dispType; + } + AstDisplay(FileLine* fl, VDisplayType dispType, AstNode* filep, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_Display(fl) { + setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); + setNOp3p(filep); + m_displayType = dispType; + } + ASTNODE_NODE_FUNCS(Display) + virtual void dump(std::ostream& str) const override; + virtual const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + virtual string verilogKwd() const override { + return (filep() ? string("$f") + string(displayType().ascii()) + : string("$") + string(displayType().ascii())); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* samep) const override { + return displayType() == static_cast(samep)->displayType(); + } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + VDisplayType displayType() const { return m_displayType; } + void displayType(VDisplayType type) { m_displayType = type; } + // * = Add a newline for $display + bool addNewline() const { return displayType().addNewline(); } + void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter + AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } + AstNode* filep() const { return op3p(); } + void filep(AstNodeVarRef* nodep) { setNOp3p((AstNode*)nodep); } +}; +class AstDpiExportUpdated final : public AstNodeStmt { + // Denotes that the referenced variable may have been updated via a DPI Export +public: + inline AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep); + ASTNODE_NODE_FUNCS(DpiExportUpdated) + inline AstVarScope* varScopep() const; +}; +class AstDumpCtl final : public AstNodeStmt { + // $dumpon etc + // Parents: expr + // Child: expr based on type of control statement + const VDumpCtlType m_ctlType; // Type of operation +public: + AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) + : ASTGEN_SUPER_DumpCtl(fl) + , m_ctlType{ctlType} { + setNOp1p(exprp); + } + ASTNODE_NODE_FUNCS(DumpCtl) + virtual string verilogKwd() const override { return ctlType().ascii(); } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool cleanOut() const { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + VDumpCtlType ctlType() const { return m_ctlType; } + AstNode* exprp() const { return op1p(); } // op2 = Expressions to output + void exprp(AstNode* nodep) { setOp1p(nodep); } +}; +class AstEventControl final : public AstNodeStmt { + // Parents: stmtlist +public: + AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_EventControl(fl) { + setNOp1p(sensesp); + setNOp2p(stmtsp); + } + ASTNODE_NODE_FUNCS(EventControl) + virtual string verilogKwd() const override { return "@(%l) %r"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return false; } + virtual int instrCount() const override { return 0; } + AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } + AstNode* stmtsp() const { return op2p(); } +}; +class AstFClose final : public AstNodeStmt { + // Parents: stmtlist + // Children: file which must be a varref +public: + AstFClose(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FClose(fl) { + setNOp2p(filep); + } + ASTNODE_NODE_FUNCS(FClose) + virtual string verilogKwd() const override { return "$fclose"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op2p(); } + void filep(AstNodeVarRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstFFlush final : public AstNodeStmt { + // Parents: stmtlist + // Children: file which must be a varref +public: + AstFFlush(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FFlush(fl) { + setNOp2p(filep); + } + ASTNODE_NODE_FUNCS(FFlush) + virtual string verilogKwd() const override { return "$fflush"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op2p(); } + void filep(AstNodeVarRef* nodep) { setNOp2p((AstNode*)nodep); } +}; +class AstFOpen final : public AstNodeStmt { + // Although a system function in IEEE, here a statement which sets the file pointer (MCD) +public: + AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) + : ASTGEN_SUPER_FOpen(fl) { + setOp1p(filep); + setOp2p(filenamep); + setOp3p(modep); + } + ASTNODE_NODE_FUNCS(FOpen) + virtual string verilogKwd() const override { return "$fopen"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op1p(); } + AstNode* filenamep() const { return op2p(); } + AstNode* modep() const { return op3p(); } +}; +class AstFOpenMcd final : public AstNodeStmt { + // Although a system function in IEEE, here a statement which sets the file pointer (MCD) +public: + AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) + : ASTGEN_SUPER_FOpenMcd(fl) { + setOp1p(filep); + setOp2p(filenamep); + } + ASTNODE_NODE_FUNCS(FOpenMcd) + virtual string verilogKwd() const override { return "$fopen"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* filep() const { return op1p(); } + AstNode* filenamep() const { return op2p(); } +}; +class AstFinish final : public AstNodeStmt { +public: + explicit AstFinish(FileLine* fl) + : ASTGEN_SUPER_Finish(fl) {} + ASTNODE_NODE_FUNCS(Finish) + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output + virtual bool isUnlikely() const override { return true; } + virtual int instrCount() const override { return 0; } // Rarely executes + virtual bool same(const AstNode* samep) const override { + return fileline() == samep->fileline(); + } +}; +class AstForeach final : public AstNodeStmt { +public: + AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) + : ASTGEN_SUPER_Foreach(fl) { + setOp1p(arrayp); + addNOp4p(bodysp); + } + ASTNODE_NODE_FUNCS(Foreach) + AstNode* arrayp() const { return op1p(); } // op1 = array and index vars + AstNode* bodysp() const { return op4p(); } // op4 = body of loop + virtual bool isGateOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstJumpBlock final : public AstNodeStmt { + // Block of code including a JumpGo and JumpLabel + // Parents: {statement list} + // Children: {statement list, with JumpGo and JumpLabel below} +private: + AstJumpLabel* m_labelp = nullptr; // [After V3Jump] Pointer to declaration + int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment +public: + // After construction must call ->labelp to associate with appropriate label + AstJumpBlock(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_JumpBlock(fl) { + addNOp1p(stmtsp); + } + virtual const char* broken() const override; + virtual void cloneRelink() override; + ASTNODE_NODE_FUNCS(JumpBlock) + virtual int instrCount() const override { return 0; } + virtual bool maybePointedTo() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // op1 = Statements + AstNode* stmtsp() const { return op1p(); } // op1 = List of statements + void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block + void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); } + int labelNum() const { return m_labelNum; } + void labelNum(int flag) { m_labelNum = flag; } + AstJumpLabel* labelp() const { return m_labelp; } + void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } +}; +class AstJumpGo final : public AstNodeStmt { + // Jump point; branch down to a JumpLabel + // No support for backward jumps at present + // Parents: {statement list with JumpBlock above} + // Children: none +private: + AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration +public: + AstJumpGo(FileLine* fl, AstJumpLabel* labelp) + : ASTGEN_SUPER_JumpGo(fl) + , m_labelp{labelp} {} + ASTNODE_NODE_FUNCS(JumpGo); + const char* broken() const override; + void cloneRelink() override; + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* samep) const override { + return labelp() == static_cast(samep)->labelp(); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } + AstJumpLabel* labelp() const { return m_labelp; } +}; +class AstJumpLabel final : public AstNodeStmt { + // Jump point declaration + // Parents: {statement list with JumpBlock above} + // Children: none +private: + AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration +public: + AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) + : ASTGEN_SUPER_JumpLabel(fl) + , m_blockp{blockp} {} + ASTNODE_NODE_FUNCS(JumpLabel) + virtual bool maybePointedTo() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(!blockp()->brokeExistsAbove()); + BROKEN_RTN(blockp()->labelp() != this); + return nullptr; + } + virtual void cloneRelink() override { + if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); + } + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return 0; } + virtual bool same(const AstNode* samep) const override { + return blockp() == static_cast(samep)->blockp(); + } + AstJumpBlock* blockp() const { return m_blockp; } +}; +class AstMonitorOff final : public AstNodeStmt { + const bool m_off; // Monitor off. Using 0=on allows faster init and comparison + +public: + AstMonitorOff(FileLine* fl, bool off) + : ASTGEN_SUPER_MonitorOff(fl) + , m_off{off} {} + ASTNODE_NODE_FUNCS(MonitorOff) + virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } + virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt + virtual bool isPredictOptimizable() const override { + return false; + } // Though deleted before opt + virtual bool isPure() const override { return false; } // Though deleted before opt + virtual bool isOutputter() const override { return true; } // Though deleted before opt + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool same(const AstNode* samep) const override { + return m_off == static_cast(samep)->m_off; + } + bool off() const { return m_off; } +}; +class AstPrintTimeScale final : public AstNodeStmt { + // Parents: stmtlist + string m_name; // Parent module name + VTimescale m_timeunit; // Parent module time unit +public: + explicit AstPrintTimeScale(FileLine* fl) + : ASTGEN_SUPER_PrintTimeScale(fl) {} + ASTNODE_NODE_FUNCS(PrintTimeScale) + virtual void name(const string& name) override { m_name = name; } + virtual string name() const override { return m_name; } // * = Var name + virtual void dump(std::ostream& str) const override; + virtual string verilogKwd() const override { return "$printtimescale"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstRelease final : public AstNodeStmt { + // Procedural 'release' statement +public: + AstRelease(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Release(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(Release); + AstNode* lhsp() const { return op1p(); } +}; +class AstRepeat final : public AstNodeStmt { +public: + AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) + : ASTGEN_SUPER_Repeat(fl) { + setOp2p(countp); + addNOp3p(bodysp); + } + ASTNODE_NODE_FUNCS(Repeat) + AstNode* countp() const { return op2p(); } // op2 = condition to continue + AstNode* bodysp() const { return op3p(); } // op3 = body of loop + virtual bool isGateOptimizable() const override { + return false; + } // Not relevant - converted to FOR + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstReturn final : public AstNodeStmt { +public: + explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) + : ASTGEN_SUPER_Return(fl) { + setNOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(Return) + virtual string verilogKwd() const override { return "return"; } + AstNode* lhsp() const { return op1p(); } + virtual bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstSFormat final : public AstNodeStmt { + // Parents: statement container + // Children: string to load + // Children: SFORMATF to generate print string +public: + AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_SFormat(fl) { + setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); + setOp3p(lhsp); + } + AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER_SFormat(fl) { + setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); + setOp3p(lhsp); + } + ASTNODE_NODE_FUNCS(SFormat) + virtual const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + virtual string verilogKwd() const override { return "$sformat"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return true; } + virtual bool isPure() const override { return true; } + virtual bool isOutputter() const override { return false; } + virtual bool cleanOut() const { return false; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter + AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } + AstNode* lhsp() const { return op3p(); } + void lhsp(AstNode* nodep) { setOp3p(nodep); } +}; +class AstStop final : public AstNodeStmt { +public: + AstStop(FileLine* fl, bool maybe) + : ASTGEN_SUPER_Stop(fl) {} + ASTNODE_NODE_FUNCS(Stop) + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { + return false; + } // SPECIAL: $display has 'visual' ordering + virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output + virtual bool isUnlikely() const override { return true; } + virtual int instrCount() const override { return 0; } // Rarely executes + virtual bool same(const AstNode* samep) const override { + return fileline() == samep->fileline(); + } +}; +class AstSysFuncAsTask final : public AstNodeStmt { + // Call what is normally a system function (with a return) in a non-return context + // Parents: stmtlist + // Children: a system function +public: + AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_SysFuncAsTask(fl) { + addNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(SysFuncAsTask) + virtual string verilogKwd() const override { return ""; } + virtual bool isGateOptimizable() const override { return true; } + virtual bool isPredictOptimizable() const override { return true; } + virtual bool isPure() const override { return true; } + virtual bool isOutputter() const override { return false; } + virtual int instrCount() const override { return 0; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval + void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval +}; +class AstSysIgnore final : public AstNodeStmt { + // Parents: stmtlist + // Children: varrefs or exprs +public: + AstSysIgnore(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_SysIgnore(fl) { + addNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(SysIgnore) + virtual string verilogKwd() const override { return "$ignored"; } + virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt + virtual bool isPredictOptimizable() const override { + return false; + } // Though deleted before opt + virtual bool isPure() const override { return false; } // Though deleted before opt + virtual bool isOutputter() const override { return true; } // Though deleted before opt + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output + void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output +}; +class AstSystemT final : public AstNodeStmt { + // $system used as task +public: + AstSystemT(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SystemT(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(SystemT) + virtual string verilogKwd() const override { return "$system"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool isUnlikely() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + AstNode* lhsp() const { return op1p(); } +}; +class AstTimeFormat final : public AstNodeStmt { + // Parents: stmtlist +public: + AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, + AstNode* widthp) + : ASTGEN_SUPER_TimeFormat(fl) { + setOp1p(unitsp); + setOp2p(precisionp); + setOp3p(suffixp); + setOp4p(widthp); + } + ASTNODE_NODE_FUNCS(TimeFormat) + virtual string verilogKwd() const override { return "$timeformat"; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + AstNode* unitsp() const { return op1p(); } + AstNode* precisionp() const { return op2p(); } + AstNode* suffixp() const { return op3p(); } + AstNode* widthp() const { return op4p(); } +}; +class AstTraceDecl final : public AstNodeStmt { + // Trace point declaration + // Separate from AstTraceInc; as a declaration can't be deleted + // Parents: {statement list} + // Children: expression being traced +private: + uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines + const string m_showname; // Name of variable + const VNumRange m_bitRange; // Property of var the trace details + const VNumRange m_arrayRange; // Property of var the trace details + const uint32_t m_codeInc; // Code increment + const VVarType m_varType; // Type of variable (for localparam vs. param) + const VBasicDTypeKwd m_declKwd; // Keyword at declaration time + const VDirection m_declDirection; // Declared direction input/output etc +public: + AstTraceDecl(FileLine* fl, const string& showname, + AstVar* varp, // For input/output state etc + AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange) + : ASTGEN_SUPER_TraceDecl(fl) + , m_showname{showname} + , m_bitRange{bitRange} + , m_arrayRange{arrayRange} + , m_codeInc( + ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() + * (VL_EDATASIZE / 32))) // A code is always 32-bits + , m_varType{varp->varType()} + , m_declKwd{varp->declKwd()} + , m_declDirection{varp->declDirection()} { + dtypeFrom(valuep); + addNOp1p(valuep); + } + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return 100; } // Large... + ASTNODE_NODE_FUNCS(TraceDecl) + virtual string name() const override { return m_showname; } + virtual bool maybePointedTo() const override { return true; } + virtual bool hasDType() const override { return true; } + virtual bool same(const AstNode* samep) const override { return false; } + string showname() const { return m_showname; } // * = Var name + // Details on what we're tracing + uint32_t code() const { return m_code; } + void code(uint32_t code) { m_code = code; } + uint32_t codeInc() const { return m_codeInc; } + const VNumRange& bitRange() const { return m_bitRange; } + const VNumRange& arrayRange() const { return m_arrayRange; } + VVarType varType() const { return m_varType; } + VBasicDTypeKwd declKwd() const { return m_declKwd; } + VDirection declDirection() const { return m_declDirection; } + AstNode* valuep() const { return op1p(); } +}; +class AstTraceInc final : public AstNodeStmt { + // Trace point dump + // Parents: {statement list} + // Children: op1: things to emit before this node, + // op2: expression being traced (from decl) + +private: + AstTraceDecl* m_declp; // Pointer to declaration + const bool m_full; // Is this a full vs incremental dump + const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc + +public: + AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0) + : ASTGEN_SUPER_TraceInc(fl) + , m_declp{declp} + , m_full{full} + , m_baseCode{baseCode} { + dtypeFrom(declp); + addOp2p(declp->valuep()->cloneTree(true)); + } + ASTNODE_NODE_FUNCS(TraceInc) + virtual const char* broken() const override { + BROKEN_RTN(!declp()->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } + virtual void dump(std::ostream& str) const override; + virtual int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } + virtual bool hasDType() const override { return true; } + virtual bool same(const AstNode* samep) const override { + return declp() == static_cast(samep)->declp(); + } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isOutputter() const override { return true; } + // but isPure() true + // op1 = Statements before the value + AstNode* precondsp() const { return op1p(); } + void addPrecondsp(AstNode* newp) { addOp1p(newp); } + AstNode* valuep() const { return op2p(); } + AstTraceDecl* declp() const { return m_declp; } + bool full() const { return m_full; } + uint32_t baseCode() const { return m_baseCode; } +}; +class AstTracePopNamePrefix final : public AstNodeStmt { + const unsigned m_count; // How many levels to pop +public: + AstTracePopNamePrefix(FileLine* fl, unsigned count) + : ASTGEN_SUPER_TracePopNamePrefix(fl) + , m_count{count} {} + ASTNODE_NODE_FUNCS(TracePopNamePrefix) + virtual bool same(const AstNode* samep) const override { return false; } + unsigned count() const { return m_count; } +}; +class AstTracePushNamePrefix final : public AstNodeStmt { + const string m_prefix; // Prefix to add to signal names +public: + AstTracePushNamePrefix(FileLine* fl, const string& prefix) + : ASTGEN_SUPER_TracePushNamePrefix(fl) + , m_prefix{prefix} {} + ASTNODE_NODE_FUNCS(TracePushNamePrefix) + virtual bool same(const AstNode* samep) const override { return false; } + string prefix() const { return m_prefix; } +}; +class AstUCStmt final : public AstNodeStmt { + // User $c statement +public: + AstUCStmt(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_UCStmt(fl) { + addNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(UCStmt) + AstNode* bodysp() const { return op1p(); } // op1 = expressions to print + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return false; } + virtual bool isPure() const override { return false; } + virtual bool isOutputter() const override { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstWait final : public AstNodeStmt { +public: + AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) + : ASTGEN_SUPER_Wait(fl) { + setOp2p(condp); + addNOp3p(bodysp); + } + ASTNODE_NODE_FUNCS(Wait) + AstNode* bodysp() const { return op3p(); } // op3 = body of loop + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstWaitFork final : public AstNodeStmt { + // A "wait fork" statement +public: + explicit AstWaitFork(FileLine* fl) + : ASTGEN_SUPER_WaitFork(fl) {} + ASTNODE_NODE_FUNCS(WaitFork) +}; +class AstWhile final : public AstNodeStmt { +public: + AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp = nullptr, AstNode* incsp = nullptr) + : ASTGEN_SUPER_While(fl) { + setOp2p(condp); + addNOp3p(bodysp); + addNOp4p(incsp); + } + ASTNODE_NODE_FUNCS(While) + // op1 = prepare statements for condition (exec every loop) + AstNode* precondsp() const { return op1p(); } + AstNode* condp() const { return op2p(); } // op2 = condition to continue + AstNode* bodysp() const { return op3p(); } // op3 = body of loop + AstNode* incsp() const { return op4p(); } // op4 = increment (if from a FOR loop) + void addPrecondsp(AstNode* newp) { addOp1p(newp); } + void addBodysp(AstNode* newp) { addOp3p(newp); } + void addIncsp(AstNode* newp) { addOp4p(newp); } + virtual bool isGateOptimizable() const override { return false; } + virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // Stop statement searchback here + virtual void addBeforeStmt(AstNode* newp, AstNode* belowp) override; + // Stop statement searchback here + virtual void addNextStmt(AstNode* newp, AstNode* belowp) override; + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } +}; +class AstWith final : public AstNodeStmt { + // Used as argument to method, then to AstCMethodHard + // dtypep() contains the with lambda's return dtype + // Parents: funcref (similar to AstArg) + // Children: LambdaArgRef that declares the item variable + // Children: LambdaArgRef that declares the item.index variable + // Children: math (equation establishing the with) +public: + AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, + AstNode* exprp) + : ASTGEN_SUPER_With(fl) { + addOp1p((AstNode*)indexArgRefp); + addOp2p((AstNode*)valueArgRefp); + addNOp3p(exprp); + } + ASTNODE_NODE_FUNCS(With) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual bool hasDType() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype + return nullptr; + } + // + AstLambdaArgRef* indexArgRefp() const { return VN_AS(op1p(), LambdaArgRef); } + AstLambdaArgRef* valueArgRefp() const { return VN_AS(op2p(), LambdaArgRef); } + AstNode* exprp() const { return op3p(); } +}; +class AstWithParse final : public AstNodeStmt { + // In early parse, FUNC(index) WITH equation-using-index + // Replaced with AstWith + // Parents: math|stmt + // Children: funcref, math +public: + AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) + : ASTGEN_SUPER_WithParse(fl) { + statement(stmt); + setOp1p(funcrefp); + addNOp2p(exprp); + } + ASTNODE_NODE_FUNCS(WithParse) + virtual bool same(const AstNode* /*samep*/) const override { return true; } + // + AstNode* funcrefp() const { return op1p(); } + AstNode* exprp() const { return op2p(); } +}; + +// === AstNodeAssign === +class AstAssign final : public AstNodeAssign { +public: + AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) { + dtypeFrom(lhsp); + } + ASTNODE_NODE_FUNCS(Assign) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssign(this->fileline(), lhsp, rhsp); + } + virtual bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignAlias final : public AstNodeAssign { + // Like AstAssignW, but a true bidirect interconnection alias + // If both sides are wires, there's no LHS vs RHS, +public: + AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) + : ASTGEN_SUPER_AssignAlias(fl, (AstNode*)lhsp, (AstNode*)rhsp) {} + ASTNODE_NODE_FUNCS(AssignAlias) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + V3ERROR_NA_RETURN(nullptr); + } + virtual bool brokeLhsMustBeLvalue() const override { return false; } +}; +class AstAssignDly final : public AstNodeAssign { +public: + AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} + ASTNODE_NODE_FUNCS(AssignDly) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignDly(this->fileline(), lhsp, rhsp); + } + virtual bool isGateOptimizable() const override { return false; } + virtual string verilogKwd() const override { return "<="; } + virtual bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignForce final : public AstNodeAssign { + // Procedural 'force' statement +public: + AstAssignForce(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(AssignForce) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignForce{this->fileline(), lhsp, rhsp}; + } + virtual bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignPost final : public AstNodeAssign { + // Like Assign, but predelayed assignment requiring special order handling +public: + AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(AssignPost) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignPost(this->fileline(), lhsp, rhsp); + } + virtual bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignPre final : public AstNodeAssign { + // Like Assign, but predelayed assignment requiring special order handling +public: + AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(AssignPre) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignPre(this->fileline(), lhsp, rhsp); + } + virtual bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignVarScope final : public AstNodeAssign { + // Assign two VarScopes to each other +public: + AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { + dtypeFrom(rhsp); + } + ASTNODE_NODE_FUNCS(AssignVarScope) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignVarScope(this->fileline(), lhsp, rhsp); + } + virtual bool brokeLhsMustBeLvalue() const override { return false; } +}; +class AstAssignW final : public AstNodeAssign { + // Like assign, but wire/assign's in verilog, the only setting of the specified variable +public: + AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(AssignW) + AstStrengthSpec* strengthSpecp() const { return VN_AS(op4p(), StrengthSpec); } + void strengthSpecp(AstStrengthSpec* const strengthSpecp) { setOp4p((AstNode*)strengthSpecp); } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignW(this->fileline(), lhsp, rhsp); + } + virtual bool brokeLhsMustBeLvalue() const override { return true; } + AstAlways* convertToAlways() { + AstNode* const lhs1p = lhsp()->unlinkFrBack(); + AstNode* const rhs1p = rhsp()->unlinkFrBack(); + AstAlways* const newp = new AstAlways(fileline(), VAlwaysKwd::ALWAYS, nullptr, + new AstAssign(fileline(), lhs1p, rhs1p)); + replaceWith(newp); // User expected to then deleteTree(); + return newp; + } +}; + +// === AstNodeCCall === +class AstCCall final : public AstNodeCCall { + // C++ function call + // Parents: Anything above a statement + // Children: Args to the function + + string m_selfPointer; // Output code object pointer (e.g.: 'this') + +public: + AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} + ASTNODE_NODE_FUNCS(CCall) + + string selfPointer() const { return m_selfPointer; } + void selfPointer(const string& value) { m_selfPointer = value; } + string selfPointerProtect(bool useSelfForThis) const; +}; +class AstCMethodCall final : public AstNodeCCall { + // C++ method call + // Parents: Anything above a statement + // Children: Args to the function +public: + AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { + setOp1p(fromp); + } + ASTNODE_NODE_FUNCS(CMethodCall) + virtual const char* broken() const override { + BROKEN_BASE_RTN(AstNodeCCall::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } + AstNode* fromp() const { + return op1p(); + } // op1 = Extracting what (nullptr=TBD during parsing) + void fromp(AstNode* nodep) { setOp1p(nodep); } +}; +class AstCNew final : public AstNodeCCall { + // C++ new() call + // Parents: Anything above an expression + // Children: Args to the function +public: + AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CNew(fl, funcp, argsp) { + statement(false); + } + virtual bool hasDType() const override { return true; } + ASTNODE_NODE_FUNCS(CNew) +}; + +// === AstNodeCase === +class AstCase final : public AstNodeCase { + // Case statement + // Parents: {statement list} + // exprp Children: MATHs + // casesp Children: CASEITEMs +private: + VCaseType m_casex; // 0=case, 1=casex, 2=casez + bool m_fullPragma = false; // Synthesis full_case + bool m_parallelPragma = false; // Synthesis parallel_case + bool m_uniquePragma = false; // unique case + bool m_unique0Pragma = false; // unique0 case + bool m_priorityPragma = false; // priority case +public: + AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) + : ASTGEN_SUPER_Case(fl, exprp, casesp) + , m_casex{casex} {} + ASTNODE_NODE_FUNCS(Case) + virtual string verilogKwd() const override { + return casez() ? "casez" : casex() ? "casex" : "case"; + } + virtual bool same(const AstNode* samep) const override { + return m_casex == static_cast(samep)->m_casex; + } + bool casex() const { return m_casex == VCaseType::CT_CASEX; } + bool casez() const { return m_casex == VCaseType::CT_CASEZ; } + bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } + bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } + void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } + bool fullPragma() const { return m_fullPragma; } + void fullPragma(bool flag) { m_fullPragma = flag; } + bool parallelPragma() const { return m_parallelPragma; } + void parallelPragma(bool flag) { m_parallelPragma = flag; } + bool uniquePragma() const { return m_uniquePragma; } + void uniquePragma(bool flag) { m_uniquePragma = flag; } + bool unique0Pragma() const { return m_unique0Pragma; } + void unique0Pragma(bool flag) { m_unique0Pragma = flag; } + bool priorityPragma() const { return m_priorityPragma; } + void priorityPragma(bool flag) { m_priorityPragma = flag; } +}; +class AstGenCase final : public AstNodeCase { + // Generate Case statement + // Parents: {statement list} + // exprp Children: MATHs + // casesp Children: CASEITEMs +public: + AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) + : ASTGEN_SUPER_GenCase(fl, exprp, casesp) {} + ASTNODE_NODE_FUNCS(GenCase) +}; + +// === AstNodeCoverOrAssert === +class AstAssert final : public AstNodeCoverOrAssert { +public: + ASTNODE_NODE_FUNCS(Assert) + AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, + const string& name = "") + : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { + addNOp3p(failsp); + } + AstNode* failsp() const { return op3p(); } // op3 = if assertion fails +}; +class AstAssertIntrinsic final : public AstNodeCoverOrAssert { + // A $cast or other compiler inserted assert, that must run even without --assert option +public: + ASTNODE_NODE_FUNCS(AssertIntrinsic) + AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, + bool immediate, const string& name = "") + : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { + addNOp3p(failsp); + } + AstNode* failsp() const { return op3p(); } // op3 = if assertion fails +}; +class AstCover final : public AstNodeCoverOrAssert { +public: + ASTNODE_NODE_FUNCS(Cover) + AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, + const string& name = "") + : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} + AstNode* coverincp() const { return op3p(); } // op3 = coverage node + void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node + virtual bool immediate() const { return false; } +}; +class AstRestrict final : public AstNodeCoverOrAssert { +public: + ASTNODE_NODE_FUNCS(Restrict) + AstRestrict(FileLine* fl, AstNode* propp) + : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} +}; + +// === AstNodeFTaskRef === +class AstFuncRef final : public AstNodeFTaskRef { + // A reference to a function +public: + AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} + AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} + ASTNODE_NODE_FUNCS(FuncRef) + virtual bool hasDType() const override { return true; } +}; +class AstMethodCall final : public AstNodeFTaskRef { + // A reference to a member task (or function) + // PARENTS: stmt/math + // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it +public: + AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { + setOp2p(fromp); + dtypep(nullptr); // V3Width will resolve + } + AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { + setOp2p(fromp); + } + ASTNODE_NODE_FUNCS(MethodCall) + virtual const char* broken() const override { + BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } + virtual void dump(std::ostream& str) const override; + virtual bool hasDType() const override { return true; } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } + AstNode* fromp() const { + return op2p(); + } // op2 = Extracting what (nullptr=TBD during parsing) + void fromp(AstNode* nodep) { setOp2p(nodep); } +}; +class AstNew final : public AstNodeFTaskRef { + // New as constructor + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNew(FileLine* fl, AstNode* pinsp) + : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} + ASTNODE_NODE_FUNCS(New) + virtual bool cleanOut() const { return true; } + virtual bool same(const AstNode* /*samep*/) const override { return true; } + virtual bool hasDType() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } +}; +class AstTaskRef final : public AstNodeFTaskRef { + // A reference to a task +public: + AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { + statement(true); + } + AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} + ASTNODE_NODE_FUNCS(TaskRef) +}; + +// === AstNodeFor === +class AstGenFor final : public AstNodeFor { +public: + AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) + : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, bodysp) {} + ASTNODE_NODE_FUNCS(GenFor) +}; + +// === AstNodeIf === +class AstGenIf final : public AstNodeIf { +public: + AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) + : ASTGEN_SUPER_GenIf(fl, condp, ifsp, elsesp) {} + ASTNODE_NODE_FUNCS(GenIf) +}; +class AstIf final : public AstNodeIf { +private: + bool m_uniquePragma; // unique case + bool m_unique0Pragma; // unique0 case + bool m_priorityPragma; // priority case +public: + AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp = nullptr, AstNode* elsesp = nullptr) + : ASTGEN_SUPER_If(fl, condp, ifsp, elsesp) { + m_uniquePragma = false; + m_unique0Pragma = false; + m_priorityPragma = false; + } + ASTNODE_NODE_FUNCS(If) + bool uniquePragma() const { return m_uniquePragma; } + void uniquePragma(bool flag) { m_uniquePragma = flag; } + bool unique0Pragma() const { return m_unique0Pragma; } + void unique0Pragma(bool flag) { m_unique0Pragma = flag; } + bool priorityPragma() const { return m_priorityPragma; } + void priorityPragma(bool flag) { m_priorityPragma = flag; } +}; + +// === AstNodeReadWriteMem === +class AstReadMem final : public AstNodeReadWriteMem { +public: + AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} + ASTNODE_NODE_FUNCS(ReadMem); + virtual string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } + virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } +}; +class AstWriteMem final : public AstNodeReadWriteMem { +public: + AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} + ASTNODE_NODE_FUNCS(WriteMem) + virtual string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } + virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } +}; + +// === AstNodeText === +class AstScCtor final : public AstNodeText { +public: + AstScCtor(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScCtor(fl, textp) {} + ASTNODE_NODE_FUNCS(ScCtor) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } +}; +class AstScDtor final : public AstNodeText { +public: + AstScDtor(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScDtor(fl, textp) {} + ASTNODE_NODE_FUNCS(ScDtor) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } +}; +class AstScHdr final : public AstNodeText { +public: + AstScHdr(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScHdr(fl, textp) {} + ASTNODE_NODE_FUNCS(ScHdr) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } +}; +class AstScImp final : public AstNodeText { +public: + AstScImp(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScImp(fl, textp) {} + ASTNODE_NODE_FUNCS(ScImp) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } +}; +class AstScImpHdr final : public AstNodeText { +public: + AstScImpHdr(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScImpHdr(fl, textp) {} + ASTNODE_NODE_FUNCS(ScImpHdr) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const override { return true; } +}; +class AstScInt final : public AstNodeText { +public: + AstScInt(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScInt(fl, textp) {} + ASTNODE_NODE_FUNCS(ScInt) + virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + virtual bool isOutputter() const 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) {} + ASTNODE_NODE_FUNCS(Text) +}; +class AstTextBlock final : public AstNodeSimpleText { +private: + 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) {} + ASTNODE_NODE_FUNCS(TextBlock) + void commas(bool flag) { m_commas = flag; } + bool commas() const { return m_commas; } + AstNode* nodesp() const { return op1p(); } + void addNodep(AstNode* nodep) { addOp1p(nodep); } + void addText(FileLine* fl, const string& textp, bool tracking = false) { + addNodep(new AstText(fl, textp, tracking)); + } +}; + +#endif // Guard diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d534622e5..3ed73a6a7 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -155,6 +155,51 @@ void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Numb } } +void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, + AstRange* rangep) { + // wantwidth=0 means figure it out, but if a widthmin is >=0 + // we allow width 0 so that {{0{x}},y} works properly + // wantwidthmin=-1: default, use wantwidth if it is non zero + m.m_keyword = kwd; + // Implicitness: // "parameter X" is implicit and sized from initial + // value, "parameter reg x" not + if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) { + if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC; + } + if (numer == VSigning::NOSIGN) { + if (keyword().isSigned()) { + numer = VSigning::SIGNED; + } else if (keyword().isUnsigned()) { + numer = VSigning::UNSIGNED; + } + } + numeric(numer); + if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width + if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false); + const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth; + widthForce(wantwidth, wmin); + } else if (!rangep) { // Set based on keyword properties + // V3Width will pull from this width + if (keyword().width() > 1 && !isOpaque()) { + m.m_nrange.init(keyword().width() - 1, 0, false); + } + widthForce(keyword().width(), keyword().width()); + } else { + widthForce(rangep->elementsConst(), + rangep->elementsConst()); // Maybe unknown if parameters underneath it + } + setNOp1p(rangep); + dtypep(this); +} + +void AstBasicDType::cvtRangeConst() { + if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) { + m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()}; + rangep()->unlinkFrBackWithNext()->deleteTree(); + rangep(nullptr); + } +} + int AstBasicDType::widthAlignBytes() const { if (width() <= 8) { return 1; @@ -1026,6 +1071,11 @@ AstConstPool::AstConstPool(FileLine* fl) addOp1p(m_modp); m_modp->addStmtp(m_scopep); } +const char* AstConstPool::broken() const { + BROKEN_RTN(m_modp && !m_modp->brokeExists()); + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; +} AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) { FileLine* const fl = initp->fileline(); @@ -1297,11 +1347,19 @@ void AstCell::dump(std::ostream& str) const { str << " ->UNLINKED:" << modName(); } } +const char* AstCell::broken() const { + BROKEN_RTN(m_modp && !m_modp->brokeExists()); + return nullptr; +} void AstCellInline::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << origModName(); str << " [scopep=" << reinterpret_cast(scopep()) << "]"; } +const char* AstCellInline::broken() const { + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; +} const char* AstClassPackage::broken() const { BROKEN_BASE_RTN(AstNodeModule::broken()); BROKEN_RTN(m_classp && !m_classp->brokeExists()); @@ -1346,6 +1404,17 @@ void AstClass::dump(std::ostream& str) const { if (isExtended()) str << " [EXT]"; if (isVirtual()) str << " [VIRT]"; } +const char* AstClass::broken() const { + BROKEN_BASE_RTN(AstNodeModule::broken()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstClass::cloneRelink() { + AstNodeModule::cloneRelink(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} AstClass* AstClassExtends::classp() const { const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' @@ -1368,6 +1437,18 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "class:" << name(); } +const char* AstClassRefDType::broken() const { + BROKEN_RTN(m_classp && !m_classp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstClassRefDType::cloneRelink() { + if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} +string AstClassRefDType::name() const { return classp() ? classp()->name() : ""; } void AstNodeCoverOrAssert::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (immediate()) str << " [IMMEDIATE]"; @@ -1385,6 +1466,11 @@ void AstEnumItemRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +const char* AstEnumItemRef::broken() const { + BROKEN_RTN(m_itemp && !m_itemp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (cellName() != "") str << " cell=" << cellName(); @@ -1416,6 +1502,46 @@ void AstInitArray::dump(std::ostream& str) const { str << " [" << itr.first << "]=" << reinterpret_cast(itr.second); } } +const char* AstInitArray::broken() const { + for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + BROKEN_RTN(!it->second); + BROKEN_RTN(!it->second->brokeExists()); + } + return nullptr; +} +void AstInitArray::cloneRelink() { + for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->second->clonep()) it->second = it->second->clonep(); + } +} +AstNode* AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) { + // Returns old value, caller must garbage collect + AstNode* oldp = nullptr; + const auto it = m_map.find(index); + if (it != m_map.end()) { + oldp = it->second->valuep(); + it->second->valuep(newp); + } else { + AstInitItem* const itemp = new AstInitItem(fileline(), newp); + m_map.emplace(index, itemp); + addOp2p(itemp); + } + return oldp; +} +AstNode* AstInitArray::getIndexValuep(uint64_t index) const { + const auto it = m_map.find(index); + if (it == m_map.end()) { + return nullptr; + } else { + return it->second->valuep(); + } +} +AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const { + AstNode* valuep = getIndexValuep(index); + if (!valuep) valuep = defaultp(); + return valuep; +} + void AstJumpGo::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -1425,6 +1551,13 @@ void AstJumpGo::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +const char* AstJumpGo::broken() const { + BROKEN_RTN(!labelp()->brokeExistsBelow()); + return nullptr; +} +void AstJumpGo::cloneRelink() { + if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); +} void AstJumpLabel::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -1447,6 +1580,13 @@ void AstMemberSel::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstMemberSel::cloneRelink() { + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); +} +const char* AstMemberSel::broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return nullptr; +} void AstMethodCall::dump(std::ostream& str) const { this->AstNodeFTaskRef::dump(str); if (isStatement()) str << " [STMT]"; @@ -1468,6 +1608,13 @@ void AstModportFTaskRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstModportFTaskRef::broken() const { + BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); + return nullptr; +} +void AstModportFTaskRef::cloneRelink() { + if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); +} void AstModportVarRef::dump(std::ostream& str) const { this->AstNode::dump(str); if (direction().isAny()) str << " " << direction(); @@ -1478,6 +1625,13 @@ void AstModportVarRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstModportVarRef::broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return nullptr; +} +void AstModportVarRef::cloneRelink() { + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); +} void AstPin::dump(std::ostream& str) const { this->AstNode::dump(str); if (modVarp()) { @@ -1488,6 +1642,17 @@ void AstPin::dump(std::ostream& str) const { } if (svImplicit()) str << " [.SV]"; } +const char* AstPin::broken() const { + BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); + BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); + return nullptr; +} +string AstPin::prettyOperatorName() const { + return modVarp() + ? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "") + + "port connection " + modVarp()->prettyNameQ()) + : "port connection"; +} void AstPrintTimeScale::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " " << timeunit(); @@ -1533,6 +1698,23 @@ void AstRefDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstRefDType::broken() const { + BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists()); + BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstRefDType::cloneRelink() { + if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep(); + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} +AstNodeDType* AstRefDType::subDTypep() const { + if (typedefp()) return typedefp()->subDTypep(); + return refDTypep(); // Maybe nullptr +} void AstNodeUOrStructDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (packed()) str << " [PACKED]"; @@ -1603,6 +1785,32 @@ void AstNetlist::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << timeunit() << "/" << timeprecision() << "]"; } +const char* AstNetlist::broken() const { + BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists()); + BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists()); + BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); + BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); + BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists()); + BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists()); + return nullptr; +} +AstPackage* AstNetlist::dollarUnitPkgAddp() { + if (!m_dollarUnitPkgp) { + m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName()); + // packages are always libraries; don't want to make them a "top" + m_dollarUnitPkgp->inLibrary(true); + m_dollarUnitPkgp->modTrace(false); // may reconsider later + m_dollarUnitPkgp->internal(true); + addModulep(m_dollarUnitPkgp); + } + return m_dollarUnitPkgp; +} +void AstNetlist::createTopScope(AstScope* scopep) { + UASSERT(scopep, "Must not be nullptr"); + UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits"); + m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep}; + scopep->modp()->addStmtp(v3Global.rootp()->topScopep()); +} void AstNodeModule::dump(std::ostream& str) const { this->AstNode::dump(str); str << " L" << level(); @@ -1620,10 +1828,24 @@ void AstPackageExport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +const char* AstPackageExport ::broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return nullptr; +} +void AstPackageExport::cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); +} void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +const char* AstPackageImport::broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return nullptr; +} +void AstPackageImport::cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); +} void AstPatMember::dump(std::ostream& str) const { this->AstNodeMath::dump(str); if (isDefault()) str << " [DEFAULT]"; @@ -1691,10 +1913,30 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "[*]"; } +bool AstWildcardArrayDType::same(const AstNode* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); +} +bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); +} void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "[]"; } +bool AstUnsizedArrayDType::same(const AstNode* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); +} +bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); +} void AstEmptyQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "emptyq"; @@ -1742,6 +1984,9 @@ void AstVarRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +bool AstVarRef::same(const AstNode* samep) const { + return same(static_cast(samep)); +} void AstVar::dump(std::ostream& str) const { this->AstNode::dump(str); if (isSc()) str << " [SC]"; @@ -1804,6 +2049,13 @@ void AstClassOrPackageRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +AstNodeModule* AstClassOrPackageRef::classOrPackagep() const { + AstNode* foundp = m_classOrPackageNodep; + while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); + if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp(); + return VN_CAST(foundp, NodeModule); +} + void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); if (colon()) str << " [::]"; @@ -1817,6 +2069,16 @@ void AstActive::dump(std::ostream& str) const { str << "UNLINKED"; } } +const char* AstActive::broken() const { + BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); + return nullptr; +} +void AstActive::cloneRelink() { + if (m_sensesp->clonep()) { + m_sensesp = m_sensesp->clonep(); + UASSERT(m_sensesp, "Bad clone cross link: " << this); + } +} void AstNodeFTaskRef::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); @@ -1920,6 +2182,14 @@ void AstCFunc::dump(std::ostream& str) const { if (isDestructor()) str << " [DTOR]"; if (isVirtual()) str << " [VIRT]"; } +const char* AstCFunc::broken() const { + BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); + return nullptr; +} +void AstCFunc::cloneRelink() { + if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep(); +} + void AstCUse::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << useType() << "]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h deleted file mode 100644 index b5724847b..000000000 --- a/src/V3AstNodes.h +++ /dev/null @@ -1,9592 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Ast node structure -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2022 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 -// -//************************************************************************* - -#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 -#endif - -//###################################################################### -// Standard defines for all AstNode final classes - -#define ASTNODE_NODE_FUNCS_NO_DTOR(name) \ - virtual void accept(VNVisitor& v) override { v.visit(this); } \ - virtual AstNode* clone() override { return new Ast##name(*this); } \ - static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ - } \ - Ast##name* cloneTree(bool cloneNext) { \ - return static_cast(AstNode::cloneTree(cloneNext)); \ - } \ - Ast##name* clonep() const { return static_cast(AstNode::clonep()); } - -#define ASTNODE_NODE_FUNCS(name) \ - virtual ~Ast##name() override = default; \ - ASTNODE_NODE_FUNCS_NO_DTOR(name) - -//###################################################################### -// Macros generated by 'astgen' - -#include "V3AstNodes__gen_macros.h" - -//###################################################################### -//=== Ast* : Specific types -// Netlist interconnect - -class AstConst final : public AstNodeMath { - // A constant -private: - V3Number m_num; // Constant value - void initWithNumber() { - if (m_num.isDouble()) { - dtypeSetDouble(); - } else if (m_num.isString()) { - dtypeSetString(); - } else { - dtypeSetLogicUnsized(m_num.width(), (m_num.sized() ? 0 : m_num.widthMin()), - VSigning::fromBool(m_num.isSigned())); - } - m_num.nodep(this); - } - -public: - AstConst(FileLine* fl, const V3Number& num) - : ASTGEN_SUPER_Const(fl) - , m_num(num) { - initWithNumber(); - } - class WidthedValue {}; // for creator type-overload selection - AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) - : ASTGEN_SUPER_Const(fl) - , m_num(this, width, value) { - initWithNumber(); - } - class DTyped {}; // for creator type-overload selection - // Zero/empty constant with a type matching nodetypep - AstConst(FileLine* fl, DTyped, const AstNodeDType* nodedtypep) - : ASTGEN_SUPER_Const(fl) - , m_num(this, nodedtypep) { - initWithNumber(); - } - class StringToParse {}; // for creator type-overload selection - AstConst(FileLine* fl, StringToParse, const char* sourcep) - : ASTGEN_SUPER_Const(fl) - , m_num(this, sourcep) { - initWithNumber(); - } - class VerilogStringLiteral {}; // for creator type-overload selection - AstConst(FileLine* fl, VerilogStringLiteral, const string& str) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::VerilogStringLiteral(), this, str) { - initWithNumber(); - } - AstConst(FileLine* fl, uint32_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); - } - class Unsized32 {}; // for creator type-overload selection - AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - m_num.width(32, false); - dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); - } - class Signed32 {}; // for creator type-overload selection - AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - m_num.width(32, true); - dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); - } - class Unsized64 {}; // for creator type-overload selection - AstConst(FileLine* fl, Unsized64, uint64_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 64, 0) { - m_num.setQuad(num); - dtypeSetLogicSized(64, VSigning::UNSIGNED); - } - class SizedEData {}; // for creator type-overload selection - AstConst(FileLine* fl, SizedEData, uint64_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, VL_EDATASIZE, 0) { - m_num.setQuad(num); - dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); - } - class RealDouble {}; // for creator type-overload selection - AstConst(FileLine* fl, RealDouble, double num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 64) { - m_num.setDouble(num); - dtypeSetDouble(); - } - class String {}; // for creator type-overload selection - AstConst(FileLine* fl, String, const string& num) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::String(), this, num) { - dtypeSetString(); - } - class BitFalse {}; - AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 - : ASTGEN_SUPER_Const(fl) - , m_num(this, 1, 0) { - dtypeSetBit(); - } - // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 - class BitTrue {}; - AstConst(FileLine* fl, BitTrue, bool on = true) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 1, on) { - dtypeSetBit(); - } - class Null {}; - AstConst(FileLine* fl, Null) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::Null{}, this) { - dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here - initWithNumber(); - } - ASTNODE_NODE_FUNCS(Const) - virtual string name() const override { return num().ascii(); } // * = Value - const V3Number& num() const { return m_num; } // * = Value - V3Number& num() { return m_num; } // * = Value - uint32_t toUInt() const { return num().toUInt(); } - int32_t toSInt() const { return num().toSInt(); } - uint64_t toUQuad() const { return num().toUQuad(); } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* samep) const override { - const AstConst* const sp = static_cast(samep); - return num().isCaseEq(sp->num()); - } - virtual int instrCount() const override { return widthInstrs(); } - bool isEqAllOnes() const { return num().isEqAllOnes(width()); } - bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } - // Parse string and create appropriate type of AstConst. - // May return nullptr on parse failure. - static AstConst* parseParamLiteral(FileLine* fl, const string& literal); -}; - -class AstEmpty final : public AstNode { - // Represents something missing, e.g. a missing argument in FOREACH -public: - explicit AstEmpty(FileLine* fl) - : ASTGEN_SUPER_Empty(fl) {} - ASTNODE_NODE_FUNCS(Empty) - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstEmptyQueue final : public AstNodeMath { -public: - explicit AstEmptyQueue(FileLine* fl) - : ASTGEN_SUPER_EmptyQueue(fl) {} - ASTNODE_NODE_FUNCS(EmptyQueue) - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() override { return "{}"; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool cleanOut() const override { return true; } -}; - -class AstRange final : public AstNodeRange { - // Range specification, for use under variables and cells -public: - AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) - : ASTGEN_SUPER_Range(fl) { - setOp2p(leftp); - setOp3p(rightp); - } - AstRange(FileLine* fl, int left, int right) - : ASTGEN_SUPER_Range(fl) { - setOp2p(new AstConst(fl, left)); - setOp3p(new AstConst(fl, right)); - } - AstRange(FileLine* fl, const VNumRange& range) - : ASTGEN_SUPER_Range(fl) { - setOp2p(new AstConst(fl, range.left())); - setOp3p(new AstConst(fl, range.right())); - } - ASTNODE_NODE_FUNCS(Range) - AstNode* leftp() const { return op2p(); } - AstNode* rightp() const { return op3p(); } - int leftConst() const { - AstConst* const constp = VN_CAST(leftp(), Const); - return (constp ? constp->toSInt() : 0); - } - int rightConst() const { - AstConst* const constp = VN_CAST(rightp(), Const); - return (constp ? constp->toSInt() : 0); - } - int hiConst() const { - const int l = leftConst(); - const int r = rightConst(); - return l > r ? l : r; - } - int loConst() const { - const int l = leftConst(); - const int r = rightConst(); - return l > r ? r : l; - } - int elementsConst() const { return hiConst() - loConst() + 1; } - bool littleEndian() const { return leftConst() < rightConst(); } - virtual void dump(std::ostream& str) const override; - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstBracketRange final : public AstNodeRange { - // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, - // unknown until lhsp type is determined -public: - AstBracketRange(FileLine* fl, AstNode* elementsp) - : ASTGEN_SUPER_BracketRange(fl) { - setOp1p(elementsp); - } - ASTNODE_NODE_FUNCS(BracketRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // Will be removed in V3Width, which relies on this - // being a child not a dtype pointed node - virtual bool maybePointedTo() const override { return false; } - AstNode* elementsp() const { return op1p(); } -}; - -class AstUnsizedRange final : public AstNodeRange { - // Unsized range specification, for open arrays -public: - explicit AstUnsizedRange(FileLine* fl) - : ASTGEN_SUPER_UnsizedRange(fl) {} - ASTNODE_NODE_FUNCS(UnsizedRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { return "[]"; } - virtual bool same(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) {} - ASTNODE_NODE_FUNCS(WildcardRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { return "[*]"; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstStrengthSpec final : public AstNode { -private: - 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} {} - - ASTNODE_NODE_FUNCS(StrengthSpec) - VStrength strength0() { return m_s0; } - VStrength strength1() { return m_s1; } - virtual void dump(std::ostream& str) const override; -}; - -class AstGatePin final : public AstNodeMath { - // Possibly expand a gate primitive input pin value to match the range of the gate primitive -public: - AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) - : ASTGEN_SUPER_GatePin(fl) { - setOp1p(lhsp); - setOp2p(rangep); - } - ASTNODE_NODE_FUNCS(GatePin) - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstNode* exprp() const { return op1p(); } // op1 = Pin expression - AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Range of pin -}; - -//###################################################################### -// Classes - -class AstClassPackage final : public AstNodeModule { - // The static information portion of a class (treated similarly to a package) - AstClass* m_classp - = nullptr; // Class package this is under (weak pointer, hard link is other way) -public: - AstClassPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER_ClassPackage(fl, name) {} - ASTNODE_NODE_FUNCS(ClassPackage) - virtual string verilogKwd() const override { return "classpackage"; } - virtual const char* broken() const override; - virtual void cloneRelink() override; - virtual bool timescaleMatters() const override { return false; } - AstClass* classp() const { return m_classp; } - void classp(AstClass* classp) { m_classp = classp; } -}; - -class AstClass final : public AstNodeModule { - // TYPES - using MemberNameMap = std::map; - // MEMBERS - MemberNameMap m_members; // Members or method children - AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under - bool m_virtual = false; // Virtual class - bool m_extended = false; // Is extension or extended by other classes - void insertCache(AstNode* nodep); - -public: - AstClass(FileLine* fl, const string& name) - : ASTGEN_SUPER_Class(fl, name) {} - ASTNODE_NODE_FUNCS(Class) - virtual string verilogKwd() const override { return "class"; } - virtual bool maybePointedTo() const override { return true; } - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeModule::broken()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - AstNodeModule::cloneRelink(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool timescaleMatters() const override { return false; } - // op1/op2/op3 in AstNodeModule - AstClassPackage* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } - AstNode* membersp() const { return stmtsp(); } // op2 = List of statements - void addMembersp(AstNode* nodep) { - insertCache(nodep); - addStmtp(nodep); - } - AstClassExtends* extendsp() const { return VN_AS(op4p(), ClassExtends); } - void extendsp(AstNode* nodep) { addNOp4p(nodep); } - void clearCache() { m_members.clear(); } - void repairCache(); - AstNode* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } - bool isExtended() const { return m_extended; } - void isExtended(bool flag) { m_extended = flag; } - bool isVirtual() const { return m_virtual; } - void isVirtual(bool flag) { m_virtual = flag; } - // Return true if this class is an extension of base class (SLOW) - // Accepts nullptrs - static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); -}; - -class AstClassExtends final : public AstNode { - // Children: List of AstParseRef for packages/classes - // during early parse, then moves to dtype -public: - AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) - : ASTGEN_SUPER_ClassExtends(fl) { - setNOp2p(classOrPkgsp); // Only for parser - } - ASTNODE_NODE_FUNCS(ClassExtends) - virtual bool hasDType() const override { return true; } - virtual string verilogKwd() const override { return "extends"; } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - AstNode* classOrPkgsp() const { return op2p(); } - AstClass* classp() const; // Class being extended (after link) -}; - -//###################################################################### -//==== Data Types - -class AstParamTypeDType final : public AstNodeDType { - // Parents: MODULE - // A parameter type statement; much like a var or typedef -private: - const VVarType m_varType; // Type of variable (for localparam vs. param) - string m_name; // Name of variable -public: - AstParamTypeDType(FileLine* fl, VVarType type, const string& name, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_ParamTypeDType(fl) - , m_varType{type} - , m_name{name} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(ParamTypeDType) - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return dtypep() ? dtypep() : childDTypep(); - } - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstParamTypeDType* const sp = static_cast(samep); - return type() == samep->type() && sp - && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); - } - virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - VVarType varType() const { return m_varType; } // * = Type of variable - bool isParam() const { return true; } - bool isGParam() const { return (varType() == VVarType::GPARAM); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstTypedef final : public AstNode { -private: - string m_name; - bool m_attrPublic; - string m_tag; // Holds the string of the verilator tag -- used in XML output. -public: - AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_Typedef(fl) - , m_name{name} { - childDTypep(dtp); // Only for parser - addAttrsp(attrsp); - dtypep(nullptr); // V3Width will resolve - m_attrPublic = false; - } - ASTNODE_NODE_FUNCS(Typedef) - virtual void dump(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } - AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - bool attrPublic() const { return m_attrPublic; } - void attrPublic(bool flag) { m_attrPublic = flag; } - virtual void tag(const string& text) override { m_tag = text; } - virtual string tag() const override { return m_tag; } -}; - -class AstTypedefFwd final : public AstNode { - // Forward declaration of a type; stripped after netlist parsing is complete -private: - string m_name; - -public: - AstTypedefFwd(FileLine* fl, const string& name) - : ASTGEN_SUPER_TypedefFwd(fl) - , m_name{name} {} - ASTNODE_NODE_FUNCS(TypedefFwd) - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } -}; - -class AstDefImplicitDType final : public AstNodeDType { - // For parsing enum/struct/unions that are declared with a variable rather than typedef - // This allows "var enum {...} a,b" to share the enum definition for both variables - // After link, these become typedefs -private: - string m_name; - void* m_containerp; // In what scope is the name unique, so we can know what are duplicate - // definitions (arbitrary value) - const int m_uniqueNum; - -public: - AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_DefImplicitDType(fl) - , m_name{name} - , m_containerp{containerp} - , m_uniqueNum{uniqueNumInc()} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(DefImplicitDType) - int uniqueNum() const { return m_uniqueNum; } - virtual bool same(const AstNode* samep) const override { - const AstDefImplicitDType* const sp = static_cast(samep); - return uniqueNum() == sp->uniqueNum(); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return type() == samep->type() && same(samep); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return dtypep() ? dtypep() : childDTypep(); - } - void* containerp() const { return m_containerp; } - // METHODS - // op1 = Range of variable - AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - virtual bool isCompound() const override { return false; } -}; - -class AstAssocArrayDType final : public AstNodeDType { - // Associative array data type, ie "[some_dtype]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: DTYPE (the key, which remains here as a pointer) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) - AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) -public: - AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER_AssocArrayDType(fl) { - childDTypep(dtp); // Only for parser - keyChildDTypep(keyDtp); // Only for parser - refDTypep(nullptr); - keyDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstAssocArrayDType(FileLine* fl, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER_AssocArrayDType(fl) { - refDTypep(dtp); - keyDTypep(keyDtp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(AssocArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - BROKEN_RTN(!((m_keyDTypep && !childDTypep() && m_keyDTypep->brokeExists()) - || (!m_keyDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - if (!asamep->keyDTypep()) return false; - return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual string prettyDTypeName() const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; } - virtual void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); } - // - AstNodeDType* keyDTypep() const { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } - void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } - // op1 = Range of variable - AstNodeDType* keyChildDTypep() const { return VN_AS(op2p(), NodeDType); } - void keyChildDTypep(AstNodeDType* nodep) { setOp2p(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstBracketArrayDType final : public AstNodeDType { - // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" - // only for early parsing then becomes another data type - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: DTYPE (the key) -public: - AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) - : ASTGEN_SUPER_BracketArrayDType(fl) { - setOp1p(dtp); // Only for parser - setOp2p(elementsp); // Only for parser - } - ASTNODE_NODE_FUNCS(BracketArrayDType) - virtual bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - virtual AstNodeDType* subDTypep() const override { return childDTypep(); } - // op2 = Range of variable - AstNode* elementsp() const { return op2p(); } - // METHODS - // Will be removed in V3Width, which relies on this - // being a child not a dtype pointed node - virtual bool maybePointedTo() const override { return false; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); } - virtual int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } - virtual bool isCompound() const override { return true; } -}; - -class AstDynArrayDType final : public AstNodeDType { - // Dynamic array data type, ie "[]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) -public: - AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_DynArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) - : ASTGEN_SUPER_DynArrayDType(fl) { - refDTypep(dtp); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(DynArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return subDTypep() == asamep->subDTypep(); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual string prettyDTypeName() const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstPackArrayDType final : public AstNodeArrayDType { - // Packed array data type, ie "some_dtype [2:0] var_name" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) -public: - AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_PackArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - setOp2p(rangep); - dtypep(nullptr); // V3Width will resolve - const int width = subDTypep()->width() * rangep->elementsConst(); - widthForce(width, width); - } - AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_PackArrayDType(fl) { - refDTypep(dtp); - setOp2p(rangep); - dtypep(this); - const int width = subDTypep()->width() * rangep->elementsConst(); - widthForce(width, width); - } - ASTNODE_NODE_FUNCS(PackArrayDType) - virtual string prettyDTypeName() const override; - virtual bool isCompound() const override { return false; } -}; - -class AstUnpackArrayDType final : public AstNodeArrayDType { - // Array data type, ie "some_dtype var_name [2:0]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) - bool m_isCompound = false; // Non-POD subDType, or parent requires compound -public: - AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_UnpackArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - setOp2p(rangep); - dtypep(nullptr); // V3Width will resolve - // For backward compatibility AstNodeArrayDType and others inherit - // width and signing from the subDType/base type - widthFromSub(subDTypep()); - } - AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_UnpackArrayDType(fl) { - refDTypep(dtp); - setOp2p(rangep); - dtypep(this); - // For backward compatibility AstNodeArrayDType and others inherit - // width and signing from the subDType/base type - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(UnpackArrayDType) - virtual string prettyDTypeName() const override; - virtual bool same(const AstNode* samep) const override { - const AstUnpackArrayDType* const sp = static_cast(samep); - return m_isCompound == sp->m_isCompound; - } - // Outer dimension comes first. The first element is this node. - std::vector unpackDimensions(); - void isCompound(bool flag) { m_isCompound = flag; } - virtual bool isCompound() const override { return m_isCompound; } -}; - -class AstUnsizedArrayDType final : public AstNodeDType { - // Unsized/open-range Array data type, ie "some_dtype var_name []" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) -public: - AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_UnsizedArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(UnsizedArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstWildcardArrayDType final : public AstNodeDType { - // Wildcard index type associative array data type, ie "some_dtype var_name [*]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) -public: - AstWildcardArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_WildcardArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(WildcardArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { - return sizeof(std::map); - } - virtual int widthTotalBytes() const override { - return sizeof(std::map); - } - virtual bool isCompound() const override { return true; } -}; - -class AstBasicDType final : public AstNodeDType { - // Builtin atomic/vectored data type - // Children: RANGE (converted to constant in V3Width) -private: - struct Members { - VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type - VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) - bool operator==(const Members& rhs) const { - return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; - } - } m; - // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) -public: - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, signst, 0, -1, nullptr); - } - AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER_BasicDType(fl) { - init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); - } - AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER_BasicDType(fl) { - init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); - } - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, numer, wantwidth, widthmin, nullptr); - } - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, numer, range.elements(), widthmin, nullptr); - m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be - } - // See also addRange in verilog.y -private: - void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, - AstRange* rangep) { - // wantwidth=0 means figure it out, but if a widthmin is >=0 - // we allow width 0 so that {{0{x}},y} works properly - // wantwidthmin=-1: default, use wantwidth if it is non zero - m.m_keyword = kwd; - // Implicitness: // "parameter X" is implicit and sized from initial - // value, "parameter reg x" not - if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) { - if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC; - } - if (numer == VSigning::NOSIGN) { - if (keyword().isSigned()) { - numer = VSigning::SIGNED; - } else if (keyword().isUnsigned()) { - numer = VSigning::UNSIGNED; - } - } - numeric(numer); - if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width - if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false); - const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth; - widthForce(wantwidth, wmin); - } else if (!rangep) { // Set based on keyword properties - // V3Width will pull from this width - if (keyword().width() > 1 && !isOpaque()) { - m.m_nrange.init(keyword().width() - 1, 0, false); - } - widthForce(keyword().width(), keyword().width()); - } else { - widthForce(rangep->elementsConst(), - rangep->elementsConst()); // Maybe unknown if parameters underneath it - } - setNOp1p(rangep); - dtypep(this); - } - -public: - ASTNODE_NODE_FUNCS(BasicDType) - virtual void dump(std::ostream& str) const override; - // width/widthMin/numeric compared elsewhere - virtual bool same(const AstNode* samep) const override { - const AstBasicDType* const sp = static_cast(samep); - return m == sp->m; - } - virtual bool similarDType(AstNodeDType* samep) const override { - return type() == samep->type() && same(samep); - } - virtual string name() const override { return m.m_keyword.ascii(); } - virtual string prettyDTypeName() const override; - virtual const char* broken() const override { - BROKEN_RTN(dtypep() != this); - return nullptr; - } - AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range of variable - void rangep(AstRange* nodep) { setNOp1p(nodep); } - void setSignedState(const VSigning& signst) { - // Note NOSIGN does NOT change the state; this is required by the parser - if (signst == VSigning::UNSIGNED) { - numeric(signst); - } else if (signst == VSigning::SIGNED) { - numeric(signst); - } - } - // METHODS - virtual AstBasicDType* basicp() const override { return (AstBasicDType*)this; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override; - virtual bool isFourstate() const override { return keyword().isFourstate(); } - VBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead - return m.m_keyword; - } - bool isBitLogic() const { return keyword().isBitLogic(); } - bool isDouble() const { return keyword().isDouble(); } - bool isEventValue() const { return keyword().isEventValue(); } - bool isOpaque() const { return keyword().isOpaque(); } - bool isString() const { return keyword().isString(); } - bool isZeroInit() const { return keyword().isZeroInit(); } - bool isRanged() const { return rangep() || m.m_nrange.ranged(); } - bool isDpiBitVec() const { // DPI uses svBitVecVal - return keyword() == VBasicDTypeKwd::BIT && isRanged(); - } - bool isDpiLogicVec() const { // DPI uses svLogicVecVal - return keyword().isFourstate() && !(keyword() == VBasicDTypeKwd::LOGIC && !isRanged()); - } - bool isDpiPrimitive() const { // DPI uses a primitive type - return !isDpiBitVec() && !isDpiLogicVec(); - } - // Generally the lo/hi/left/right funcs should be used instead of nrange() - const VNumRange& nrange() const { return m.m_nrange; } - int hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } - int lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } - int elements() const { return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); } - int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration - int right() const { return littleEndian() ? hi() : lo(); } - bool littleEndian() const { - return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); - } - bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; } - VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } - void cvtRangeConst() { // Convert to smaller representation - if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) { - m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()}; - rangep()->unlinkFrBackWithNext()->deleteTree(); - rangep(nullptr); - } - } - virtual bool isCompound() const override { return isString(); } -}; - -class AstConstDType final : public AstNodeDType { - // const data type, ie "const some_dtype var_name [2:0]" - // ConstDType are removed in V3LinkLValue and become AstVar::isConst. - // When more generic types are supported AstConstDType will be propagated further. -private: - AstNodeDType* m_refDTypep = nullptr; // Inherit from this base data type -public: - AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_ConstDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); // V3Width will resolve - dtypep(nullptr); // V3Width will resolve - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(ConstDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstConstDType* const sp = static_cast(samep); - return (m_refDTypep == sp->m_refDTypep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return skipRefp()->similarDType(samep->skipRefp()); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstClassRefDType final : public AstNodeDType { - // Reference to a class - // Children: PINs (for parameter settings) -private: - AstClass* m_classp; // data type pointed to, BELOW the AstTypedef - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy -public: - AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) - : ASTGEN_SUPER_ClassRefDType(fl) - , m_classp{classp} { - dtypep(this); - addNOp4p(paramsp); - } - ASTNODE_NODE_FUNCS(ClassRefDType) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_classp && !m_classp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - const AstClassRefDType* const asamep = static_cast(samep); - return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return this == samep || (type() == samep->type() && same(samep)); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual string name() const override { return classp() ? classp()->name() : ""; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 0; } - virtual int widthTotalBytes() const override { return 0; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual AstNodeDType* subDTypep() const override { return nullptr; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - AstClass* classp() const { return m_classp; } - void classp(AstClass* nodep) { m_classp = nodep; } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } - virtual bool isCompound() const override { return true; } -}; - -class AstIfaceRefDType final : public AstNodeDType { - // Reference to an interface, either for a port, or inside parent cell -private: - FileLine* m_modportFileline; // Where modport token was - string m_cellName; // "" = no cell, such as when connects to 'input' iface - string m_ifaceName; // Interface name - string m_modportName; // "" = no modport - AstIface* m_ifacep = nullptr; // Pointer to interface; note cellp() should override - AstCell* m_cellp = nullptr; // When exact parent cell known; not a guess - AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport -public: - AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) - : ASTGEN_SUPER_IfaceRefDType(fl) - , m_modportFileline{nullptr} - , m_cellName{cellName} - , m_ifaceName{ifaceName} - , m_modportName{""} {} - AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, - const string& ifaceName, const string& modport) - : ASTGEN_SUPER_IfaceRefDType(fl) - , m_modportFileline{modportFl} - , m_cellName{cellName} - , m_ifaceName{ifaceName} - , m_modportName{modport} {} - ASTNODE_NODE_FUNCS(IfaceRefDType) - // METHODS - virtual const char* broken() const override; - virtual void dump(std::ostream& str = std::cout) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual void cloneRelink() override; - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - FileLine* modportFileline() const { return m_modportFileline; } - string cellName() const { return m_cellName; } - void cellName(const string& name) { m_cellName = name; } - string ifaceName() const { return m_ifaceName; } - void ifaceName(const string& name) { m_ifaceName = name; } - string modportName() const { return m_modportName; } - AstIface* ifaceViaCellp() const; // Use cellp or ifacep - AstIface* ifacep() const { return m_ifacep; } - void ifacep(AstIface* nodep) { m_ifacep = nodep; } - AstCell* cellp() const { return m_cellp; } - void cellp(AstCell* nodep) { m_cellp = nodep; } - AstModport* modportp() const { return m_modportp; } - void modportp(AstModport* modportp) { m_modportp = modportp; } - bool isModport() { return !m_modportName.empty(); } - virtual bool isCompound() const override { return true; } // But not relevant -}; - -class AstQueueDType final : public AstNodeDType { - // Queue array data type, ie "[ $ ]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) -public: - AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER_QueueDType(fl) { - setNOp2p(boundp); - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER_QueueDType(fl) { - setNOp2p(boundp); - refDTypep(dtp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(QueueDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual string prettyDTypeName() const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - AstNode* boundp() const { return op2p(); } // op2 = Bound, nullptr = none - void boundp(AstNode* nodep) { setNOp2p(nodep); } - int boundConst() const { - AstConst* const constp = VN_CAST(boundp(), Const); - return (constp ? constp->toSInt() : 0); - } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstRefDType final : public AstNodeDType { -private: - // Pre-Width must reference the Typeref, not what it points to, as some child - // types like AstBracketArrayType will disappear and can't lose the handle - AstTypedef* m_typedefp = nullptr; // referenced type - // Post-width typedefs are removed and point to type directly - AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef - string m_name; // Name of an AstTypedef - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy -public: - AstRefDType(FileLine* fl, const string& name) - : ASTGEN_SUPER_RefDType(fl) - , m_name{name} {} - AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) - : ASTGEN_SUPER_RefDType(fl) - , m_name{name} { - setNOp3p(classOrPackagep); - addNOp4p(paramsp); - } - class FlagTypeOfExpr {}; // type(expr) for parser only - AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) - : ASTGEN_SUPER_RefDType(fl) { - setOp2p(typeofp); - } - ASTNODE_NODE_FUNCS(RefDType) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists()); - BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep(); - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - const AstRefDType* const asamep = static_cast(samep); - return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep - && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return skipRefp()->similarDType(samep->skipRefp()); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - virtual string prettyDTypeName() const override { - return subDTypep() ? subDTypep()->name() : prettyName(); - } - virtual AstBasicDType* basicp() const override { - return subDTypep() ? subDTypep()->basicp() : nullptr; - } - virtual AstNodeDType* subDTypep() const override { - if (typedefp()) return typedefp()->subDTypep(); - return refDTypep(); // Maybe nullptr - } - virtual AstNodeDType* skipRefp() const override { - // Skip past both the Ref and the Typedef - if (subDTypep()) { - return subDTypep()->skipRefp(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual AstNodeDType* skipRefToConstp() const override { - if (subDTypep()) { - return subDTypep()->skipRefToConstp(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual AstNodeDType* skipRefToEnump() const override { - if (subDTypep()) { - return subDTypep()->skipRefToEnump(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual int widthAlignBytes() const override { return dtypeSkipRefp()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); } - virtual void name(const string& flag) override { m_name = flag; } - // op1 = Range of variable - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - AstTypedef* typedefp() const { return m_typedefp; } - void typedefp(AstTypedef* nodep) { m_typedefp = nodep; } - AstNodeDType* refDTypep() const { return m_refDTypep; } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return refDTypep(); } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - AstNode* typeofp() const { return op2p(); } - AstNode* classOrPackageOpp() const { return op3p(); } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstStructDType final : public AstNodeUOrStructDType { -public: - // VSigning below is mispurposed to indicate if packed or not - AstStructDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} - ASTNODE_NODE_FUNCS(StructDType) - virtual string verilogKwd() const override { return "struct"; } -}; - -class AstUnionDType final : public AstNodeUOrStructDType { -public: - // UNSUP: bool isTagged; - // VSigning below is mispurposed to indicate if packed or not - AstUnionDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} - ASTNODE_NODE_FUNCS(UnionDType) - virtual string verilogKwd() const override { return "union"; } -}; - -class AstMemberDType final : public AstNodeDType { - // A member of a struct/union - // PARENT: AstNodeUOrStructDType -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) - string m_name; // Name of variable - string m_tag; // Holds the string of the verilator tag -- used in XML output. - int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member - // UNSUP: int m_randType; // Randomization type (IEEE) -public: - AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberDType(fl) - , m_name{name} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - refDTypep(nullptr); - } - AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberDType(fl) - , m_name{name} { - UASSERT(dtp, "AstMember created with no dtype"); - refDTypep(dtp); - dtypep(this); - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(MemberDType) - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - // - // (Slow) recurse down to find basic data type (Note don't need virtual - - // AstVar isn't a NodeDType) - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - // METHODS - virtual void name(const string& name) override { m_name = name; } - virtual void tag(const string& text) override { m_tag = text; } - virtual string tag() const override { return m_tag; } - int lsb() const { return m_lsb; } - void lsb(int lsb) { m_lsb = lsb; } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstEmptyQueueDType final : public AstNodeDType { - // For EmptyQueue -public: - explicit AstEmptyQueueDType(FileLine* fl) - : ASTGEN_SUPER_EmptyQueueDType(fl) { - dtypep(this); - } - ASTNODE_NODE_FUNCS(EmptyQueueDType) - virtual void dumpSmall(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual bool undead() const override { return true; } - virtual AstNodeDType* subDTypep() const override { return nullptr; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - virtual bool isCompound() const override { return false; } -}; - -class AstVoidDType final : public AstNodeDType { - // For e.g. a function returning void -public: - explicit AstVoidDType(FileLine* fl) - : ASTGEN_SUPER_VoidDType(fl) { - dtypep(this); - } - ASTNODE_NODE_FUNCS(VoidDType) - virtual void dumpSmall(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual bool undead() const override { return true; } - virtual AstNodeDType* subDTypep() const override { return nullptr; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - virtual bool isCompound() const override { return false; } -}; - -class AstEnumItem final : public AstNode { -private: - string m_name; - -public: - // Parents: ENUM - AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) - : ASTGEN_SUPER_EnumItem(fl) - , m_name{name} { - addNOp1p(rangep); - addNOp2p(initp); - } - ASTNODE_NODE_FUNCS(EnumItem) - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range for name appending - void rangep(AstRange* nodep) { addOp1p(nodep); } - AstNode* valuep() const { return op2p(); } // op2 = Value - void valuep(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstEnumItemRef final : public AstNodeMath { -private: - AstEnumItem* m_itemp; // [AfterLink] Pointer to item - AstNodeModule* m_classOrPackagep; // Package hierarchy -public: - AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) - : ASTGEN_SUPER_EnumItemRef(fl) - , m_itemp{itemp} - , m_classOrPackagep{classOrPackagep} { - dtypeFrom(m_itemp); - } - ASTNODE_NODE_FUNCS(EnumItemRef) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return itemp()->name(); } - virtual int instrCount() const override { return 0; } - virtual const char* broken() const override { - BROKEN_RTN(m_itemp && !m_itemp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstEnumItemRef* const sp = static_cast(samep); - return itemp() == sp->itemp(); - } - AstEnumItem* itemp() const { return m_itemp; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } -}; - -class AstEnumDType final : public AstNodeDType { - // Parents: TYPEDEF/MODULE - // Children: ENUMVALUEs -private: - string m_name; // Name from upper typedef, if any - AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width - const int m_uniqueNum = 0; - -public: - AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) - : ASTGEN_SUPER_EnumDType(fl) - , m_uniqueNum{uniqueNumInc()} { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - addNOp2p(itemsp); - dtypep(nullptr); // V3Width will resolve - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(EnumDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - int uniqueNum() const { return m_uniqueNum; } - virtual bool same(const AstNode* samep) const override { - const AstEnumDType* const sp = static_cast(samep); - return uniqueNum() == sp->uniqueNum(); - } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } // op1 = Data type - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - // op1 = Range of variable - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - AstEnumItem* itemsp() const { return VN_AS(op2p(), EnumItem); } // op2 = AstEnumItem's - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - int itemCount() const { - size_t count = 0; - for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++; - return count; - } - virtual bool isCompound() const override { return false; } -}; - -class AstParseTypeDType final : public AstNodeDType { - // Parents: VAR - // During parsing, this indicates the type of a parameter is a "parameter type" - // e.g. the data type is a container of any data type -public: - explicit AstParseTypeDType(FileLine* fl) - : ASTGEN_SUPER_ParseTypeDType(fl) {} - ASTNODE_NODE_FUNCS(ParseTypeDType) - AstNodeDType* dtypep() const { return nullptr; } - // METHODS - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 0; } - virtual int widthTotalBytes() const override { return 0; } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -//###################################################################### - -class AstArraySel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); - } - } - -public: - AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { - init(fromp); - } - AstArraySel(FileLine* fl, AstNode* fromp, int bit) - : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { - init(fromp); - } - ASTNODE_NODE_FUNCS(ArraySel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstArraySel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; /* How can from be a const? */ - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - // Special operators - // Return base var (or const) nodep dereferences - static AstNode* baseFromp(AstNode* nodep, bool overMembers); -}; - -class AstAssocSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), AssocArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), AssocArrayDType)->subDTypep()); - } - } - -public: - AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { - init(fromp); - } - ASTNODE_NODE_FUNCS(AssocSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssocSel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstWildcardSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep()); - } - } - -public: - AstWildcardSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) { - init(fromp); - } - ASTNODE_NODE_FUNCS(WildcardSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstWildcardSel{this->fileline(), lhsp, rhsp}; - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstWordSel final : public AstNodeSel { - // Select a single word from a multi-word wide value -public: - AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { - dtypeSetUInt32(); // Always used on WData arrays so returns edata size - } - ASTNODE_NODE_FUNCS(WordSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstWordSel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { - return "%li[%ri]"; - } // Not %k, as usually it's a small constant rhsp - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstSelLoopVars final : public AstNode { - // Parser only concept "[id, id, id]" for a foreach statement - // Unlike normal selects elements is a list -public: - AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) - : ASTGEN_SUPER_SelLoopVars(fl) { - setOp1p(fromp); - addNOp2p(elementsp); - } - ASTNODE_NODE_FUNCS(SelLoopVars) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool maybePointedTo() const override { return false; } - AstNode* fromp() const { return op1p(); } - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* elementsp() const { return op2p(); } -}; - -class AstSelExtract final : public AstNodePreSel { - // Range extraction, gets replaced with AstSel -public: - AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) - : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} - ASTNODE_NODE_FUNCS(SelExtract) - AstNode* leftp() const { return rhsp(); } - AstNode* rightp() const { return thsp(); } -}; - -class AstSelBit final : public AstNodePreSel { - // Single bit range extraction, perhaps with non-constant selection or array selection - // Gets replaced during link with AstArraySel or AstSel -public: - AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(SelBit) - AstNode* bitp() const { return rhsp(); } -}; - -class AstSelPlus final : public AstNodePreSel { - // +: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} - ASTNODE_NODE_FUNCS(SelPlus) - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; - -class AstSelMinus final : public AstNodePreSel { - // -: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} - ASTNODE_NODE_FUNCS(SelMinus) - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; - -class AstSel final : public AstNodeTriop { - // Multiple bit range extraction - // Parents: math|stmt - // Children: varref|arraysel, math, constant math - // Tempting to have an access() style method here as LHS selects are quite - // different, but that doesn't play well with V3Inst and bidirects which don't know direction -private: - VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid - int m_declElWidth; // If a packed array, the number of bits per element -public: - AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) - : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) - , m_declElWidth{1} { - if (VN_IS(widthp, Const)) { - dtypeSetLogicSized(VN_AS(widthp, Const)->toUInt(), VSigning::UNSIGNED); - } - } - AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) - : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) - , m_declElWidth{1} { - dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(Sel) - virtual void dump(std::ostream& str) const override; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, - const V3Number& width) override { - out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { - return widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%lw, %P, %li, %ri)" - : isWide() ? "VL_SEL_%nq%lq%rq%tq(%nw,%lw, %P, %li, %ri, %ti)" - : "VL_SEL_%nq%lq%rq%tq(%lw, %P, %li, %ri, %ti)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } - virtual int instrCount() const override { - return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression - AstNode* widthp() const { return op3p(); } // op3 = Width - int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); } - int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); } - int msbConst() const { return lsbConst() + widthConst() - 1; } - VNumRange& declRange() { return m_declRange; } - const VNumRange& declRange() const { return m_declRange; } - void declRange(const VNumRange& flag) { m_declRange = flag; } - int declElWidth() const { return m_declElWidth; } - void declElWidth(int flag) { m_declElWidth = flag; } -}; - -class AstSliceSel final : public AstNodeTriop { - // Multiple array element extraction - // Parents: math|stmt - // Children: varref|arraysel, math, constant math -private: - VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid -public: - AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) - : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), - new AstConst(fl, declRange.elements())) - , m_declRange{declRange} {} - ASTNODE_NODE_FUNCS(SliceSel) - virtual void dump(std::ostream& str) const override; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, - const V3Number& width) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Removed before EmitC - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } - virtual int instrCount() const override { return 10; } // Removed before matters - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - // For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods - VNumRange& declRange() { return m_declRange; } - const VNumRange& declRange() const { return m_declRange; } - void declRange(const VNumRange& flag) { m_declRange = flag; } -}; - -class AstMethodCall final : public AstNodeFTaskRef { - // A reference to a member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it -public: - AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - setOp2p(fromp); - dtypep(nullptr); // V3Width will resolve - } - AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - setOp2p(fromp); - } - ASTNODE_NODE_FUNCS(MethodCall) - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } - AstNode* fromp() const { - return op2p(); - } // op2 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstCMethodHard final : public AstNodeStmt { - // A reference to a "C" hardcoded member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. -private: - string m_name; // Name of method - bool m_pure = false; // Pure optimizable -public: - AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - setOp1p(fromp); - dtypep(nullptr); // V3Width will resolve - addNOp2p(pinsp); - } - AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - setOp1p(fromp); - addNOp2p(pinsp); - } - ASTNODE_NODE_FUNCS(CMethodHard) - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual void name(const string& name) override { m_name = name; } - virtual bool same(const AstNode* samep) const override { - const AstCMethodHard* asamep = static_cast(samep); - return (m_name == asamep->m_name); - } - virtual bool isPure() const override { return m_pure; } - void pure(bool flag) { m_pure = flag; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list - void addPinsp(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstVar final : public AstNode { - // A variable (in/out/wire/reg/param) inside a module -private: - 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 - VBasicDTypeKwd m_declKwd; // Keyword at declaration time - VLifetime m_lifetime; // Lifetime - VVarAttrClocker m_attrClocker; - MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var - int m_pinNum = 0; // For XML, if non-zero the connection pin number - bool m_ansi : 1; // ANSI port list variable (for dedup check) - 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_funcReturn : 1; // Return variable for a function - bool m_attrClockEn : 1; // User clock enable attribute - 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_isRand : 1; // Random variable - 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 isAutomatic) - bool m_isPulldown : 1; // Tri0 - bool m_isPullup : 1; // Tri1 - bool m_isIfaceParent : 1; // dtype is reference to interface present in this module - 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 - - 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_funcReturn = false; - m_attrClockEn = false; - m_attrScBv = false; - m_attrIsolateAssign = false; - m_attrSFormat = false; - m_attrSplitVar = false; - m_fileDescr = false; - m_isRand = false; - m_isConst = false; - m_isContinuously = false; - m_hasStrengthAssignment = false; - m_isStatic = false; - m_isPulldown = false; - m_isPullup = false; - m_isIfaceParent = 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_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 - if (dtp->basicp()) { - m_declKwd = dtp->basicp()->keyword(); - } else { - m_declKwd = VBasicDTypeKwd::LOGIC; - } - } - 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); - if (dtp->basicp()) { - m_declKwd = dtp->basicp()->keyword(); - } else { - m_declKwd = VBasicDTypeKwd::LOGIC; - } - } - 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); - m_declKwd = VBasicDTypeKwd::LOGIC; - } - 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); - m_declKwd = VBasicDTypeKwd::BIT; - } - 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); - m_declKwd = examplep->declKwd(); - } - ASTNODE_NODE_FUNCS(Var) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual string origName() const override { return m_origName; } // * = Original name - void origName(const string& name) { m_origName = name; } - VVarType varType() const { 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 { return m_direction; } - bool isIO() const { 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; - } - VBasicDTypeKwd declKwd() const { return m_declKwd; } - 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); - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - // op2 = Net delay - AstNode* delayp() const { return op2p(); } - void delayp(AstNode* const nodep) { setNOp2p(nodep); } - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - // (Slow) recurse down to find basic data type (Note don't need virtual - - // AstVar isn't a NodeDType) - AstBasicDType* basicp() const { return subDTypep()->basicp(); } - // op3 = Initial value that never changes (static const), or constructor argument for - // MTASKSTATE variables - AstNode* valuep() const { return op3p(); } - // It's valuep(), not constp(), as may be more complicated than an AstConst - void valuep(AstNode* nodep) { setOp3p(nodep); } - void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } - AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - void ansi(bool flag) { m_ansi = flag; } - void declTyped(bool flag) { m_declTyped = flag; } - void attrClockEn(bool flag) { m_attrClockEn = flag; } - 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 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 isRand(bool flag) { m_isRand = 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; } - void funcLocal(bool flag) { m_funcLocal = flag; } - void funcReturn(bool flag) { m_funcReturn = flag; } - void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } - bool hasStrengthAssignment() { return m_hasStrengthAssignment; } - void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } - bool isDpiOpenArray() const { 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; } - // METHODS - virtual void name(const string& name) override { m_name = name; } - virtual void tag(const string& text) override { m_tag = text; } - virtual 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; } - bool isInoutish() const { return m_direction.isInoutish(); } - bool isNonOutput() const { return m_direction.isNonOutput(); } - bool isReadOnly() const { return m_direction.isReadOnly(); } - bool isWritable() const { return m_direction.isWritable(); } - bool isTristate() const { return m_tristate; } - bool isPrimaryIO() const { return m_primaryIO; } - bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } - bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } - bool isIfaceParent() const { return m_isIfaceParent; } - bool isSignal() const { return varType().isSignal(); } - bool isNet() const { return varType().isNet(); } - 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() == VVarType::LPARAM || varType() == VVarType::GPARAM); - } - 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 { return m_usedClock; } - bool isUsedParam() const { return m_usedParam; } - bool isUsedLoopIdx() const { return m_usedLoopIdx; } - bool isSc() const { return m_sc; } - bool isScQuad() const; - bool isScBv() const; - bool isScUint() const; - bool isScBigUint() const; - bool isScSensitive() const { return m_scSensitive; } - bool isSigPublic() const; - bool isSigModPublic() const { return m_sigModPublic; } - bool isSigUserRdPublic() const { return m_sigUserRdPublic; } - bool isSigUserRWPublic() const { return m_sigUserRWPublic; } - bool isTrace() const { return m_trace; } - bool isRand() const { return m_isRand; } - bool isConst() const { return m_isConst; } - bool isStatic() const { return m_isStatic; } - bool isLatched() const { return m_isLatched; } - bool isFuncLocal() const { return m_funcLocal; } - bool isFuncReturn() const { return m_funcReturn; } - bool isPullup() const { return m_isPullup; } - bool isPulldown() const { return m_isPulldown; } - bool attrClockEn() const { return m_attrClockEn; } - 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; } - VVarAttrClocker attrClocker() const { return m_attrClocker; } - virtual string verilogKwd() const override; - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - void propagateAttrFrom(AstVar* fromp) { - // This is getting connected to fromp; keep attributes - // Note the method below too - if (fromp->attrClockEn()) attrClockEn(true); - if (fromp->attrFileDescr()) attrFileDescr(true); - if (fromp->attrIsolateAssign()) attrIsolateAssign(true); - if (fromp->isContinuously()) isContinuously(true); - } - bool gateMultiInputOptimizable() const { - // Ok to gate optimize; must return false if propagateAttrFrom would do anything - return (!attrClockEn() && !isUsedClock()); - } - void combineType(AstVar* typevarp) { - // This is same as typevarp (for combining input & reg decls) - // "this" is the input var. typevarp is the reg var. - propagateAttrFrom(typevarp); - combineType(typevarp->varType()); - if (typevarp->isSigPublic()) sigPublic(true); - if (typevarp->isSigModPublic()) sigModPublic(true); - if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true); - if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true); - if (typevarp->attrScClocked()) attrScClocked(true); - } - void inlineAttrReset(const string& name) { - if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) { - m_varType = VVarType::TRIWIRE; - } - m_direction = VDirection::NONE; - m_name = name; - } - static AstVar* scVarRecurse(AstNode* nodep); - void addProducingMTaskId(int id) { m_mtaskIds.insert(id); } - void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } - const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } - void pinNum(int id) { m_pinNum = id; } - int pinNum() const { return m_pinNum; } -}; - -class AstDefParam final : public AstNode { - // A defparam assignment - // Parents: MODULE - // Children: math -private: - 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, AstNode* rhsp) - : ASTGEN_SUPER_DefParam(fl) { - setOp1p(rhsp); - m_name = name; - m_path = path; - } - virtual string name() const override { return m_name; } // * = Scope name - ASTNODE_NODE_FUNCS(DefParam) - virtual bool same(const AstNode*) const override { return true; } - AstNode* rhsp() const { return op1p(); } // op1 = Assign from - string path() const { return m_path; } -}; - -class AstImplicit final : public AstNode { - // Create implicit wires and do nothing else, for gates that are ignored - // Parents: MODULE -public: - AstImplicit(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_Implicit(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(Implicit) - AstNode* exprsp() const { return op1p(); } // op1 = Assign from -}; - -class AstScope final : public AstNode { - // A particular usage of a cell - // Parents: MODULE - // Children: NODEBLOCK -private: - // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope - string m_name; // Name - AstScope* const m_aboveScopep; // Scope above this one in the hierarchy (nullptr if top) - AstCell* const m_aboveCellp; // Cell above this in the hierarchy (nullptr if top) - AstNodeModule* const m_modp; // Module scope corresponds to -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} {} - ASTNODE_NODE_FUNCS(Scope) - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return m_name; } // * = Scope name - virtual void name(const string& name) override { m_name = name; } - virtual void dump(std::ostream& str) const override; - string nameDotless() const; - string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } - AstNodeModule* modp() const { return m_modp; } - void addVarp(AstVarScope* nodep) { addOp1p((AstNode*)nodep); } - AstVarScope* varsp() const { return VN_AS(op1p(), VarScope); } // op1 = AstVarScope's - void addActivep(AstNode* nodep) { addOp2p(nodep); } - AstNode* blocksp() const { return op2p(); } // op2 = Block names - void addFinalClkp(AstNode* nodep) { addOp3p(nodep); } - AstNode* finalClksp() const { return op3p(); } // op3 = Final assigns for clock correction - AstScope* aboveScopep() const { return m_aboveScopep; } - AstCell* aboveCellp() const { return m_aboveCellp; } - bool isTop() const { return aboveScopep() == nullptr; } // At top of hierarchy -}; - -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). - // Parent: Top level AstModule - // Children: AstSenTree, AstScope - friend class AstNetlist; // Only the AstNetlist can create one - AstTopScope(FileLine* fl, AstScope* ascopep) - : ASTGEN_SUPER_TopScope(fl) { - addOp2p(ascopep); - } - -public: - ASTNODE_NODE_FUNCS(TopScope) - virtual bool maybePointedTo() const override { return true; } - AstSenTree* senTreesp() const { return VN_AS(op1p(), SenTree); } - void addSenTreep(AstSenTree* nodep) { addOp1p((AstNode*)nodep); } - AstScope* scopep() const { return VN_AS(op2p(), Scope); } -}; - -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 -private: - AstScope* m_scopep; // Scope variable is underneath - AstVar* m_varp; // [AfterLink] Pointer to variable itself - bool m_circular : 1; // Used in circular ordering dependency, need change detect - 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_circular = false; - m_trace = true; - dtypeFrom(varp); - } - ASTNODE_NODE_FUNCS(VarScope) - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) { - m_varp = m_varp->clonep(); - UASSERT(m_scopep->clonep(), "No clone cross link: " << this); - m_scopep = m_scopep->clonep(); - } - } - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return scopep()->name() + "->" + varp()->name(); } - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under - void scopep(AstScope* nodep) { m_scopep = nodep; } - bool isCircular() const { return m_circular; } - void circular(bool flag) { m_circular = flag; } - bool isTrace() const { return m_trace; } - void trace(bool flag) { m_trace = flag; } -}; - -class AstVarRef final : public AstNodeVarRef { - // A reference to a variable (lvalue or rvalue) -public: - AstVarRef(FileLine* fl, const string& name, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} - // This form only allowed post-link because output/wire compression may - // lead to deletion of AstVar's - AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} - // This form only allowed post-link (see above) - AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { - varScopep(varscp); - } - ASTNODE_NODE_FUNCS(VarRef) - virtual void dump(std::ostream& str) const override; - virtual bool same(const AstNode* samep) const override { - return same(static_cast(samep)); - } - inline bool same(const AstVarRef* samep) const { - if (varScopep()) { - return (varScopep() == samep->varScopep() && access() == samep->access()); - } else { - return (selfPointer() == samep->selfPointer() - && varp()->name() == samep->varp()->name() && access() == samep->access()); - } - } - inline bool sameNoLvalue(AstVarRef* samep) const { - if (varScopep()) { - return (varScopep() == samep->varScopep()); - } else { - return (selfPointer() == samep->selfPointer() - && (!selfPointer().empty() || !samep->selfPointer().empty()) - && varp()->name() == samep->varp()->name()); - } - } - virtual int instrCount() const override { - return widthInstrs() * (access().isReadOrRW() ? INSTR_COUNT_LD : 1); - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } -}; - -class AstVarXRef final : public AstNodeVarRef { - // A VarRef to something in another module before AstScope. - // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope -private: - string m_dotted; // Dotted part of scope the name()'ed reference is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out -public: - AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) - , m_dotted{dotted} {} - AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) - , m_dotted{dotted} { - dtypeFrom(varp); - } - ASTNODE_NODE_FUNCS(VarXRef) - virtual void dump(std::ostream& str) const override; - string dotted() const { return m_dotted; } - void dotted(const string& dotted) { m_dotted = dotted; } - string inlinedDots() const { return m_inlinedDots; } - void inlinedDots(const string& flag) { m_inlinedDots = flag; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode* samep) const override { - const AstVarXRef* asamep = static_cast(samep); - return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp() - && name() == asamep->name() && dotted() == asamep->dotted()); - } -}; - -class AstAddrOfCFunc final : public AstNodeMath { - // Get address of CFunc -private: - AstCFunc* m_funcp; // Pointer to function itself - -public: - AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp) - : ASTGEN_SUPER_AddrOfCFunc(fl) - , m_funcp{funcp} { - dtypep(findCHandleDType()); - } - -public: - ASTNODE_NODE_FUNCS(AddrOfCFunc) - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstCFunc* funcp() const { return m_funcp; } -}; - -class AstPin final : public AstNode { - // A pin on a cell -private: - int m_pinNum; // Pin number - string m_name; // Pin name, or "" for number based interconnect - AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule. - AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule. - bool m_param = false; // Pin connects to parameter - bool m_svImplicit = false; // Pin is SystemVerilog .name'ed -public: - AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) - : ASTGEN_SUPER_Pin(fl) - , m_pinNum{pinNum} - , m_name{name} { - setNOp1p(exprp); - } - AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) - : ASTGEN_SUPER_Pin(fl) - , m_pinNum{pinNum} - , m_name{varname->name()} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Pin) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); - BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); - return nullptr; - } - virtual string name() const override { return m_name; } // * = Pin name, ""=go by number - virtual void name(const string& name) override { m_name = name; } - virtual string prettyOperatorName() const override { - return modVarp() - ? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " - : "") - + "port connection " + modVarp()->prettyNameQ()) - : "port connection"; - } - bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked - int pinNum() const { return m_pinNum; } - void exprp(AstNode* nodep) { addOp1p(nodep); } - // op1 = Expression connected to pin, nullptr if unconnected - AstNode* exprp() const { return op1p(); } - 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 svImplicit() const { return m_svImplicit; } - void svImplicit(bool flag) { m_svImplicit = flag; } -}; - -class AstArg final : public AstNode { - // An argument to a function/task -private: - string m_name; // Pin name, or "" for number based interconnect -public: - AstArg(FileLine* fl, const string& name, AstNode* exprp) - : ASTGEN_SUPER_Arg(fl) - , m_name{name} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Arg) - virtual string name() const override { return m_name; } // * = Pin name, ""=go by number - virtual void name(const string& name) override { m_name = name; } - void exprp(AstNode* nodep) { addOp1p(nodep); } - // op1 = Expression connected to pin, nullptr if unconnected - AstNode* exprp() const { return op1p(); } - bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } -}; - -class AstModule final : public AstNodeModule { - // A module declaration -private: - const bool m_isProgram; // Module represents a program -public: - AstModule(FileLine* fl, const string& name, bool program = false) - : ASTGEN_SUPER_Module(fl, name) - , m_isProgram{program} {} - ASTNODE_NODE_FUNCS(Module) - virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } - virtual bool timescaleMatters() const override { return true; } -}; - -class AstNotFoundModule final : public AstNodeModule { - // A missing module declaration -public: - AstNotFoundModule(FileLine* fl, const string& name) - : ASTGEN_SUPER_NotFoundModule(fl, name) {} - ASTNODE_NODE_FUNCS(NotFoundModule) - virtual string verilogKwd() const override { return "/*not-found-*/ module"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstPackage final : public AstNodeModule { - // A package declaration -public: - AstPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER_Package(fl, name) {} - ASTNODE_NODE_FUNCS(Package) - virtual string verilogKwd() const override { return "package"; } - virtual 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) - : ASTGEN_SUPER_Primitive(fl, name) {} - ASTNODE_NODE_FUNCS(Primitive) - virtual string verilogKwd() const override { return "primitive"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstPackageExportStarStar final : public AstNode { - // A package export *::* declaration -public: - // cppcheck-suppress noExplicitConstructor - AstPackageExportStarStar(FileLine* fl) - : ASTGEN_SUPER_PackageExportStarStar(fl) {} - ASTNODE_NODE_FUNCS(PackageExportStarStar) -}; - -class AstPackageExport final : public AstNode { -private: - // A package export declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy -public: - AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER_PackageExport(fl) - , m_name{name} - , m_packagep{packagep} {} - ASTNODE_NODE_FUNCS(PackageExport) - virtual const char* broken() const override { - BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } -}; - -class AstPackageImport final : public AstNode { -private: - // A package import declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy -public: - AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER_PackageImport(fl) - , m_name{name} - , m_packagep{packagep} {} - ASTNODE_NODE_FUNCS(PackageImport) - virtual const char* broken() const override { - BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } -}; - -class AstIface final : public AstNodeModule { - // A module declaration -public: - AstIface(FileLine* fl, const string& name) - : ASTGEN_SUPER_Iface(fl, name) {} - ASTNODE_NODE_FUNCS(Iface) - // Interfaces have `timescale applicability but lots of code seems to - // get false warnings if we enable this - virtual string verilogKwd() const override { return "interface"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstMemberSel final : public AstNodeMath { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - string m_name; - AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection -public: - AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) - : ASTGEN_SUPER_MemberSel(fl) - , m_name{name} { - setOp1p(fromp); - dtypep(nullptr); // V3Width will resolve - } - AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberSel(fl) - , m_name{dtp->name()} { - setOp1p(fromp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(MemberSel) - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); - } - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return true; - } // dtype comparison does it - virtual int instrCount() const override { return widthInstrs(); } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstVar* varp() const { return m_varp; } - void varp(AstVar* nodep) { m_varp = nodep; } -}; - -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 -private: - string m_name; // Name of the variable referenced - bool m_export; // Type of the function (import/export) - AstNodeFTask* m_ftaskp = nullptr; // Link to the function -public: - AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) - : ASTGEN_SUPER_ModportFTaskRef(fl) - , m_name{name} - , m_export{isExport} {} - ASTNODE_NODE_FUNCS(ModportFTaskRef) - virtual const char* broken() const override { - BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual void cloneRelink() override { - if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); - } - 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 -private: - string m_name; // Name of the variable referenced - VDirection m_direction; // Direction of the variable (in/out) - AstVar* m_varp = nullptr; // Link to the actual Var -public: - AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) - : ASTGEN_SUPER_ModportVarRef(fl) - , m_name{name} - , m_direction{direction} {} - ASTNODE_NODE_FUNCS(ModportVarRef) - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); - } - virtual string name() const override { return m_name; } - void direction(const VDirection& flag) { m_direction = flag; } - VDirection direction() const { return m_direction; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - void varp(AstVar* varp) { m_varp = varp; } -}; - -class AstModport final : public AstNode { - // A modport in an interface -private: - string m_name; // Name of the modport -public: - AstModport(FileLine* fl, const string& name, AstNode* varsp) - : ASTGEN_SUPER_Modport(fl) - , m_name{name} { - addNOp1p(varsp); - } - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - ASTNODE_NODE_FUNCS(Modport) - AstNode* varsp() const { return op1p(); } // op1 = List of Vars -}; - -class AstIntfRef final : public AstNode { - // An interface reference -private: - string m_name; // Name of the reference -public: - AstIntfRef(FileLine* fl, const string& name) - : ASTGEN_SUPER_IntfRef(fl) - , m_name{name} {} - virtual string name() const override { return m_name; } - ASTNODE_NODE_FUNCS(IntfRef) -}; - -class AstCell final : public AstNode { - // A instantiation cell or interface call (don't know which until link) -private: - 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 - AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced - 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} { - addNOp1p(pinsp); - addNOp2p(paramsp); - setNOp3p(rangep); - } - ASTNODE_NODE_FUNCS(Cell) - // No cloneRelink, we presume cloneee's want the same module linkages - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_modp && !m_modp->brokeExists()); - return nullptr; - } - virtual bool maybePointedTo() const override { return true; } - // ACCESSORS - virtual string name() const override { return m_name; } // * = Cell name - virtual void name(const string& name) override { m_name = name; } - virtual 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; } - AstPin* pinsp() const { return VN_AS(op1p(), Pin); } // op1 = List of cell ports - // op2 = List of parameter #(##) values - AstPin* paramsp() const { return VN_AS(op2p(), Pin); } - // op3 = Range of arrayed instants (nullptr=not ranged) - AstRange* rangep() const { return VN_AS(op3p(), Range); } - // op4 = List of interface references - AstIntfRef* intfRefp() const { return VN_AS(op4p(), IntfRef); } - AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated - void addPinsp(AstPin* nodep) { addOp1p(nodep); } - void addParamsp(AstPin* nodep) { addOp2p(nodep); } - void addIntfRefp(AstIntfRef* nodep) { addOp4p(nodep); } - 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 -private: - string m_name; // Cell name, possibly {a}__DOT__{b}... - const string - m_origModName; // Original name of the module, ignoring name() changes, for dot lookup - AstScope* m_scopep = nullptr; // The scope that the cell is inlined into - 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} {} - ASTNODE_NODE_FUNCS(CellInline) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - // ACCESSORS - virtual string name() const override { return m_name; } // * = Cell name - string origModName() const { return m_origModName; } // * = modp()->origName() before inlining - virtual void name(const string& name) override { m_name = name; } - void scopep(AstScope* scp) { m_scopep = scp; } - AstScope* scopep() const { return m_scopep; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstCellRef final : public AstNode { - // As-of-yet unlinkable reference into a cell -private: - string m_name; // Cell name -public: - AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) - : ASTGEN_SUPER_CellRef(fl) - , m_name{name} { - addNOp1p(cellp); - addNOp2p(exprp); - } - ASTNODE_NODE_FUNCS(CellRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Array name - AstNode* cellp() const { return op1p(); } // op1 = Cell - AstNode* exprp() const { return op2p(); } // op2 = Expression -}; - -class AstCellArrayRef final : public AstNode { - // As-of-yet unlinkable reference into an array of cells -private: - string m_name; // Array name -public: - AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) - : ASTGEN_SUPER_CellArrayRef(fl) - , m_name{name} { - addNOp1p(selectExprp); - } - ASTNODE_NODE_FUNCS(CellArrayRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Array name - AstNode* selp() const { return op1p(); } // op1 = Select expression -}; - -class AstUnlinkedRef final : public AstNode { - // As-of-yet unlinkable Ref -private: - string m_name; // Var name -public: - AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) - : ASTGEN_SUPER_UnlinkedRef(fl) - , m_name{name} { - addNOp1p(refp); - addNOp2p(crp); - } - ASTNODE_NODE_FUNCS(UnlinkedRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Var name - AstNode* refp() const { return op1p(); } // op1 = VarXRef or AstNodeFTaskRef - AstNode* cellrefp() const { return op2p(); } // op2 = CellArrayRef or CellRef -}; - -class AstBind final : public AstNode { - // Parents: MODULE - // Children: CELL -private: - 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"); - addNOp1p(cellsp); - } - ASTNODE_NODE_FUNCS(Bind) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Bind Target name - virtual void name(const string& name) override { m_name = name; } - AstNode* cellsp() const { return op1p(); } // op1 = cells -}; - -class AstPort final : public AstNode { - // A port (in/out/inout) on a module -private: - int m_pinNum; // Pin number - 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} {} - ASTNODE_NODE_FUNCS(Port) - virtual string name() const override { return m_name; } // * = Port name - int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation - AstNode* exprp() const { return op1p(); } // op1 = Expression connected to port -}; - -//###################################################################### - -class AstParseRef final : public AstNode { - // A reference to a variable, function or task - // We don't know which at parse time due to bison constraints - // The link stages will replace this with AstVarRef, or AstTaskRef, etc. - // Parents: math|stmt - // Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel) -private: - VParseRefExp m_expect; // Type we think it should resolve to - string m_name; - -public: - AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, - AstNodeFTaskRef* ftaskrefp = nullptr) - : ASTGEN_SUPER_ParseRef(fl) - , m_expect{expect} - , m_name{name} { - setNOp1p(lhsp); - setNOp2p(ftaskrefp); - } - ASTNODE_NODE_FUNCS(ParseRef) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool same(const AstNode* samep) const override { - const AstParseRef* const asamep = static_cast(samep); - return (expect() == asamep->expect() && m_name == asamep->m_name); - } - virtual void name(const string& name) override { m_name = name; } - VParseRefExp expect() const { return m_expect; } - void expect(VParseRefExp exp) { m_expect = exp; } - // op1 = Components - AstNode* lhsp() const { return op1p(); } // op1 = List of statements - AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference - void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference -}; - -class AstClassOrPackageRef final : public AstNode { -private: - string m_name; - // Node not NodeModule to appease some early parser usage - AstNode* m_classOrPackageNodep; // Package hierarchy -public: - AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, - AstNode* paramsp) - : ASTGEN_SUPER_ClassOrPackageRef(fl) - , m_name{name} - , m_classOrPackageNodep{classOrPackageNodep} { - addNOp4p(paramsp); - } - ASTNODE_NODE_FUNCS(ClassOrPackageRef) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) { - m_classOrPackageNodep = m_classOrPackageNodep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - return (m_classOrPackageNodep - == static_cast(samep)->m_classOrPackageNodep); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } - void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } - AstNodeModule* classOrPackagep() const { - AstNode* foundp = m_classOrPackageNodep; - while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); - if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp(); - return VN_CAST(foundp, NodeModule); - } - AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = nodep; } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } -}; - -class AstDot final : public AstNode { - // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef - // These are eliminated in the link stage - const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) -public: - AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Dot(fl) - , m_colon{colon} { - setOp1p(lhsp); - setOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(Dot) - // For parser, make only if non-null package - static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { - if (!packageOrClassp) return rhsp; - return new AstDot(fl, true, packageOrClassp, rhsp); - } - virtual void dump(std::ostream& str) const override; - AstNode* lhsp() const { return op1p(); } - void rhsp(AstNode* nodep) { setOp2p(nodep); } - AstNode* rhsp() const { return op2p(); } - bool colon() const { return m_colon; } -}; - -class AstUnbounded final : public AstNodeMath { - // A $ in the parser, used for unbounded and queues - // Due to where is used, treated as Signed32 -public: - explicit AstUnbounded(FileLine* fl) - : ASTGEN_SUPER_Unbounded(fl) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(Unbounded) - virtual string emitVerilog() override { return "$"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } -}; - -//###################################################################### - -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) {} - ASTNODE_NODE_FUNCS(Task) -}; - -class AstFunc final : public AstNodeFTask { - // A function inside a module -public: - AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) - : ASTGEN_SUPER_Func(fl, name, stmtp) { - addNOp1p(fvarsp); - } - ASTNODE_NODE_FUNCS(Func) - virtual bool hasDType() const override { return true; } -}; - -class AstTaskRef final : public AstNodeFTaskRef { - // A reference to a task -public: - AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { - statement(true); - } - AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} - ASTNODE_NODE_FUNCS(TaskRef) -}; - -class AstFuncRef final : public AstNodeFTaskRef { - // A reference to a function -public: - AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} - AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} - ASTNODE_NODE_FUNCS(FuncRef) - virtual bool hasDType() const override { return true; } -}; - -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) -private: - 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} {} - ASTNODE_NODE_FUNCS(DpiExport) - virtual string name() const override { return m_name; } - virtual void name(const string& name) override { m_name = name; } - string cname() const { return m_cname; } - void cname(const string& cname) { m_cname = cname; } -}; - -class AstWithParse final : public AstNodeStmt { - // In early parse, FUNC(index) WITH equation-using-index - // Replaced with AstWith - // Parents: math|stmt - // Children: funcref, math -public: - AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) - : ASTGEN_SUPER_WithParse(fl) { - statement(stmt); - setOp1p(funcrefp); - addNOp2p(exprp); - } - ASTNODE_NODE_FUNCS(WithParse) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* funcrefp() const { return op1p(); } - AstNode* exprp() const { return op2p(); } -}; - -class AstLambdaArgRef final : public AstNodeMath { - // Lambda argument usage - // These are not AstVarRefs because we need to be able to delete/clone lambdas during - // optimizations and AstVar's are painful to remove. -private: - string m_name; // Name of variable - bool m_index; // Index, not value - -public: - AstLambdaArgRef(FileLine* fl, const string& name, bool index) - : ASTGEN_SUPER_LambdaArgRef(fl) - , m_name{name} - , m_index(index) {} - ASTNODE_NODE_FUNCS(LambdaArgRef) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual string emitVerilog() override { return name(); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual string name() const override { return m_name; } // * = Var name - virtual void name(const string& name) override { m_name = name; } - bool index() const { return m_index; } -}; - -class AstWith final : public AstNodeStmt { - // Used as argument to method, then to AstCMethodHard - // dtypep() contains the with lambda's return dtype - // Parents: funcref (similar to AstArg) - // Children: LambdaArgRef that declares the item variable - // Children: LambdaArgRef that declares the item.index variable - // Children: math (equation establishing the with) -public: - AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, - AstNode* exprp) - : ASTGEN_SUPER_With(fl) { - addOp1p(indexArgRefp); - addOp2p(valueArgRefp); - addNOp3p(exprp); - } - ASTNODE_NODE_FUNCS(With) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool hasDType() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype - BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype - return nullptr; - } - // - AstLambdaArgRef* indexArgRefp() const { return VN_AS(op1p(), LambdaArgRef); } - AstLambdaArgRef* valueArgRefp() const { return VN_AS(op2p(), LambdaArgRef); } - AstNode* exprp() const { return op3p(); } -}; - -//###################################################################### - -class AstSenItem final : public AstNode { - // Parents: SENTREE - // Children: (optional) VARREF -private: - VEdgeType m_edgeType; // Edge type -public: - class Combo {}; // for creator type-overload selection - class Illegal {}; // for creator type-overload selection - class Initial {}; // for creator type-overload selection - class Settle {}; // for creator type-overload selection - class Never {}; // for creator type-overload selection - AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{edgeType} { - setOp1p(varrefp); - } - AstSenItem(FileLine* fl, Combo) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_COMBO} {} - AstSenItem(FileLine* fl, Illegal) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_ILLEGAL} {} - AstSenItem(FileLine* fl, Initial) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_INITIAL} {} - AstSenItem(FileLine* fl, Settle) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_SETTLE} {} - AstSenItem(FileLine* fl, Never) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_NEVER} {} - ASTNODE_NODE_FUNCS(SenItem) - virtual void dump(std::ostream& str) const override; - virtual bool same(const AstNode* samep) const override { - return edgeType() == static_cast(samep)->edgeType(); - } - VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge - void edgeType(VEdgeType type) { - m_edgeType = type; - editCountInc(); - } // * = Posedge/negedge - AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized - AstNodeVarRef* varrefp() const { - return VN_CAST(op1p(), NodeVarRef); - } // op1 = Signal sensitized - // - bool isClocked() const { return edgeType().clockedStmt(); } - bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } - bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } - bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } - bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } - bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } - bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } -}; - -class AstSenTree final : public AstNode { - // A list of senitems - // Parents: MODULE | SBLOCK - // Children: SENITEM list -private: - bool m_multi = false; // Created from combo logic by ORing multiple clock domains -public: - AstSenTree(FileLine* fl, AstSenItem* sensesp) - : ASTGEN_SUPER_SenTree(fl) { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(SenTree) - virtual void dump(std::ostream& str) const override; - virtual bool maybePointedTo() const override { return true; } - bool isMulti() const { return m_multi; } - // op1 = Sensitivity list - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } - void addSensesp(AstSenItem* nodep) { addOp1p(nodep); } - void multi(bool flag) { m_multi = true; } - // METHODS - bool hasClocked() const; // Includes a clocked statement - bool hasSettle() const; // Includes a SETTLE SenItem - bool hasInitial() const; // Includes a INITIAL SenItem - bool hasCombo() const; // Includes a COMBO SenItem -}; - -class AstFinal final : public AstNodeProcedure { -public: - AstFinal(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_Final(fl, bodysp) {} - ASTNODE_NODE_FUNCS(Final) -}; - -class AstInitial final : public AstNodeProcedure { -public: - AstInitial(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_Initial(fl, bodysp) {} - ASTNODE_NODE_FUNCS(Initial) -}; - -class AstInitialAutomatic final : public AstNodeProcedure { - // Automatic variable initialization - // That is, it runs every function start, or class construction -public: - AstInitialAutomatic(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_InitialAutomatic(fl, bodysp) {} - ASTNODE_NODE_FUNCS(InitialAutomatic) -}; - -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* bodysp) - : ASTGEN_SUPER_InitialStatic(fl, bodysp) {} - ASTNODE_NODE_FUNCS(InitialStatic) -}; - -class AstAlways final : public AstNodeProcedure { - const VAlwaysKwd m_keyword; - -public: - AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_Always(fl, bodysp) - , m_keyword{keyword} { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(Always) - // - virtual void dump(std::ostream& str) const override; - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list - void sensesp(AstSenTree* nodep) { setOp1p(nodep); } - VAlwaysKwd keyword() const { return m_keyword; } -}; - -class AstAlwaysPostponed final : public AstNodeProcedure { - // Like always but postponement scheduling region - -public: - AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPostponed(fl, bodysp) {} - ASTNODE_NODE_FUNCS(AlwaysPostponed) -}; - -class AstAlwaysPost final : public AstNodeProcedure { - // Like always but post assignments for memory assignment IFs -public: - AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPost(fl, bodysp) { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(AlwaysPost) -}; - -class AstAlwaysPublic final : public AstNodeStmt { - // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ - // Body statements are just AstVarRefs to the public signals -public: - AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPublic(fl) { - addNOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(AlwaysPublic) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addStmtp(AstNode* nodep) { addOp2p(nodep); } - // Special accessors - bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstAssign final : public AstNodeAssign { -public: - AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) - : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Assign) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssign(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignAlias final : public AstNodeAssign { - // Like AstAssignW, but a true bidirect interconnection alias - // If both sides are wires, there's no LHS vs RHS, -public: - AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) - : ASTGEN_SUPER_AssignAlias(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignAlias) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - V3ERROR_NA_RETURN(nullptr); - } - virtual bool brokeLhsMustBeLvalue() const override { return false; } -}; - -class AstAssignDly final : public AstNodeAssign { -public: - AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) - : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} - ASTNODE_NODE_FUNCS(AssignDly) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignDly(this->fileline(), lhsp, rhsp); - } - virtual bool isGateOptimizable() const override { return false; } - virtual string verilogKwd() const override { return "<="; } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignW final : public AstNodeAssign { - // Like assign, but wire/assign's in verilog, the only setting of the specified variable -public: - AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignW) - AstStrengthSpec* strengthSpecp() const { return VN_AS(op4p(), StrengthSpec); } - void strengthSpecp(AstStrengthSpec* const strengthSpecp) { setOp4p((AstNode*)strengthSpecp); } - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignW(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } - AstAlways* convertToAlways() { - AstNode* const lhs1p = lhsp()->unlinkFrBack(); - AstNode* const rhs1p = rhsp()->unlinkFrBack(); - AstAlways* const newp = new AstAlways(fileline(), VAlwaysKwd::ALWAYS, nullptr, - new AstAssign(fileline(), lhs1p, rhs1p)); - replaceWith(newp); // User expected to then deleteTree(); - return newp; - } -}; - -class AstAssignVarScope final : public AstNodeAssign { - // Assign two VarScopes to each other -public: - AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { - dtypeFrom(rhsp); - } - ASTNODE_NODE_FUNCS(AssignVarScope) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignVarScope(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return false; } -}; - -class AstPull final : public AstNode { -private: - bool m_direction; - -public: - AstPull(FileLine* fl, AstNode* lhsp, bool direction) - : ASTGEN_SUPER_Pull(fl) { - setOp1p(lhsp); - m_direction = direction; - } - ASTNODE_NODE_FUNCS(Pull) - virtual bool same(const AstNode* samep) const override { - return direction() == static_cast(samep)->direction(); - } - void lhsp(AstNode* np) { setOp1p(np); } - AstNode* lhsp() const { return op1p(); } // op1 = Assign to - uint32_t direction() const { return (uint32_t)m_direction; } -}; - -class AstAssignForce final : public AstNodeAssign { - // Procedural 'force' statement -public: - AstAssignForce(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignForce) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignForce{this->fileline(), lhsp, rhsp}; - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstRelease final : public AstNodeStmt { - // Procedural 'release' statement -public: - AstRelease(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Release(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(Release); - AstNode* lhsp() const { return op1p(); } -}; - -class AstAssignPre final : public AstNodeAssign { - // Like Assign, but predelayed assignment requiring special order handling -public: - AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignPre) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignPre(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignPost final : public AstNodeAssign { - // Like Assign, but predelayed assignment requiring special order handling -public: - AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignPost) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignPost(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstDpiExportUpdated final : public AstNodeStmt { - // Denotes that the referenced variable may have been updated via a DPI Export -public: - AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep) - : ASTGEN_SUPER_DpiExportUpdated(fl) { - addOp1p(new AstVarRef{fl, varScopep, VAccess::WRITE}); - } - ASTNODE_NODE_FUNCS(DpiExportUpdated) - AstVarScope* varScopep() const { return VN_AS(op1p(), VarRef)->varScopep(); } -}; - -class AstExprStmt final : public AstNodeMath { - // Perform a statement, often assignment inside an expression/math node, - // the parent gets passed the 'resultp()'. - // resultp is evaluated AFTER the statement(s). -public: - AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) - : ASTGEN_SUPER_ExprStmt(fl) { - addOp1p(stmtsp); - setOp2p(resultp); // Possibly in future nullptr could mean return rhsp() - dtypeFrom(resultp); - } - ASTNODE_NODE_FUNCS(ExprStmt) - // ACCESSORS - AstNode* stmtsp() const { return op1p(); } - void addStmtsp(AstNode* nodep) { addOp1p(nodep); } - AstNode* resultp() const { return op2p(); } - // METHODS - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstComment final : public AstNodeStmt { - // Some comment to put into the output stream - // Parents: {statement list} - // Children: none -private: - const bool m_showAt; // Show "at " - const string m_name; // Text of comment -public: - AstComment(FileLine* fl, const string& name, bool showAt = false) - : ASTGEN_SUPER_Comment(fl) - , m_showAt{showAt} - , m_name{name} {} - ASTNODE_NODE_FUNCS(Comment) - virtual string name() const override { return m_name; } // * = Text - virtual bool same(const AstNode* samep) const override { - return true; - } // Ignore name in comments - virtual bool showAt() const { return m_showAt; } -}; - -class AstCond final : public AstNodeCond { - // Conditional ?: statement - // Parents: MATH - // Children: MATH -public: - AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER_Cond(fl, condp, expr1p, expr2p) {} - ASTNODE_NODE_FUNCS(Cond) - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { - return new AstCond(this->fileline(), condp, expr1p, expr2p); - } -}; - -class AstCondBound final : public AstNodeCond { - // Conditional ?: statement, specially made for safety checking of array bounds - // Parents: MATH - // Children: MATH -public: - AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER_CondBound(fl, condp, expr1p, expr2p) {} - ASTNODE_NODE_FUNCS(CondBound) - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { - return new AstCondBound(this->fileline(), condp, expr1p, expr2p); - } -}; - -class AstCoverDecl final : public AstNodeStmt { - // Coverage analysis point declaration - // Parents: {statement list} - // Children: none -private: - AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get - // data from instead - string m_page; - string m_text; - string m_hier; - string m_linescov; - int m_offset; // Offset column numbers to uniq-ify IFs - int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment -public: - AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, - int offset) - : ASTGEN_SUPER_CoverDecl(fl) { - m_page = page; - m_text = comment; - m_linescov = linescov; - m_offset = offset; - m_binNum = 0; - m_dataDeclp = nullptr; - } - ASTNODE_NODE_FUNCS(CoverDecl) - virtual const char* broken() const override { - BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists()); - if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing - v3fatalSrc("dataDeclp should point to real data, not be a list"); - } - return nullptr; - } - virtual void cloneRelink() override { - if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } - virtual bool maybePointedTo() const override { return true; } - void binNum(int flag) { m_binNum = flag; } - int binNum() const { return m_binNum; } - int offset() const { return m_offset; } - const string& comment() const { return m_text; } // text to insert in code - const string& linescov() const { return m_linescov; } - const string& page() const { return m_page; } - const string& hier() const { return m_hier; } - void hier(const string& flag) { m_hier = flag; } - void comment(const string& flag) { m_text = flag; } - virtual bool same(const AstNode* samep) const override { - const AstCoverDecl* const asamep = static_cast(samep); - return (fileline() == asamep->fileline() && linescov() == asamep->linescov() - && hier() == asamep->hier() && comment() == asamep->comment()); - } - virtual bool isPredictOptimizable() const override { return false; } - void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } - // dataDecl nullptr means "use this one", but often you want "this" to - // indicate to get data from here - AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } - AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } -}; - -class AstCoverInc final : public AstNodeStmt { - // Coverage analysis point; increment coverage count - // Parents: {statement list} - // Children: none -private: - AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration -public: - AstCoverInc(FileLine* fl, AstCoverDecl* declp) - : ASTGEN_SUPER_CoverInc(fl) - , m_declp{declp} {} - ASTNODE_NODE_FUNCS(CoverInc) - virtual const char* broken() const override { - BROKEN_RTN(!declp()->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_declp->clonep()) m_declp = m_declp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } - virtual bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - // but isPure() true - AstCoverDecl* declp() const { return m_declp; } // Where defined -}; - -class AstCoverToggle final : public AstNodeStmt { - // Toggle analysis of given signal - // Parents: MODULE - // Children: AstCoverInc, orig var, change det var -public: - AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) - : ASTGEN_SUPER_CoverToggle(fl) { - setOp1p(incp); - setOp2p(origp); - setOp3p(changep); - } - ASTNODE_NODE_FUNCS(CoverToggle) - virtual int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isOutputter() const override { - return false; // Though the AstCoverInc under this is an outputter - } - // but isPure() true - AstCoverInc* incp() const { return VN_AS(op1p(), CoverInc); } - void incp(AstCoverInc* nodep) { setOp1p(nodep); } - AstNode* origp() const { return op2p(); } - AstNode* changep() const { return op3p(); } -}; - -class AstDelay final : public AstNodeStmt { - // Delay statement -public: - AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp) - : ASTGEN_SUPER_Delay(fl) { - setOp1p(lhsp); - setNOp2p(stmtsp); - } - ASTNODE_NODE_FUNCS(Delay) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* lhsp() const { return op1p(); } // op1 = delay value - void lhsp(AstNode* nodep) { setOp1p(nodep); } - void stmtsp(AstNode* nodep) { setOp2p(nodep); } // op2 = statements under delay - AstNode* stmtsp() const { return op2p(); } -}; - -class AstGenCase final : public AstNodeCase { - // Generate Case statement - // Parents: {statement list} - // exprp Children: MATHs - // casesp Children: CASEITEMs -public: - AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER_GenCase(fl, exprp, casesp) {} - ASTNODE_NODE_FUNCS(GenCase) -}; - -class AstCase final : public AstNodeCase { - // Case statement - // Parents: {statement list} - // exprp Children: MATHs - // casesp Children: CASEITEMs -private: - VCaseType m_casex; // 0=case, 1=casex, 2=casez - bool m_fullPragma = false; // Synthesis full_case - bool m_parallelPragma = false; // Synthesis parallel_case - bool m_uniquePragma = false; // unique case - bool m_unique0Pragma = false; // unique0 case - bool m_priorityPragma = false; // priority case -public: - AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER_Case(fl, exprp, casesp) - , m_casex{casex} {} - ASTNODE_NODE_FUNCS(Case) - virtual string verilogKwd() const override { - return casez() ? "casez" : casex() ? "casex" : "case"; - } - virtual bool same(const AstNode* samep) const override { - return m_casex == static_cast(samep)->m_casex; - } - bool casex() const { return m_casex == VCaseType::CT_CASEX; } - bool casez() const { return m_casex == VCaseType::CT_CASEZ; } - bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } - bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } - void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } - bool fullPragma() const { return m_fullPragma; } - void fullPragma(bool flag) { m_fullPragma = flag; } - bool parallelPragma() const { return m_parallelPragma; } - void parallelPragma(bool flag) { m_parallelPragma = flag; } - bool uniquePragma() const { return m_uniquePragma; } - void uniquePragma(bool flag) { m_uniquePragma = flag; } - bool unique0Pragma() const { return m_unique0Pragma; } - void unique0Pragma(bool flag) { m_unique0Pragma = flag; } - bool priorityPragma() const { return m_priorityPragma; } - void priorityPragma(bool flag) { m_priorityPragma = flag; } -}; - -class AstCaseItem final : public AstNode { - // Single item of a case statement - // Parents: CASE - // condsp Children: MATH (Null condition used for default block) - // bodysp Children: Statements -public: - AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) - : ASTGEN_SUPER_CaseItem(fl) { - addNOp1p(condsp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(CaseItem) - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - AstNode* condsp() const { return op1p(); } // op1 = list of possible matching expressions - AstNode* bodysp() const { return op2p(); } // op2 = what to do - void condsp(AstNode* nodep) { setOp1p(nodep); } - void addBodysp(AstNode* newp) { addOp2p(newp); } - bool isDefault() const { return condsp() == nullptr; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstSFormatF final : public AstNode { - // Convert format to string, generally under an AstDisplay or AstSFormat - // Also used as "real" function for /*verilator sformat*/ functions - string m_text; - const bool m_hidden; // Under display, etc - bool m_hasFormat; // Has format code - const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' - VTimescale m_timeunit; // Parent module time unit -public: - class NoFormat {}; - AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_SFormatF(fl) - , m_text{text} - , m_hidden{hidden} - , m_hasFormat{true} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addNOp1p(exprsp); - addNOp2p(nullptr); - } - AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', - bool hidden = true) - : ASTGEN_SUPER_SFormatF(fl) - , m_text{""} - , m_hidden{hidden} - , m_hasFormat{false} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addNOp1p(exprsp); - addNOp2p(nullptr); - } - ASTNODE_NODE_FUNCS(SFormatF) - virtual string name() const override { return m_text; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - virtual string verilogKwd() const override { return "$sformatf"; } - void addExprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstScopeName* scopeNamep() const { return VN_AS(op2p(), ScopeName); } - void scopeNamep(AstNode* nodep) { setNOp2p(nodep); } - bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive - return (name().find("%m") != string::npos || name().find("%M") != string::npos); - } - bool hidden() const { return m_hidden; } - void hasFormat(bool flag) { m_hasFormat = flag; } - bool hasFormat() const { return m_hasFormat; } - char missingArgChar() const { return m_missingArgChar; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstDisplay final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref - // Children: SFORMATF to generate print string -private: - VDisplayType m_displayType; - -public: - AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNode* filep, - AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER_Display(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); - setNOp3p(filep); - m_displayType = dispType; - } - AstDisplay(FileLine* fl, VDisplayType dispType, AstNode* filep, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_Display(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); - setNOp3p(filep); - m_displayType = dispType; - } - ASTNODE_NODE_FUNCS(Display) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { - return (filep() ? string("$f") + string(displayType().ascii()) - : string("$") + string(displayType().ascii())); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); - } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - VDisplayType displayType() const { return m_displayType; } - void displayType(VDisplayType type) { m_displayType = type; } - // * = Add a newline for $display - bool addNewline() const { return displayType().addNewline(); } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } - AstNode* filep() const { return op3p(); } - void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); } -}; - -class AstDumpCtl final : public AstNodeStmt { - // $dumpon etc - // Parents: expr - // Child: expr based on type of control statement - const VDumpCtlType m_ctlType; // Type of operation -public: - AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) - : ASTGEN_SUPER_DumpCtl(fl) - , m_ctlType{ctlType} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(DumpCtl) - virtual string verilogKwd() const override { return ctlType().ascii(); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool cleanOut() const { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - VDumpCtlType ctlType() const { return m_ctlType; } - AstNode* exprp() const { return op1p(); } // op2 = Expressions to output - void exprp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstElabDisplay final : public AstNode { - // Parents: stmtlist - // Children: SFORMATF to generate print string -private: - VDisplayType m_displayType; - -public: - AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp) - : ASTGEN_SUPER_ElabDisplay(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp)); - m_displayType = dispType; - } - ASTNODE_NODE_FUNCS(ElabDisplay) - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { - return (string("$") + string(displayType().ascii())); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); - } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - VDisplayType displayType() const { return m_displayType; } - void displayType(VDisplayType type) { m_displayType = type; } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } -}; - -class AstSFormat final : public AstNodeStmt { - // Parents: statement container - // Children: string to load - // Children: SFORMATF to generate print string -public: - AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_SFormat(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); - setOp3p(lhsp); - } - AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER_SFormat(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); - setOp3p(lhsp); - } - ASTNODE_NODE_FUNCS(SFormat) - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { return "$sformat"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isPure() const override { return true; } - virtual bool isOutputter() const override { return false; } - virtual bool cleanOut() const { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } - AstNode* lhsp() const { return op3p(); } - void lhsp(AstNode* nodep) { setOp3p(nodep); } -}; - -class AstSysFuncAsTask final : public AstNodeStmt { - // Call what is normally a system function (with a return) in a non-return context - // Parents: stmtlist - // Children: a system function -public: - AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_SysFuncAsTask(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(SysFuncAsTask) - virtual string verilogKwd() const override { return ""; } - virtual bool isGateOptimizable() const override { return true; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isPure() const override { return true; } - virtual bool isOutputter() const override { return false; } - virtual int instrCount() const override { return 0; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval - void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval -}; - -class AstSysIgnore final : public AstNodeStmt { - // Parents: stmtlist - // Children: varrefs or exprs -public: - AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_SysIgnore(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(SysIgnore) - virtual string verilogKwd() const override { return "$ignored"; } - virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt - virtual bool isPredictOptimizable() const override { - return false; - } // Though deleted before opt - virtual bool isPure() const override { return false; } // Though deleted before opt - virtual bool isOutputter() const override { return true; } // Though deleted before opt - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output -}; - -class AstFClose final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFClose(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FClose(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FClose) - virtual string verilogKwd() const override { return "$fclose"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFOpen final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) -public: - AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) - : ASTGEN_SUPER_FOpen(fl) { - setOp1p(filep); - setOp2p(filenamep); - setOp3p(modep); - } - ASTNODE_NODE_FUNCS(FOpen) - virtual string verilogKwd() const override { return "$fopen"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op1p(); } - AstNode* filenamep() const { return op2p(); } - AstNode* modep() const { return op3p(); } -}; - -class AstFOpenMcd final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) -public: - AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) - : ASTGEN_SUPER_FOpenMcd(fl) { - setOp1p(filep); - setOp2p(filenamep); - } - ASTNODE_NODE_FUNCS(FOpenMcd) - virtual string verilogKwd() const override { return "$fopen"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op1p(); } - AstNode* filenamep() const { return op2p(); } -}; - -class AstFFlush final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFFlush(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FFlush(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FFlush) - virtual string verilogKwd() const override { return "$fflush"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFRead final : public AstNodeMath { - // Parents: expr - // Children: varrefs to load - // Children: file which must be a varref - // Children: low index - // Children: count -public: - AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) - : ASTGEN_SUPER_FRead(fl) { - setOp1p(memp); - setOp2p(filep); - setNOp3p(startp); - setNOp4p(countp); - } - ASTNODE_NODE_FUNCS(FRead) - virtual string verilogKwd() const override { return "$fread"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* memp() const { return op1p(); } - void memp(AstNode* nodep) { setOp1p(nodep); } - AstNode* filep() const { return op2p(); } - void filep(AstNode* nodep) { setOp2p(nodep); } - AstNode* startp() const { return op3p(); } - void startp(AstNode* nodep) { setNOp3p(nodep); } - AstNode* countp() const { return op4p(); } - void countp(AstNode* nodep) { setNOp4p(nodep); } -}; - -class AstFRewind final : public AstNodeMath { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFRewind(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FRewind(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FRewind) - virtual string verilogKwd() const override { return "$frewind"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFTell final : public AstNodeMath { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFTell(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FTell(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FTell) - virtual string verilogKwd() const override { return "$ftell"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFSeek final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: offset - // Children: operation -public: - AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) - : ASTGEN_SUPER_FSeek(fl) { - setOp2p(filep); - setNOp3p(offset); - setNOp4p(operation); - } - ASTNODE_NODE_FUNCS(FSeek) - virtual string verilogKwd() const override { return "$fseek"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNode* nodep) { setOp2p(nodep); } - AstNode* offset() const { return op3p(); } - void offset(AstNode* nodep) { setNOp3p(nodep); } - AstNode* operation() const { return op4p(); } - void operation(AstNode* nodep) { setNOp4p(nodep); } -}; - -class AstFScanF final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: varrefs to load -private: - string m_text; - -public: - AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) - : ASTGEN_SUPER_FScanF(fl) - , m_text{text} { - addNOp1p(exprsp); - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FScanF) - virtual string name() const override { return m_text; } - virtual string verilogKwd() const override { return "$fscanf"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstSScanF final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: varrefs to load -private: - string m_text; - -public: - AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) - : ASTGEN_SUPER_SScanF(fl) - , m_text{text} { - addNOp1p(exprsp); - setOp2p(fromp); - } - ASTNODE_NODE_FUNCS(SScanF) - virtual string name() const override { return m_text; } - virtual string verilogKwd() const override { return "$sscanf"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstNode* fromp() const { return op2p(); } - void fromp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { -private: - const bool m_isHex; // readmemh, not readmemb -public: - AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, - AstNode* lsbp, AstNode* msbp) - : AstNodeStmt(t, fl) - , m_isHex(hex) { - setOp1p(filenamep); - setOp2p(memp); - setNOp3p(lsbp); - setNOp4p(msbp); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return isHex() == static_cast(samep)->isHex(); - } - bool isHex() const { return m_isHex; } - AstNode* filenamep() const { return op1p(); } - AstNode* memp() const { return op2p(); } - AstNode* lsbp() const { return op3p(); } - AstNode* msbp() const { return op4p(); } - virtual const char* cFuncPrefixp() const = 0; -}; - -class AstReadMem final : public AstNodeReadWriteMem { -public: - AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, - AstNode* msbp) - : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} - ASTNODE_NODE_FUNCS(ReadMem); - virtual string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } - virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } -}; - -class AstWriteMem final : public AstNodeReadWriteMem { -public: - AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, - AstNode* msbp) - : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} - ASTNODE_NODE_FUNCS(WriteMem) - virtual string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } - virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } -}; - -class AstMonitorOff final : public AstNodeStmt { - const bool m_off; // Monitor off. Using 0=on allows faster init and comparison - -public: - AstMonitorOff(FileLine* fl, bool off) - : ASTGEN_SUPER_MonitorOff(fl) - , m_off{off} {} - ASTNODE_NODE_FUNCS(MonitorOff) - virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } - virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt - virtual bool isPredictOptimizable() const override { - return false; - } // Though deleted before opt - virtual bool isPure() const override { return false; } // Though deleted before opt - virtual bool isOutputter() const override { return true; } // Though deleted before opt - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* samep) const override { - return m_off == static_cast(samep)->m_off; - } - bool off() const { return m_off; } -}; - -class AstSystemT final : public AstNodeStmt { - // $system used as task -public: - AstSystemT(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SystemT(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(SystemT) - virtual string verilogKwd() const override { return "$system"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } -}; - -class AstSystemF final : public AstNodeMath { - // $system used as function -public: - AstSystemF(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SystemF(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(SystemF) - virtual string verilogKwd() const override { return "$system"; } - virtual string emitVerilog() override { return verilogKwd(); } - virtual string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } -}; - -class AstValuePlusArgs final : public AstNodeMath { - // Parents: expr - // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs -public: - AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) - : ASTGEN_SUPER_ValuePlusArgs(fl) { - setOp1p(searchp); - setOp2p(outp); - } - ASTNODE_NODE_FUNCS(ValuePlusArgs) - virtual string verilogKwd() const override { return "$value$plusargs"; } - virtual string emitVerilog() override { return "%f$value$plusargs(%l, %k%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return !outp(); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* searchp() const { return op1p(); } // op1 = Search expression - void searchp(AstNode* nodep) { setOp1p(nodep); } - AstNode* outp() const { return op2p(); } // op2 = Expressions to output - void outp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstTestPlusArgs final : public AstNodeMath { - // Parents: expr - // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs -public: - AstTestPlusArgs(FileLine* fl, AstNode* searchp) - : ASTGEN_SUPER_TestPlusArgs(fl) { - setOp1p(searchp); - } - ASTNODE_NODE_FUNCS(TestPlusArgs) - virtual string verilogKwd() const override { return "$test$plusargs"; } - virtual string emitVerilog() override { return verilogKwd(); } - virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* searchp() const { return op1p(); } // op1 = Search expression - void searchp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstGenFor final : public AstNodeFor { -public: - AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) - : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, bodysp) {} - ASTNODE_NODE_FUNCS(GenFor) -}; - -class AstForeach final : public AstNodeStmt { -public: - AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) - : ASTGEN_SUPER_Foreach(fl) { - setOp1p(arrayp); - addNOp4p(bodysp); - } - ASTNODE_NODE_FUNCS(Foreach) - AstNode* arrayp() const { return op1p(); } // op1 = array and index vars - AstNode* bodysp() const { return op4p(); } // op4 = body of loop - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstRepeat final : public AstNodeStmt { -public: - AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) - : ASTGEN_SUPER_Repeat(fl) { - setOp2p(countp); - addNOp3p(bodysp); - } - ASTNODE_NODE_FUNCS(Repeat) - AstNode* countp() const { return op2p(); } // op2 = condition to continue - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - virtual bool isGateOptimizable() const override { - return false; - } // Not relevant - converted to FOR - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstWait final : public AstNodeStmt { -public: - AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) - : ASTGEN_SUPER_Wait(fl) { - setOp2p(condp); - addNOp3p(bodysp); - } - ASTNODE_NODE_FUNCS(Wait) - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstWhile final : public AstNodeStmt { -public: - AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp = nullptr, AstNode* incsp = nullptr) - : ASTGEN_SUPER_While(fl) { - setOp2p(condp); - addNOp3p(bodysp); - addNOp4p(incsp); - } - ASTNODE_NODE_FUNCS(While) - // op1 = prepare statements for condition (exec every loop) - AstNode* precondsp() const { return op1p(); } - AstNode* condp() const { return op2p(); } // op2 = condition to continue - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - AstNode* incsp() const { return op4p(); } // op4 = increment (if from a FOR loop) - void addPrecondsp(AstNode* newp) { addOp1p(newp); } - void addBodysp(AstNode* newp) { addOp3p(newp); } - void addIncsp(AstNode* newp) { addOp4p(newp); } - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // Stop statement searchback here - virtual void addBeforeStmt(AstNode* newp, AstNode* belowp) override; - // Stop statement searchback here - virtual void addNextStmt(AstNode* newp, AstNode* belowp) override; - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstBreak final : public AstNodeStmt { -public: - explicit AstBreak(FileLine* fl) - : ASTGEN_SUPER_Break(fl) {} - ASTNODE_NODE_FUNCS(Break) - virtual string verilogKwd() const override { return "break"; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstContinue final : public AstNodeStmt { -public: - explicit AstContinue(FileLine* fl) - : ASTGEN_SUPER_Continue(fl) {} - ASTNODE_NODE_FUNCS(Continue) - virtual string verilogKwd() const override { return "continue"; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstDisable final : public AstNodeStmt { -private: - string m_name; // Name of block -public: - AstDisable(FileLine* fl, const string& name) - : ASTGEN_SUPER_Disable(fl) - , m_name{name} {} - ASTNODE_NODE_FUNCS(Disable) - virtual string name() const override { return m_name; } // * = Block name - virtual void name(const string& flag) override { m_name = flag; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstDisableFork final : public AstNodeStmt { - // A "disable fork" statement -public: - explicit AstDisableFork(FileLine* fl) - : ASTGEN_SUPER_DisableFork(fl) {} - ASTNODE_NODE_FUNCS(DisableFork) -}; - -class AstWaitFork final : public AstNodeStmt { - // A "wait fork" statement -public: - explicit AstWaitFork(FileLine* fl) - : ASTGEN_SUPER_WaitFork(fl) {} - ASTNODE_NODE_FUNCS(WaitFork) -}; - -class AstReturn final : public AstNodeStmt { -public: - explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) - : ASTGEN_SUPER_Return(fl) { - setNOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(Return) - virtual string verilogKwd() const override { return "return"; } - AstNode* lhsp() const { return op1p(); } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstGenIf final : public AstNodeIf { -public: - AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : ASTGEN_SUPER_GenIf(fl, condp, ifsp, elsesp) {} - ASTNODE_NODE_FUNCS(GenIf) -}; - -class AstIf final : public AstNodeIf { -private: - bool m_uniquePragma; // unique case - bool m_unique0Pragma; // unique0 case - bool m_priorityPragma; // priority case -public: - AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp = nullptr, AstNode* elsesp = nullptr) - : ASTGEN_SUPER_If(fl, condp, ifsp, elsesp) { - m_uniquePragma = false; - m_unique0Pragma = false; - m_priorityPragma = false; - } - ASTNODE_NODE_FUNCS(If) - bool uniquePragma() const { return m_uniquePragma; } - void uniquePragma(bool flag) { m_uniquePragma = flag; } - bool unique0Pragma() const { return m_unique0Pragma; } - void unique0Pragma(bool flag) { m_unique0Pragma = flag; } - bool priorityPragma() const { return m_priorityPragma; } - void priorityPragma(bool flag) { m_priorityPragma = flag; } -}; - -class AstJumpBlock final : public AstNodeStmt { - // Block of code including a JumpGo and JumpLabel - // Parents: {statement list} - // Children: {statement list, with JumpGo and JumpLabel below} -private: - AstJumpLabel* m_labelp = nullptr; // [After V3Jump] Pointer to declaration - int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment -public: - // After construction must call ->labelp to associate with appropriate label - AstJumpBlock(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER_JumpBlock(fl) { - addNOp1p(stmtsp); - } - virtual const char* broken() const override; - virtual void cloneRelink() override; - ASTNODE_NODE_FUNCS(JumpBlock) - virtual int instrCount() const override { return 0; } - virtual bool maybePointedTo() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block - void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); } - int labelNum() const { return m_labelNum; } - void labelNum(int flag) { m_labelNum = flag; } - AstJumpLabel* labelp() const { return m_labelp; } - void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } -}; - -class AstJumpLabel final : public AstNodeStmt { - // Jump point declaration - // Parents: {statement list with JumpBlock above} - // Children: none -private: - AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration -public: - AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) - : ASTGEN_SUPER_JumpLabel(fl) - , m_blockp{blockp} {} - ASTNODE_NODE_FUNCS(JumpLabel) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(!blockp()->brokeExistsAbove()); - BROKEN_RTN(blockp()->labelp() != this); - return nullptr; - } - virtual void cloneRelink() override { - if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 0; } - virtual bool same(const AstNode* samep) const override { - return blockp() == static_cast(samep)->blockp(); - } - AstJumpBlock* blockp() const { return m_blockp; } -}; - -class AstJumpGo final : public AstNodeStmt { - // Jump point; branch down to a JumpLabel - // No support for backward jumps at present - // Parents: {statement list with JumpBlock above} - // Children: none -private: - AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration -public: - AstJumpGo(FileLine* fl, AstJumpLabel* labelp) - : ASTGEN_SUPER_JumpGo(fl) - , m_labelp{labelp} {} - ASTNODE_NODE_FUNCS(JumpGo); - virtual const char* broken() const override { - BROKEN_RTN(!labelp()->brokeExistsBelow()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* samep) const override { - return labelp() == static_cast(samep)->labelp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } - AstJumpLabel* labelp() const { return m_labelp; } -}; - -class AstChangeDet final : public AstNodeStmt { - // A comparison to determine change detection, common & must be fast. -public: - // Null lhs+rhs used to indicate change needed with no spec vars - AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ChangeDet(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ChangeDet) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } // xor, or/logor - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsAssoc final : public AstNodeMath { - // Construct an assoc array and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstConsAssoc(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER_ConsAssoc(fl) { - setNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(ConsAssoc) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* defaultp() const { return op1p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; -class AstSetAssoc final : public AstNodeMath { - // Set an assoc array element and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER_SetAssoc(fl) { - setOp1p(lhsp); - setNOp2p(keyp); - setOp3p(valuep); - } - ASTNODE_NODE_FUNCS(SetAssoc) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } - AstNode* valuep() const { return op3p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsWildcard final : public AstNodeMath { - // Construct a wildcard assoc array and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstConsWildcard(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER_ConsWildcard(fl) { - setNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(ConsWildcard) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* defaultp() const { return op1p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; -class AstSetWildcard final : public AstNodeMath { - // Set a wildcard assoc array element and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER_SetWildcard(fl) { - setOp1p(lhsp); - setNOp2p(keyp); - setOp3p(valuep); - } - ASTNODE_NODE_FUNCS(SetWildcard) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } - AstNode* valuep() const { return op3p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsDynArray final : public AstNodeMath { - // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} - // Parents: math - // Children: expression (elements or other queues) -public: - explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER_ConsDynArray(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ConsDynArray) - virtual string emitVerilog() override { return "'{%l, %r}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } // op1 = expression - AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsQueue final : public AstNodeMath { - // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} - // Parents: math - // Children: expression (elements or other queues) -public: - explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER_ConsQueue(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ConsQueue) - virtual string emitVerilog() override { return "'{%l, %r}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } // op1 = expression - AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstBegin final : public AstNodeBlock { - // A Begin/end named block, only exists shortly after parsing until linking - // Parents: statement - // Children: statements -private: - bool m_generate; // Underneath a generate - const bool m_implied; // 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} - , m_implied{implied} {} - ASTNODE_NODE_FUNCS(Begin) - virtual void dump(std::ostream& str) const override; - // op1p is statements in NodeBlock - AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, - // might NOT be a GenFor, as loop unrolling replaces with Begin - void addGenforp(AstGenFor* nodep) { addOp2p(nodep); } - void generate(bool flag) { m_generate = flag; } - bool generate() const { return m_generate; } - bool implied() const { return m_implied; } -}; - -class AstFork final : public AstNodeBlock { - // A fork named block - // Parents: statement - // Children: statements -private: - 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) {} - ASTNODE_NODE_FUNCS(Fork) - virtual void dump(std::ostream& str) const override; - VJoinType joinType() const { return m_joinType; } - void joinType(const VJoinType& flag) { m_joinType = flag; } -}; - -class AstInside final : public AstNodeMath { -public: - AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) - : ASTGEN_SUPER_Inside(fl) { - addOp1p(exprp); - addOp2p(itemsp); - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Inside) - AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with - // op2 = RHS, possibly a list of expr or AstInsideRange - AstNode* itemsp() const { return op2p(); } - virtual string emitVerilog() override { return "%l inside { %r }"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } // NA -}; - -class AstInsideRange final : public AstNodeMath { -public: - AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_InsideRange(fl) { - addOp1p(lhsp); - addOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(InsideRange) - AstNode* lhsp() const { return op1p(); } // op1 = LHS - AstNode* rhsp() const { return op2p(); } // op2 = RHS - virtual string emitVerilog() override { return "[%l:%r]"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } // NA - // Create AstAnd(AstGte(...), AstLte(...)) - AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); -}; - -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) -public: - // Parents: INITARRAY - AstInitItem(FileLine* fl, AstNode* valuep) - : ASTGEN_SUPER_InitItem(fl) { - addOp1p(valuep); - } - ASTNODE_NODE_FUNCS(InitItem) - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return false; } // See valuep()'s dtype instead - AstNode* valuep() const { return op1p(); } // op1 = Value - void valuep(AstNode* nodep) { addOp1p(nodep); } -}; - -class AstInitArray final : public AstNode { - // Set a var to a map of values - // The list of initsp() is not relevant - // If default is specified, the vector may be sparse, and not provide each value. - // Key values are C++ array style, with lo() at index 0 - // Parents: ASTVAR::init() - // Children: AstInitItem -public: - using KeyItemMap = std::map; - -private: - KeyItemMap m_map; // Node value for each array index -public: - AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp) - : ASTGEN_SUPER_InitArray(fl) { - dtypep(newDTypep); - addNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(InitArray) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { - BROKEN_RTN(!it->second); - BROKEN_RTN(!it->second->brokeExists()); - } - return nullptr; - } - virtual void cloneRelink() override { - for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { - if (it->second->clonep()) it->second = it->second->clonep(); - } - } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - // Only works if exact same children, instead should override comparison - // of children list, and instead use map-vs-map key/value compare - return m_map == static_cast(samep)->m_map; - } - AstNode* defaultp() const { return op1p(); } // op1 = Default if sparse - void defaultp(AstNode* newp) { setOp1p(newp); } - AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions - void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); } - const KeyItemMap& map() const { return m_map; } - AstNode* addIndexValuep(uint64_t index, AstNode* newp) { - // Returns old value, caller must garbage collect - AstNode* oldp = nullptr; - const auto it = m_map.find(index); - if (it != m_map.end()) { - oldp = it->second->valuep(); - it->second->valuep(newp); - } else { - AstInitItem* const itemp = new AstInitItem(fileline(), newp); - m_map.emplace(index, itemp); - addOp2p(itemp); - } - return oldp; - } - AstNode* getIndexValuep(uint64_t index) const { - const auto it = m_map.find(index); - if (it == m_map.end()) { - return nullptr; - } else { - return it->second->valuep(); - } - } - AstNode* getIndexDefaultedValuep(uint64_t index) const { - AstNode* valuep = getIndexValuep(index); - if (!valuep) valuep = defaultp(); - return valuep; - } -}; - -class AstNew final : public AstNodeFTaskRef { - // New as constructor - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNew(FileLine* fl, AstNode* pinsp) - : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} - ASTNODE_NODE_FUNCS(New) - virtual bool cleanOut() const { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool hasDType() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstNewCopy final : public AstNodeMath { - // New as shallow copy - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNewCopy(FileLine* fl, AstNode* rhsp) - : ASTGEN_SUPER_NewCopy(fl) { - dtypeFrom(rhsp); // otherwise V3Width will resolve - setNOp1p(rhsp); - } - ASTNODE_NODE_FUNCS(NewCopy) - virtual string emitVerilog() override { return "new"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* rhsp() const { return op1p(); } -}; - -class AstNewDynamic final : public AstNodeMath { - // New for dynamic array - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) - : ASTGEN_SUPER_NewDynamic(fl) { - dtypeFrom(rhsp); // otherwise V3Width will resolve - setNOp1p(sizep); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(NewDynamic) - virtual string emitVerilog() override { return "new"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* sizep() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } -}; - -class AstPragma final : public AstNode { -private: - const VPragmaType m_pragType; // Type of pragma -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} {} - ASTNODE_NODE_FUNCS(Pragma) - VPragmaType pragType() const { return m_pragType; } // *=type of the pragma - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return pragType() == static_cast(samep)->pragType(); - } -}; - -class AstPrintTimeScale final : public AstNodeStmt { - // Parents: stmtlist - string m_name; // Parent module name - VTimescale m_timeunit; // Parent module time unit -public: - explicit AstPrintTimeScale(FileLine* fl) - : ASTGEN_SUPER_PrintTimeScale(fl) {} - ASTNODE_NODE_FUNCS(PrintTimeScale) - virtual void name(const string& name) override { m_name = name; } - virtual string name() const override { return m_name; } // * = Var name - virtual void dump(std::ostream& str) const override; - virtual string verilogKwd() const override { return "$printtimescale"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstStop final : public AstNodeStmt { -public: - AstStop(FileLine* fl, bool maybe) - : ASTGEN_SUPER_Stop(fl) {} - ASTNODE_NODE_FUNCS(Stop) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual int instrCount() const override { return 0; } // Rarely executes - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstFinish final : public AstNodeStmt { -public: - explicit AstFinish(FileLine* fl) - : ASTGEN_SUPER_Finish(fl) {} - ASTNODE_NODE_FUNCS(Finish) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual int instrCount() const override { return 0; } // Rarely executes - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstNullCheck final : public AstNodeUniop { - // Return LHS after checking that LHS is non-null - // Children: VarRef or something returning pointer -public: - AstNullCheck(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_NullCheck(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(NullCheck) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual int instrCount() const override { return 1; } // Rarely executes - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstEventControl final : public AstNodeStmt { - // Parents: stmtlist -public: - AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) - : ASTGEN_SUPER_EventControl(fl) { - setNOp1p(sensesp); - setNOp2p(stmtsp); - } - ASTNODE_NODE_FUNCS(EventControl) - virtual string verilogKwd() const override { return "@(%l) %r"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return false; } - virtual int instrCount() const override { return 0; } - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } - AstNode* stmtsp() const { return op2p(); } -}; - -class AstTimeFormat final : public AstNodeStmt { - // Parents: stmtlist -public: - AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, - AstNode* widthp) - : ASTGEN_SUPER_TimeFormat(fl) { - setOp1p(unitsp); - setOp2p(precisionp); - setOp3p(suffixp); - setOp4p(widthp); - } - ASTNODE_NODE_FUNCS(TimeFormat) - virtual string verilogKwd() const override { return "$timeformat"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - AstNode* unitsp() const { return op1p(); } - AstNode* precisionp() const { return op2p(); } - AstNode* suffixp() const { return op3p(); } - AstNode* widthp() const { return op4p(); } -}; - -class AstTracePushNamePrefix final : public AstNodeStmt { - const string m_prefix; // Prefix to add to signal names -public: - AstTracePushNamePrefix(FileLine* fl, const string& prefix) - : ASTGEN_SUPER_TracePushNamePrefix(fl) - , m_prefix{prefix} {} - ASTNODE_NODE_FUNCS(TracePushNamePrefix) - virtual bool same(const AstNode* samep) const override { return false; } - string prefix() const { return m_prefix; } -}; - -class AstTracePopNamePrefix final : public AstNodeStmt { - const unsigned m_count; // How many levels to pop -public: - AstTracePopNamePrefix(FileLine* fl, unsigned count) - : ASTGEN_SUPER_TracePopNamePrefix(fl) - , m_count{count} {} - ASTNODE_NODE_FUNCS(TracePopNamePrefix) - virtual bool same(const AstNode* samep) const override { return false; } - unsigned count() const { return m_count; } -}; - -class AstTraceDecl final : public AstNodeStmt { - // Trace point declaration - // Separate from AstTraceInc; as a declaration can't be deleted - // Parents: {statement list} - // Children: expression being traced -private: - uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines - const string m_showname; // Name of variable - const VNumRange m_bitRange; // Property of var the trace details - const VNumRange m_arrayRange; // Property of var the trace details - const uint32_t m_codeInc; // Code increment - const VVarType m_varType; // Type of variable (for localparam vs. param) - const VBasicDTypeKwd m_declKwd; // Keyword at declaration time - const VDirection m_declDirection; // Declared direction input/output etc -public: - AstTraceDecl(FileLine* fl, const string& showname, - AstVar* varp, // For input/output state etc - AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange) - : ASTGEN_SUPER_TraceDecl(fl) - , m_showname{showname} - , m_bitRange{bitRange} - , m_arrayRange{arrayRange} - , m_codeInc( - ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() - * (VL_EDATASIZE / 32))) // A code is always 32-bits - , m_varType{varp->varType()} - , m_declKwd{varp->declKwd()} - , m_declDirection{varp->declDirection()} { - dtypeFrom(valuep); - addNOp1p(valuep); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 100; } // Large... - ASTNODE_NODE_FUNCS(TraceDecl) - virtual string name() const override { return m_showname; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { return false; } - string showname() const { return m_showname; } // * = Var name - // Details on what we're tracing - uint32_t code() const { return m_code; } - void code(uint32_t code) { m_code = code; } - uint32_t codeInc() const { return m_codeInc; } - const VNumRange& bitRange() const { return m_bitRange; } - const VNumRange& arrayRange() const { return m_arrayRange; } - VVarType varType() const { return m_varType; } - VBasicDTypeKwd declKwd() const { return m_declKwd; } - VDirection declDirection() const { return m_declDirection; } - AstNode* valuep() const { return op1p(); } -}; - -class AstTraceInc final : public AstNodeStmt { - // Trace point dump - // Parents: {statement list} - // Children: op1: things to emit before this node, - // op2: expression being traced (from decl) - -private: - AstTraceDecl* m_declp; // Pointer to declaration - const bool m_full; // Is this a full vs incremental dump - const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc - -public: - AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0) - : ASTGEN_SUPER_TraceInc(fl) - , m_declp{declp} - , m_full{full} - , m_baseCode{baseCode} { - dtypeFrom(declp); - addOp2p(declp->valuep()->cloneTree(true)); - } - ASTNODE_NODE_FUNCS(TraceInc) - virtual const char* broken() const override { - BROKEN_RTN(!declp()->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_declp->clonep()) m_declp = m_declp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - // but isPure() true - // op1 = Statements before the value - AstNode* precondsp() const { return op1p(); } - void addPrecondsp(AstNode* newp) { addOp1p(newp); } - AstNode* valuep() const { return op2p(); } - AstTraceDecl* declp() const { return m_declp; } - bool full() const { return m_full; } - uint32_t baseCode() const { return m_baseCode; } -}; - -class AstActive final : public AstNode { - // Block of code with sensitivity activation - // Parents: MODULE | CFUNC - // Children: SENTREE, statements -private: - string m_name; - AstSenTree* m_sensesp; - -public: - AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) - : ASTGEN_SUPER_Active(fl) { - m_name = name; // Copy it - UASSERT(sensesp, "Sensesp required arg"); - m_sensesp = sensesp; - } - ASTNODE_NODE_FUNCS(Active) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - virtual const char* broken() const override { - BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_sensesp->clonep()) { - m_sensesp = m_sensesp->clonep(); - UASSERT(m_sensesp, "Bad clone cross link: " << this); - } - } - // Statements are broken into pieces, as some must come before others. - void sensesp(AstSenTree* nodep) { m_sensesp = nodep; } - AstSenTree* sensesp() const { return m_sensesp; } - // op1 = Sensitivity tree, if a clocked block in early stages - void sensesStorep(AstSenTree* nodep) { addOp1p(nodep); } - AstSenTree* sensesStorep() const { return VN_AS(op1p(), SenTree); } - // op2 = Combo logic - AstNode* stmtsp() const { return op2p(); } - void addStmtsp(AstNode* nodep) { addOp2p(nodep); } - // METHODS - bool hasInitial() const { return m_sensesp->hasInitial(); } - bool hasSettle() const { return m_sensesp->hasSettle(); } - bool hasClocked() const { return m_sensesp->hasClocked(); } -}; - -class AstAttrOf final : public AstNode { -private: - // Return a value of a attribute, for example a LSB or array LSB of a signal - VAttrType m_attrType; // What sort of extraction -public: - AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) - : ASTGEN_SUPER_AttrOf(fl) { - setNOp1p(fromp); - setNOp2p(dimp); - m_attrType = attrtype; - } - ASTNODE_NODE_FUNCS(AttrOf) - AstNode* fromp() const { return op1p(); } - AstNode* dimp() const { return op2p(); } - VAttrType attrType() const { return m_attrType; } - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstScopeName final : public AstNodeMath { - // For display %m and DPI context imports - // Parents: DISPLAY - // Children: TEXT -private: - bool m_dpiExport = false; // Is for dpiExport - const bool m_forFormat = false; // Is for a format %m - string scopeNameFormatter(AstText* scopeTextp) const; - string scopePrettyNameFormatter(AstText* scopeTextp) const; - -public: - class ForFormat {}; - AstScopeName(FileLine* fl, bool forFormat) - : ASTGEN_SUPER_ScopeName(fl) - , m_forFormat{forFormat} { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(ScopeName) - virtual bool same(const AstNode* samep) const override { - return (m_dpiExport == static_cast(samep)->m_dpiExport - && m_forFormat == static_cast(samep)->m_forFormat); - } - virtual string emitVerilog() override { return ""; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - AstText* scopeAttrp() const { return VN_AS(op1p(), Text); } - void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } - AstText* scopeEntrp() const { return VN_AS(op2p(), Text); } - void scopeEntrp(AstNode* nodep) { addOp2p(nodep); } - string scopeSymName() const { // Name for __Vscope variable including children - return scopeNameFormatter(scopeAttrp()); - } - string scopeDpiName() const { // Name for DPI import scope - return scopeNameFormatter(scopeEntrp()); - } - string scopePrettySymName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeAttrp()); - } - string scopePrettyDpiName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeEntrp()); - } - bool dpiExport() const { return m_dpiExport; } - void dpiExport(bool flag) { m_dpiExport = flag; } - bool forFormat() const { return m_forFormat; } -}; - -class AstUdpTable final : public AstNode { -public: - AstUdpTable(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_UdpTable(fl) { - addNOp1p(bodysp); - } - ASTNODE_NODE_FUNCS(UdpTable) - // op1 = List of UdpTableLines - AstUdpTableLine* bodysp() const { return VN_AS(op1p(), UdpTableLine); } -}; - -class AstUdpTableLine final : public AstNode { - string m_text; - -public: - AstUdpTableLine(FileLine* fl, const string& text) - : ASTGEN_SUPER_UdpTableLine(fl) - , m_text{text} {} - ASTNODE_NODE_FUNCS(UdpTableLine) - virtual string name() const override { return m_text; } - string text() const { return m_text; } -}; - -//====================================================================== -// non-ary ops - -class AstRand final : public AstNodeMath { - // $random/$random(seed) or $urandom/$urandom(seed) - // Return a random number, based upon width() -private: - const bool m_urandom = false; // $urandom vs $random - const bool m_reset = false; // Random reset, versus always random -public: - class Reset {}; - AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) - : ASTGEN_SUPER_Rand(fl) - , m_reset{reset} { - dtypep(dtp); - } - AstRand(FileLine* fl, AstNode* seedp, bool urandom) - : ASTGEN_SUPER_Rand(fl) - , m_urandom(urandom) { - setNOp1p(seedp); - } - ASTNODE_NODE_FUNCS(Rand) - virtual string emitVerilog() override { - return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)") - : (m_urandom ? "%f$urandom()" : "%f$random()"); - } - virtual string emitC() override { - return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" - : seedp() - ? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" : "VL_RANDOM_SEEDED_%nq%lq(%li)") - : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // - : "VL_RANDOM_%nq()"; - } - virtual bool cleanOut() const override { return false; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool combinable(const AstRand* samep) const { - return !seedp() && !samep->seedp() && reset() == samep->reset() - && urandom() == samep->urandom(); - } - AstNode* seedp() const { return op1p(); } - bool reset() const { return m_reset; } - bool urandom() const { return m_urandom; } -}; - -class AstURandomRange final : public AstNodeBiop { - // $urandom_range -public: - explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { - dtypeSetUInt32(); // Says IEEE - } - ASTNODE_NODE_FUNCS(URandomRange) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstURandomRange(fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%f$urandom_range(%l, %r)"; } - virtual string emitC() override { return "VL_URANDOM_RANGE_%nq(%li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } -}; - -class AstTime final : public AstNodeTermop { - VTimescale m_timeunit; // Parent module time unit -public: - AstTime(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER_Time(fl) - , m_timeunit{timeunit} { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(Time) - virtual string emitVerilog() override { return "%f$time"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_TIME; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstTimeD final : public AstNodeTermop { - VTimescale m_timeunit; // Parent module time unit -public: - AstTimeD(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER_TimeD(fl) - , m_timeunit{timeunit} { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(TimeD) - virtual string emitVerilog() override { return "%f$realtime"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_TIME; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstUCFunc final : public AstNodeMath { - // User's $c function - // Perhaps this should be an AstNodeListop; but there's only one list math right now -public: - AstUCFunc(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_UCFunc(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(UCFunc) - virtual bool cleanOut() const override { return false; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isSubstOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Unary ops - -class AstNegate final : public AstNodeUniop { -public: - AstNegate(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Negate(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Negate) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); } - virtual string emitVerilog() override { return "%f(- %l)"; } - virtual string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } -}; -class AstNegateD final : public AstNodeUniop { -public: - AstNegateD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_NegateD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(NegateD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegateD(lhs); } - virtual string emitVerilog() override { return "%f(- %l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstRedAnd final : public AstNodeUniop { -public: - AstRedAnd(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedAnd(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedAnd) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } - virtual string emitVerilog() override { return "%f(& %l)"; } - virtual string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstRedOr final : public AstNodeUniop { -public: - AstRedOr(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedOr(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedOr) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } - virtual string emitVerilog() override { return "%f(| %l)"; } - virtual string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstRedXor final : public AstNodeUniop { -public: - AstRedXor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedXor(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedXor) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } - virtual string emitVerilog() override { return "%f(^ %l)"; } - virtual string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { - const int w = lhsp()->width(); - return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16); - } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return 1 + V3Number::log2b(width()); } -}; - -class AstLenN final : public AstNodeUniop { - // Length of a string -public: - AstLenN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LenN(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(LenN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); } - virtual string emitVerilog() override { return "%f(%l)"; } - virtual string emitC() override { return "VL_LEN_IN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstLogNot final : public AstNodeUniop { -public: - AstLogNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LogNot(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogNot) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } - virtual string emitVerilog() override { return "%f(! %l)"; } - virtual string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; } - virtual string emitSimpleOperator() override { return "!"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstNot final : public AstNodeUniop { -public: - AstNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Not(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Not) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); } - virtual string emitVerilog() override { return "%f(~ %l)"; } - virtual string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; } - virtual string emitSimpleOperator() override { return "~"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } -}; -class AstExtend final : public AstNodeUniop { - // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() -public: - AstExtend(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Extend(fl, lhsp) {} - AstExtend(FileLine* fl, AstNode* lhsp, int width) - : ASTGEN_SUPER_Extend(fl, lhsp) { - dtypeSetLogicSized(width, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(Extend) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { - return false; // Because the EXTEND operator self-casts - } - virtual int instrCount() const override { return 0; } -}; -class AstExtendS final : public AstNodeUniop { - // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() -public: - AstExtendS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ExtendS(fl, lhsp) {} - AstExtendS(FileLine* fl, AstNode* lhsp, int width) - // Important that widthMin be correct, as opExtend requires it after V3Expand - : ASTGEN_SUPER_ExtendS(fl, lhsp) { - dtypeSetLogicSized(width, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ExtendS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opExtendS(lhs, lhsp()->widthMinV()); - } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { - return false; // Because the EXTEND operator self-casts - } - virtual int instrCount() const override { return 0; } - virtual bool signedFlavor() const override { return true; } -}; -class AstSigned final : public AstNodeUniop { - // $signed(lhs) -public: - AstSigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Signed(fl, lhsp) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(Signed) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAssign(lhs); - out.isSigned(false); - } - virtual string emitVerilog() override { return "%f$signed(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters - virtual int instrCount() const override { return 0; } -}; -class AstUnsigned final : public AstNodeUniop { - // $unsigned(lhs) -public: - AstUnsigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Unsigned(fl, lhsp) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(Unsigned) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAssign(lhs); - out.isSigned(false); - } - virtual string emitVerilog() override { return "%f$unsigned(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters - virtual int instrCount() const override { return 0; } -}; -class AstRToIS final : public AstNodeUniop { - // $rtoi(lhs) -public: - AstRToIS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RToIS(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(RToIS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); } - virtual string emitVerilog() override { return "%f$rtoi(%l)"; } - virtual string emitC() override { return "VL_RTOI_I_D(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstRToIRoundS final : public AstNodeUniop { - // Convert real to integer, with arbitrary sized output (not just "integer" format) -public: - AstRToIRoundS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(RToIRoundS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opRToIRoundS(lhs); - } - virtual string emitVerilog() override { return "%f$rtoi_rounded(%l)"; } - virtual string emitC() override { - return isWide() ? "VL_RTOIROUND_%nq_D(%nw, %P, %li)" : "VL_RTOIROUND_%nq_D(%li)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstIToRD final : public AstNodeUniop { - // $itor where lhs is unsigned -public: - AstIToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IToRD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(IToRD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIToRD(lhs); } - virtual string emitVerilog() override { return "%f$itor(%l)"; } - virtual string emitC() override { return "VL_ITOR_D_%lq(%lw, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstISToRD final : public AstNodeUniop { - // $itor where lhs is signed -public: - AstISToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ISToRD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(ISToRD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opISToRD(lhs); } - virtual string emitVerilog() override { return "%f$itor($signed(%l))"; } - virtual string emitC() override { return "VL_ISTOR_D_%lq(%lw, %li)"; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstRealToBits final : public AstNodeUniop { -public: - AstRealToBits(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RealToBits(fl, lhsp) { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(RealToBits) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opRealToBits(lhs); - } - virtual string emitVerilog() override { return "%f$realtobits(%l)"; } - virtual string emitC() override { return "VL_CVT_Q_D(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstBitsToRealD final : public AstNodeUniop { -public: - AstBitsToRealD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(BitsToRealD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opBitsToRealD(lhs); - } - virtual string emitVerilog() override { return "%f$bitstoreal(%l)"; } - virtual string emitC() override { return "VL_CVT_D_Q(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; - -class AstCLog2 final : public AstNodeUniop { -public: - AstCLog2(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CLog2(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(CLog2) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } - virtual string emitVerilog() override { return "%f$clog2(%l)"; } - virtual string emitC() override { return "VL_CLOG2_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstCountBits final : public AstNodeQuadop { - // Number of bits set in vector -public: - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), - ctrl1p->cloneTree(false)) {} - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} - ASTNODE_NODE_FUNCS(CountBits) - virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, - const V3Number& ctrl2, const V3Number& ctrl3) override { - out.opCountBits(expr, ctrl1, ctrl2, ctrl3); - } - virtual string emitVerilog() override { return "%f$countbits(%l, %r, %f, %o)"; } - virtual string emitC() override { return ""; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool cleanFhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool sizeMattersFhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstCountOnes final : public AstNodeUniop { - // Number of bits set in vector -public: - AstCountOnes(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CountOnes(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CountOnes) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opCountOnes(lhs); - } - virtual string emitVerilog() override { return "%f$countones(%l)"; } - virtual string emitC() override { return "VL_COUNTONES_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstIsUnknown final : public AstNodeUniop { - // True if any unknown bits -public: - AstIsUnknown(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IsUnknown(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(IsUnknown) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opIsUnknown(lhs); - } - virtual string emitVerilog() override { return "%f$isunknown(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstIsUnbounded final : public AstNodeUniop { - // True if is unmbounded ($) -public: - AstIsUnbounded(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(IsUnbounded) - virtual void numberOperate(V3Number& out, const V3Number&) override { - // Any constant isn't unbounded - out.setZero(); - } - virtual string emitVerilog() override { return "%f$isunbounded(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstOneHot final : public AstNodeUniop { - // True if only single bit set in vector -public: - AstOneHot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_OneHot(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(OneHot) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); } - virtual string emitVerilog() override { return "%f$onehot(%l)"; } - virtual string emitC() override { return "VL_ONEHOT_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 4; } -}; -class AstOneHot0 final : public AstNodeUniop { - // True if only single bit, or no bits set in vector -public: - AstOneHot0(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_OneHot0(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(OneHot0) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); } - virtual string emitVerilog() override { return "%f$onehot0(%l)"; } - virtual string emitC() override { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 3; } -}; - -class AstCast final : public AstNode { - // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc -public: - AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - setOp1p(lhsp); - setOp2p(dtp); - dtypeFrom(dtp); - } - AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - setOp1p(lhsp); - dtypeFrom(dtp); - } - ASTNODE_NODE_FUNCS(Cast) - virtual bool hasDType() const override { return true; } - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* fromp() const { return lhsp(); } - void lhsp(AstNode* nodep) { setOp1p(nodep); } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op2p(), NodeDType); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } -}; - -class AstCastDynamic final : public AstNodeBiop { - // Verilog $cast used as a function - // Task usage of $cast is converted during parse to assert($cast(...)) - // Parents: MATH - // Children: MATH - // lhsp() is value (we are converting FROM) to match AstCCast etc, this - // is opposite of $cast's order, because the first access is to the - // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). -public: - AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(CastDynamic) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstCastDynamic(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f$cast(%r, %l)"; } - virtual string emitC() override { return "VL_DYNAMIC_CAST(%r, %l)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 20; } - virtual bool isPure() const override { return true; } - AstNode* fromp() const { return lhsp(); } - AstNode* top() const { return rhsp(); } -}; - -class AstCastParse final : public AstNode { - // Cast to appropriate type, where we haven't determined yet what the data type is -public: - AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) - : ASTGEN_SUPER_CastParse(fl) { - setOp1p(lhsp); - setOp2p(dtp); - } - ASTNODE_NODE_FUNCS(CastParse) - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* dtp() const { return op2p(); } -}; - -class AstCastSize final : public AstNode { - // Cast to specific size; signed/twostate inherited from lower element per IEEE -public: - AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) - : ASTGEN_SUPER_CastSize(fl) { - setOp1p(lhsp); - setOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(CastSize) - // No hasDType because widthing removes this node before the hasDType check - virtual string emitVerilog() { return "((%r)'(%l))"; } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } -}; - -class AstCCast final : public AstNodeUniop { - // Cast to C-based data type -private: - int m_size; - -public: - AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) - : ASTGEN_SUPER_CCast(fl, lhsp) { - m_size = setwidth; - if (setwidth) { - if (minwidth == -1) minwidth = setwidth; - dtypeSetLogicUnsized(setwidth, minwidth, VSigning::UNSIGNED); - } - } - AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) - : ASTGEN_SUPER_CCast(fl, lhsp) { - dtypeFrom(typeFromp); - m_size = width(); - } - ASTNODE_NODE_FUNCS(CCast) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } - virtual string emitVerilog() override { return "%f$_CAST(%l)"; } - virtual string emitC() override { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast - virtual bool same(const AstNode* samep) const override { - return size() == static_cast(samep)->size(); - } - virtual void dump(std::ostream& str = std::cout) const override; - // - int size() const { return m_size; } -}; - -class AstCvtPackString final : public AstNodeUniop { - // Convert to Verilator Packed String (aka verilog "string") -public: - AstCvtPackString(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CvtPackString(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(CvtPackString) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$_CAST(%l)"; } - virtual string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstFEof final : public AstNodeUniop { -public: - AstFEof(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FEof(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FEof) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$feof(%l)"; } - virtual string emitC() override { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } -}; - -class AstFError final : public AstNodeMath { -public: - AstFError(FileLine* fl, AstNode* filep, AstNode* strp) - : ASTGEN_SUPER_FError(fl) { - setOp1p(filep); - setOp2p(strp); - } - ASTNODE_NODE_FUNCS(FError) - virtual string emitVerilog() override { return "%f$ferror(%l, %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - void filep(AstNode* nodep) { setOp1p(nodep); } - AstNode* filep() const { return op1p(); } - void strp(AstNode* nodep) { setOp2p(nodep); } - AstNode* strp() const { return op2p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstFGetC final : public AstNodeUniop { -public: - AstFGetC(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FGetC(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FGetC) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$fgetc(%l)"; } - // Non-existent filehandle returns EOF - virtual string emitC() override { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } -}; - -class AstFUngetC final : public AstNodeBiop { -public: - AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(FUngetC) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstFUngetC(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f$ungetc(%r, %l)"; } - // Non-existent filehandle returns EOF - virtual string emitC() override { - return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } - AstNode* charp() const { return rhsp(); } -}; - -class AstNodeSystemUniop VL_NOT_FINAL : public AstNodeUniop { -public: - AstNodeSystemUniop(VNType t, FileLine* fl, AstNode* lhsp) - : AstNodeUniop(t, fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_BASE_FUNCS(NodeSystemUniop) - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } - virtual bool doubleFlavor() const override { return true; } -}; - -class AstLogD final : public AstNodeSystemUniop { -public: - AstLogD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LogD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(LogD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::log(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$ln(%l)"; } - virtual string emitC() override { return "log(%li)"; } -}; -class AstLog10D final : public AstNodeSystemUniop { -public: - AstLog10D(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Log10D(fl, lhsp) {} - ASTNODE_NODE_FUNCS(Log10D) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::log10(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$log10(%l)"; } - virtual string emitC() override { return "log10(%li)"; } -}; - -class AstExpD final : public AstNodeSystemUniop { -public: - AstExpD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ExpD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(ExpD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::exp(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$exp(%l)"; } - virtual string emitC() override { return "exp(%li)"; } -}; - -class AstSqrtD final : public AstNodeSystemUniop { -public: - AstSqrtD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SqrtD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SqrtD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sqrt(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sqrt(%l)"; } - virtual string emitC() override { return "sqrt(%li)"; } -}; - -class AstFloorD final : public AstNodeSystemUniop { -public: - AstFloorD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FloorD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FloorD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::floor(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$floor(%l)"; } - virtual string emitC() override { return "floor(%li)"; } -}; - -class AstCeilD final : public AstNodeSystemUniop { -public: - AstCeilD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CeilD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CeilD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::ceil(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$ceil(%l)"; } - virtual string emitC() override { return "ceil(%li)"; } -}; - -class AstSinD final : public AstNodeSystemUniop { -public: - AstSinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SinD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sin(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sin(%l)"; } - virtual string emitC() override { return "sin(%li)"; } -}; - -class AstCosD final : public AstNodeSystemUniop { -public: - AstCosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CosD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::cos(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$cos(%l)"; } - virtual string emitC() override { return "cos(%li)"; } -}; - -class AstTanD final : public AstNodeSystemUniop { -public: - AstTanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TanD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::tan(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$tan(%l)"; } - virtual string emitC() override { return "tan(%li)"; } -}; - -class AstAsinD final : public AstNodeSystemUniop { -public: - AstAsinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AsinD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AsinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::asin(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$asin(%l)"; } - virtual string emitC() override { return "asin(%li)"; } -}; - -class AstAcosD final : public AstNodeSystemUniop { -public: - AstAcosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AcosD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AcosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::acos(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$acos(%l)"; } - virtual string emitC() override { return "acos(%li)"; } -}; - -class AstAtanD final : public AstNodeSystemUniop { -public: - AstAtanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AtanD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AtanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::atan(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atan(%l)"; } - virtual string emitC() override { return "atan(%li)"; } -}; - -class AstSinhD final : public AstNodeSystemUniop { -public: - AstSinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SinhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sinh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sinh(%l)"; } - virtual string emitC() override { return "sinh(%li)"; } -}; - -class AstCoshD final : public AstNodeSystemUniop { -public: - AstCoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CoshD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::cosh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$cosh(%l)"; } - virtual string emitC() override { return "cosh(%li)"; } -}; - -class AstTanhD final : public AstNodeSystemUniop { -public: - AstTanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TanhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::tanh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$tanh(%l)"; } - virtual string emitC() override { return "tanh(%li)"; } -}; - -class AstAsinhD final : public AstNodeSystemUniop { -public: - AstAsinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AsinhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AsinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::asinh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$asinh(%l)"; } - virtual string emitC() override { return "asinh(%li)"; } -}; - -class AstAcoshD final : public AstNodeSystemUniop { -public: - AstAcoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AcoshD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AcoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::acosh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$acosh(%l)"; } - virtual string emitC() override { return "acosh(%li)"; } -}; - -class AstAtanhD final : public AstNodeSystemUniop { -public: - AstAtanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AtanhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AtanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::atanh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atanh(%l)"; } - virtual string emitC() override { return "atanh(%li)"; } -}; -class AstToLowerN final : public AstNodeUniop { - // string.tolower() -public: - AstToLowerN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ToLowerN(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ToLowerN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opToLowerN(lhs); - } - virtual string emitVerilog() override { return "%l.tolower()"; } - virtual string emitC() override { return "VL_TOLOWER_NN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstToUpperN final : public AstNodeUniop { - // string.toupper() -public: - AstToUpperN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ToUpperN(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ToUpperN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opToUpperN(lhs); - } - virtual string emitVerilog() override { return "%l.toupper()"; } - virtual string emitC() override { return "VL_TOUPPER_NN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstTimeImport final : public AstNodeUniop { - // Take a constant that represents a time and needs conversion based on time units - VTimescale m_timeunit; // Parent module time unit -public: - AstTimeImport(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TimeImport(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TimeImport) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstAtoN final : public AstNodeUniop { - // string.atoi(), atobin(), atohex(), atooct(), atoireal() -public: - enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; - -private: - const FmtType m_fmt; // Operation type -public: - AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) - : ASTGEN_SUPER_AtoN(fl, lhsp) - , m_fmt{fmt} { - fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(AtoN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAtoN(lhs, m_fmt); - } - virtual string name() const override { - switch (m_fmt) { - case ATOI: return "atoi"; - case ATOHEX: return "atohex"; - case ATOOCT: return "atooct"; - case ATOBIN: return "atobin"; - case ATOREAL: return "atoreal"; - default: V3ERROR_NA; - } - } - virtual string emitVerilog() override { return "%l." + name() + "()"; } - virtual string emitC() override { - switch (m_fmt) { - case ATOI: return "VL_ATOI_N(%li, 10)"; - case ATOHEX: return "VL_ATOI_N(%li, 16)"; - case ATOOCT: return "VL_ATOI_N(%li, 8)"; - case ATOBIN: return "VL_ATOI_N(%li, 2)"; - case ATOREAL: return "std::atof(%li.c_str())"; - default: V3ERROR_NA; - } - } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - FmtType format() const { return m_fmt; } -}; - -//====================================================================== -// Binary ops - -class AstLogOr final : public AstNodeBiop { - // LOGOR with optional side effects - // Side effects currently used in some V3Width code - // TBD if this concept is generally adopted for side-effect tracking - // versus V3Const tracking it itself - bool m_sideEffect = false; // Has side effect, relies on short-circuiting -public: - AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogOr) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogOr(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogOr(lhs, rhs); - } - virtual bool same(const AstNode* samep) const override { - const AstLogOr* const sp = static_cast(samep); - return m_sideEffect == sp->m_sideEffect; - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string emitVerilog() override { return "%k(%l %f|| %r)"; } - virtual string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "||"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - virtual bool isPure() const override { return !m_sideEffect; } - void sideEffect(bool flag) { m_sideEffect = flag; } - bool sideEffect() const { return m_sideEffect; } -}; -class AstLogAnd final : public AstNodeBiop { -public: - AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogAnd) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogAnd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogAnd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f&& %r)"; } - virtual string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "&&"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstLogEq final : public AstNodeBiCom { -public: - AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogEq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogEq(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<-> %r)"; } - virtual string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<->"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstLogIf final : public AstNodeBiop { -public: - AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogIf) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogIf(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogIf(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f-> %r)"; } - virtual string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "->"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstOr final : public AstNodeBiComAsv { -public: - AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Or) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstOr(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opOr(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f| %r)"; } - virtual string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "|"; } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstAnd final : public AstNodeBiComAsv { -public: - AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_And(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(And) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAnd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAnd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f& %r)"; } - virtual string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "&"; } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstXor final : public AstNodeBiComAsv { -public: - AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Xor) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstXor(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opXor(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f^ %r)"; } - virtual string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "^"; } - virtual bool cleanOut() const override { return false; } // Lclean && Rclean - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEq final : public AstNodeBiCom { -public: - AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Eq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEq(this->fileline(), lhsp, rhsp); - } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, - AstNode* rhsp); // Return AstEq/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEqD final : public AstNodeBiCom { -public: - AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEqD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstEqN final : public AstNodeBiCom { -public: - AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEqN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstNeq final : public AstNodeBiCom { -public: - AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Neq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeq(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqD final : public AstNodeBiCom { -public: - AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeqD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstNeqN final : public AstNodeBiCom { -public: - AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeqN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstLt final : public AstNodeBiop { -public: - AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Lt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLt(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLt(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstLtD final : public AstNodeBiop { -public: - AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstLtS final : public AstNodeBiop { -public: - AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstLtN final : public AstNodeBiop { -public: - AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstGt final : public AstNodeBiop { -public: - AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Gt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGt(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGt(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstGtD final : public AstNodeBiop { -public: - AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstGtS final : public AstNodeBiop { -public: - AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstGtN final : public AstNodeBiop { -public: - AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstGte final : public AstNodeBiop { -public: - AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Gte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGte(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGte(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstGteD final : public AstNodeBiop { -public: - AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstGteS final : public AstNodeBiop { -public: - AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstGteN final : public AstNodeBiop { -public: - AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstLte final : public AstNodeBiop { -public: - AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Lte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLte(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLte(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstLteD final : public AstNodeBiop { -public: - AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstLteS final : public AstNodeBiop { -public: - AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstLteN final : public AstNodeBiop { -public: - AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstShiftL final : public AstNodeBiop { -public: - AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ShiftL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftL(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftL(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<< %r)"; } - virtual string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { - return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstShiftR final : public AstNodeBiop { -public: - AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ShiftR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftR(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftR(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>> %r)"; } - virtual string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { - return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - // LHS size might be > output size, so don't want to force size - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstShiftRS final : public AstNodeBiop { - // Shift right with sign extension, >>> operator - // Output data type's width determines which bit is used for sign extension -public: - AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { - // Important that widthMin be correct, as opExtend requires it after V3Expand - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); - } - ASTNODE_NODE_FUNCS(ShiftRS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftRS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); - } - virtual string emitVerilog() override { return "%k(%l %f>>> %r)"; } - virtual string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstAdd final : public AstNodeBiComAsv { -public: - AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Add) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAdd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAdd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } - virtual string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "+"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } -}; -class AstAddD final : public AstNodeBiComAsv { -public: - AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(AddD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAddD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAddD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "+"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstSub final : public AstNodeBiop { -public: - AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Sub) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstSub(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opSub(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f- %r)"; } - virtual string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } -}; -class AstSubD final : public AstNodeBiop { -public: - AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(SubD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstSubD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opSubD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f- %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstMul final : public AstNodeBiComAsv { -public: - AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Mul) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMul(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMul(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "*"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } -}; -class AstMulD final : public AstNodeBiComAsv { -public: - AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(MulD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMulD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMulD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "*"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstMulS final : public AstNodeBiComAsv { -public: - AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(MulS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMulS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMulS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } - virtual bool signedFlavor() const override { return true; } -}; -class AstDiv final : public AstNodeBiop { -public: - AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Div) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDiv(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDiv(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } -}; -class AstDivD final : public AstNodeBiop { -public: - AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(DivD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDivD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDivD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "/"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstDivS final : public AstNodeBiop { -public: - AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(DivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDivS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDivS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } - virtual bool signedFlavor() const override { return true; } -}; -class AstModDiv final : public AstNodeBiop { -public: - AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(ModDiv) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstModDiv(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opModDiv(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } - virtual string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } -}; -class AstModDivS final : public AstNodeBiop { -public: - AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(ModDivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstModDivS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opModDivS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } - virtual string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPow final : public AstNodeBiop { -public: - AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Pow) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPow(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPow(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } -}; -class AstPowD final : public AstNodeBiop { -public: - AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(PowD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { return "pow(%li,%ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV * 5; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstPowSU final : public AstNodeBiop { -public: - AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowSU) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowSU(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowSU(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPowSS final : public AstNodeBiop { -public: - AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowSS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowSS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowSS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPowUS final : public AstNodeBiop { -public: - AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowUS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowUS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowUS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPreAdd final : public AstNodeTriop { - // Pre-increment/add - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only ++ not += - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PreAdd) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(++%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPreSub final : public AstNodeTriop { - // Pre-decrement/subtract - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only -- not -= - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PreSub) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(--%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPostAdd final : public AstNodeTriop { - // Post-increment/add - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only ++ not += - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PostAdd) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(%r++)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPostSub final : public AstNodeTriop { - // Post-decrement/subtract - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only -- not -= - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PostSub) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(%r--)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstEqCase final : public AstNodeBiCom { -public: - AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqCase(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCaseEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f=== %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqCase final : public AstNodeBiCom { -public: - AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqCase(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCaseNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!== %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEqWild final : public AstNodeBiop { - // Note wildcard operator rhs differs from lhs -public: - AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqWild(this->fileline(), lhsp, rhsp); - } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, - AstNode* rhsp); // Return AstEqWild/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opWildEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f==? %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqWild final : public AstNodeBiop { -public: - AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqWild(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opWildNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!=? %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstConcat final : public AstNodeBiop { - // If you're looking for {#{}}, see AstReplicate -public: - AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { - if (lhsp->dtypep() && rhsp->dtypep()) { - dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), - VSigning::UNSIGNED); - } - } - ASTNODE_NODE_FUNCS(Concat) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstConcat(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opConcat(lhs, rhs); - } - virtual string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstConcatN final : public AstNodeBiop { - // String concatenate -public: - AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ConcatN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstConcatN(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opConcatN(lhs, rhs); - } - virtual string emitC() override { return "VL_CONCATN_NNN(%li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstReplicate final : public AstNodeBiop { - // Also used as a "Uniop" flavor of Concat, e.g. "{a}" - // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() -public: - AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { - if (lhsp) { - if (const AstConst* const constp = VN_CAST(rhsp, Const)) { - dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); - } - } - } - AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : AstReplicate(fl, lhsp, new AstConst(fl, repCount)) {} - ASTNODE_NODE_FUNCS(Replicate) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstReplicate(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opRepl(lhs, rhs); - } - virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } - virtual string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstReplicateN final : public AstNodeBiop { - // String replicate -public: - AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { - dtypeSetString(); - } - AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : AstReplicateN(fl, lhsp, new AstConst(fl, repCount)) {} - ASTNODE_NODE_FUNCS(ReplicateN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstReplicateN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opReplN(lhs, rhs); - } - virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } - virtual string emitC() override { return "VL_REPLICATEN_NN%rq(%li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } - virtual bool stringFlavor() const override { return true; } -}; -class AstStreamL final : public AstNodeStream { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: - AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(StreamL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstStreamL(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{ << %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opStreamL(lhs, rhs); - } - virtual string emitC() override { return "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstStreamR final : public AstNodeStream { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: - AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(StreamR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstStreamR(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{ >> %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAssign(lhs); - } - virtual string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstBufIf1 final : public AstNodeBiop { - // lhs is enable, rhs is data to drive - // Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp - // bit enables respective rhsp bit -public: - AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(BufIf1) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstBufIf1(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opBufIf1(lhs, rhs); - } - virtual string emitVerilog() override { return "bufif(%r,%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstFGetS final : public AstNodeBiop { -public: - AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(FGetS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstFGetS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; } - virtual string emitC() override { - return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)" - : "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - AstNode* strgp() const { return lhsp(); } - AstNode* filep() const { return rhsp(); } -}; - -class AstNodeSystemBiop VL_NOT_FINAL : public AstNodeBiop { -public: - AstNodeSystemBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeBiop(t, fl, lhsp, rhsp) { - dtypeSetDouble(); - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } - virtual bool doubleFlavor() const override { return true; } -}; - -class AstAtan2D final : public AstNodeSystemBiop { -public: - AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(Atan2D) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAtan2D(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.setDouble(std::atan2(lhs.toDouble(), rhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atan2(%l,%r)"; } - virtual string emitC() override { return "atan2(%li,%ri)"; } -}; - -class AstHypotD final : public AstNodeSystemBiop { -public: - AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(HypotD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstHypotD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.setDouble(std::hypot(lhs.toDouble(), rhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$hypot(%l,%r)"; } - virtual string emitC() override { return "hypot(%li,%ri)"; } -}; - -class AstPutcN final : public AstNodeTriop { - // Verilog string.putc() -public: - AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(PutcN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - out.opPutcN(lhs, rhs, ths); - } - virtual string name() const override { return "putc"; } - virtual string emitVerilog() override { return "%k(%l.putc(%r,%t))"; } - virtual string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } -}; - -class AstGetcN final : public AstNodeBiop { - // Verilog string.getc() -public: - AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { - dtypeSetBitSized(8, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(GetcN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGetcN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGetcN(lhs, rhs); - } - virtual string name() const override { return "getc"; } - virtual string emitVerilog() override { return "%k(%l.getc(%r))"; } - virtual string emitC() override { return "VL_GETC_N(%li,%ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstGetcRefN final : public AstNodeBiop { - // Verilog string[#] on the left-hand-side of assignment - // Spec says is of type byte (not string of single character) -public: - AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { - dtypeSetBitSized(8, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(GetcRefN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGetcRefN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k%l[%r]"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstSubstrN final : public AstNodeTriop { - // Verilog string.substr() -public: - AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(SubstrN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - out.opSubstrN(lhs, rhs, ths); - } - virtual string name() const override { return "substr"; } - virtual string emitVerilog() override { return "%k(%l.substr(%r,%t))"; } - virtual string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } -}; - -class AstCompareNN final : public AstNodeBiop { - // Verilog str.compare() and str.icompare() -private: - const bool m_ignoreCase; // True for str.icompare() -public: - AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) - : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) - , m_ignoreCase{ignoreCase} { - dtypeSetUInt32(); - } - ASTNODE_NODE_FUNCS(CompareNN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstCompareNN(this->fileline(), lhsp, rhsp, m_ignoreCase); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCompareNN(lhs, rhs, m_ignoreCase); - } - virtual string name() const override { return m_ignoreCase ? "icompare" : "compare"; } - virtual string emitVerilog() override { - return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))"; - } - virtual string emitC() override { - return m_ignoreCase ? "VL_CMP_NN(%li,%ri,true)" : "VL_CMP_NN(%li,%ri,false)"; - } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstFell final : public AstNodeMath { - // Verilog $fell - // Parents: math - // Children: expression -public: - AstFell(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Fell(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Fell) - virtual string emitVerilog() override { return "$fell(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstPast final : public AstNodeMath { - // Verilog $past - // Parents: math - // Children: expression -public: - AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) - : ASTGEN_SUPER_Past(fl) { - addOp1p(exprp); - addNOp2p(ticksp); - } - ASTNODE_NODE_FUNCS(Past) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstNode* ticksp() const { return op2p(); } // op2 = ticks or nullptr means 1 - AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain - void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstRose final : public AstNodeMath { - // Verilog $rose - // Parents: math - // Children: expression -public: - AstRose(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Rose(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Rose) - virtual string emitVerilog() override { return "$rose(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstSampled final : public AstNodeMath { - // Verilog $sampled - // Parents: math - // Children: expression -public: - AstSampled(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Sampled(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Sampled) - virtual string emitVerilog() override { return "$sampled(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return 0; } - AstNode* exprp() const { return op1p(); } // op1 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstStable final : public AstNodeMath { - // Verilog $stable - // Parents: math - // Children: expression -public: - AstStable(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Stable(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Stable) - virtual string emitVerilog() override { return "$stable(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstPattern final : public AstNodeMath { - // Verilog '{a,b,c,d...} - // Parents: AstNodeAssign, AstPattern, ... - // Children: expression, AstPattern, AstPatReplicate -public: - AstPattern(FileLine* fl, AstNode* itemsp) - : ASTGEN_SUPER_Pattern(fl) { - addNOp2p(itemsp); - } - ASTNODE_NODE_FUNCS(Pattern) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc - void addItemsp(AstNode* nodep) { addOp2p(nodep); } -}; -class AstPatMember final : public AstNodeMath { - // Verilog '{a} or '{a{b}} - // Parents: AstPattern - // Children: expression, AstPattern, replication count -private: - bool m_default = false; - -public: - AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) - : ASTGEN_SUPER_PatMember(fl) { - addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); - } - ASTNODE_NODE_FUNCS(PatMember) - virtual string emitVerilog() override { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs() * 2; } - virtual void dump(std::ostream& str = std::cout) const override; - // op1 = expression to assign or another AstPattern (list if replicated) - AstNode* lhssp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) - AstNode* repp() const { return op3p(); } // op3 = replication count, or nullptr for count 1 - bool isDefault() const { return m_default; } - void isDefault(bool flag) { m_default = flag; } -}; - -class AstImplication final : public AstNodeMath { - // Verilog |-> |=> - // Parents: math - // Children: expression -public: - AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) - : ASTGEN_SUPER_Implication(fl) { - setOp1p(lhs); - setOp2p(rhs); - } - ASTNODE_NODE_FUNCS(Implication) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain - void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Assertions - -class AstClocking final : public AstNode { - // Set default clock region - // Parents: MODULE - // Children: Assertions -public: - AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_Clocking(fl) { - addOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(Clocking) - // op1 = Sensitivity list - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } - AstNode* bodysp() const { return op2p(); } // op2 = Body -}; - -//====================================================================== -// PSL - -class AstPropClocked final : public AstNode { - // A clocked property - // Parents: ASSERT|COVER (property) - // Children: SENITEM, Properties -public: - AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) - : ASTGEN_SUPER_PropClocked(fl) { - addNOp1p(sensesp); - addNOp2p(disablep); - addOp3p(propp); - } - ASTNODE_NODE_FUNCS(PropClocked) - virtual bool hasDType() const override { - return true; - } // Used under Cover, which expects a bool child - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } // op1 = Sensitivity list - AstNode* disablep() const { return op2p(); } // op2 = disable - AstNode* propp() const { return op3p(); } // op3 = property -}; - -class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { - // Cover or Assert - // Parents: {statement list} - // Children: expression, report string -private: - const bool m_immediate; // Immediate assertion/cover - string m_name; // Name to report -public: - AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, bool immediate, - const string& name = "") - : AstNodeStmt{t, fl} - , m_immediate{immediate} - , m_name{name} { - addOp1p(propp); - addNOp4p(passsp); - } - ASTNODE_BASE_FUNCS(NodeCoverOrAssert) - virtual string name() const override { return m_name; } // * = Var name - virtual bool same(const AstNode* samep) const override { return samep->name() == name(); } - virtual void name(const string& name) override { m_name = name; } - virtual void dump(std::ostream& str = std::cout) const override; - AstNode* propp() const { return op1p(); } // op1 = property - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - AstNode* passsp() const { return op4p(); } // op4 = statements (assert/cover passes) - bool immediate() const { return m_immediate; } -}; - -class AstAssert final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Assert) - AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, - const string& name = "") - : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { - addNOp3p(failsp); - } - AstNode* failsp() const { return op3p(); } // op3 = if assertion fails -}; - -class AstAssertIntrinsic final : public AstNodeCoverOrAssert { - // A $cast or other compiler inserted assert, that must run even without --assert option -public: - ASTNODE_NODE_FUNCS(AssertIntrinsic) - AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, - bool immediate, const string& name = "") - : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { - addNOp3p(failsp); - } - AstNode* failsp() const { return op3p(); } // op3 = if assertion fails -}; - -class AstCover final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Cover) - AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, - const string& name = "") - : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} - AstNode* coverincp() const { return op3p(); } // op3 = coverage node - void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node - virtual bool immediate() const { return false; } -}; - -class AstRestrict final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Restrict) - AstRestrict(FileLine* fl, AstNode* propp) - : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} -}; - -//====================================================================== -// Text based nodes - -class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText { -private: - 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) - : AstNodeText(t, fl, textp) - , m_tracking(tracking) {} - ASTNODE_BASE_FUNCS(NodeSimpleText) - void tracking(bool flag) { m_tracking = flag; } - bool tracking() const { return m_tracking; } -}; - -class AstText final : public AstNodeSimpleText { -public: - AstText(FileLine* fl, const string& textp, bool tracking = false) - : ASTGEN_SUPER_Text(fl, textp, tracking) {} - ASTNODE_NODE_FUNCS(Text) -}; - -class AstTextBlock final : public AstNodeSimpleText { -private: - 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) {} - ASTNODE_NODE_FUNCS(TextBlock) - void commas(bool flag) { m_commas = flag; } - bool commas() const { return m_commas; } - AstNode* nodesp() const { return op1p(); } - void addNodep(AstNode* nodep) { addOp1p(nodep); } - void addText(FileLine* fl, const string& textp, bool tracking = false) { - addNodep(new AstText(fl, textp, tracking)); - } -}; - -class AstScCtor final : public AstNodeText { -public: - AstScCtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScCtor(fl, textp) {} - ASTNODE_NODE_FUNCS(ScCtor) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScDtor final : public AstNodeText { -public: - AstScDtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScDtor(fl, textp) {} - ASTNODE_NODE_FUNCS(ScDtor) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScHdr final : public AstNodeText { -public: - AstScHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScHdr(fl, textp) {} - ASTNODE_NODE_FUNCS(ScHdr) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScImp final : public AstNodeText { -public: - AstScImp(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScImp(fl, textp) {} - ASTNODE_NODE_FUNCS(ScImp) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScImpHdr final : public AstNodeText { -public: - AstScImpHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScImpHdr(fl, textp) {} - ASTNODE_NODE_FUNCS(ScImpHdr) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScInt final : public AstNodeText { -public: - AstScInt(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScInt(fl, textp) {} - ASTNODE_NODE_FUNCS(ScInt) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstUCStmt final : public AstNodeStmt { - // User $c statement -public: - AstUCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_UCStmt(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(UCStmt) - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Emitted file nodes - -class AstNodeFile VL_NOT_FINAL : public AstNode { - // Emitted Otput file - // Parents: NETLIST - // Children: AstTextBlock -private: - string m_name; ///< Filename -public: - AstNodeFile(VNType t, FileLine* fl, const string& name) - : AstNode(t, fl) { - m_name = name; - } - ASTNODE_BASE_FUNCS(NodeFile) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void tblockp(AstTextBlock* tblockp) { setOp1p(tblockp); } - AstTextBlock* tblockp() { return VN_AS(op1p(), TextBlock); } -}; - -//====================================================================== -// Emit V nodes - -class AstVFile final : public AstNodeFile { - // Verilog output file - // Parents: NETLIST -public: - AstVFile(FileLine* fl, const string& name) - : ASTGEN_SUPER_VFile(fl, name) {} - ASTNODE_NODE_FUNCS(VFile) - virtual void dump(std::ostream& str = std::cout) const override; -}; - -//====================================================================== -// Emit C nodes - -class AstCFile final : public AstNodeFile { - // C++ output file - // Parents: NETLIST -private: - 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} {} - ASTNODE_NODE_FUNCS(CFile) - virtual void dump(std::ostream& str = std::cout) const override; - 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) { m_support = flag; } -}; - -class AstCFunc final : public AstNode { - // C++ function - // Parents: MODULE/SCOPE - // Children: VAR/statements -private: - AstScope* m_scopep; - 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_ctorInits; // Constructor sub-class inits - 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_isFinal : 1; // This is a function corresponding to a SystemVerilog 'final' block - 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 - 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_pure : 1; // Pure 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 - bool m_dpiTraceInit : 1; // DPI trace_init -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_isFinal = 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; - m_entryPoint = false; - m_pure = false; - m_dpiContext = false; - m_dpiExportDispatcher = false; - m_dpiExportImpl = false; - m_dpiImportPrototype = false; - m_dpiImportWrapper = false; - m_dpiTraceInit = false; - } - ASTNODE_NODE_FUNCS(CFunc) - virtual string name() const override { return m_name; } - virtual const char* broken() const override { - BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); - return nullptr; - } - virtual void cloneRelink() override { - if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep(); - } - virtual bool maybePointedTo() const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - virtual bool same(const AstNode* samep) const override { - const AstCFunc* const asamep = static_cast(samep); - return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) - && (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits()) - && isLoose() == asamep->isLoose() - && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); - } - // - virtual void name(const string& name) override { m_name = name; } - virtual int instrCount() const override { - return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0; - } - 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 { 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); } - 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 isFinal() const { return m_isFinal; } - void isFinal(bool flag) { m_isFinal = flag; } - bool slow() const { 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 ctorInits(const string& str) { m_ctorInits = str; } - string ctorInits() const { return m_ctorInits; } - 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; } - bool entryPoint() const { return m_entryPoint; } - void entryPoint(bool flag) { m_entryPoint = flag; } - bool pure() const { return m_pure; } - void pure(bool flag) { m_pure = flag; } - bool dpiContext() const { return m_dpiContext; } - void dpiContext(bool flag) { m_dpiContext = flag; } - bool dpiExportDispatcher() const { 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 { return m_dpiImportPrototype; } - void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; } - bool dpiImportWrapper() const { return m_dpiImportWrapper; } - void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; } - void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } - bool dpiTraceInit() const { return m_dpiTraceInit; } - // - // If adding node accessors, see below emptyBody - AstNode* argsp() const { return op1p(); } - void addArgsp(AstNode* nodep) { addOp1p(nodep); } - AstNode* initsp() const { return op2p(); } - void addInitsp(AstNode* nodep) { addOp2p(nodep); } - AstNode* stmtsp() const { return op3p(); } - void addStmtsp(AstNode* nodep) { addOp3p(nodep); } - AstNode* finalsp() const { return op4p(); } - void addFinalsp(AstNode* nodep) { addOp4p(nodep); } - // Special methods - bool emptyBody() const { - return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr - && finalsp() == nullptr; - } -}; - -class AstCCall final : public AstNodeCCall { - // C++ function call - // Parents: Anything above a statement - // Children: Args to the function - - string m_selfPointer; // Output code object pointer (e.g.: 'this') - -public: - AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} - ASTNODE_NODE_FUNCS(CCall) - - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; -}; - -class AstCMethodCall final : public AstNodeCCall { - // C++ method call - // Parents: Anything above a statement - // Children: Args to the function -public: - AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { - setOp1p(fromp); - } - ASTNODE_NODE_FUNCS(CMethodCall) - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeCCall::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstCNew final : public AstNodeCCall { - // C++ new() call - // Parents: Anything above an expression - // Children: Args to the function -public: - AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CNew(fl, funcp, argsp) { - statement(false); - } - virtual bool hasDType() const override { return true; } - ASTNODE_NODE_FUNCS(CNew) -}; - -class AstCReturn final : public AstNodeStmt { - // C++ return from a function - // Parents: CFUNC/statement - // Children: Math -public: - AstCReturn(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CReturn(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(CReturn) - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* lhsp() const { return op1p(); } -}; - -class AstCMath final : public AstNodeMath { -private: - const bool m_cleanOut; - bool m_pure; // Pure optimizable -public: - // Emit C textual math function (like AstUCFunc) - AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_CMath(fl) - , m_cleanOut{true} - , m_pure{false} { - addOp1p(exprsp); - dtypeFrom(exprsp); - } - AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true) - : ASTGEN_SUPER_CMath(fl) - , m_cleanOut{cleanOut} - , m_pure{true} { - addNOp1p(new AstText(fl, textStmt, true)); - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(CMath) - virtual bool isGateOptimizable() const override { return m_pure; } - virtual bool isPredictOptimizable() const override { return m_pure; } - virtual bool cleanOut() const override { return m_cleanOut; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void addBodysp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - bool pure() const { return m_pure; } - void pure(bool flag) { m_pure = flag; } -}; - -class AstCReset final : public AstNodeStmt { - // Reset variable at startup -public: - AstCReset(FileLine* fl, AstVarRef* exprsp) - : ASTGEN_SUPER_CReset(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(CReset) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstVarRef* varrefp() const { return VN_AS(op1p(), VarRef); } // op1 = varref to reset -}; - -class AstCStmt final : public AstNodeStmt { - // Emit C statement -public: - AstCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_CStmt(fl) { - addNOp1p(exprsp); - } - AstCStmt(FileLine* fl, const string& textStmt) - : ASTGEN_SUPER_CStmt(fl) { - addNOp1p(new AstText(fl, textStmt, true)); - } - ASTNODE_NODE_FUNCS(CStmt) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void addBodysp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print -}; - -class AstCUse final : public AstNode { - // C++ use of a class or #include; indicates need of forward declaration - // Parents: NODEMODULE -private: - const VUseType m_useType; // What sort of use this is - const string m_name; - -public: - AstCUse(FileLine* fl, VUseType useType, const string& name) - : ASTGEN_SUPER_CUse(fl) - , m_useType{useType} - , m_name{name} {} - ASTNODE_NODE_FUNCS(CUse) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - VUseType useType() const { return m_useType; } -}; - -class AstMTaskBody final : public AstNode { - // Hold statements for each MTask -private: - ExecMTask* m_execMTaskp = nullptr; - -public: - explicit AstMTaskBody(FileLine* fl) - : ASTGEN_SUPER_MTaskBody(fl) {} - ASTNODE_NODE_FUNCS(MTaskBody); - virtual const char* broken() const override { - BROKEN_RTN(!m_execMTaskp); - return nullptr; - } - AstNode* stmtsp() const { return op1p(); } - void addStmtsp(AstNode* nodep) { addOp1p(nodep); } - 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; } - virtual void dump(std::ostream& str = std::cout) const override; -}; - -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. -private: - 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); - ASTNODE_NODE_FUNCS_NO_DTOR(ExecGraph) - virtual ~AstExecGraph() override; - virtual const char* broken() const override { - BROKEN_RTN(!m_depGraphp); - return nullptr; - } - virtual string name() const override { return m_name; } - V3Graph* depGraphp() { return m_depGraphp; } - const V3Graph* depGraphp() const { return m_depGraphp; } - // op1: The mtask bodies - AstMTaskBody* mTaskBodiesp() const { return VN_AS(op1p(), MTaskBody); } - void addMTaskBodyp(AstMTaskBody* bodyp) { addOp1p(bodyp); } - // op2: In later phases, the statements that start the parallel execution - void addStmtsp(AstNode* stmtp) { addOp2p(stmtp); } -}; - -class AstSplitPlaceholder final : public AstNode { -public: - // Dummy node used within V3Split; never exists outside of V3Split. - explicit AstSplitPlaceholder(FileLine* fl) - : ASTGEN_SUPER_SplitPlaceholder(fl) {} - ASTNODE_NODE_FUNCS(SplitPlaceholder) -}; - -//###################################################################### -// Right below top - -class AstTypeTable final : public AstNode { - // Container for hash of standard data types - // Children: NODEDTYPEs - AstEmptyQueueDType* m_emptyQueuep = nullptr; - AstQueueDType* m_queueIndexp = nullptr; - AstVoidDType* m_voidp = nullptr; - AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{}; - // - using DetailedMap = std::map; - DetailedMap m_detailedMap; - -public: - explicit AstTypeTable(FileLine* fl); - ASTNODE_NODE_FUNCS(TypeTable) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_emptyQueuep && !m_emptyQueuep->brokeExists()); - BROKEN_RTN(m_queueIndexp && !m_queueIndexp->brokeExists()); - BROKEN_RTN(m_voidp && !m_voidp->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { V3ERROR_NA; } - AstNodeDType* typesp() const { return VN_AS(op1p(), NodeDType); } // op1 = List of dtypes - void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); } - 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); - AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl); - AstQueueDType* findQueueIndexDType(FileLine* fl); - AstVoidDType* findVoidDType(FileLine* fl); - void clearCache(); - void repairCache(); - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstConstPool final : public AstNode { - // Container for const static data - std::unordered_multimap m_tables; // Constant tables (unpacked arrays) - std::unordered_multimap m_consts; // Constant tables (scalars) - AstModule* const m_modp; // The Module holding the Scope below ... - AstScope* const m_scopep; // Scope holding the constant variables - - AstVarScope* createNewEntry(const string& name, AstNode* initp); - -public: - explicit AstConstPool(FileLine* fl); - ASTNODE_NODE_FUNCS(ConstPool) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_modp && !m_modp->brokeExists()); - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - virtual 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); -}; - -//###################################################################### -// Top - -class AstNetlist final : public AstNode { - // All modules are under this single top node. - // Parents: none - // Children: MODULEs & CFILEs -private: - AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup - AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup - AstPackage* m_dollarUnitPkgp = nullptr; // $unit - AstCFunc* m_evalp = nullptr; // The '_eval' function - AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable - AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module - VTimescale m_timeunit; // Global time unit - VTimescale m_timeprecision; // Global time precision - bool m_changeRequest = false; // Have _change_request method - bool m_timescaleSpecified = false; // Input HDL specified timescale - uint32_t m_nextFreeMTaskID = 1; // Next unique MTask ID within netlist - // starts at 1 so 0 means no MTask ID - uint32_t m_nextFreeMTaskProfilingID = 0; // Next unique ID to use for PGO -public: - AstNetlist(); - ASTNODE_NODE_FUNCS(Netlist) - virtual const char* broken() const override { - BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists()); - BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists()); - BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); - BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); - BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists()); - BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { V3ERROR_NA; } - virtual string name() const override { return "$root"; } - virtual void dump(std::ostream& str) const override; - AstNodeModule* modulesp() const { // op1 = List of modules - return VN_AS(op1p(), NodeModule); - } - AstNodeModule* topModulep() const { // Top module in hierarchy - return modulesp(); // First one in the list, for now - } - void addModulep(AstNodeModule* modulep) { addOp1p(modulep); } - AstNodeFile* filesp() const { return VN_AS(op2p(), NodeFile); } // op2 = List of files - void addFilesp(AstNodeFile* filep) { addOp2p(filep); } - void addMiscsp(AstNode* nodep) { addOp3p(nodep); } - AstTypeTable* typeTablep() { return m_typeTablep; } - void changeRequest(bool specified) { m_changeRequest = specified; } - bool changeRequest() const { return m_changeRequest; } - AstConstPool* constPoolp() { return m_constPoolp; } - AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; } - AstPackage* dollarUnitPkgAddp() { - if (!m_dollarUnitPkgp) { - m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName()); - // packages are always libraries; don't want to make them a "top" - m_dollarUnitPkgp->inLibrary(true); - m_dollarUnitPkgp->modTrace(false); // may reconsider later - m_dollarUnitPkgp->internal(true); - addModulep(m_dollarUnitPkgp); - } - return m_dollarUnitPkgp; - } - AstCFunc* evalp() const { return m_evalp; } - void evalp(AstCFunc* evalp) { m_evalp = evalp; } - AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; } - void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } - AstTopScope* topScopep() const { return m_topScopep; } - void createTopScope(AstScope* scopep) { - UASSERT(scopep, "Must not be nullptr"); - UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits"); - m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep}; - scopep->modp()->addStmtp(v3Global.rootp()->topScopep()); - } - 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; } - uint32_t allocNextMTaskID() { return m_nextFreeMTaskID++; } - uint32_t allocNextMTaskProfilingID() { return m_nextFreeMTaskProfilingID++; } - uint32_t usedMTaskProfilingIDs() const { return m_nextFreeMTaskProfilingID; } -}; - -//###################################################################### - -#include "V3AstInlines.h" - -#endif // Guard diff --git a/src/astgen b/src/astgen index f8860dce0..d1fa39f31 100755 --- a/src/astgen +++ b/src/astgen @@ -4,13 +4,14 @@ import argparse import glob +import os import re import sys # from pprint import pprint, pformat class Node: - def __init__(self, name, superClass): + def __init__(self, name, superClass, file, lineno): self._name = name self._superClass = superClass self._subClasses = [] # Initially list, but tuple after completion @@ -19,6 +20,9 @@ class Node: self._typeId = None # Concrete type identifier number for leaf classes self._typeIdMin = None # Lowest type identifier number for class self._typeIdMax = None # Highest type identifier number for class + self._file = file # File this class is defined in + self._lineno = lineno # Line this class is defined on + self._ordIdx = None # Ordering index of this class @property def name(self): @@ -32,6 +36,14 @@ class Node: def isCompleted(self): return isinstance(self._subClasses, tuple) + @property + def file(self): + return self._file + + @property + def lineno(self): + return self._lineno + # Pre completion methods def addSubClass(self, subClass): assert not self.isCompleted @@ -39,20 +51,25 @@ class Node: # Computes derived properties over entire class hierarchy. # No more changes to the hierarchy are allowed once this was called - def complete(self, typeId=0): + def complete(self, typeId=0, ordIdx=0): assert not self.isCompleted # Sort sub-classes and convert to tuple, which marks completion - self._subClasses = tuple(sorted(self._subClasses, - key=lambda _: _.name)) + self._subClasses = tuple( + sorted(self._subClasses, + key=lambda _: (bool(_._subClasses), _.name))) + + self._ordIdx = ordIdx + ordIdx = ordIdx + 1 + # Leaves if self.isLeaf: self._typeId = typeId - return typeId + 1 + return typeId + 1, ordIdx # Non-leaves for subClass in self._subClasses: - typeId = subClass.complete(typeId) - return typeId + typeId, ordIdx = subClass.complete(typeId, ordIdx) + return typeId, ordIdx # Post completion methods @property @@ -117,6 +134,11 @@ class Node: self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses) return self._typeIdMax + @property + def ordIdx(self): + assert self.isCompleted + return self._ordIdx + def isSubClassOf(self, other): assert self.isCompleted if self is other: @@ -472,7 +494,7 @@ class Cpt: def read_types(filename): with open(filename) as fh: - for line in fh: + for (lineno, line) in enumerate(fh, start=1): line = re.sub(r'//.*$', '', line) if re.match(r'^\s*$', line): continue @@ -485,12 +507,12 @@ def read_types(filename): if re.search(r'Ast', supern) or classn == "AstNode": classn = re.sub(r'^Ast', '', classn) supern = re.sub(r'^Ast', '', supern) - if supern: - superClass = Nodes[supern] - node = Node(classn, superClass) - Nodes[supern].addSubClass(node) - else: - node = Node(classn, None) + if not supern: + sys.exit("%Error: 'Ast{}' has no super-class".format( + classn)) + superClass = Nodes[supern] + node = Node(classn, superClass, filename, lineno) + superClass.addSubClass(node) Nodes[classn] = node @@ -701,6 +723,9 @@ Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") parser.add_argument('-I', action='store', help='source code include directory') +parser.add_argument('--astdef', + action='append', + help='add AST definition file (relative to -I)') parser.add_argument('--classes', action='store_true', help='makes class declaration files') @@ -710,8 +735,13 @@ parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames') Args = parser.parse_args() -read_types(Args.I + "/V3Ast.h") -read_types(Args.I + "/V3AstNodes.h") +# Set up the root AstNode type. It is standalone so we don't need to parse the +# sources for this. +Nodes["Node"] = Node("Node", None, "AstNode", 1) + +# Read Ast node definitions +for filename in Args.astdef: + read_types(os.path.join(Args.I, filename)) # Compute derived properties over the whole AstNode hierarchy Nodes["Node"].complete() @@ -731,6 +761,36 @@ for node in SortedNodes: "%Error: Non-final AstNode subclasses must be named AstNode*: Ast" + node.name) +# Check ordering of node definitions +files = tuple(sorted(set(_.file for _ in SortedNodes))) + +hasOrderingError = False +for file in files: + nodes = tuple(filter(lambda _, f=file: _.file == f, SortedNodes)) + expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx))) + actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno)) + expect = { + node: pred + for pred, node in zip((None, ) + expectOrder[:-1], expectOrder) + } + actual = { + node: pred + for pred, node in zip((None, ) + actualOrder[:-1], actualOrder) + } + for node in nodes: + if expect[node] != actual[node]: + hasOrderingError = True + pred = expect[node] + print(file + ":" + str(node.lineno) + + ": %Error: Definition of 'Ast" + node.name + + "' is out of order. Should be " + + ("right after 'Ast" + pred.name + + "'" if pred else "first in file") + ".", + file=sys.stderr) + +if hasOrderingError: + sys.exit("%Error: Stopping due to out of order definitions listed above") + read_stages(Args.I + "/Verilator.cpp") source_files = glob.glob(Args.I + "/*.y") diff --git a/src/cppcheck_filtered b/src/cppcheck_filtered index 7e803b306..2b96dc070 100755 --- a/src/cppcheck_filtered +++ b/src/cppcheck_filtered @@ -117,7 +117,7 @@ def _suppress(filename, linenum, eid): if filename == "*": return False - # Cleanup for e.g. ../V3AstNodes.h + # Cleanup for e.g. ../V3AstNode*.h filename = re.sub(r'^\.\./(.*)', r'src/\1', filename) # Specific suppressions