verilator/src/V3AstNodeExpr.h

5759 lines
251 KiB
C
Raw Normal View History

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: AstNode sub-types representing expressions
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
2025-01-01 14:30:25 +01:00
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU Lesser
// General Public License Version 3 or the Perl Artistic License Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
//
// This files contains all 'AstNode' sub-types that represent expressions,
// i.e.: those constructs that represent, or evaluate to [a possible void]
// value. The root of the hierarchy is 'AstNodeExpr'.
//
// Think of expressions in a very general sense as constructs that "name
// things". The "thing" can be considered the value, but can be highly
// structured. For example, an AstConst can name the value '1', which is
// hopefully familiar. On the opposite end of the spectrum of "things" named by
// expressions, consider AstClassOrPackageRef, that can name a collection of
// pairs (specifically the collection of ('member name', 'member thing')
// pairs). Nevertheless, that collection itself can be considered a value. The
// valid composition of expressions then defines the calculus of values in the
// language.
//
//*************************************************************************
#ifndef VERILATOR_V3ASTNODEEXPR_H_
#define VERILATOR_V3ASTNODEEXPR_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 AstNodeExpr VL_NOT_FINAL : public AstNode {
// An expression tree node
protected:
AstNodeExpr(VNType t, FileLine* fl)
: AstNode{t, fl} {}
public:
ASTGEN_MEMBERS_AstNodeExpr;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
// TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final.
bool hasDType() const override VL_MT_SAFE { 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 emitSMT() const { return ""; };
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 expr node
// Until then isOpaque indicates we shouldn't constant optimize this node type
bool isOpaque() const { return VN_IS(this, CvtPackString); }
// Wrap This expression into an AstStmtExpr to denote it occurs in statement position
inline AstStmtExpr* makeStmt();
// Returns an error message if widthMin() is not correct otherwise returns nullptr like
// broken()
virtual const char* widthMismatch() const VL_MT_STABLE { return nullptr; }
};
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
// Binary expression
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: AstNodeExpr{t, fl} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
public:
ASTGEN_MEMBERS_AstNodeBiop;
// 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?
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); }
};
class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop {
// Binary expr with commutative properties
protected:
AstNodeBiCom(VNType t, FileLine* fl, AstNodeExpr* lhs, AstNodeExpr* rhs)
: AstNodeBiop{t, fl, lhs, rhs} {}
public:
ASTGEN_MEMBERS_AstNodeBiCom;
};
class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom {
// Binary expr with commutative & associative properties
protected:
AstNodeBiComAsv(VNType t, FileLine* fl, AstNodeExpr* lhs, AstNodeExpr* rhs)
: AstNodeBiCom{t, fl, lhs, rhs} {}
public:
ASTGEN_MEMBERS_AstNodeBiComAsv;
};
class AstNodeDistBiop VL_NOT_FINAL : public AstNodeBiop {
public:
AstNodeDistBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: AstNodeBiop{t, fl, lhsp, rhsp} {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstNodeDistBiop;
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_DBL_TRIG; }
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
};
class AstNodeSel VL_NOT_FINAL : public AstNodeBiop {
// Single bit range extraction, perhaps with non-constant selection or array selection
// @astgen alias op1 := fromp // Expression we are indexing into
// @astgen alias op2 := bitp // The index // TODO: rename to idxp
protected:
AstNodeSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
: AstNodeBiop{t, fl, fromp, bitp} {}
public:
ASTGEN_MEMBERS_AstNodeSel;
int bitConst() const;
};
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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: AstNodeBiop{t, fl, lhsp, rhsp} {
if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED);
}
public:
ASTGEN_MEMBERS_AstNodeStream;
};
class AstNodeSystemBiopD VL_NOT_FINAL : public AstNodeBiop {
public:
AstNodeSystemBiopD(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
2022-11-22 02:41:32 +01:00
: AstNodeBiop{t, fl, lhsp, rhsp} {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstNodeSystemBiopD;
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_DBL_TRIG; }
bool doubleFlavor() const override { return true; }
};
class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr {
// A call of a C++ function, perhaps a AstCFunc or perhaps globally named
// @astgen op2 := argsp : List[AstNodeExpr] // Note: op1 used by some sub-types only
//
// @astgen ptr := m_funcp : AstCFunc // Function being called
string m_argTypes;
2023-10-24 15:51:46 +02:00
bool m_superReference = false; // Called with super reference
protected:
AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
: AstNodeExpr{t, fl}
, m_funcp{funcp} {
addArgsp(argsp);
}
public:
ASTGEN_MEMBERS_AstNodeCCall;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
int instrCount() const override { return INSTR_COUNT_CALL; }
bool sameNode(const AstNode* samep) const override {
const AstNodeCCall* const asamep = VN_DBG_AS(samep, NodeCCall);
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
}
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override;
bool isOutputter() override { return !isPure(); }
AstCFunc* funcp() const { return m_funcp; }
void funcp(AstCFunc* funcp) { m_funcp = funcp; }
string argTypes() const { return m_argTypes; }
void argTypes(const string& str) { m_argTypes = str; }
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { return true; }
2023-10-24 15:51:46 +02:00
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
// A reference to a task (or function)
// @astgen op1 := namep : Optional[AstNode]
// op2 used by some sub-types only
// @astgen op3 := pinsp : List[AstNodeExpr]
// @astgen op4 := scopeNamep : Optional[AstScopeName]
//
// @astgen ptr := m_taskp : Optional[AstNodeFTask] // [AfterLink] Pointer to task referenced
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package of the task
ASTGEN_MEMBERS_AstNodeFTaskRef; // Gen pointers before other members for performance
private:
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)
VIsCached m_purity; // Pure state
protected:
AstNodeFTaskRef(VNType t, FileLine* fl, const string& name, AstNodeExpr* pinsp)
: AstNodeExpr{t, fl}
, m_name{name} {
addPinsp(pinsp);
}
public:
const char* broken() const override;
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
bool isGateOptimizable() const override;
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; }
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; }
bool isPure() override;
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
private:
bool getPurityRecurse() const;
};
class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr {
// Something that becomes an AstSel
// @astgen op1 := fromp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : Optional[AstNodeExpr]
// @astgen op4 := attrp : Optional[AstAttrOf]
VIsCached m_purity; // Pure state
protected:
AstNodePreSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: AstNodeExpr{t, fl} {
this->fromp(fromp);
this->rhsp(rhsp);
this->thsp(thsp);
}
public:
ASTGEN_MEMBERS_AstNodePreSel;
// METHODS
bool sameNode(const AstNode*) const override { return true; }
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return fromp()->isPure() && rhsp()->isPure() && (!thsp() || thsp()->isPure());
}
};
class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr {
// 4-ary expression
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : AstNodeExpr
// @astgen op4 := fhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeQuadop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp,
AstNodeExpr* fhsp)
: AstNodeExpr{t, fl} {
this->lhsp(lhsp);
this->rhsp(rhsp);
this->thsp(thsp);
this->fhsp(fhsp);
}
public:
ASTGEN_MEMBERS_AstNodeQuadop;
// 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
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure() && fhsp()->isPure();
}
};
class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr {
2022-12-10 03:06:27 +01:00
// Terminal operator -- an operator with no "inputs"
protected:
AstNodeTermop(VNType t, FileLine* fl)
: AstNodeExpr{t, fl} {}
public:
ASTGEN_MEMBERS_AstNodeTermop;
bool isSystemFunc() const override { return true; }
};
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
// Ternary expression
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := thsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: AstNodeExpr{t, fl} {
this->lhsp(lhsp);
this->rhsp(rhsp);
this->thsp(thsp);
}
public:
ASTGEN_MEMBERS_AstNodeTriop;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(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
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
private:
bool getPurityRecurse() const {
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure();
}
};
class AstNodeDistTriop VL_NOT_FINAL : public AstNodeTriop {
public:
AstNodeDistTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNodeExpr* thsp)
: AstNodeTriop{t, fl, lhsp, rhsp, thsp} {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstNodeDistTriop;
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool cleanThs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_DBL_TRIG; }
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
V3ERROR_NA;
}
};
class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr {
// Unary expression
// @astgen op1 := lhsp : AstNodeExpr
VIsCached m_purity; // Pure state
protected:
AstNodeUniop(VNType t, FileLine* fl, AstNodeExpr* lhsp)
: AstNodeExpr{t, fl} {
dtypeFrom(lhsp);
this->lhsp(lhsp);
}
public:
ASTGEN_MEMBERS_AstNodeUniop;
// METHODS
void dump(std::ostream& str) const override;
void dumpJson(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?
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
};
class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop {
public:
AstNodeSystemUniopD(VNType t, FileLine* fl, AstNodeExpr* lhsp)
2022-11-22 02:41:32 +01:00
: AstNodeUniop{t, fl, lhsp} {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstNodeSystemUniopD;
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_DBL_TRIG; }
bool doubleFlavor() const override { return true; }
};
class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr {
// An AstVarRef or AstVarXRef
// @astgen ptr := m_varp : Optional[AstVar] // [AfterLink] Pointer to variable itself
// @astgen ptr := m_varScopep : Optional[AstVarScope] // Varscope for hierarchy
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package of the variable
ASTGEN_MEMBERS_AstNodeVarRef; // Gen pointers before other members for performance
private:
VAccess m_access; // Left hand side assignment
VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this')
protected:
AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access)
: AstNodeExpr{t, fl}
, m_access{access} {
// May have varp==nullptr
this->varp(varp);
}
public:
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return widthInstrs(); }
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) {
m_varp = varp;
dtypeFrom(reinterpret_cast<AstNode*>(varp));
}
AstVarScope* varScopep() const { return m_varScopep; }
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
const VSelfPointerText& selfPointer() const { return m_selfPointer; }
void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; }
string selfPointerProtect(bool useSelfForThis) const {
return selfPointer().protect(useSelfForThis, protect());
}
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
static AstNodeVarRef* varRefLValueRecurse(AstNode* nodep);
};
// === Concrete node types =====================================================
// === AstNodeExpr ===
class AstAddrOfCFunc final : public AstNodeExpr {
// Get address of CFunc
// @astgen ptr := m_funcp : AstCFunc // Pointer to function itself
public:
AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp)
: ASTGEN_SUPER_AddrOfCFunc(fl)
, m_funcp{funcp} {
dtypep(findCHandleDType());
}
public:
ASTGEN_MEMBERS_AstAddrOfCFunc;
void dump(std::ostream& str) const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
AstCFunc* funcp() const { return m_funcp; }
};
class AstArg final : public AstNodeExpr {
// An argument to a function/task, which is either an expression, or is a placeholder for an
// omitted argument.
// TODO: AstArg should not be AstNodeExpr, but is currently used as such widely. Fix later.
// @astgen op1 := exprp : Optional[AstNodeExpr] // nullptr if omitted
string m_name; // Pin name, or "" for number based interconnect
public:
AstArg(FileLine* fl, const string& name, AstNodeExpr* exprp)
: ASTGEN_SUPER_Arg(fl)
, m_name{name} {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstArg;
bool hasDType() const override VL_MT_SAFE { return false; }
string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) override { m_name = name; }
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstAttrOf final : public AstNodeExpr {
// Return a value of a attribute, for example a LSB or array LSB of a signal
// @astgen op1 := fromp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
// @astgen op2 := dimp : Optional[AstNodeExpr]
VAttrType m_attrType; // What sort of extraction
string m_name; // Name for some attributes
public:
AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr,
AstNodeExpr* dimp = nullptr)
: ASTGEN_SUPER_AttrOf(fl) {
this->fromp(fromp);
this->dimp(dimp);
m_attrType = attrtype;
}
ASTGEN_MEMBERS_AstAttrOf;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
VAttrType attrType() const { return m_attrType; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstCExpr final : public AstNodeExpr {
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
// C expression emitted into output, with some arbitrary nodes interspersed
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
const bool m_pure; // Pure optimizable
void init(const string& text, int setwidth) {
if (!text.empty()) add(text);
if (setwidth) {
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
} else {
dtypeSetVoid(); // Caller to override if necessary
}
}
public:
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
class Pure {};
explicit AstCExpr(FileLine* fl, const string& text = "", int setwidth = 0)
: ASTGEN_SUPER_CExpr(fl)
, m_pure{false} {
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
init(text, setwidth);
}
AstCExpr(FileLine* fl, Pure, const string& text = "", int setwidth = 0)
: ASTGEN_SUPER_CExpr(fl)
, m_pure{true} {
init(text, setwidth);
}
ASTGEN_MEMBERS_AstCExpr;
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
// METHODS
bool cleanOut() const override { return true; }
std::string emitC() override { V3ERROR_NA_RETURN(""); }
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return m_pure; }
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
bool isOutputter() override { return true; }
bool isPredictOptimizable() const override { return m_pure; }
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
bool isPure() override { return m_pure; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
// Add some text, or a node to this expression
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
void add(AstNode* nodep) { addNodesp(nodep); }
};
class AstCExprUser final : public AstNodeExpr {
2025-10-22 15:18:27 +02:00
// User '$c' or '$cpure' expression - Like AstCStmt, with text tracking and optimizations
// disabled.
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
//
// Use AstCExpr instead, unless the text is from user input.
//
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
2025-10-22 15:18:27 +02:00
const bool m_pure; // Whether the function is pure
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
public:
2025-10-22 15:18:27 +02:00
class Pure {};
explicit AstCExprUser(FileLine* fl)
2025-10-22 15:18:27 +02:00
: ASTGEN_SUPER_CExprUser(fl)
, m_pure{false} {}
AstCExprUser(FileLine* fl, Pure)
: ASTGEN_SUPER_CExprUser(fl)
, m_pure{true} {}
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
ASTGEN_MEMBERS_AstCExprUser;
// METHODS
bool cleanOut() const override { return false; }
std::string emitC() override { V3ERROR_NA_RETURN(""); }
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
2025-10-22 15:18:27 +02:00
bool isGateOptimizable() const override { return m_pure; }
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
bool isOutputter() override { return true; }
2025-10-22 15:18:27 +02:00
bool isPredictOptimizable() const override { return m_pure; }
bool isPure() override { return m_pure; }
Internals: Refactor text based Ast constructs (#6280) (#6571) Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Add some text, or a node to this expression
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
void add(AstNode* nodep) { addNodesp(nodep); }
};
class AstCMethodHard final : public AstNodeExpr {
// A reference to a "C" hardcoded member task (or function)
// PARENTS: stmt/expr
// @astgen op1 := fromp : AstNodeExpr // Subject of method call
// @astgen op2 := pinsp : List[AstNodeExpr] // Arguments
VCMethod m_method; // Which method to call
bool m_pure = false; // Pure optimizable
bool m_usePtr = false; // Use '->' not '.'
public:
AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, VCMethod method, AstNodeExpr* pinsp = nullptr)
: ASTGEN_SUPER_CMethodHard(fl)
, m_method{method} {
this->fromp(fromp);
addPinsp(pinsp);
setPurity();
}
ASTGEN_MEMBERS_AstCMethodHard;
string name() const override VL_MT_STABLE { return method().ascii(); }
bool sameNode(const AstNode* samep) const override {
const AstCMethodHard* const asamep = VN_DBG_AS(samep, CMethodHard);
return (m_method == asamep->m_method);
}
bool isPure() override { return m_pure; }
int instrCount() const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool usePtr() const { return m_usePtr; }
void usePtr(bool flag) { m_usePtr = flag; }
VCMethod method() const VL_MT_STABLE { return m_method; }
void method(VCMethod value) { m_method = value; }
private:
void setPurity();
};
class AstCast final : public AstNodeExpr {
// Cast to appropriate data type
// @astgen op1 := fromp : AstNodeExpr
// @astgen op2 := childDTypep : Optional[AstNodeDType]
public:
AstCast(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, AstNodeDType* dtp)
: ASTGEN_SUPER_Cast(fl) {
this->fromp(fromp);
childDTypep(dtp);
dtypeFrom(dtp);
}
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCast(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_Cast(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCast;
string emitVerilog() override { return "((%d)'(%l))"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastParse final : public AstNodeExpr {
// Cast to appropriate type, where we haven't determined yet what the data type is
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := dtp : AstNode
public:
AstCastParse(FileLine* fl, AstNodeExpr* lhsp, AstNode* dtp)
: ASTGEN_SUPER_CastParse(fl) {
this->lhsp(lhsp);
this->dtp(dtp);
}
ASTGEN_MEMBERS_AstCastParse;
string emitVerilog() override { return "((%d)'(%l))"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstCastSize final : public AstNodeExpr {
// Cast to specific size; signed/twostate inherited from lower element per IEEE
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstConst
public:
AstCastSize(FileLine* fl, AstNodeExpr* lhsp, AstConst* rhsp)
: ASTGEN_SUPER_CastSize(fl) {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstCastSize;
// No hasDType because widthing removes this node before the hasDType check
string emitVerilog() override { return "((%r)'(%l))"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstCellArrayRef final : public AstNodeExpr {
// As-of-yet unlinkable reference into an array of cells
// @astgen op1 := selp : List[AstNodeExpr] // Select expression
string m_name; // Array name
public:
AstCellArrayRef(FileLine* fl, const string& name, AstNodeExpr* selp)
: ASTGEN_SUPER_CellArrayRef(fl)
, m_name{name} {
addSelp(selp);
}
ASTGEN_MEMBERS_AstCellArrayRef;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstCellRef final : public AstNodeExpr {
// As-of-yet unlinkable reference into a cell
// @astgen op1 := cellp : AstNode
// @astgen op2 := exprp : AstNode<AstNodeExpr|AstNodeDType>
string m_name; // Cell name
public:
AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp)
: ASTGEN_SUPER_CellRef(fl)
, m_name{name} {
this->cellp(cellp);
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstCellRef;
// ACCESSORS
string name() const override VL_MT_STABLE { return m_name; } // * = Array name
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstClassOrPackageRef final : public AstNodeExpr {
// @astgen op1 := paramsp : List[AstPin]
string m_name;
// Node not NodeModule to appease some early parser usage
// @astgen ptr := m_classOrPackageNodep : Optional[AstNode] // Class/package referenced
public:
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
AstPin* paramsp)
: ASTGEN_SUPER_ClassOrPackageRef(fl)
, m_name{name}
, m_classOrPackageNodep{classOrPackageNodep} {
addParamsp(paramsp);
}
ASTGEN_MEMBERS_AstClassOrPackageRef;
// METHODS
bool sameNode(const AstNode* samep) const override {
return (m_classOrPackageNodep
== VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep);
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
// There's no classOrPackagep(); use classOrPackageNodep() to get Node,
// or iterating to package with classOrPackageSkipp()
AstNodeModule* classOrPackageSkipp() const;
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
void classOrPackagep(AstNodeModule* nodep) {
m_classOrPackageNodep = reinterpret_cast<AstNode*>(nodep);
}
bool hasDType() const override VL_MT_SAFE { return false; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstConsAssoc final : public AstNodeExpr {
// Construct an assoc array and return object, '{}
// @astgen op1 := defaultp : Optional[AstNode]
public:
AstConsAssoc(FileLine* fl, AstNode* defaultp)
: ASTGEN_SUPER_ConsAssoc(fl) {
this->defaultp(defaultp);
}
ASTGEN_MEMBERS_AstConsAssoc;
string emitVerilog() override { return "'{}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstConsDynArray final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := rhsp : Optional[AstNode]
const bool m_lhsIsValue; // LHS constructs value inside the queue, not concat
const bool m_rhsIsValue; // RHS constructs value inside the queue, not concat
public:
explicit AstConsDynArray(FileLine* fl)
: ASTGEN_SUPER_ConsDynArray(fl)
, m_lhsIsValue{false}
, m_rhsIsValue{false} {}
explicit AstConsDynArray(FileLine* fl, bool lhsIsValue, AstNode* lhsp, bool rhsIsValue,
AstNode* rhsp)
: ASTGEN_SUPER_ConsDynArray(fl)
, m_lhsIsValue{lhsIsValue}
, m_rhsIsValue{rhsIsValue} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsDynArray;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string emitVerilog() override { return "'{%l, %r}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* samep) const override {
const AstConsDynArray* const sp = VN_DBG_AS(samep, ConsDynArray);
return m_lhsIsValue == sp->m_lhsIsValue && m_rhsIsValue == sp->m_rhsIsValue;
}
bool lhsIsValue() const { return m_lhsIsValue; }
bool rhsIsValue() const { return m_rhsIsValue; }
};
class AstConsPackMember final : public AstNodeExpr {
2025-08-26 00:47:08 +02:00
// Construct a packed array single element [member1: value1]
// Don't need the member we are constructing, as the dtypep can get us to it
// @astgen op2 := rhsp : AstNodeExpr
public:
explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ConsPackMember(fl) {
this->dtypep(dtypep);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsPackMember;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstConsPackUOrStruct final : public AstNodeExpr {
// Construct a packed struct and return object, '{member1: value1, member2: value2}
// Don't need the class we are constructing, as the dtypep can get us to it
// @astgen op1 := membersp : List[AstConsPackMember]
public:
explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep,
AstConsPackMember* membersp = nullptr)
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
this->dtypep(dtypep);
addMembersp(membersp);
}
ASTGEN_MEMBERS_AstConsPackUOrStruct;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstConsQueue final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := rhsp : Optional[AstNode]
const bool m_lhsIsValue; // LHS constructs value inside the queue, not concat
const bool m_rhsIsValue; // RHS constructs value inside the queue, not concat
public:
explicit AstConsQueue(FileLine* fl)
: ASTGEN_SUPER_ConsQueue(fl)
, m_lhsIsValue{false}
, m_rhsIsValue{false} {}
explicit AstConsQueue(FileLine* fl, bool lhsIsValue, AstNode* lhsp, bool rhsIsValue,
AstNode* rhsp)
: ASTGEN_SUPER_ConsQueue(fl)
, m_lhsIsValue{lhsIsValue}
, m_rhsIsValue{rhsIsValue} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsQueue;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string emitVerilog() override { return "'{%l, %r}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* samep) const override {
const AstConsQueue* const sp = VN_DBG_AS(samep, ConsQueue);
return m_lhsIsValue == sp->m_lhsIsValue && m_rhsIsValue == sp->m_rhsIsValue;
}
bool lhsIsValue() const { return m_lhsIsValue; }
bool rhsIsValue() const { return m_rhsIsValue; }
};
class AstConsWildcard final : public AstNodeExpr {
// Construct a wildcard assoc array and return object, '{}
// @astgen op1 := defaultp : Optional[AstNode]
public:
AstConsWildcard(FileLine* fl, AstNode* defaultp)
: ASTGEN_SUPER_ConsWildcard(fl) {
this->defaultp(defaultp);
}
ASTGEN_MEMBERS_AstConsWildcard;
string emitVerilog() override { return "'{}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstConst final : public AstNodeExpr {
// A constant
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.widthToFit()),
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) { // Need () constructor
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, V3Number::VerilogNumberLiteral{}, sourcep} {
initWithNumber();
}
class VerilogStringLiteral {}; // for creator type-overload selection
AstConst(FileLine* fl, VerilogStringLiteral, const string& str)
: ASTGEN_SUPER_Const(fl)
, m_num{this, V3Number::VerilogStringLiteral{}, str} {
initWithNumber();
}
AstConst(FileLine* fl, uint32_t num)
: ASTGEN_SUPER_Const(fl)
, m_num(this, 32, num) { // Need () constructor
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) { // Need () constructor
m_num.width(32, false);
dtypeSetLogicUnsized(32, m_num.widthToFit(), 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) { // Need () constructor
m_num.width(32, true);
dtypeSetLogicUnsized(32, m_num.widthToFit(), 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) { // Need () constructor
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) { // Need () constructor
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) { // Need () constructor
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{this, V3Number::String{}, 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) { // Need () constructor
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) { // Need () constructor
dtypeSetBit();
}
class All0 {};
AstConst(FileLine* fl, All0)
: ASTGEN_SUPER_Const(fl)
, m_num{this, V3Number::VerilogNumberLiteral{}, "'0"} {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class All1 {};
AstConst(FileLine* fl, All1)
: ASTGEN_SUPER_Const(fl)
, m_num{this, V3Number::VerilogNumberLiteral{}, "'1"} {
initWithNumber();
fl->warnOff(V3ErrorCode::NEWERSTD, true);
}
class Null {};
AstConst(FileLine* fl, Null)
: ASTGEN_SUPER_Const(fl)
, m_num{this, V3Number::Null{}} {
dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here
initWithNumber();
}
2022-12-23 13:34:49 +01:00
class OneStep {};
AstConst(FileLine* fl, OneStep)
: ASTGEN_SUPER_Const(fl)
, m_num{this, V3Number::OneStep{}} {
2022-12-23 13:34:49 +01:00
dtypeSetLogicSized(64, VSigning::UNSIGNED);
initWithNumber();
}
ASTGEN_MEMBERS_AstConst;
string name() const override VL_MT_STABLE { return num().ascii(); } // * = Value
const V3Number& num() const VL_MT_SAFE { return m_num; } // * = Value
V3Number& num() { return m_num; } // * = Value
uint32_t toUInt() const { return num().toUInt(); }
int32_t toSInt() const VL_MT_SAFE { return num().toSInt(); }
uint64_t toUQuad() const { return num().toUQuad(); }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* samep) const override {
const AstConst* const sp = VN_DBG_AS(samep, Const);
return num().isCaseEq(sp->num());
}
void cloneRelink() override { m_num.nodep(this); }
const char* broken() const override {
BROKEN_RTN(m_num.nodep() && m_num.nodep() != this);
return nullptr;
}
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 AstConstraintRef final : public AstNodeExpr {
// A reference to a constraint identifier
2024-08-21 12:16:44 +02:00
// @astgen op1 := fromp : Optional[AstNodeExpr]
//
2024-08-21 12:16:44 +02:00
// @astgen ptr := m_constrp : AstConstraint // The constraint pointed to
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package of constraint
public:
2024-08-21 12:16:44 +02:00
AstConstraintRef(FileLine* fl, AstNodeExpr* fromp, AstConstraint* constrp)
: ASTGEN_SUPER_ConstraintRef(fl) {
this->fromp(fromp);
this->constrp(constrp);
dtypep(findConstraintRefDType());
}
ASTGEN_MEMBERS_AstConstraintRef;
2024-08-21 12:16:44 +02:00
string name() const override VL_MT_STABLE;
AstConstraint* constrp() const VL_MT_STABLE { return m_constrp; }
void constrp(AstConstraint* nodep) { m_constrp = nodep; }
AstNodeModule* classOrPackagep() const VL_MT_STABLE { return m_classOrPackagep; }
// TODO: this setter is unused
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
};
class AstCvtArrayToArray final : public AstNodeExpr {
// Copy/Cast from dynamic/unpacked types to dynamic/unpacked types
// @astgen op1 := fromp : AstNodeExpr
private:
const bool m_reverse; // whether ordering gets reversed in this operation (ex: {<<{expr}})
const int m_blockSize; // num bits per block in a streaming operation (ex: 4 in {<<4{expr}}))
const int m_dstElementBits; // num bits in lhs (ex: 8 if to byte-queue, 1 if to bit-queue)
const int m_srcElementBits; // num bits in rhs (ex 8 if from byte-queue, 1 if from bit-queue)
public:
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCvtArrayToArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp, bool reverse,
int blockSize, int dstElementBits, int srcElementBits)
: ASTGEN_SUPER_CvtArrayToArray(fl)
, m_reverse{reverse}
, m_blockSize{blockSize}
, m_dstElementBits{dstElementBits}
, m_srcElementBits{srcElementBits} {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtArrayToArray;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool reverse() const { return m_reverse; }
int blockSize() const { return m_blockSize; }
int dstElementBits() const { return m_dstElementBits; }
int srcElementBits() const { return m_srcElementBits; }
};
class AstCvtArrayToPacked final : public AstNodeExpr {
// Cast from dynamic queue data type to packed array
// @astgen op1 := fromp : AstNodeExpr
public:
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCvtArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtArrayToPacked(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtArrayToPacked;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtPackedToArray final : public AstNodeExpr {
// Cast from packed array to dynamic/unpacked queue data type
// @astgen op1 := fromp : AstNodeExpr
public:
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCvtPackedToArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtPackedToArray(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtPackedToArray;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtUnpackedToQueue final : public AstNodeExpr {
// Cast from unpacked array to dynamic/unpacked queue data type
// @astgen op1 := fromp : AstNodeExpr
public:
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCvtUnpackedToQueue(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtUnpackedToQueue(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtUnpackedToQueue;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { return "VL_CVT_UNPACK_TO_Q(%P, %li)"; }
bool cleanOut() const override { return true; }
};
class AstDist final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := itemsp : List[AstDistItem]
public:
AstDist(FileLine* fl, AstNodeExpr* exprp, AstDistItem* itemsp)
: ASTGEN_SUPER_Inside(fl) {
this->exprp(exprp);
addItemsp(itemsp);
dtypeSetBit();
}
ASTGEN_MEMBERS_AstDist;
string emitVerilog() override { return "%l dist { %r }"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; } // NA
};
class AstDistItem final : public AstNodeExpr {
// Constraint distribution item
// @astgen op1 := rangep : AstNodeExpr
// @astgen op2 := weightp : AstNodeExpr
bool m_isWhole = false; // True for weight ':/', false for ':='
public:
AstDistItem(FileLine* fl, AstNodeExpr* rangep, AstNodeExpr* weightp)
: ASTGEN_SUPER_DistItem(fl) {
this->rangep(rangep);
this->weightp(weightp);
}
ASTGEN_MEMBERS_AstDistItem;
string emitVerilog() override { return "%l "s + (m_isWhole ? ":/" : ":=") + " %r"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; } // NA
void isWhole(bool flag) { m_isWhole = flag; }
bool isWhole() const { return m_isWhole; }
};
class AstDot final : public AstNodeExpr {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage
// @astgen op1 := lhsp : AstNode<AstNodeExpr|AstNodeDType>
// @astgen op2 := rhsp : AstNode<AstNodeExpr|AstNodeDType>
//
// We don't have a list of elements as it's probably legal to do '(foo.bar).(baz.bap)'
const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)
public:
AstDot(FileLine* fl, bool colon, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Dot(fl)
, m_colon{colon} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstDot;
// For parser, make only if non-null package
static AstNodeExpr* newIfPkg(FileLine* fl, AstNodeExpr* packageOrClassp, AstNodeExpr* rhsp) {
if (!packageOrClassp) return rhsp;
2022-11-13 01:51:03 +01:00
return new AstDot{fl, true, packageOrClassp, rhsp};
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
bool colon() const { return m_colon; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstEmptyQueue final : public AstNodeExpr {
public:
explicit AstEmptyQueue(FileLine* fl)
: ASTGEN_SUPER_EmptyQueue(fl) {}
ASTGEN_MEMBERS_AstEmptyQueue;
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitVerilog() override { return "{}"; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool cleanOut() const override { return true; }
};
class AstEnumItemRef final : public AstNodeExpr {
// @astgen ptr := m_itemp : Optional[AstEnumItem] // [AfterLink] Pointer to item
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package defined in
string m_name; // Name of enum (for param relink)
public:
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
: ASTGEN_SUPER_EnumItemRef(fl)
, m_name{itemp->name()}
, m_itemp{itemp}
, m_classOrPackagep{classOrPackagep} {
dtypeFrom(m_itemp);
}
ASTGEN_MEMBERS_AstEnumItemRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
2025-12-09 02:17:40 +01:00
const char* broken() const override;
string name() const override VL_MT_STABLE { return itemp() ? itemp()->name() : m_name; }
int instrCount() const override { return 0; }
bool sameNode(const AstNode* samep) const override {
const AstEnumItemRef* const sp = VN_DBG_AS(samep, EnumItemRef);
return itemp() == sp->itemp();
}
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
void itemp(AstEnumItem* nodep) { m_itemp = nodep; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
};
class AstExprStmt final : public AstNodeExpr {
// Perform a statement, often assignment inside an expression node,
// the parent gets passed the 'resultp()'.
// resultp is evaluated AFTER the statement(s).
// @astgen op1 := stmtsp : List[AstNode]
// @astgen op2 := resultp : AstNodeExpr
private:
bool m_hasResult = true;
public:
AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNodeExpr* resultp)
: ASTGEN_SUPER_ExprStmt(fl) {
addStmtsp(stmtsp);
this->resultp(resultp);
dtypeFrom(resultp);
}
ASTGEN_MEMBERS_AstExprStmt;
// METHODS
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
2023-05-24 02:52:30 +02:00
bool cleanOut() const override { return true; }
bool isPure() override {
if (AstNode::afterCommentp(stmtsp())) return false;
return resultp()->isPure();
}
bool sameNode(const AstNode*) const override { return true; }
bool hasResult() { return m_hasResult; }
void hasResult(bool flag) { m_hasResult = flag; }
};
class AstFError final : public AstNodeExpr {
// @astgen op1 := filep : AstNode
// @astgen op2 := strp : AstNode
public:
AstFError(FileLine* fl, AstNode* filep, AstNode* strp)
: ASTGEN_SUPER_FError(fl) {
this->filep(filep);
this->strp(strp);
}
ASTGEN_MEMBERS_AstFError;
string emitVerilog() override { return "%f$ferror(%l, %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs() * 64; }
2023-03-16 01:49:59 +01:00
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isSystemFunc() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2023-03-12 00:11:01 +01:00
};
class AstFOpen final : public AstNodeExpr {
// @astgen op2 := filenamep : AstNodeExpr
// @astgen op3 := modep : AstNodeExpr
public:
AstFOpen(FileLine* fl, AstNodeExpr* filenamep, AstNodeExpr* modep)
: ASTGEN_SUPER_FOpen(fl) {
this->filenamep(filenamep);
this->modep(modep);
}
ASTGEN_MEMBERS_AstFOpen;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
string verilogKwd() const override { return "$fopen"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
2023-03-12 00:11:01 +01:00
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
2023-03-12 00:11:01 +01:00
};
class AstFOpenMcd final : public AstNodeExpr {
// @astgen op2 := filenamep : AstNodeExpr
public:
AstFOpenMcd(FileLine* fl, AstNodeExpr* filenamep)
: ASTGEN_SUPER_FOpenMcd(fl) {
this->filenamep(filenamep);
}
ASTGEN_MEMBERS_AstFOpenMcd;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
string verilogKwd() const override { return "$fopen"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
2023-03-12 00:11:01 +01:00
bool isUnlikely() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstFRead final : public AstNodeExpr {
// @astgen op1 := memp : AstNode // VarRef for result
// @astgen op2 := filep : AstNode // file (must be a VarRef)
// @astgen op3 := startp : Optional[AstNode] // Offset
// @astgen op4 := countp : Optional[AstNode] // Size
public:
AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp)
: ASTGEN_SUPER_FRead(fl) {
this->memp(memp);
this->filep(filep);
this->startp(startp);
this->countp(countp);
}
ASTGEN_MEMBERS_AstFRead;
string verilogKwd() const override { return "$fread"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstFRewind final : public AstNodeExpr {
// @astgen op1 := filep : Optional[AstNode]
public:
AstFRewind(FileLine* fl, AstNode* filep)
: ASTGEN_SUPER_FRewind(fl) {
this->filep(filep);
}
ASTGEN_MEMBERS_AstFRewind;
string verilogKwd() const override { return "$frewind"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstFScanF final : public AstNodeExpr {
// @astgen op1 := exprsp : List[AstNode] // VarRefs for results
// @astgen op2 := filep : Optional[AstNode] // file (must be a VarRef)
string m_text;
public:
AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp)
: ASTGEN_SUPER_FScanF(fl)
, m_text{text} {
addExprsp(exprsp);
this->filep(filep);
}
ASTGEN_MEMBERS_AstFScanF;
string name() const override VL_MT_STABLE { return m_text; }
string verilogKwd() const override { return "$fscanf"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* samep) const override {
return text() == VN_DBG_AS(samep, FScanF)->text();
}
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text = text; }
bool isSystemFunc() const override { return true; }
};
class AstFSeek final : public AstNodeExpr {
// @astgen op1 := filep : AstNode // file (must be a VarRef)
// @astgen op2 := offset : Optional[AstNode]
// @astgen op3 := operation : Optional[AstNode]
public:
AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation)
: ASTGEN_SUPER_FSeek(fl) {
this->filep(filep);
this->offset(offset);
this->operation(operation);
}
ASTGEN_MEMBERS_AstFSeek;
string verilogKwd() const override { return "$fseek"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstFTell final : public AstNodeExpr {
// @astgen op1 := filep : AstNode // file (must be a VarRef)
public:
AstFTell(FileLine* fl, AstNode* filep)
: ASTGEN_SUPER_FTell(fl) {
this->filep(filep);
}
ASTGEN_MEMBERS_AstFTell;
string verilogKwd() const override { return "$ftell"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstFalling final : public AstNodeExpr {
// Verilog $falling_gclk
// @astgen op1 := exprp : AstNodeExpr
public:
AstFalling(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_Falling(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstFalling;
string emitVerilog() override { return "$falling_gclk(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstFell final : public AstNodeExpr {
// Verilog $fell
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstFell(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Fell(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstFell;
string emitVerilog() override { return "$fell(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstFuture final : public AstNodeExpr {
// Verilog $future_gclk
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstFuture(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Future(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstFuture;
string emitVerilog() override { return "$future_gclk(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstGatePin final : public AstNodeExpr {
// Possibly expand a gate primitive input pin value to match the range of the gate primitive
// @astgen op1 := exprp : AstNodeExpr // Pin expression
// @astgen op2 := rangep : AstRange // Range of pin
public:
AstGatePin(FileLine* fl, AstNodeExpr* exprp, AstRange* rangep)
: ASTGEN_SUPER_GatePin(fl) {
this->exprp(exprp);
this->rangep(rangep);
}
ASTGEN_MEMBERS_AstGatePin;
string emitVerilog() override { return "%l"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstImplication final : public AstNodeExpr {
2023-09-04 03:02:42 +02:00
// Verilog Implication Operator
// Nonoverlapped "|=>"
// Overlapped "|->"
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
// @astgen op3 := sentreep : Optional[AstSenTree]
private:
const bool m_isOverlapped; // True if overlapped
public:
AstImplication(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, bool isOverlapped)
: ASTGEN_SUPER_Implication(fl)
, m_isOverlapped{isOverlapped} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstImplication;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isOverlapped() const { return m_isOverlapped; }
};
class AstInitArray final : public AstNodeExpr {
// This is also used as an array value in V3Simulate/const prop.
// Would be better called as 'AstConstArray'
// 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()
// @astgen op1 := defaultp : Optional[AstNodeExpr] // Default, if sparse
// @astgen op2 := initsp : List[AstNode] // Initial value expressions
//
public:
using KeyItemMap = std::map<uint64_t, AstInitItem*>;
private:
KeyItemMap m_map; // Node value for each array index
// METHODS
void dumpInitList(std::ostream& str) const;
public:
AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNodeExpr* defaultp)
: ASTGEN_SUPER_InitArray(fl) {
dtypep(newDTypep);
this->defaultp(defaultp);
}
ASTGEN_MEMBERS_AstInitArray;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override;
void cloneRelink() override;
bool sameNode(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 == VN_DBG_AS(samep, InitArray)->m_map;
}
void addValuep(AstNodeExpr* newp) { addIndexValuep(m_map.size(), newp); }
const KeyItemMap& map() const { return m_map; }
void addIndexValuep(uint64_t index, AstNodeExpr* newp);
AstNodeExpr* getIndexValuep(uint64_t index) const;
AstNodeExpr* getIndexDefaultedValuep(uint64_t index) const;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstInside final : public AstNodeExpr {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := itemsp : List[AstNodeExpr]
public:
AstInside(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* itemsp)
: ASTGEN_SUPER_Inside(fl) {
this->exprp(exprp);
addItemsp(itemsp);
dtypeSetBit();
}
ASTGEN_MEMBERS_AstInside;
string emitVerilog() override { return "%l inside { %r }"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; } // NA
};
class AstInsideRange final : public AstNodeExpr {
// @astgen op1 := lhsp : AstNodeExpr
// @astgen op2 := rhsp : AstNodeExpr
public:
AstInsideRange(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_InsideRange(fl) {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstInsideRange;
string emitVerilog() override { return "[%l:%r]"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; } // NA
// Create AstAnd(AstGte(...), AstLte(...))
AstNodeExpr* newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp, AstNodeExpr* rhsp);
};
class AstLambdaArgRef final : public AstNodeExpr {
// 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.
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} {}
ASTGEN_MEMBERS_AstLambdaArgRef;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
string emitVerilog() override { return name(); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool index() const { return m_index; }
bool isExprCoverageEligible() const override { return false; }
};
class AstMemberSel final : public AstNodeExpr {
// @astgen op1 := fromp : AstNodeExpr
//
// @astgen ptr := m_varp : Optional[AstVar] // Post link, variable in class that is selecting
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
string m_name;
2023-06-30 09:12:22 +02:00
VAccess m_access; // Read or write, as in AstNodeVarRef
public:
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name)
: ASTGEN_SUPER_MemberSel(fl)
, m_name{name} {
this->fromp(fromp);
dtypep(nullptr); // V3Width will resolve
}
AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp);
ASTGEN_MEMBERS_AstMemberSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
2023-06-30 09:12:22 +02:00
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
2023-05-29 09:35:53 +02:00
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* samep) const override;
int instrCount() const override { return widthInstrs(); }
AstVar* varp() const { return m_varp; }
void varp(AstVar* nodep) { m_varp = nodep; }
};
class AstNewCopy final : public AstNodeExpr {
// New as shallow copy
// @astgen op1 := rhsp : AstNodeExpr
public:
AstNewCopy(FileLine* fl, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NewCopy(fl) {
dtypeFrom(rhsp); // otherwise V3Width will resolve
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstNewCopy;
string emitVerilog() override { return "new"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int instrCount() const override { return widthInstrs(); }
};
class AstNewDynamic final : public AstNodeExpr {
// New for dynamic array
// @astgen op1 := sizep : AstNodeExpr
// @astgen op2 := rhsp : Optional[AstNodeExpr]
public:
AstNewDynamic(FileLine* fl, AstNodeExpr* sizep, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NewDynamic(fl) {
dtypeFrom(rhsp); // otherwise V3Width will resolve
this->sizep(sizep);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstNewDynamic;
string emitVerilog() override { return "new"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int instrCount() const override { return widthInstrs(); }
};
class AstPExpr final : public AstNodeExpr {
// Property expression
// @astgen op1 := bodyp : AstBegin
public:
explicit AstPExpr(FileLine* fl, AstBegin* bodyp, AstNodeDType* dtypep)
: ASTGEN_SUPER_PExpr(fl) {
this->bodyp(bodyp);
this->dtypep(dtypep);
}
ASTGEN_MEMBERS_AstPExpr;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
};
class AstParseHolder final : public AstNodeExpr {
// A reference to something soon to replace, used in a select at parse time
// that needs conversion to pull the upper lvalue later
public:
explicit AstParseHolder(FileLine* fl)
: ASTGEN_SUPER_ParseHolder(fl) {}
ASTGEN_MEMBERS_AstParseHolder;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstParseRef final : public AstNodeExpr {
// 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.
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := ftaskrefp : Optional[AstNodeFTaskRef]
string m_name;
public:
AstParseRef(FileLine* fl, const string& name, AstNode* lhsp = nullptr,
AstNodeFTaskRef* ftaskrefp = nullptr)
: ASTGEN_SUPER_ParseRef(fl)
, m_name{name} {
this->lhsp(lhsp);
this->ftaskrefp(ftaskrefp);
}
ASTGEN_MEMBERS_AstParseRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
bool sameNode(const AstNode* samep) const override {
const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef);
return m_name == asamep->m_name;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstPast final : public AstNodeExpr {
// Verilog $past
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := ticksp : Optional[AstNode]
// @astgen op3 := sentreep : Optional[AstSenTree]
public:
2025-07-02 00:00:04 +02:00
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNode* ticksp = nullptr,
AstSenTree* sentreep = nullptr)
: ASTGEN_SUPER_Past(fl) {
this->exprp(exprp);
this->ticksp(ticksp);
2025-07-02 00:00:04 +02:00
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstPast;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstPatMember final : public AstNodeExpr {
// Verilog '{a} or '{a{b}}
// Parents: AstPattern
// Children: expression, AstPattern, replication count, decoded nodep if TEXT
// Expression to assign or another AstPattern (list if replicated)
// @astgen op1 := lhssp : List[AstNodeExpr]
// @astgen op2 := keyp : Optional[AstNode]
// @astgen op3 := repp : Optional[AstNodeExpr] // replication count, or nullptr for count 1
// @astgen op4 := varrefp : Optional[AstNodeExpr] // Decoded variable if TEXT
bool m_isDefault = false; // Has default
bool m_isConcat = false; // From concatenate
public:
AstPatMember(FileLine* fl, AstNodeExpr* lhssp, AstNode* keyp, AstNodeExpr* repp)
: ASTGEN_SUPER_PatMember(fl) {
addLhssp(lhssp);
this->keyp(keyp);
this->repp(repp);
}
ASTGEN_MEMBERS_AstPatMember;
string emitVerilog() override { return lhssp() ? "%f{%r{%k%l}}" : "%l"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs() * 2; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool isConcat() const { return m_isConcat; }
void isConcat(bool flag) { m_isConcat = flag; }
bool isDefault() const { return m_isDefault; }
void isDefault(bool flag) { m_isDefault = flag; }
};
class AstPattern final : public AstNodeExpr {
// Verilog '{a,b,c,d...}
// Parents: AstNodeAssign, AstPattern, ...
// Children: expression, AstPattern, AstPatReplicate
// @astgen op1 := childDTypep : Optional[AstNodeDType]
// @astgen op2 := itemsp : List[AstNode] // AstPatReplicate, AstPatMember, etc
public:
AstPattern(FileLine* fl, AstNode* itemsp)
: ASTGEN_SUPER_Pattern(fl) {
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstPattern;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
};
class AstRand final : public AstNodeExpr {
// $random/$random(seed) or $urandom/$urandom(seed)
// Return a random number, based upon width()
// @astgen op1 := seedp : Optional[AstNode]
const bool m_urandom; // $urandom vs $random
public:
class Reset {};
AstRand(FileLine* fl, AstNode* seedp, bool urandom)
: ASTGEN_SUPER_Rand(fl)
, m_urandom{urandom} {
this->seedp(seedp);
}
2025-11-30 15:04:42 +01:00
class SRandomU32 {};
AstRand(FileLine* fl, SRandomU32)
: ASTGEN_SUPER_Rand(fl)
, m_urandom{true} {
dtypeSetUInt32();
}
ASTGEN_MEMBERS_AstRand;
string emitVerilog() override {
return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)")
: (m_urandom ? "%f$urandom()" : "%f$random()");
}
string emitC() override {
if (seedp()) {
if (urandom()) {
return "VL_URANDOM_SEEDED_%nq%lq(%li)";
} else {
return "VL_RANDOM_SEEDED_%nq%lq(%li)";
}
}
if (isWide()) {
return "VL_RANDOM_%nq(%nw, %P)";
} else {
return "VL_RANDOM_%nq()";
}
}
bool cleanOut() const override { return false; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return !seedp(); }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool combinable(const AstRand* samep) const {
return !seedp() && !samep->seedp() && urandom() == samep->urandom();
}
bool urandom() const { return m_urandom; }
};
class AstRandRNG final : public AstNodeExpr {
// Random used in a class using VlRNG
// Return a random number, based upon width()
public:
AstRandRNG(FileLine* fl, AstNodeDType* dtp)
: ASTGEN_SUPER_RandRNG(fl) {
dtypep(dtp);
}
ASTGEN_MEMBERS_AstRandRNG;
string emitVerilog() override { return "%f$rngrandom()"; }
string emitC() override {
return isWide() ? "VL_RANDOM_RNG_%nq(__Vm_rng, %nw, %P)" //
: "VL_RANDOM_RNG_%nq(__Vm_rng)";
}
bool cleanOut() const override { return false; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstRising final : public AstNodeExpr {
// Verilog $rising_gclk
// @astgen op1 := exprp : AstNodeExpr
public:
AstRising(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_Rising(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstRising;
string emitVerilog() override { return "$rising_gclk(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstRose final : public AstNodeExpr {
// Verilog $rose
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstRose(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Rose(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstRose;
string emitVerilog() override { return "$rose(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstSExpr final : public AstNodeExpr {
// Sequence expression
// @astgen op1 := preExprp: Optional[AstNodeExpr]
// @astgen op2 := delayp : AstNodeStmt<AstDelay|AstBegin>
// @astgen op3 := exprp : AstNodeExpr
public:
explicit AstSExpr(FileLine* fl, AstNodeExpr* preExprp, AstNodeStmt* delayp, AstNodeExpr* exprp)
: ASTGEN_SUPER_SExpr(fl) {
this->preExprp(preExprp);
this->delayp(delayp);
this->exprp(exprp);
}
explicit AstSExpr(FileLine* fl, AstNodeStmt* delayp, AstNodeExpr* exprp)
: ASTGEN_SUPER_SExpr(fl) {
this->preExprp(nullptr);
this->delayp(delayp);
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstSExpr;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
};
class AstSFormatF final : public AstNodeExpr {
// Convert format to string, generally under an AstDisplay or AstSFormat
// Also used as "real" function for /*verilator sformat*/ functions
// @astgen op1 := exprsp : List[AstNodeExpr]
// @astgen op2 := scopeNamep : Optional[AstScopeName]
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, AstNodeExpr* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_SFormatF(fl)
, m_text{text}
, m_hidden{hidden}
, m_hasFormat{true}
, m_missingArgChar{missingArgChar} {
dtypeSetString();
addExprsp(exprsp);
}
AstSFormatF(FileLine* fl, NoFormat, AstNodeExpr* exprsp, char missingArgChar = 'd',
bool hidden = true)
: ASTGEN_SUPER_SFormatF(fl)
, m_text{""}
, m_hidden{hidden}
, m_hasFormat{false}
, m_missingArgChar{missingArgChar} {
dtypeSetString();
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSFormatF;
string name() const override VL_MT_STABLE { return m_text; }
void name(const string& name) override { m_text = name; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool sameNode(const AstNode* samep) const override {
return text() == VN_DBG_AS(samep, SFormatF)->text();
}
string verilogKwd() const override { return "$sformatf"; }
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text = text; }
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; }
bool hasFormat() const { return m_hasFormat; }
void hasFormat(bool flag) { m_hasFormat = flag; }
char missingArgChar() const { return m_missingArgChar; }
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
bool isSystemFunc() const override { return true; }
};
class AstSScanF final : public AstNodeExpr {
// @astgen op1 := exprsp : List[AstNode] // VarRefs for results
// @astgen op2 := fromp : AstNode
string m_text;
2025-09-01 20:40:22 +02:00
VTimescale m_timeunit; // Parent module time unit
public:
AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp)
: ASTGEN_SUPER_SScanF(fl)
, m_text{text} {
addExprsp(exprsp);
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstSScanF;
string name() const override VL_MT_STABLE { return m_text; }
string verilogKwd() const override { return "$sscanf"; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: makes output
bool cleanOut() const override { return false; }
bool sameNode(const AstNode* samep) const override {
2025-09-01 20:40:22 +02:00
const AstSScanF* const asamep = VN_DBG_AS(samep, SScanF);
return text() == asamep->text() && timeunit() == asamep->timeunit();
}
string text() const { return m_text; } // * = Text to display
2025-09-01 20:40:22 +02:00
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
bool isSystemFunc() const override { return true; }
};
class AstSampled final : public AstNodeExpr {
// Verilog $sampled
// @astgen op1 := exprp : AstNode // AstNodeExpr or AstPropSpec
public:
AstSampled(FileLine* fl, AstNode* exprp)
: ASTGEN_SUPER_Sampled(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstSampled;
string emitVerilog() override { return "$sampled(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return 0; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstScopeName final : public AstNodeExpr {
// For display %m and DPI context imports
// Parents: AstSFormatF, AstNodeFTaskRef, AstNodeFTask
std::string m_scopeAttr;
std::string m_scopeEntr;
bool m_dpiExport = false; // Is for dpiExport
const bool m_forFormat; // Is for a format %m
static std::string scopeNameFormatter(const std::string& text);
static std::string scopePrettyNameFormatter(const std::string& text);
public:
class ForFormat {};
AstScopeName(FileLine* fl, bool forFormat)
: ASTGEN_SUPER_ScopeName(fl)
, m_forFormat{forFormat} {
dtypeSetUInt64();
}
ASTGEN_MEMBERS_AstScopeName;
bool sameNode(const AstNode* samep) const override {
const AstScopeName* const sp = VN_DBG_AS(samep, ScopeName);
return m_scopeAttr == sp->m_scopeAttr //
&& m_scopeEntr == sp->m_scopeEntr //
&& m_dpiExport == sp->m_dpiExport //
&& m_forFormat == sp->m_forFormat;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
// ACCESSORS
const std::string& scopeAttr() const { return m_scopeAttr; }
void scopeAttr(const std::string& val) { m_scopeAttr = val; }
const std::string& scopeEntr() const { return m_scopeEntr; }
void scopeEntr(const std::string& val) { m_scopeEntr = val; }
bool dpiExport() const { return m_dpiExport; }
void dpiExport(bool flag) { m_dpiExport = flag; }
bool forFormat() const { return m_forFormat; }
// Name for __Vscopep variable including children
string scopeSymName() const { return scopeNameFormatter(m_scopeAttr); }
// Name for DPI import scope
string scopeDpiName() const { return scopeNameFormatter(m_scopeEntr); }
// Name for __Vscopep variable including children
string scopePrettySymName() const { return scopePrettyNameFormatter(m_scopeAttr); }
// Name for __Vscopep variable including children
string scopePrettyDpiName() const { return scopePrettyNameFormatter(m_scopeEntr); }
};
class AstSelLoopVars final : public AstNodeExpr {
// Parser only concept "[id, id, id]" for a foreach statement
// Unlike normal selects elements is a list
// TODO: Should not be an AstNodeExpr, model foreach better
// @astgen op1 := fromp : AstNodeExpr
// @astgen op2 := elementsp : List[AstNode]
public:
AstSelLoopVars(FileLine* fl, AstNodeExpr* fromp, AstNode* elementsp)
: ASTGEN_SUPER_SelLoopVars(fl) {
this->fromp(fromp);
addElementsp(elementsp);
}
ASTGEN_MEMBERS_AstSelLoopVars;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool maybePointedTo() const override VL_MT_SAFE { return false; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
bool hasDType() const override VL_MT_SAFE { return false; }
};
class AstSetAssoc final : public AstNodeExpr {
// Set an assoc array element and return object, '{}
// @astgen op1 := lhsp : AstNode
// @astgen op2 := keyp : Optional[AstNode]
// @astgen op3 := valuep : AstNodeExpr
public:
AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNodeExpr* valuep)
: ASTGEN_SUPER_SetAssoc(fl) {
this->lhsp(lhsp);
this->keyp(keyp);
this->valuep(valuep);
}
ASTGEN_MEMBERS_AstSetAssoc;
string emitVerilog() override { return "'{}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstSetWildcard final : public AstNodeExpr {
// Set a wildcard assoc array element and return object, '{}
// @astgen op1 := lhsp : AstNode
// @astgen op2 := keyp : Optional[AstNode]
// @astgen op3 := valuep : AstNodeExpr
public:
AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNodeExpr* valuep)
: ASTGEN_SUPER_SetWildcard(fl) {
this->lhsp(lhsp);
this->keyp(keyp);
this->valuep(valuep);
}
ASTGEN_MEMBERS_AstSetWildcard;
string emitVerilog() override { return "'{}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstStable final : public AstNodeExpr {
// Verilog $stable
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := sentreep : Optional[AstSenTree]
public:
AstStable(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep)
: ASTGEN_SUPER_Stable(fl) {
this->exprp(exprp);
this->sentreep(sentreep);
}
ASTGEN_MEMBERS_AstStable;
string emitVerilog() override { return "$stable(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
2022-11-18 01:12:54 +01:00
class AstStackTraceF final : public AstNodeExpr {
// $stacktrace used as function
public:
explicit AstStackTraceF(FileLine* fl)
2022-11-18 01:12:54 +01:00
: ASTGEN_SUPER_StackTraceF(fl) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstStackTraceF;
string verilogKwd() const override { return "$stacktrace"; }
string emitVerilog() override { return verilogKwd(); }
string emitC() override { return "VL_STACKTRACE_N()"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
2022-11-18 01:12:54 +01:00
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2022-11-18 01:12:54 +01:00
};
class AstSteady final : public AstNodeExpr {
// Verilog $steady_gclk
// @astgen op1 := exprp : AstNodeExpr
public:
AstSteady(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_Steady(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstSteady;
string emitVerilog() override { return "$steady_gclk(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
2022-12-21 01:22:42 +01:00
class AstStructSel final : public AstNodeExpr {
// Unpacked struct/union member access
2022-12-21 01:22:42 +01:00
// Parents: math|stmt
// Children: varref, math
// @astgen op1 := fromp : AstNodeExpr
string m_name; // Name of the member
public:
AstStructSel(FileLine* fl, AstNodeExpr* fromp, const string& name)
: ASTGEN_SUPER_StructSel(fl)
, m_name{name} {
this->fromp(fromp);
dtypep(nullptr); // V3Width will resolve
}
ASTGEN_MEMBERS_AstStructSel;
string name() const override VL_MT_STABLE { return m_name; }
void name(const string& name) override { m_name = name; }
2022-12-21 01:22:42 +01:00
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override {
// Not a union
return VN_IS(fromp()->dtypep()->skipRefp(), StructDType);
}
bool sameNode(const AstNode* samep) const override {
const AstStructSel* const sp = VN_DBG_AS(samep, StructSel);
2022-12-21 01:22:42 +01:00
return m_name == sp->m_name;
}
int instrCount() const override { return widthInstrs(); }
};
class AstSysIgnore final : public AstNodeExpr {
// @astgen op1 := exprsp : List[AstNode] // Expressions to output (???)
public:
AstSysIgnore(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_SysIgnore(fl) {
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSysIgnore;
string verilogKwd() const override { return "$ignored"; }
bool isGateOptimizable() const override { return false; } // Though deleted before opt
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
bool isPure() override { return false; } // Though deleted before opt
bool isOutputter() override { return true; } // Though deleted before opt
int instrCount() const override { return INSTR_COUNT_PLI; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstSystemF final : public AstNodeExpr {
// $system used as function
// @astgen op1 := lhsp : AstNode
public:
AstSystemF(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER_SystemF(fl) {
this->lhsp(lhsp);
}
ASTGEN_MEMBERS_AstSystemF;
string verilogKwd() const override { return "$system"; }
string emitVerilog() override { return verilogKwd(); }
string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isOutputter() override { return true; }
bool isUnlikely() const override { return true; }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; }
};
class AstTestPlusArgs final : public AstNodeExpr {
// Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs.
// @astgen op1 := searchp : Optional[AstNode]
public:
AstTestPlusArgs(FileLine* fl, AstNode* searchp)
: ASTGEN_SUPER_TestPlusArgs(fl) {
this->searchp(searchp);
}
ASTGEN_MEMBERS_AstTestPlusArgs;
string verilogKwd() const override { return "$test$plusargs"; }
string emitVerilog() override { return verilogKwd(); }
string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
// but isPure() true
bool isSystemFunc() const override { return true; }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstThisRef final : public AstNodeExpr {
// Reference to 'this'.
// @astgen op1 := childDTypep : Optional[AstClassRefDType] // dtype of the node
public:
AstThisRef(FileLine* fl, VFlagChildDType, AstClassRefDType* dtypep)
: ASTGEN_SUPER_ThisRef(fl) {
childDTypep(dtypep);
}
AstThisRef(FileLine* fl, AstClassRefDType* dtypep)
: ASTGEN_SUPER_ThisRef(fl) {
this->dtypep(dtypep);
}
ASTGEN_MEMBERS_AstThisRef;
string emitC() override { return "this"; }
string emitVerilog() override { return "this"; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool cleanOut() const override { return true; }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
};
2022-11-17 03:10:39 +01:00
class AstTimePrecision final : public AstNodeExpr {
// Verilog $timeprecision
public:
explicit AstTimePrecision(FileLine* fl)
2022-11-17 03:10:39 +01:00
: ASTGEN_SUPER_TimePrecision(fl) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstTimePrecision;
string emitVerilog() override { return "$timeprecision"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isSystemFunc() const override { return true; }
2022-11-17 03:10:39 +01:00
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2022-11-17 03:10:39 +01:00
};
class AstTimeUnit final : public AstNodeExpr {
VTimescale m_timeunit; // Parent module time unit
// Verilog $timeunit
public:
explicit AstTimeUnit(FileLine* fl)
2022-11-17 03:10:39 +01:00
: ASTGEN_SUPER_TimeUnit(fl) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstTimeUnit;
string emitVerilog() override { return "$timeunit"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isSystemFunc() const override { return true; }
2022-11-17 03:10:39 +01:00
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
2022-11-17 03:10:39 +01:00
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
2022-11-17 03:10:39 +01:00
};
class AstUnbounded final : public AstNodeExpr {
// 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();
}
ASTGEN_MEMBERS_AstUnbounded;
string emitVerilog() override { return "$"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstUnlinkedRef final : public AstNodeExpr {
// As-of-yet unlinkable Ref
// @astgen op1 := refp : AstNode
// @astgen op2 := cellrefp : AstNode
string m_name; // Var name // TODO: There is no way to access this, fix or remove
public:
AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* cellrefp)
: ASTGEN_SUPER_UnlinkedRef(fl)
, m_name{name} {
this->refp(refp);
this->cellrefp(cellrefp);
}
ASTGEN_MEMBERS_AstUnlinkedRef;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstValuePlusArgs final : public AstNodeExpr {
// Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs.
// @astgen op1 := searchp : Optional[AstNode]
// @astgen op2 := outp : AstNode // VarRef for result
public:
AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp)
: ASTGEN_SUPER_ValuePlusArgs(fl) {
this->searchp(searchp);
this->outp(outp);
}
ASTGEN_MEMBERS_AstValuePlusArgs;
string verilogKwd() const override { return "$value$plusargs"; }
string emitVerilog() override { return "%f$value$plusargs(%l, %k%r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return !outp(); }
bool isSystemFunc() const override { return true; }
bool cleanOut() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstWith final : public AstNodeExpr {
// 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: expression (equation establishing the with)
// @astgen op1 := indexArgRefp : AstLambdaArgRef
// @astgen op2 := valueArgRefp : AstLambdaArgRef
// @astgen op3 := exprp : List[AstNode] // Pins, expression and constraints
// TODO: Separate expression and constraints
public:
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
AstNode* exprp)
: ASTGEN_SUPER_With(fl) {
this->indexArgRefp(indexArgRefp);
this->valueArgRefp(valueArgRefp);
addExprp(exprp);
}
ASTGEN_MEMBERS_AstWith;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
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;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
class AstWithParse final : public AstNodeExpr {
// In early parse, FUNC(index) WITH equation-using-index
// Replaced with AstWith
// Parents: expr|stmt
// Children: funcref, expr
// @astgen op1 := funcrefp : AstNodeExpr
// @astgen op3 := exprsp : List[AstNode] // With's parenthesis part
// @astgen op4 := constraintsp : List[AstNode] // With's braces part
public:
AstWithParse(FileLine* fl, AstNodeExpr* funcrefp, AstNode* exprsp,
AstNode* constraintsp = nullptr)
: ASTGEN_SUPER_WithParse(fl) {
this->funcrefp(funcrefp);
addExprsp(exprsp);
addConstraintsp(constraintsp);
}
ASTGEN_MEMBERS_AstWithParse;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
};
// === 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstBufIf1;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opBufIf1(lhs, rhs);
}
string emitVerilog() override { return "bufif(%r,%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean
bool cleanOut() const override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
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(...))
// 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().
// @astgen alias op1 := fromp
// @astgen alias op2 := top
public:
AstCastDynamic(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstCastDynamic;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
V3ERROR_NA;
}
string emitVerilog() override { return "%f$cast(%r, %l)"; }
string emitC() override { return "VL_DYNAMIC_CAST(%r, %l)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return widthInstrs() * 20; }
bool isPure() override { return false; }
};
class AstCompareNN final : public AstNodeBiop {
// Verilog str.compare() and str.icompare()
const bool m_ignoreCase; // True for str.icompare()
public:
AstCompareNN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, bool ignoreCase)
: ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp)
, m_ignoreCase{ignoreCase} {
dtypeSetUInt32();
}
ASTGEN_MEMBERS_AstCompareNN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opCompareNN(lhs, rhs, m_ignoreCase);
}
string name() const override VL_MT_STABLE { return m_ignoreCase ? "icompare" : "compare"; }
string emitVerilog() override {
return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))";
}
string emitC() override {
return m_ignoreCase ? "VL_CMP_NN(%li,%ri,true)" : "VL_CMP_NN(%li,%ri,false)";
}
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstConcat final : public AstNodeBiop {
// If you're looking for {#{}}, see AstReplicate
public:
AstConcat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Concat(fl, lhsp, rhsp) {
if (lhsp->dtypep() && rhsp->dtypep()) {
dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(),
VSigning::UNSIGNED);
}
}
ASTGEN_MEMBERS_AstConcat;
string emitVerilog() override { return "%f{%l, %k%r}"; }
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opConcat(lhs, rhs);
}
string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(concat %l %r)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; }
};
class AstConcatN final : public AstNodeBiop {
// String concatenate
public:
AstConcatN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstConcatN;
string emitVerilog() override { return "%f{%l, %k%r}"; }
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opConcatN(lhs, rhs);
}
string emitC() override { return "VL_CONCATN_NNN(%li, %ri)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstDiv final : public AstNodeBiop {
public:
AstDiv(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Div(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstDiv;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opDiv(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f/ %r)"; }
string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvudiv %l %r)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; }
};
class AstDivD final : public AstNodeBiop {
public:
AstDivD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DivD(fl, lhsp, rhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstDivD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opDivD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f/ %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "/"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL_DIV; }
bool doubleFlavor() const override { return true; }
};
class AstDivS final : public AstNodeBiop {
public:
AstDivS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DivS(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstDivS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opDivS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f/ %r)"; }
string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvsdiv %l %r)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; }
bool signedFlavor() const override { return true; }
};
class AstEqWild final : public AstNodeBiop {
// Note wildcard operator rhs differs from lhs
public:
AstEqWild(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqWild;
// Return AstEqWild/AstEqD
static AstNodeBiop* newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp);
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opWildEq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f==? %r)"; }
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstFGetS final : public AstNodeBiop {
public:
AstFGetS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstFGetS;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%f$fgets(%l,%r)"; }
string emitC() override {
return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)"
: "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isSystemFunc() const override { return true; }
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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstFUngetC;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%f$ungetc(%r, %l)"; }
// Non-existent filehandle returns EOF
string emitC() override {
return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return widthInstrs() * 64; }
2023-03-16 01:49:59 +01:00
bool isPredictOptimizable() const override { return false; }
bool isPure() 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) {
dtypeSetBitSized(8, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstGetcN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGetcN(lhs, rhs);
}
string name() const override VL_MT_STABLE { return "getc"; }
string emitVerilog() override { return "%k(%l.getc(%r))"; }
string emitC() override { return "VL_GETC_N(%li,%ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) {
dtypeSetBitSized(8, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstGetcRefN;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k%l[%r]"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstGt final : public AstNodeBiop {
public:
AstGt(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Gt(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGt;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGt(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f> %r)"; }
string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvugt %l %r))"; }
string emitSimpleOperator() override { return ">"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstGtD final : public AstNodeBiop {
public:
AstGtD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GtD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGtD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGtD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f> %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return ">"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstGtN final : public AstNodeBiop {
public:
AstGtN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GtN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGtN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGtN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f> %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return ">"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstGtS final : public AstNodeBiop {
public:
AstGtS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GtS(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGtS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGtS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f> %r)"; }
string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvsgt %l %r))"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstGte final : public AstNodeBiop {
public:
AstGte(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Gte(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGte;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGte(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>= %r)"; }
string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvuge %l %r))"; }
string emitSimpleOperator() override { return ">="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstGteD final : public AstNodeBiop {
public:
AstGteD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GteD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGteD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGteD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return ">="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstGteN final : public AstNodeBiop {
public:
AstGteN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GteN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGteN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGteN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return ">="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstGteS final : public AstNodeBiop {
public:
AstGteS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_GteS(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstGteS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opGteS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>= %r)"; }
string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvsge %l %r))"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstLogAnd final : public AstNodeBiop {
public:
AstLogAnd(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLogAnd;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogAnd(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f&& %r)"; }
string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvand %l %r)"; }
string emitSimpleOperator() override { return "&&"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
};
class AstLogIf final : public AstNodeBiop {
public:
AstLogIf(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLogIf;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogIf(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f-> %r)"; }
string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (=> (__Vbool %l) (__Vbool %r)))"; }
string emitSimpleOperator() override { return "->"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
};
class AstLogOr final : public AstNodeBiop {
public:
AstLogOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLogOr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogOr(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f|| %r)"; }
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvor %l %r)"; }
string emitSimpleOperator() override { return "||"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
};
class AstLt final : public AstNodeBiop {
public:
AstLt(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Lt(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLt;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLt(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f< %r)"; }
string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvult %l %r))"; }
string emitSimpleOperator() override { return "<"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstLtD final : public AstNodeBiop {
public:
AstLtD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LtD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLtD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLtD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f< %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "<"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstLtN final : public AstNodeBiop {
public:
AstLtN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LtN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLtN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLtN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f< %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "<"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstLtS final : public AstNodeBiop {
public:
AstLtS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LtS(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLtS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLtS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f< %r)"; }
string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvslt %l %r))"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstLte final : public AstNodeBiop {
public:
AstLte(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Lte(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLte;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLte(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<= %r)"; }
string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvule %l %r))"; }
string emitSimpleOperator() override { return "<="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstLteD final : public AstNodeBiop {
public:
AstLteD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LteD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLteD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLteD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "<="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstLteN final : public AstNodeBiop {
public:
AstLteN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LteN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLteN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLteN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "<="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstLteS final : public AstNodeBiop {
public:
AstLteS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LteS(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLteS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLteS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<= %r)"; }
string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (bvsle %l %r))"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstModDiv final : public AstNodeBiop {
public:
AstModDiv(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstModDiv;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opModDiv(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f%% %r)"; }
string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvurem %l %r)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; }
};
class AstModDivS final : public AstNodeBiop {
public:
AstModDivS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstModDivS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opModDivS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f%% %r)"; }
string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvsmod %l %r)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; }
bool signedFlavor() const override { return true; }
};
class AstNeqWild final : public AstNodeBiop {
public:
AstNeqWild(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqWild;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opWildNeq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!=? %r)"; }
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstPow final : public AstNodeBiop {
public:
AstPow(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Pow(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstPow;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opPow(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f** %r)"; }
string emitC() override { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; }
};
class AstPowD final : public AstNodeBiop {
public:
AstPowD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_PowD(fl, lhsp, rhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstPowD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opPowD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f** %r)"; }
string emitC() override { return "pow(%li,%ri)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL_DIV * 5; }
bool doubleFlavor() const override { return true; }
};
class AstPowSS final : public AstNodeBiop {
public:
AstPowSS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstPowSS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opPowSS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f** %r)"; }
string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; }
bool signedFlavor() const override { return true; }
};
class AstPowSU final : public AstNodeBiop {
public:
AstPowSU(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstPowSU;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opPowSU(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f** %r)"; }
string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; }
bool signedFlavor() const override { return true; }
};
class AstPowUS final : public AstNodeBiop {
public:
AstPowUS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstPowUS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opPowUS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f** %r)"; }
string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; }
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()
// @astgen alias op1 := srcp
// @astgen alias op2 := countp
public:
AstReplicate(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) {
if (lhsp) {
if (const AstConst* const constp = VN_CAST(rhsp, Const)) {
if (constp->num().isFourState()
|| (constp->dtypep()->isSigned() && constp->num().isNegative())) {
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
} else {
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
}
}
}
}
AstReplicate(FileLine* fl, AstNodeExpr* lhsp, uint32_t repCount)
2022-11-13 01:51:03 +01:00
: AstReplicate{fl, lhsp, new AstConst{fl, repCount}} {}
ASTGEN_MEMBERS_AstReplicate;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opRepl(lhs, rhs);
}
string emitVerilog() override { return "%f{%r{%k%l}}"; }
string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSMT() const override {
return "((_ repeat " + cvtToStr(width() / lhsp()->width()) + ") %l)";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; }
};
class AstReplicateN final : public AstNodeBiop {
// String replicate
public:
AstReplicateN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstReplicateN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opReplN(lhs, rhs);
}
string emitVerilog() override { return "%f{%r{%k%l}}"; }
string emitC() override { return "VL_REPLICATEN_NN%rq(%li, %ri)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; }
bool stringFlavor() const override { return true; }
};
class AstSel final : public AstNodeBiop {
// *Resolved* (tyep checked) multiple bit range extraction. Always const width
// @astgen alias op1 := fromp
// @astgen alias op2 := lsbp
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
// Selection width (!= this->width() from V3Clean onwards, != this->widthMin() in V3Width)
int m_widthConst;
public:
AstSel(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* lsbp, int bitwidth)
: ASTGEN_SUPER_Sel(fl, fromp, lsbp)
, m_declElWidth{1}
, m_widthConst{bitwidth} {
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
}
AstSel(FileLine* fl, AstNodeExpr* fromp, int lsb, int bitwidth)
: ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb)) // Need () constructor
, m_declElWidth{1}
, m_widthConst{bitwidth} {
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) override {
out.opSel(from, bit.toUInt() + widthConst() - 1, bit.toUInt());
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override {
return widthConst() == 1 ? "VL_BITSEL_%nq%lq%rqI(%lw, %P, %li, %ri)"
: isWide() ? "VL_SEL_%nq%lq%rqI(%nw, %lw, %P, %li, %ri, %nw)"
: "VL_SEL_%nq%lq%rqI(%lw, %P, %li, %ri, %nw)";
}
string emitSMT() const override { return "((_ extract %t %r) %l)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sameNode(const AstNode* otherp) const override {
return widthConst() == VN_DBG_AS(otherp, Sel)->widthConst();
}
int instrCount() const override {
return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10) + 1;
}
int widthConst() const { return m_widthConst; }
void widthConst(int value) { m_widthConst = value; }
int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); }
int msbConst() const { return lsbConst() + widthConst() - 1; }
VNumRange& declRange() VL_MT_STABLE { return m_declRange; }
const VNumRange& declRange() const VL_MT_STABLE { 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 AstShiftL final : public AstNodeBiop {
public:
AstShiftL(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftL;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftL(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<< %r)"; }
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvshl %l %r)"; }
string emitSimpleOperator() override {
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftLOvr final : public AstNodeBiop {
// Like ShiftL but checks for an over shift and returns zeros
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftL
public:
AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftLOvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftL(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<< %r)"; }
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftR final : public AstNodeBiop {
public:
AstShiftR(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftR;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftR(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>> %r)"; }
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvlshr %l %r)"; }
string emitSimpleOperator() override {
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
// LHS size might be > output size, so don't want to force size
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstShiftROvr final : public AstNodeBiop {
// Like ShiftR but checks for an over shift and returns zeros
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftR
public:
AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstShiftROvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftR(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f>> %r)"; }
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
// LHS size might be > output size, so don't want to force size
bool sizeMattersLhs() const override { return false; }
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, AstNodeExpr* lhsp, AstNodeExpr* 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);
}
ASTGEN_MEMBERS_AstShiftRS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
}
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
string emitSMT() const override { return "(bvashr %l %r)"; }
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstShiftRSOvr final : public AstNodeBiop {
// Shift right with sign extension, >>> operator, checks for an over shift and returns zeros
// Output data type's width determines which bit is used for sign extension
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftRSOvr
public:
AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) {
// Important that widthMin be correct, as opExtend requires it after V3Expand
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
}
ASTGEN_MEMBERS_AstShiftRSOvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
}
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool signedFlavor() const override { return true; }
};
class AstSub final : public AstNodeBiop {
public:
AstSub(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Sub(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstSub;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opSub(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f- %r)"; }
string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvsub %l %r)"; }
string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
};
class AstSubD final : public AstNodeBiop {
public:
AstSubD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_SubD(fl, lhsp, rhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstSubD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opSubD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f- %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstURandomRange final : public AstNodeBiop {
// $urandom_range
public:
AstURandomRange(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) {
dtypeSetUInt32(); // Says IEEE
}
ASTGEN_MEMBERS_AstURandomRange;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%f$urandom_range(%l, %r)"; }
string emitC() override { return "VL_URANDOM_RANGE_%nq(%li, %ri)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_PLI; }
};
// === AstNodeBiCom ===
class AstEq final : public AstNodeBiCom {
public:
AstEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Eq(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEq;
// Return AstEq/AstEqD
static AstNodeBiop* newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp);
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opEq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f== %r)"; }
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstEqCase final : public AstNodeBiCom {
public:
AstEqCase(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqCase;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opCaseEq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f=== %r)"; }
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstEqD final : public AstNodeBiCom {
public:
AstEqD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opEqD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f== %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstEqN final : public AstNodeBiCom {
public:
AstEqN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opEqN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f== %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstEqT final : public AstNodeBiCom {
// Equal (==) for data types
public:
AstEqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqT(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstEqT;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l %f== %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
};
class AstLogEq final : public AstNodeBiCom {
public:
AstLogEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLogEq;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opLogEq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f<-> %r)"; }
string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvxnor %l %r)"; }
string emitSimpleOperator() override { return "<->"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
};
class AstNeq final : public AstNodeBiCom {
public:
AstNeq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Neq(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeq;
static AstNodeBiop* newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp);
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opNeq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!= %r)"; }
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "!="; }
string emitSMT() const override { return "(__Vbv (not (= %l %r)))"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstNeqCase final : public AstNodeBiCom {
public:
AstNeqCase(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqCase;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opCaseNeq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!== %r)"; }
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
};
class AstNeqD final : public AstNodeBiCom {
public:
AstNeqD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opNeqD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstNeqN final : public AstNodeBiCom {
public:
AstNeqN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opNeqN(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
bool stringFlavor() const override { return true; }
};
class AstNeqT final : public AstNodeBiCom {
// Not-equal (!=) for data types
public:
AstNeqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqT(fl, lhsp, rhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstNeqT;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l %f!= %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_STR; }
};
// === AstNodeBiComAsv ===
class AstAdd final : public AstNodeBiComAsv {
public:
AstAdd(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Add(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstAdd;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opAdd(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f+ %r)"; }
string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvadd %l %r)"; }
string emitSimpleOperator() override { return "+"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
};
class AstAddD final : public AstNodeBiComAsv {
public:
AstAddD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_AddD(fl, lhsp, rhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstAddD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opAddD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f+ %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "+"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstAnd final : public AstNodeBiComAsv {
public:
AstAnd(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_And(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstAnd;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opAnd(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f& %r)"; }
string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvand %l %r)"; }
string emitSimpleOperator() override { return "&"; }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
const char* widthMismatch() const override VL_MT_STABLE;
};
class AstMul final : public AstNodeBiComAsv {
public:
AstMul(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Mul(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstMul;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opMul(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f* %r)"; }
string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvmul %l %r)"; }
string emitSimpleOperator() override { return "*"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; }
};
class AstMulD final : public AstNodeBiComAsv {
public:
AstMulD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_MulD(fl, lhsp, rhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstMulD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opMulD(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f* %r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "*"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstMulS final : public AstNodeBiComAsv {
public:
AstMulS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_MulS(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstMulS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opMulS(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f* %r)"; }
string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
string emitSimpleOperator() override { return ""; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; }
bool sizeMattersRhs() const override { return true; }
int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; }
bool signedFlavor() const override { return true; }
};
class AstOr final : public AstNodeBiComAsv {
public:
AstOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Or(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstOr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opOr(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f| %r)"; }
string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvor %l %r)"; }
string emitSimpleOperator() override { return "|"; }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
const char* widthMismatch() const override VL_MT_STABLE;
};
class AstXor final : public AstNodeBiComAsv {
public:
AstXor(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Xor(fl, lhsp, rhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstXor;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opXor(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f^ %r)"; }
string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; }
string emitSMT() const override { return "(bvxor %l %r)"; }
string emitSimpleOperator() override { return "^"; }
bool cleanOut() const override { return false; } // Lclean && Rclean
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
const char* widthMismatch() const override VL_MT_STABLE;
};
// === AstNodeDistBiop ===
class AstDistChiSquare final : public AstNodeDistBiop {
public:
AstDistChiSquare(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DistChiSquare(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstDistChiSquare;
string emitVerilog() override { return "%f$dist_chi_square(%l, %r)"; }
string emitC() override { return "VL_DIST_CHI_SQUARE(%li, %ri)"; }
};
class AstDistExponential final : public AstNodeDistBiop {
public:
AstDistExponential(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DistExponential(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstDistExponential;
string emitVerilog() override { return "%f$dist_exponential(%l, %r)"; }
string emitC() override { return "VL_DIST_EXPONENTIAL(%li, %ri)"; }
};
class AstDistPoisson final : public AstNodeDistBiop {
public:
AstDistPoisson(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DistPoisson(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstDistPoisson;
string emitVerilog() override { return "%f$dist_poisson(%l, %r)"; }
string emitC() override { return "VL_DIST_POISSON(%li, %ri)"; }
};
class AstDistT final : public AstNodeDistBiop {
public:
AstDistT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_DistT(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstDistT;
string emitVerilog() override { return "%f$dist_t(%l, %r)"; }
string emitC() override { return "VL_DIST_T(%li, %ri)"; }
};
// === AstNodeSel ===
class AstArraySel final : public AstNodeSel {
void init(const 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, AstNodeExpr* fromp, AstNodeExpr* bitp)
: ASTGEN_SUPER_ArraySel(fl, fromp, bitp) {
init(fromp);
}
AstArraySel(FileLine* fl, AstNodeExpr* fromp, int bit)
2022-11-13 01:51:03 +01:00
: ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { // Need () constructor
init(fromp);
}
ASTGEN_MEMBERS_AstArraySel;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l%f[%r])"; }
string emitC() override { return "%li%k[%ri]"; }
string emitSMT() const override { return "(select %l %r)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign
bool isPredictOptimizable() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
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 {
void init(const 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, AstNodeExpr* fromp, AstNodeExpr* bitp)
: ASTGEN_SUPER_AssocSel(fl, fromp, bitp) {
init(fromp);
}
ASTGEN_MEMBERS_AstAssocSel;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l%f[%r])"; }
string emitC() override { return "%li%k[%ri]"; }
string emitSMT() const override { return "(select %l %r)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isGateOptimizable() const override { return false; } // AssocSel creates on miss
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // AssocSel creates on miss
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int instrCount() const override { return widthInstrs(); }
};
class AstWildcardSel final : public AstNodeSel {
void init(const 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, AstNodeExpr* fromp, AstNodeExpr* bitp)
: ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) {
init(fromp);
}
ASTGEN_MEMBERS_AstWildcardSel;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l%f[%r])"; }
string emitC() override { return "%li%k[%ri]"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign
bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
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, AstNodeExpr* fromp, AstNodeExpr* bitp)
: ASTGEN_SUPER_WordSel(fl, fromp, bitp) {
dtypeSetUInt32(); // Always used on WData arrays so returns edata size
}
ASTGEN_MEMBERS_AstWordSel;
void numberOperate(V3Number&, const V3Number&, const V3Number&) override { V3ERROR_NA; }
string emitVerilog() override { return "%k(%l%f[%r])"; }
string emitC() override {
return "%li[%ri]";
} // Not %k, as usually it's a small constant rhsp
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sameNode(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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstStreamL;
string emitVerilog() override { return "%f{ << %r %k{%l} }"; }
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opStreamL(lhs, rhs);
}
string emitC() override { return "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
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, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstStreamR;
string emitVerilog() override { return "%f{ >> %r %k{%l} }"; }
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opAssign(lhs);
}
string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; }
};
// === AstNodeSystemBiopD ===
class AstAtan2D final : public AstNodeSystemBiopD {
public:
AstAtan2D(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstAtan2D;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.setDouble(std::atan2(lhs.toDouble(), rhs.toDouble()));
}
string emitVerilog() override { return "%f$atan2(%l,%r)"; }
string emitC() override { return "atan2(%li,%ri)"; }
};
class AstHypotD final : public AstNodeSystemBiopD {
public:
AstHypotD(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {}
ASTGEN_MEMBERS_AstHypotD;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.setDouble(std::hypot(lhs.toDouble(), rhs.toDouble()));
}
string emitVerilog() override { return "%f$hypot(%l,%r)"; }
string emitC() override { return "hypot(%li,%ri)"; }
};
// === AstNodeCCall ===
class AstCCall final : public AstNodeCCall {
// C++ function call
VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this')
public:
AstCCall(FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
2025-09-07 23:18:23 +02:00
: ASTGEN_SUPER_CCall(fl, funcp, argsp) {
UASSERT_OBJ(funcp, this, "CCall created calling null function");
}
ASTGEN_MEMBERS_AstCCall;
const VSelfPointerText& selfPointer() const { return m_selfPointer; }
void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; }
string selfPointerProtect(bool useSelfForThis) const {
return selfPointer().protect(useSelfForThis, protect());
}
};
class AstCMethodCall final : public AstNodeCCall {
// C++ method call
// @astgen op1 := fromp : AstNodeExpr
public:
AstCMethodCall(FileLine* fl, AstNodeExpr* fromp, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
: ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) {
this->fromp(fromp);
2025-09-07 23:18:23 +02:00
UASSERT_OBJ(funcp, this, "CMethodCall created calling null function");
}
ASTGEN_MEMBERS_AstCMethodCall;
};
class AstCNew final : public AstNodeCCall {
// C++ new() call
public:
AstCNew(FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
: ASTGEN_SUPER_CNew(fl, funcp, argsp) {}
ASTGEN_MEMBERS_AstCNew;
};
// === AstNodeFTaskRef ===
class AstFuncRef final : public AstNodeFTaskRef {
// A reference to a function
2023-10-24 15:51:46 +02:00
bool m_superReference = false; // Called with super reference
public:
inline AstFuncRef(FileLine* fl, AstFunc* taskp, AstNodeExpr* pinsp);
AstFuncRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
: ASTGEN_SUPER_FuncRef(fl, name, pinsp) {}
ASTGEN_MEMBERS_AstFuncRef;
2023-10-24 15:51:46 +02:00
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
class AstMethodCall final : public AstNodeFTaskRef {
// A reference to a member task (or function)
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
// @astgen op2 := fromp : AstNodeExpr
//
public:
AstMethodCall(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name,
AstNodeExpr* pinsp)
: ASTGEN_SUPER_MethodCall(fl, name, pinsp) {
this->fromp(fromp);
dtypep(nullptr); // V3Width will resolve
}
AstMethodCall(FileLine* fl, AstNodeExpr* fromp, const string& name, AstNodeExpr* pinsp)
: ASTGEN_SUPER_MethodCall(fl, name, pinsp) {
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstMethodCall;
};
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
2025-04-09 04:09:40 +02:00
bool m_isImplicit = false; // Implicitly generated from extends args
2025-07-03 01:54:57 +02:00
bool m_isScoped = false; // Had :: scope when parsed
public:
2025-07-03 01:54:57 +02:00
AstNew(FileLine* fl, AstNodeExpr* pinsp, bool isScoped = false)
: ASTGEN_SUPER_New(fl, "new", pinsp)
, m_isScoped{isScoped} {}
ASTGEN_MEMBERS_AstNew;
2025-07-03 01:54:57 +02:00
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int instrCount() const override { return widthInstrs(); }
2025-04-09 04:09:40 +02:00
bool isImplicit() const { return m_isImplicit; }
void isImplicit(bool flag) { m_isImplicit = flag; }
2025-07-03 01:54:57 +02:00
bool isScoped() const { return m_isScoped; }
void isScoped(bool flag) { m_isScoped = flag; }
bool isPure() override { return false; }
};
class AstTaskRef final : public AstNodeFTaskRef {
// A reference to a task
2023-10-24 15:51:46 +02:00
bool m_superReference = false; // Called with super reference
public:
inline AstTaskRef(FileLine* fl, AstTask* taskp, AstNodeExpr* pinsp);
AstTaskRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
: ASTGEN_SUPER_TaskRef(fl, name, pinsp) {
dtypeSetVoid();
}
ASTGEN_MEMBERS_AstTaskRef;
2023-10-24 15:51:46 +02:00
bool superReference() const { return m_superReference; }
void superReference(bool flag) { m_superReference = flag; }
};
// === 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
// @astgen alias op2 := bitp
2024-10-24 15:40:54 +02:00
private:
VAccess m_access; // Left hand side assignment
public:
AstSelBit(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
: ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) {
UASSERT_OBJ(!v3Global.assertDTypesResolved(), this,
"not coded to create after dtypes resolved");
}
ASTGEN_MEMBERS_AstSelBit;
2024-10-24 15:40:54 +02:00
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; }
};
class AstSelExtract final : public AstNodePreSel {
// Range extraction, gets replaced with AstSel
// @astgen alias op2 := leftp
// @astgen alias op3 := rightp
public:
AstSelExtract(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* msbp, AstNodeExpr* lsbp)
: ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {}
ASTGEN_MEMBERS_AstSelExtract;
};
class AstSelMinus final : public AstNodePreSel {
// -: range extraction, perhaps with non-constant selection
// Gets replaced during link with AstSel
// @astgen alias op2 := bitp
// @astgen alias op3 := widthp
public:
AstSelMinus(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp, AstNodeExpr* widthp)
: ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {}
ASTGEN_MEMBERS_AstSelMinus;
};
class AstSelPlus final : public AstNodePreSel {
// +: range extraction, perhaps with non-constant selection
// Gets replaced during link with AstSel
// @astgen alias op2 := bitp
// @astgen alias op3 := widthp
public:
AstSelPlus(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp, AstNodeExpr* widthp)
: ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {}
ASTGEN_MEMBERS_AstSelPlus;
};
// === AstNodeQuadop ===
class AstCountBits final : public AstNodeQuadop {
// Number of bits set in vector
public:
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTreePure(false),
ctrl1p->cloneTreePure(false)) {}
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTreePure(false)) {}
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p,
AstNodeExpr* ctrl3p)
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
ASTGEN_MEMBERS_AstCountBits;
void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1,
const V3Number& ctrl2, const V3Number& ctrl3) override {
out.opCountBits(expr, ctrl1, ctrl2, ctrl3);
}
string emitVerilog() override { return "%f$countbits(%l, %r, %f, %o)"; }
string emitC() override { return ""; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool cleanThs() const override { return true; }
bool cleanFhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
bool sizeMattersFhs() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return widthInstrs() * 16; }
};
// === AstNodeTermop ===
class AstInferredDisable final : public AstNodeTermop {
public:
explicit AstInferredDisable(FileLine* fl)
: ASTGEN_SUPER_InferredDisable(fl) {
dtypeSetLogicSized(1, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstInferredDisable;
string emitVerilog() override { return "%f$inferred_disable"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isSystemFunc() const override { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
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();
}
ASTGEN_MEMBERS_AstTime;
string emitVerilog() override { return "%f$time"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_TIME; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
};
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();
}
ASTGEN_MEMBERS_AstTimeD;
string emitVerilog() override { return "%f$realtime"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isSystemFunc() const override { return true; }
int instrCount() const override { return INSTR_COUNT_TIME; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
};
// === AstNodeTriop ===
class AstCond final : public AstNodeTriop {
// @astgen alias op1 := condp
// @astgen alias op2 := thenp
// @astgen alias op3 := elsep
public:
AstCond(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep);
ASTGEN_MEMBERS_AstCond;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
out.opAssign(lhs.isNeqZero() ? rhs : ths);
}
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
bool cleanOut() const override { return false; } // clean if e1 & e2 clean
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return false; }
bool cleanThs() const override { return false; } // Propagates up
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
};
class AstPostAdd final : public AstNodeTriop {
// Post-increment/add
// 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstPostAdd;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
V3ERROR_NA; // Need to modify lhs
}
string emitVerilog() override { return "%k(%r++)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanRhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanThs() const override { V3ERROR_NA_RETURN(false); }
bool sizeMattersLhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersRhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersThs() const override { V3ERROR_NA_RETURN(true); }
};
class AstPostSub final : public AstNodeTriop {
// Post-decrement/subtract
// 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstPostSub;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
V3ERROR_NA; // Need to modify lhs
}
string emitVerilog() override { return "%k(%r--)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanRhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanThs() const override { V3ERROR_NA_RETURN(false); }
bool sizeMattersLhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersRhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersThs() const override { V3ERROR_NA_RETURN(true); }
};
class AstPreAdd final : public AstNodeTriop {
// Pre-increment/add
// 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstPreAdd;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
V3ERROR_NA; // Need to modify lhs
}
string emitVerilog() override { return "%k(++%r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanRhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanThs() const override { V3ERROR_NA_RETURN(false); }
bool sizeMattersLhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersRhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersThs() const override { V3ERROR_NA_RETURN(true); }
};
class AstPreSub final : public AstNodeTriop {
// Pre-decrement/subtract
// 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, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstPreSub;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
V3ERROR_NA; // Need to modify lhs
}
string emitVerilog() override { return "%k(--%r)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
bool cleanLhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanRhs() const override { V3ERROR_NA_RETURN(false); }
bool cleanThs() const override { V3ERROR_NA_RETURN(false); }
bool sizeMattersLhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersRhs() const override { V3ERROR_NA_RETURN(true); }
bool sizeMattersThs() const override { V3ERROR_NA_RETURN(true); }
};
class AstPutcN final : public AstNodeTriop {
// Verilog string.putc()
public:
AstPutcN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* ths)
: ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstPutcN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
out.opPutcN(lhs, rhs, ths);
}
string name() const override VL_MT_STABLE { return "putc"; }
string emitVerilog() override { return "%k(%l.putc(%r,%t))"; }
string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool cleanThs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
};
class AstSliceSel final : public AstNodeTriop {
// Multiple array element extraction
// @astgen alias op1 := fromp
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
public:
AstSliceSel(FileLine* fl, AstNodeExpr* fromp, const VNumRange& declRange)
2022-11-13 01:51:03 +01:00
: ASTGEN_SUPER_SliceSel(fl, fromp,
new AstConst(fl, declRange.lo()), // Need () constructor
new AstConst(fl, declRange.elements())) // Need () constructor
, m_declRange{declRange} {}
ASTGEN_MEMBERS_AstSliceSel;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo,
const V3Number& width) override {
V3ERROR_NA;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); } // Removed before EmitC
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return true; }
bool cleanThs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
bool sameNode(const AstNode*) const override { return true; }
int instrCount() const override { return 10; } // Removed before matters
// For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods
VNumRange& declRange() VL_MT_STABLE { return m_declRange; }
const VNumRange& declRange() const VL_MT_STABLE { return m_declRange; }
};
class AstSubstrN final : public AstNodeTriop {
// Verilog string.substr()
public:
AstSubstrN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* ths)
: ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstSubstrN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) override {
out.opSubstrN(lhs, rhs, ths);
}
string name() const override VL_MT_STABLE { return "substr"; }
string emitVerilog() override { return "%k(%l.substr(%r,%t))"; }
string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; }
string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
bool cleanThs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; }
bool sizeMattersThs() const override { return false; }
};
// === AstNodeDistTriop ===
class AstDistErlang final : public AstNodeDistTriop {
public:
AstDistErlang(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_DistErlang(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstDistErlang;
string emitVerilog() override { return "%f$dist_erlang(%l, %r, %t)"; }
string emitC() override { return "VL_DIST_ERLANG(%li, %ri, %ti)"; }
};
class AstDistNormal final : public AstNodeDistTriop {
public:
AstDistNormal(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_DistNormal(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstDistNormal;
string emitVerilog() override { return "%f$dist_normal(%l, %r, %t)"; }
string emitC() override { return "VL_DIST_NORMAL(%li, %ri, %ti)"; }
};
class AstDistUniform final : public AstNodeDistTriop {
public:
AstDistUniform(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
: ASTGEN_SUPER_DistUniform(fl, lhsp, rhsp, thsp) {}
ASTGEN_MEMBERS_AstDistUniform;
string emitVerilog() override { return "%f$dist_uniform(%l, %r, %t)"; }
string emitC() override { return "VL_DIST_UNIFORM(%li, %ri, %ti)"; }
};
// === 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, AstNodeExpr* lhsp, FmtType fmt)
: ASTGEN_SUPER_AtoN(fl, lhsp)
, m_fmt{fmt} {
fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstAtoN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
string name() const override VL_MT_STABLE {
switch (m_fmt) {
case ATOI: return "atoi";
case ATOHEX: return "atohex";
case ATOOCT: return "atooct";
case ATOBIN: return "atobin";
case ATOREAL: return "atoreal";
}
2023-02-04 00:47:37 +01:00
V3ERROR_NA_RETURN("");
}
string emitVerilog() override { return "%l." + name() + "()"; }
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())";
}
2023-02-04 00:47:37 +01:00
V3ERROR_NA_RETURN("");
}
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
FmtType format() const { return m_fmt; }
};
class AstBitsToRealD final : public AstNodeUniop {
public:
AstBitsToRealD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_BitsToRealD(fl, lhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstBitsToRealD;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opBitsToRealD(lhs); }
string emitVerilog() override { return "%f$bitstoreal(%l)"; }
string emitC() override { return "VL_CVT_D_Q(%li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } // Eliminated before matters
bool sizeMattersLhs() const override { return false; } // Eliminated before matters
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstCAwait final : public AstNodeUniop {
// Emit C++'s co_await expression
// @astgen alias op1 := exprp
//
// @astgen ptr := m_sentreep : Optional[AstSenTree] // Sentree related to this await
public:
AstCAwait(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep = nullptr)
: ASTGEN_SUPER_CAwait(fl, exprp)
, m_sentreep{sentreep} {}
ASTGEN_MEMBERS_AstCAwait;
bool isTimingControl() const override { return true; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
AstSenTree* sentreep() const { return m_sentreep; }
void clearSentreep() { m_sentreep = nullptr; }
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstCCast final : public AstNodeUniop {
// Cast to C-based data type
int m_size;
public:
AstCCast(FileLine* fl, AstNodeExpr* 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);
}
}
// cppcheck-suppress constParameterPointer
// cppcheck-suppress constParameterCallback
AstCCast(FileLine* fl, AstNodeExpr* lhsp, AstNode* typeFromp)
: ASTGEN_SUPER_CCast(fl, lhsp) {
dtypeFrom(typeFromp);
m_size = width();
}
ASTGEN_MEMBERS_AstCCast;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "%f$_CAST(%l)"; }
string emitC() override { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast
bool sameNode(const AstNode* samep) const override {
return size() == VN_DBG_AS(samep, CCast)->size();
}
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
//
int size() const { return m_size; }
};
class AstCLog2 final : public AstNodeUniop {
public:
AstCLog2(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CLog2(fl, lhsp) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstCLog2;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); }
string emitVerilog() override { return "%f$clog2(%l)"; }
string emitC() override { return "VL_CLOG2_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 16; }
bool isSystemFunc() const override { return true; }
};
2022-12-11 19:28:24 +01:00
class AstCastWrap final : public AstNodeUniop {
// A cast which has been expanded and the LHSP does all the lifting
// This remains until V3Width final commit pass to suppress ENUMVALUE warnings
public:
AstCastWrap(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CastWrap(fl, lhsp) {}
ASTGEN_MEMBERS_AstCastWrap;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return 0; }
};
class AstCountOnes final : public AstNodeUniop {
// Number of bits set in vector
public:
AstCountOnes(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CountOnes(fl, lhsp) {}
ASTGEN_MEMBERS_AstCountOnes;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCountOnes(lhs); }
string emitVerilog() override { return "%f$countones(%l)"; }
string emitC() override { return "VL_COUNTONES_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 16; }
bool isSystemFunc() const override { return true; }
};
class AstCvtPackString final : public AstNodeUniop {
// Convert to Verilator Packed String (aka verilog "string")
public:
AstCvtPackString(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CvtPackString(fl, lhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstCvtPackString;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sameNode(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, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Extend(fl, lhsp) {}
AstExtend(FileLine* fl, AstNodeExpr* lhsp, int width)
: ASTGEN_SUPER_Extend(fl, lhsp) {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstExtend;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "%l"; }
string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; }
string emitSMT() const override {
return "((_ zero_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
}
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override {
return false; // Because the EXTEND operator self-casts
}
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, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ExtendS(fl, lhsp) {}
AstExtendS(FileLine* fl, AstNodeExpr* lhsp, int width)
// Important that widthMin be correct, as opExtend requires it after V3Expand
: ASTGEN_SUPER_ExtendS(fl, lhsp) {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
}
ASTGEN_MEMBERS_AstExtendS;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.opExtendS(lhs, lhsp()->widthMinV());
}
string emitVerilog() override { return "%l"; }
string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; }
string emitSMT() const override {
return "((_ sign_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override {
return false; // Because the EXTEND operator self-casts
}
int instrCount() const override { return 0; }
bool signedFlavor() const override { return true; }
};
class AstFEof final : public AstNodeUniop {
public:
AstFEof(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_FEof(fl, lhsp) {}
ASTGEN_MEMBERS_AstFEof;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "%f$feof(%l)"; }
string emitC() override { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 16; }
2023-02-05 16:18:03 +01:00
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isSystemFunc() const override { return true; }
AstNode* filep() const { return lhsp(); }
};
class AstFGetC final : public AstNodeUniop {
public:
AstFGetC(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_FGetC(fl, lhsp) {}
ASTGEN_MEMBERS_AstFGetC;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "%f$fgetc(%l)"; }
// Non-existent filehandle returns EOF
string emitC() override { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 64; }
2023-02-05 16:18:03 +01:00
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
bool isSystemFunc() const override { return true; }
};
class AstISToRD final : public AstNodeUniop {
// $itor where lhs is signed
public:
AstISToRD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ISToRD(fl, lhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstISToRD;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opISToRD(lhs); }
string emitVerilog() override { return "%f$itor($signed(%l))"; }
string emitC() override { return "VL_ISTOR_D_%lq(%lw, %li)"; }
bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstIToRD final : public AstNodeUniop {
// $itor where lhs is unsigned
public:
AstIToRD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_IToRD(fl, lhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstIToRD;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIToRD(lhs); }
string emitVerilog() override { return "%f$itor(%l)"; }
string emitC() override { return "VL_ITOR_D_%lq(%lw, %li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstIsUnbounded final : public AstNodeUniop {
// True if is unbounded ($)
public:
AstIsUnbounded(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_IsUnbounded(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstIsUnbounded;
void numberOperate(V3Number& out, const V3Number&) override {
// Any constant isn't unbounded
out.setZero();
}
string emitVerilog() override { return "%f$isunbounded(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool isSystemFunc() const override { return true; }
};
class AstIsUnknown final : public AstNodeUniop {
// True if any unknown bits
public:
AstIsUnknown(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_IsUnknown(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstIsUnknown;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIsUnknown(lhs); }
string emitVerilog() override { return "%f$isunknown(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
bool isSystemFunc() const override { return true; }
};
class AstLenN final : public AstNodeUniop {
// Length of a string
public:
AstLenN(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_LenN(fl, lhsp) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstLenN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); }
string emitVerilog() override { return "%f(%l)"; }
string emitC() override { return "VL_LEN_IN(%li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstLogNot final : public AstNodeUniop {
public:
AstLogNot(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_LogNot(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstLogNot;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); }
string emitVerilog() override { return "%f(! %l)"; }
string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; }
string emitSMT() const override { return "(__Vbv (not (__Vbool %l)))"; }
string emitSimpleOperator() override { return "!"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
2023-03-01 05:34:33 +01:00
bool sizeMattersLhs() const override { return false; }
};
class AstNToI final : public AstNodeUniop {
// String to any-size integral
public:
AstNToI(FileLine* fl, AstNodeExpr* lhsp, AstNodeDType* dtypep = nullptr)
: ASTGEN_SUPER_NToI(fl, lhsp) {
this->dtypep(dtypep);
}
ASTGEN_MEMBERS_AstNToI;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNToI(lhs); }
string emitVerilog() override { return "'(%l)"; }
string emitC() override { return "VL_NTOI_%nq(%nw, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstNegate final : public AstNodeUniop {
public:
AstNegate(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Negate(fl, lhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstNegate;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); }
string emitVerilog() override { return "%f(- %l)"; }
string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; }
string emitSMT() const override { return "(bvneg %l)"; }
string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return true; }
};
class AstNegateD final : public AstNodeUniop {
public:
AstNegateD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_NegateD(fl, lhsp) {
dtypeSetDouble();
}
ASTGEN_MEMBERS_AstNegateD;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegateD(lhs); }
string emitVerilog() override { return "%f(- %l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool doubleFlavor() const override { return true; }
};
class AstNot final : public AstNodeUniop {
public:
AstNot(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Not(fl, lhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstNot;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); }
string emitVerilog() override { return "%f(~ %l)"; }
string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; }
string emitSMT() const override { return "(bvnot %l)"; }
string emitSimpleOperator() override { return "~"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return true; }
const char* widthMismatch() const override VL_MT_STABLE;
};
class AstNullCheck final : public AstNodeUniop {
// Return LHS after checking that LHS is non-null
public:
AstNullCheck(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_NullCheck(fl, lhsp) {
dtypeFrom(lhsp);
}
ASTGEN_MEMBERS_AstNullCheck;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
int instrCount() const override { return 1; } // Rarely executes
string emitVerilog() override { return "%l"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
bool sameNode(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, AstNodeExpr* lhsp)
: ASTGEN_SUPER_OneHot(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstOneHot;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); }
string emitVerilog() override { return "%f$onehot(%l)"; }
string emitC() override { return "VL_ONEHOT_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 4; }
bool isSystemFunc() const override { return true; }
};
class AstOneHot0 final : public AstNodeUniop {
// True if only single bit, or no bits set in vector
public:
AstOneHot0(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_OneHot0(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstOneHot0;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); }
string emitVerilog() override { return "%f$onehot0(%l)"; }
string emitC() override { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 3; }
bool isSystemFunc() const override { return true; }
};
class AstRToIRoundS final : public AstNodeUniop {
// Convert real to integer, with arbitrary sized output (not just "integer" format)
public:
AstRToIRoundS(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RToIRoundS(fl, lhsp) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstRToIRoundS;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIRoundS(lhs); }
string emitVerilog() override { return "%f$rtoi_rounded(%l)"; }
string emitC() override {
return isWide() ? "VL_RTOIROUND_%nq_D(%nw, %P, %li)" : "VL_RTOIROUND_%nq_D(%li)";
}
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstRToIS final : public AstNodeUniop {
// $rtoi(lhs)
public:
AstRToIS(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RToIS(fl, lhsp) {
dtypeSetSigned32();
}
ASTGEN_MEMBERS_AstRToIS;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); }
string emitVerilog() override { return "%f$rtoi(%l)"; }
string emitC() override { return "VL_RTOI_I_D(%li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } // Eliminated before matters
bool sizeMattersLhs() const override { return false; } // Eliminated before matters
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstRealToBits final : public AstNodeUniop {
public:
AstRealToBits(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RealToBits(fl, lhsp) {
dtypeSetUInt64();
}
ASTGEN_MEMBERS_AstRealToBits;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRealToBits(lhs); }
string emitVerilog() override { return "%f$realtobits(%l)"; }
string emitC() override { return "VL_CVT_Q_D(%li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } // Eliminated before matters
bool sizeMattersLhs() const override { return false; } // Eliminated before matters
int instrCount() const override { return INSTR_COUNT_DBL; }
bool isSystemFunc() const override { return true; }
};
class AstRedAnd final : public AstNodeUniop {
public:
AstRedAnd(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RedAnd(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstRedAnd;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); }
string emitVerilog() override { return "%f(& %l)"; }
string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstRedOr final : public AstNodeUniop {
public:
AstRedOr(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RedOr(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstRedOr;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); }
string emitVerilog() override { return "%f(| %l)"; }
string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstRedXor final : public AstNodeUniop {
public:
AstRedXor(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RedXor(fl, lhsp) {
dtypeSetBit();
}
ASTGEN_MEMBERS_AstRedXor;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); }
string emitVerilog() override { return "%f(^ %l)"; }
string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; }
bool cleanOut() const override { return false; }
bool cleanLhs() const override {
const int w = lhsp()->width();
return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16);
}
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return 1 + V3Number::log2b(width()); }
};
class AstResizeLValue final : public AstNodeUniop {
// Resize a LValue into a wider/narrower entity at function argument boundry
// Width and signness is implied from nodep->width()
public:
AstResizeLValue(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ResizeLValue(fl, lhsp) {}
ASTGEN_MEMBERS_AstResizeLValue;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "%l"; }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
int instrCount() const override { return 0; }
};
class AstSigned final : public AstNodeUniop {
// $signed(lhs)
public:
AstSigned(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Signed(fl, lhsp) {
UASSERT_OBJ(!v3Global.assertDTypesResolved(), this,
"not coded to create after dtypes resolved");
}
ASTGEN_MEMBERS_AstSigned;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.opAssign(lhs);
out.isSigned(false);
}
string emitVerilog() override { return "%f$signed(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } // Eliminated before matters
bool sizeMattersLhs() const override { return true; } // Eliminated before matters
int instrCount() const override { return 0; }
bool isSystemFunc() const override { return true; }
};
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, AstNodeExpr* lhsp)
: ASTGEN_SUPER_TimeImport(fl, lhsp) {}
ASTGEN_MEMBERS_AstTimeImport;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "%l"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; }
void dump(std::ostream& str = std::cout) const override;
void dumpJson(std::ostream& str = std::cout) const override;
VTimescale timeunit() const { return m_timeunit; }
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
};
class AstToLowerN final : public AstNodeUniop {
// string.tolower()
public:
AstToLowerN(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ToLowerN(fl, lhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstToLowerN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opToLowerN(lhs); }
string emitVerilog() override { return "%l.tolower()"; }
string emitC() override { return "VL_TOLOWER_NN(%li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstToStringN final : public AstNodeUniop {
public:
AstToStringN(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ToStringN(fl, lhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstToStringN;
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
string emitVerilog() override { return "$sformatf(\"%p\", %l)"; }
string emitC() override { return isWide() ? "VL_TO_STRING_W(%nw, %li)" : "VL_TO_STRING(%li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstToUpperN final : public AstNodeUniop {
// string.toupper()
public:
AstToUpperN(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ToUpperN(fl, lhsp) {
dtypeSetString();
}
ASTGEN_MEMBERS_AstToUpperN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opToUpperN(lhs); }
string emitVerilog() override { return "%l.toupper()"; }
string emitC() override { return "VL_TOUPPER_NN(%li)"; }
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; }
};
class AstUnsigned final : public AstNodeUniop {
// $unsigned(lhs)
public:
AstUnsigned(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Unsigned(fl, lhsp) {
UASSERT_OBJ(!v3Global.assertDTypesResolved(), this,
"not coded to create after dtypes resolved");
}
ASTGEN_MEMBERS_AstUnsigned;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.opAssign(lhs);
out.isSigned(false);
}
string emitVerilog() override { return "%f$unsigned(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } // Eliminated before matters
bool sizeMattersLhs() const override { return true; } // Eliminated before matters
int instrCount() const override { return 0; }
bool isSystemFunc() const override { return true; }
};
// === AstNodeSystemUniopD ===
class AstAcosD final : public AstNodeSystemUniopD {
public:
AstAcosD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AcosD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAcosD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::acos(lhs.toDouble()));
}
string emitVerilog() override { return "%f$acos(%l)"; }
string emitC() override { return "acos(%li)"; }
};
class AstAcoshD final : public AstNodeSystemUniopD {
public:
AstAcoshD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AcoshD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAcoshD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::acosh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$acosh(%l)"; }
string emitC() override { return "acosh(%li)"; }
};
class AstAsinD final : public AstNodeSystemUniopD {
public:
AstAsinD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AsinD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAsinD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::asin(lhs.toDouble()));
}
string emitVerilog() override { return "%f$asin(%l)"; }
string emitC() override { return "asin(%li)"; }
};
class AstAsinhD final : public AstNodeSystemUniopD {
public:
AstAsinhD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AsinhD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAsinhD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::asinh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$asinh(%l)"; }
string emitC() override { return "asinh(%li)"; }
};
class AstAtanD final : public AstNodeSystemUniopD {
public:
AstAtanD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AtanD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAtanD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::atan(lhs.toDouble()));
}
string emitVerilog() override { return "%f$atan(%l)"; }
string emitC() override { return "atan(%li)"; }
};
class AstAtanhD final : public AstNodeSystemUniopD {
public:
AstAtanhD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_AtanhD(fl, lhsp) {}
ASTGEN_MEMBERS_AstAtanhD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::atanh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$atanh(%l)"; }
string emitC() override { return "atanh(%li)"; }
};
class AstCeilD final : public AstNodeSystemUniopD {
public:
AstCeilD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CeilD(fl, lhsp) {}
ASTGEN_MEMBERS_AstCeilD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::ceil(lhs.toDouble()));
}
string emitVerilog() override { return "%f$ceil(%l)"; }
string emitC() override { return "ceil(%li)"; }
};
class AstCosD final : public AstNodeSystemUniopD {
public:
AstCosD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CosD(fl, lhsp) {}
ASTGEN_MEMBERS_AstCosD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::cos(lhs.toDouble()));
}
string emitVerilog() override { return "%f$cos(%l)"; }
string emitC() override { return "cos(%li)"; }
};
class AstCoshD final : public AstNodeSystemUniopD {
public:
AstCoshD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CoshD(fl, lhsp) {}
ASTGEN_MEMBERS_AstCoshD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::cosh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$cosh(%l)"; }
string emitC() override { return "cosh(%li)"; }
};
class AstExpD final : public AstNodeSystemUniopD {
public:
AstExpD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_ExpD(fl, lhsp) {}
ASTGEN_MEMBERS_AstExpD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::exp(lhs.toDouble()));
}
string emitVerilog() override { return "%f$exp(%l)"; }
string emitC() override { return "exp(%li)"; }
};
class AstFloorD final : public AstNodeSystemUniopD {
public:
AstFloorD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_FloorD(fl, lhsp) {}
ASTGEN_MEMBERS_AstFloorD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::floor(lhs.toDouble()));
}
string emitVerilog() override { return "%f$floor(%l)"; }
string emitC() override { return "floor(%li)"; }
};
class AstLog10D final : public AstNodeSystemUniopD {
public:
AstLog10D(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_Log10D(fl, lhsp) {}
ASTGEN_MEMBERS_AstLog10D;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::log10(lhs.toDouble()));
}
string emitVerilog() override { return "%f$log10(%l)"; }
string emitC() override { return "log10(%li)"; }
};
class AstLogD final : public AstNodeSystemUniopD {
public:
AstLogD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_LogD(fl, lhsp) {}
ASTGEN_MEMBERS_AstLogD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::log(lhs.toDouble()));
}
string emitVerilog() override { return "%f$ln(%l)"; }
string emitC() override { return "log(%li)"; }
};
class AstSinD final : public AstNodeSystemUniopD {
public:
AstSinD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_SinD(fl, lhsp) {}
ASTGEN_MEMBERS_AstSinD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::sin(lhs.toDouble()));
}
string emitVerilog() override { return "%f$sin(%l)"; }
string emitC() override { return "sin(%li)"; }
};
class AstSinhD final : public AstNodeSystemUniopD {
public:
AstSinhD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_SinhD(fl, lhsp) {}
ASTGEN_MEMBERS_AstSinhD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::sinh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$sinh(%l)"; }
string emitC() override { return "sinh(%li)"; }
};
class AstSqrtD final : public AstNodeSystemUniopD {
public:
AstSqrtD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_SqrtD(fl, lhsp) {}
ASTGEN_MEMBERS_AstSqrtD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::sqrt(lhs.toDouble()));
}
string emitVerilog() override { return "%f$sqrt(%l)"; }
string emitC() override { return "sqrt(%li)"; }
};
class AstTanD final : public AstNodeSystemUniopD {
public:
AstTanD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_TanD(fl, lhsp) {}
ASTGEN_MEMBERS_AstTanD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::tan(lhs.toDouble()));
}
string emitVerilog() override { return "%f$tan(%l)"; }
string emitC() override { return "tan(%li)"; }
};
class AstTanhD final : public AstNodeSystemUniopD {
public:
AstTanhD(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_TanhD(fl, lhsp) {}
ASTGEN_MEMBERS_AstTanhD;
void numberOperate(V3Number& out, const V3Number& lhs) override {
out.setDouble(std::tanh(lhs.toDouble()));
}
string emitVerilog() override { return "%f$tanh(%l)"; }
string emitC() override { return "tanh(%li)"; }
};
// === AstNodeVarRef ===
class AstVarRef final : public AstNodeVarRef {
// A reference to a variable (lvalue or rvalue)
std::string m_name; // Name of varref, though name() favors varp()->namep()
// if non-null pointer (e.g.: 'this')
public:
// 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);
inline AstVarRef(FileLine* fl, AstNodeModule* classOrPackagep, AstVar* varp,
const VAccess& access);
// This form only allowed post-link (see above)
inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access);
ASTGEN_MEMBERS_AstVarRef;
std::string nameThis() const { return m_name; }
inline string name() const override; // * = Var name
void name(const string& name) override { m_name = name; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
const char* broken() const override;
bool sameNode(const AstNode* samep) const override;
inline bool sameNode(const AstVarRef* samep) const;
inline bool sameNoLvalue(const AstVarRef* samep) const;
int instrCount() const override;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
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
string m_name;
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
bool m_containsGenBlock = false; // Contains gen block reference
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER_VarXRef(fl, nullptr, access)
, m_name{name}
, m_dotted{dotted} {}
inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access);
ASTGEN_MEMBERS_AstVarXRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const std::string& name) override { m_name = name; } // * = Var name
void dump(std::ostream& str) const override;
void dumpJson(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; }
bool containsGenBlock() const { return m_containsGenBlock; }
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool sameNode(const AstNode* samep) const override {
const AstVarXRef* asamep = VN_DBG_AS(samep, VarXRef);
return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp()
&& name() == asamep->name() && dotted() == asamep->dotted());
}
};
#endif // Guard