forked from github/verilator
5363 lines
230 KiB
C++
5363 lines
230 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: AstNode sub-types representing expressions
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2023 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;
|
|
// TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final.
|
|
bool hasDType() const override { return true; }
|
|
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
|
|
// For documentation on emitC format see EmitCFunc::emitOpName
|
|
virtual string emitC() = 0;
|
|
virtual string emitSimpleOperator() { return ""; } // "" means not ok to use
|
|
virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS
|
|
virtual bool cleanOut() const = 0; // True if output has extra upper bits zero
|
|
// Someday we will generically support data types on every 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();
|
|
};
|
|
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
|
|
// Binary expression
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
// @astgen op2 := rhsp : AstNodeExpr
|
|
protected:
|
|
AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: AstNodeExpr{t, fl} {
|
|
this->lhsp(lhsp);
|
|
this->rhsp(rhsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeBiop;
|
|
// Clone single node, just get same type back.
|
|
virtual AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
|
// 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 same(const AstNode*) const override { return true; }
|
|
};
|
|
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; }
|
|
int instrCount() const override { return INSTR_COUNT_DBL_TRIG; }
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
V3ERROR_NA;
|
|
return nullptr;
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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)
|
|
: 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; }
|
|
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
|
|
AstCFunc* m_funcp;
|
|
string m_argTypes;
|
|
|
|
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 cloneRelink() override;
|
|
const char* broken() const override;
|
|
int instrCount() const override { return INSTR_COUNT_CALL; }
|
|
bool same(const AstNode* samep) const override {
|
|
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
|
|
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
|
|
}
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() const override;
|
|
bool isOutputter() const override { return !isPure(); }
|
|
AstCFunc* funcp() const { return m_funcp; }
|
|
void funcp(AstCFunc* funcp) { m_funcp = funcp; }
|
|
void argTypes(const string& str) { m_argTypes = str; }
|
|
string argTypes() const { return m_argTypes; }
|
|
|
|
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const final override { return true; }
|
|
};
|
|
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]
|
|
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
|
|
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
|
string m_name; // Name of variable
|
|
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
|
bool m_pli = false; // Pli system call ($name)
|
|
protected:
|
|
AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp)
|
|
: AstNodeExpr{t, fl} {
|
|
this->namep(namep);
|
|
this->addPinsp(pinsp);
|
|
}
|
|
AstNodeFTaskRef(VNType t, FileLine* fl, const string& name, AstNodeExpr* pinsp)
|
|
: AstNodeExpr{t, fl}
|
|
, m_name{name} {
|
|
this->addPinsp(pinsp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeFTaskRef;
|
|
const char* broken() const override;
|
|
void cloneRelink() override;
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
string name() const override { 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() const override;
|
|
|
|
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
|
|
};
|
|
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]
|
|
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 same(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); }
|
|
};
|
|
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
|
|
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 same(const AstNode*) const override { return true; }
|
|
};
|
|
class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr {
|
|
// Terminal operator -- an operator with no "inputs"
|
|
protected:
|
|
AstNodeTermop(VNType t, FileLine* fl)
|
|
: AstNodeExpr{t, fl} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeTermop;
|
|
// Know no children, and hot function, so skip iterator for speed
|
|
// cppcheck-suppress functionConst
|
|
void iterateChildren(VNVisitor& v) {}
|
|
void dump(std::ostream& str) const override;
|
|
};
|
|
class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
|
|
// Ternary expression
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
// @astgen op2 := rhsp : AstNodeExpr
|
|
// @astgen op3 := thsp : AstNodeExpr
|
|
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;
|
|
// 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 same(const AstNode*) const override { return true; }
|
|
};
|
|
class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
|
|
// @astgen alias op1 := condp
|
|
// @astgen alias op2 := thenp
|
|
// @astgen alias op3 := elsep
|
|
protected:
|
|
AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
|
|
: AstNodeTriop{t, fl, condp, thenp, elsep} {
|
|
if (thenp) {
|
|
dtypeFrom(thenp);
|
|
} else if (elsep) {
|
|
dtypeFrom(elsep);
|
|
}
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeCond;
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
|
const V3Number& ths) override;
|
|
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)"; }
|
|
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; }
|
|
virtual AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) = 0;
|
|
};
|
|
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; }
|
|
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
|
|
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;
|
|
// 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 same(const AstNode*) const override { return true; }
|
|
};
|
|
class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop {
|
|
public:
|
|
AstNodeSystemUniopD(VNType t, FileLine* fl, AstNodeExpr* lhsp)
|
|
: 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; }
|
|
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
|
|
VAccess m_access; // Left hand side assignment
|
|
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
|
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
|
|
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
|
|
string m_name; // Name of variable
|
|
string m_selfPointer; // Output code object pointer (e.g.: 'this')
|
|
|
|
protected:
|
|
AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access)
|
|
: AstNodeExpr{t, fl}
|
|
, m_access{access}
|
|
, m_name{name} {
|
|
varp(nullptr);
|
|
}
|
|
AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
|
|
: AstNodeExpr{t, fl}
|
|
, m_access{access}
|
|
, m_name{name} {
|
|
// May have varp==nullptr
|
|
this->varp(varp);
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstNodeVarRef;
|
|
void dump(std::ostream& str) const override;
|
|
const char* broken() const override;
|
|
int instrCount() const override { return widthInstrs(); }
|
|
void cloneRelink() override;
|
|
string name() const override { return m_name; } // * = Var name
|
|
void name(const string& name) override { m_name = name; }
|
|
VAccess access() const { return m_access; }
|
|
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
|
|
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
|
void varp(AstVar* varp) {
|
|
m_varp = varp;
|
|
dtypeFrom((AstNode*)varp);
|
|
}
|
|
AstVarScope* varScopep() const { return m_varScopep; }
|
|
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
|
|
string selfPointer() const { return m_selfPointer; }
|
|
void selfPointer(const string& value) { m_selfPointer = value; }
|
|
string selfPointerProtect(bool useSelfForThis) const;
|
|
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
|
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
|
// Know no children, and hot function, so skip iterator for speed
|
|
// cppcheck-suppress functionConst
|
|
void iterateChildren(VNVisitor& v) {}
|
|
};
|
|
|
|
// === Concrete node types =====================================================
|
|
|
|
// === AstNodeExpr ===
|
|
class AstAddrOfCFunc final : public AstNodeExpr {
|
|
// Get address of CFunc
|
|
AstCFunc* m_funcp; // Pointer to function itself
|
|
|
|
public:
|
|
AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp)
|
|
: ASTGEN_SUPER_AddrOfCFunc(fl)
|
|
, m_funcp{funcp} {
|
|
dtypep(findCHandleDType());
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_AstAddrOfCFunc;
|
|
void cloneRelink() override;
|
|
const char* broken() 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 { return false; }
|
|
string name() const override { 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] // Expr or DType
|
|
// @astgen op2 := dimp : Optional[AstNodeExpr]
|
|
VAttrType m_attrType; // What sort of extraction
|
|
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;
|
|
VAttrType attrType() const { return m_attrType; }
|
|
void dump(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 {
|
|
// @astgen op1 := exprsp : List[AstNode] // Expressions to print
|
|
const bool m_cleanOut;
|
|
bool m_pure; // Pure optimizable
|
|
public:
|
|
// Emit C textual expr function (like AstUCFunc)
|
|
AstCExpr(FileLine* fl, AstNode* exprsp)
|
|
: ASTGEN_SUPER_CExpr(fl)
|
|
, m_cleanOut{true}
|
|
, m_pure{false} {
|
|
addExprsp(exprsp);
|
|
dtypeFrom(exprsp);
|
|
}
|
|
inline AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true);
|
|
ASTGEN_MEMBERS_AstCExpr;
|
|
bool isGateOptimizable() const override { return m_pure; }
|
|
bool isPredictOptimizable() const override { return m_pure; }
|
|
bool cleanOut() const override { return m_cleanOut; }
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool pure() const { return m_pure; }
|
|
void pure(bool flag) { m_pure = flag; }
|
|
};
|
|
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
|
|
string m_name; // Name of method
|
|
bool m_pure = false; // Pure optimizable
|
|
public:
|
|
AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name,
|
|
AstNodeExpr* pinsp = nullptr)
|
|
: ASTGEN_SUPER_CMethodHard(fl)
|
|
, m_name{name} {
|
|
// TODO: this constructor is exactly the same as the other, bar the ignored tag argument
|
|
this->fromp(fromp);
|
|
this->addPinsp(pinsp);
|
|
dtypep(nullptr); // V3Width will resolve
|
|
}
|
|
AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, const string& name,
|
|
AstNodeExpr* pinsp = nullptr)
|
|
: ASTGEN_SUPER_CMethodHard(fl)
|
|
, m_name{name} {
|
|
this->fromp(fromp);
|
|
this->addPinsp(pinsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCMethodHard;
|
|
string name() const override { return m_name; } // * = Var name
|
|
void name(const string& name) override { m_name = name; }
|
|
bool same(const AstNode* samep) const override {
|
|
const AstCMethodHard* asamep = static_cast<const AstCMethodHard*>(samep);
|
|
return (m_name == asamep->m_name);
|
|
}
|
|
bool isPure() const override { return m_pure; }
|
|
void pure(bool flag) { m_pure = flag; }
|
|
int instrCount() const override;
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { return true; }
|
|
};
|
|
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);
|
|
this->childDTypep(dtp);
|
|
dtypeFrom(dtp);
|
|
}
|
|
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} {
|
|
this->addSelp(selp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCellArrayRef;
|
|
// ACCESSORS
|
|
string name() const override { 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 : AstNodeExpr
|
|
private:
|
|
string m_name; // Cell name
|
|
public:
|
|
AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNodeExpr* exprp)
|
|
: ASTGEN_SUPER_CellRef(fl)
|
|
, m_name{name} {
|
|
this->cellp(cellp);
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCellRef;
|
|
// ACCESSORS
|
|
string name() const override { 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]
|
|
private:
|
|
string m_name;
|
|
// Node not NodeModule to appease some early parser usage
|
|
AstNode* m_classOrPackageNodep; // Package hierarchy
|
|
public:
|
|
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
|
|
AstPin* paramsp)
|
|
: ASTGEN_SUPER_ClassOrPackageRef(fl)
|
|
, m_name{name}
|
|
, m_classOrPackageNodep{classOrPackageNodep} {
|
|
this->addParamsp(paramsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstClassOrPackageRef;
|
|
// METHODS
|
|
const char* broken() const override {
|
|
BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists());
|
|
return nullptr;
|
|
}
|
|
void cloneRelink() override {
|
|
if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) {
|
|
m_classOrPackageNodep = m_classOrPackageNodep->clonep();
|
|
}
|
|
}
|
|
bool same(const AstNode* samep) const override {
|
|
return (m_classOrPackageNodep
|
|
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
|
|
}
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
string name() const override { return m_name; } // * = Var name
|
|
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
|
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
|
AstNodeModule* classOrPackagep() const;
|
|
AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); }
|
|
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = (AstNode*)nodep; }
|
|
|
|
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 same(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]
|
|
public:
|
|
explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
|
|
: ASTGEN_SUPER_ConsDynArray(fl) {
|
|
this->lhsp(lhsp);
|
|
this->rhsp(rhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConsDynArray;
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstConsPackMember final : public AstNodeExpr {
|
|
// Construct a packed array single emement [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 same(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);
|
|
this->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 same(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]
|
|
public:
|
|
explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
|
|
: ASTGEN_SUPER_ConsQueue(fl) {
|
|
this->lhsp(lhsp);
|
|
this->rhsp(rhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstConsQueue;
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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 same(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.widthMin()),
|
|
VSigning::fromBool(m_num.isSigned()));
|
|
}
|
|
m_num.nodep(this);
|
|
}
|
|
|
|
public:
|
|
AstConst(FileLine* fl, const V3Number& num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(num) {
|
|
initWithNumber();
|
|
}
|
|
class WidthedValue {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, WidthedValue, int width, uint32_t value)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, width, value) {
|
|
initWithNumber();
|
|
}
|
|
class DTyped {}; // for creator type-overload selection
|
|
// Zero/empty constant with a type matching nodetypep
|
|
AstConst(FileLine* fl, DTyped, const AstNodeDType* nodedtypep)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, nodedtypep) {
|
|
initWithNumber();
|
|
}
|
|
class StringToParse {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, StringToParse, const char* sourcep)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, sourcep) {
|
|
initWithNumber();
|
|
}
|
|
class VerilogStringLiteral {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, VerilogStringLiteral, const string& str)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(V3Number::VerilogStringLiteral{}, this, str) {
|
|
initWithNumber();
|
|
}
|
|
AstConst(FileLine* fl, uint32_t num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 32, num) {
|
|
dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED);
|
|
}
|
|
class Unsized32 {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 32, num) {
|
|
m_num.width(32, false);
|
|
dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED);
|
|
}
|
|
class Signed32 {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 32, num) {
|
|
m_num.width(32, true);
|
|
dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED);
|
|
}
|
|
class Unsized64 {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, Unsized64, uint64_t num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 64, 0) {
|
|
m_num.setQuad(num);
|
|
dtypeSetLogicSized(64, VSigning::UNSIGNED);
|
|
}
|
|
class SizedEData {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, SizedEData, uint64_t num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, VL_EDATASIZE, 0) {
|
|
m_num.setQuad(num);
|
|
dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED);
|
|
}
|
|
class RealDouble {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, RealDouble, double num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 64) {
|
|
m_num.setDouble(num);
|
|
dtypeSetDouble();
|
|
}
|
|
class String {}; // for creator type-overload selection
|
|
AstConst(FileLine* fl, String, const string& num)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(V3Number::String{}, this, num) {
|
|
dtypeSetString();
|
|
}
|
|
class BitFalse {};
|
|
AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 1, 0) {
|
|
dtypeSetBit();
|
|
}
|
|
// Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1
|
|
class BitTrue {};
|
|
AstConst(FileLine* fl, BitTrue, bool on = true)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(this, 1, on) {
|
|
dtypeSetBit();
|
|
}
|
|
class Null {};
|
|
AstConst(FileLine* fl, Null)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(V3Number::Null{}, this) {
|
|
dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here
|
|
initWithNumber();
|
|
}
|
|
class OneStep {};
|
|
AstConst(FileLine* fl, OneStep)
|
|
: ASTGEN_SUPER_Const(fl)
|
|
, m_num(V3Number::OneStep{}, this) {
|
|
dtypeSetLogicSized(64, VSigning::UNSIGNED);
|
|
initWithNumber();
|
|
}
|
|
ASTGEN_MEMBERS_AstConst;
|
|
string name() const override { 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 same(const AstNode* samep) const override {
|
|
const AstConst* const sp = static_cast<const AstConst*>(samep);
|
|
return num().isCaseEq(sp->num());
|
|
}
|
|
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 AstDot final : public AstNodeExpr {
|
|
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
|
|
// These are eliminated in the link stage
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
// @astgen op2 := rhsp : AstNodeExpr
|
|
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;
|
|
return new AstDot{fl, true, packageOrClassp, rhsp};
|
|
}
|
|
void dump(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 same(const AstNode* /*samep*/) const override { return true; }
|
|
bool cleanOut() const override { return true; }
|
|
};
|
|
class AstEnumItemRef final : public AstNodeExpr {
|
|
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
|
|
AstNodeModule* m_classOrPackagep; // Package hierarchy
|
|
public:
|
|
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
|
|
: ASTGEN_SUPER_EnumItemRef(fl)
|
|
, m_itemp{itemp}
|
|
, m_classOrPackagep{classOrPackagep} {
|
|
dtypeFrom(m_itemp);
|
|
}
|
|
ASTGEN_MEMBERS_AstEnumItemRef;
|
|
void dump(std::ostream& str) const override;
|
|
string name() const override { return itemp()->name(); }
|
|
int instrCount() const override { return 0; }
|
|
const char* broken() const override;
|
|
void cloneRelink() override {
|
|
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
|
|
}
|
|
bool same(const AstNode* samep) const override {
|
|
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
|
|
return itemp() == sp->itemp();
|
|
}
|
|
AstEnumItem* itemp() const { return m_itemp; }
|
|
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
|
|
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(""); }
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode*) const override { return true; }
|
|
};
|
|
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; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool same(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() const override { return false; } // SPECIAL: has 'visual' ordering
|
|
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) 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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool cleanOut() const override { return false; }
|
|
bool same(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 { 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() const override { return false; } // SPECIAL: has 'visual' ordering
|
|
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* samep) const override {
|
|
return text() == static_cast<const AstFScanF*>(samep)->text();
|
|
}
|
|
string text() const { return m_text; } // * = Text to display
|
|
void text(const string& text) { m_text = text; }
|
|
};
|
|
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() const override { return false; } // SPECIAL: has 'visual' ordering
|
|
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) 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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) 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 same(const AstNode* /*samep*/) 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 {
|
|
// Verilog |-> |=>
|
|
// @astgen op1 := lhsp : AstNodeExpr
|
|
// @astgen op2 := rhsp : AstNodeExpr
|
|
// @astgen op3 := sentreep : Optional[AstSenTree]
|
|
public:
|
|
AstImplication(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_Implication(fl) {
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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
|
|
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;
|
|
const char* broken() const override;
|
|
void cloneRelink() override;
|
|
bool same(const AstNode* samep) const override {
|
|
// Only works if exact same children, instead should override comparison
|
|
// of children list, and instead use map-vs-map key/value compare
|
|
return m_map == static_cast<const AstInitArray*>(samep)->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);
|
|
this->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 same(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 { return m_name; } // * = Var name
|
|
void name(const string& name) override { m_name = name; }
|
|
bool index() const { return m_index; }
|
|
};
|
|
class AstMemberSel final : public AstNodeExpr {
|
|
// @astgen op1 := fromp : AstNodeExpr
|
|
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
|
string m_name;
|
|
AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection
|
|
public:
|
|
AstMemberSel(FileLine* fl, 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, AstNodeDType* dtp)
|
|
: ASTGEN_SUPER_MemberSel(fl)
|
|
, m_name{dtp->name()} {
|
|
this->fromp(fromp);
|
|
dtypep(dtp);
|
|
}
|
|
ASTGEN_MEMBERS_AstMemberSel;
|
|
void cloneRelink() override;
|
|
const char* broken() const override;
|
|
void dump(std::ostream& str) const override;
|
|
string name() const override { return m_name; }
|
|
void name(const string& name) override { m_name = name; }
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* samep) const override { return true; } // dtype comparison does it
|
|
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 same(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 same(const AstNode* /*samep*/) const override { return true; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
};
|
|
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]
|
|
|
|
VParseRefExp m_expect; // Type we think it should resolve to
|
|
string m_name;
|
|
|
|
public:
|
|
AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr,
|
|
AstNodeFTaskRef* ftaskrefp = nullptr)
|
|
: ASTGEN_SUPER_ParseRef(fl)
|
|
, m_expect{expect}
|
|
, m_name{name} {
|
|
this->lhsp(lhsp);
|
|
this->ftaskrefp(ftaskrefp);
|
|
}
|
|
ASTGEN_MEMBERS_AstParseRef;
|
|
void dump(std::ostream& str) const override;
|
|
string name() const override { return m_name; } // * = Var name
|
|
bool same(const AstNode* samep) const override {
|
|
const AstParseRef* const asamep = static_cast<const AstParseRef*>(samep);
|
|
return (expect() == asamep->expect() && m_name == asamep->m_name);
|
|
}
|
|
void name(const string& name) override { m_name = name; }
|
|
VParseRefExp expect() const { return m_expect; }
|
|
void expect(VParseRefExp exp) { m_expect = exp; }
|
|
|
|
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:
|
|
AstPast(FileLine* fl, AstNodeExpr* exprp, AstNode* ticksp)
|
|
: ASTGEN_SUPER_Past(fl) {
|
|
this->exprp(exprp);
|
|
this->ticksp(ticksp);
|
|
}
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstPatMember final : public AstNodeExpr {
|
|
// Verilog '{a} or '{a{b}}
|
|
// Parents: AstPattern
|
|
// Children: expression, AstPattern, replication count
|
|
// 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
|
|
bool m_default = false;
|
|
|
|
public:
|
|
AstPatMember(FileLine* fl, AstNodeExpr* lhssp, AstNode* keyp, AstNodeExpr* repp)
|
|
: ASTGEN_SUPER_PatMember(fl) {
|
|
this->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;
|
|
bool isDefault() const { return m_default; }
|
|
void isDefault(bool flag) { m_default = 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 = false; // $urandom vs $random
|
|
const bool m_reset = false; // Random reset, versus always random
|
|
public:
|
|
class Reset {};
|
|
AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset)
|
|
: ASTGEN_SUPER_Rand(fl)
|
|
, m_reset{reset} {
|
|
dtypep(dtp);
|
|
}
|
|
AstRand(FileLine* fl, AstNode* seedp, bool urandom)
|
|
: ASTGEN_SUPER_Rand(fl)
|
|
, m_urandom{urandom} {
|
|
this->seedp(seedp);
|
|
}
|
|
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 {
|
|
return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)"
|
|
: seedp()
|
|
// cppcheck-has-bug-suppress knownConditionTrueFalse
|
|
? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" //
|
|
: "VL_RANDOM_SEEDED_%nq%lq(%li)")
|
|
: (isWide() ? "VL_RANDOM_%nq(%nw, %P)" //
|
|
: "VL_RANDOM_%nq()");
|
|
}
|
|
bool cleanOut() const override { return false; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool combinable(const AstRand* samep) const {
|
|
return !seedp() && !samep->seedp() && reset() == samep->reset()
|
|
&& urandom() == samep->urandom();
|
|
}
|
|
bool reset() const { return m_reset; }
|
|
bool urandom() const { return m_urandom; }
|
|
};
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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 { return m_text; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
bool same(const AstNode* samep) const override {
|
|
return text() == static_cast<const AstSFormatF*>(samep)->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; }
|
|
void hasFormat(bool flag) { m_hasFormat = flag; }
|
|
bool hasFormat() const { return m_hasFormat; }
|
|
char missingArgChar() const { return m_missingArgChar; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
|
};
|
|
class AstSScanF final : public AstNodeExpr {
|
|
// @astgen op1 := exprsp : List[AstNode] // VarRefs for results
|
|
// @astgen op2 := fromp : AstNode
|
|
string m_text;
|
|
|
|
public:
|
|
AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp)
|
|
: ASTGEN_SUPER_SScanF(fl)
|
|
, m_text{text} {
|
|
this->addExprsp(exprsp);
|
|
this->fromp(fromp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSScanF;
|
|
string name() const override { 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() const override { return false; } // SPECIAL: has 'visual' ordering
|
|
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* samep) const override {
|
|
return text() == static_cast<const AstSScanF*>(samep)->text();
|
|
}
|
|
string text() const { return m_text; } // * = Text to display
|
|
void text(const string& text) { m_text = text; }
|
|
};
|
|
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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstScopeName final : public AstNodeExpr {
|
|
// For display %m and DPI context imports
|
|
// Parents: DISPLAY
|
|
// @astgen op1 := scopeAttrp : List[AstText]
|
|
// @astgen op2 := scopeEntrp : List[AstText]
|
|
bool m_dpiExport = false; // Is for dpiExport
|
|
const bool m_forFormat = false; // Is for a format %m
|
|
string scopeNameFormatter(AstText* scopeTextp) const;
|
|
string scopePrettyNameFormatter(AstText* scopeTextp) const;
|
|
|
|
public:
|
|
class ForFormat {};
|
|
AstScopeName(FileLine* fl, bool forFormat)
|
|
: ASTGEN_SUPER_ScopeName(fl)
|
|
, m_forFormat{forFormat} {
|
|
dtypeSetUInt64();
|
|
}
|
|
ASTGEN_MEMBERS_AstScopeName;
|
|
bool same(const AstNode* samep) const override {
|
|
return (m_dpiExport == static_cast<const AstScopeName*>(samep)->m_dpiExport
|
|
&& m_forFormat == static_cast<const AstScopeName*>(samep)->m_forFormat);
|
|
}
|
|
string emitVerilog() override { return ""; }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { return true; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
string scopeSymName() const { // Name for __Vscope variable including children
|
|
return scopeNameFormatter(scopeAttrp());
|
|
}
|
|
string scopeDpiName() const { // Name for DPI import scope
|
|
return scopeNameFormatter(scopeEntrp());
|
|
}
|
|
string scopePrettySymName() const { // Name for __Vscope variable including children
|
|
return scopePrettyNameFormatter(scopeAttrp());
|
|
}
|
|
string scopePrettyDpiName() const { // Name for __Vscope variable including children
|
|
return scopePrettyNameFormatter(scopeEntrp());
|
|
}
|
|
bool dpiExport() const { return m_dpiExport; }
|
|
void dpiExport(bool flag) { m_dpiExport = flag; }
|
|
bool forFormat() const { return m_forFormat; }
|
|
};
|
|
class 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);
|
|
this->addElementsp(elementsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstSelLoopVars;
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool maybePointedTo() const override { return false; }
|
|
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
|
};
|
|
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 same(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 same(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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstStackTraceF final : public AstNodeExpr {
|
|
// $stacktrace used as function
|
|
public:
|
|
explicit AstStackTraceF(FileLine* fl)
|
|
: 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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool cleanOut() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstStructSel final : public AstNodeExpr {
|
|
// Unpacked struct member access
|
|
// Parents: math|stmt
|
|
// Children: varref, math
|
|
// @astgen op1 := fromp : AstNodeExpr
|
|
private:
|
|
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 { return m_name; }
|
|
void name(const string& name) override { m_name = name; }
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool cleanOut() const override { return false; }
|
|
bool same(const AstNode* samep) const override {
|
|
const AstStructSel* const sp = static_cast<const AstStructSel*>(samep);
|
|
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) {
|
|
this->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() const override { return false; } // Though deleted before opt
|
|
bool isOutputter() const 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() const override { return false; }
|
|
bool isOutputter() const override { return true; }
|
|
bool isUnlikely() const override { return true; }
|
|
bool cleanOut() const override { return true; }
|
|
bool same(const AstNode* /*samep*/) 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; }
|
|
bool cleanOut() const override { return true; }
|
|
bool same(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);
|
|
}
|
|
ASTGEN_MEMBERS_AstThisRef;
|
|
string emitC() override { return "this"; }
|
|
string emitVerilog() override { return "this"; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
bool cleanOut() const override { return true; }
|
|
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
|
AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); }
|
|
};
|
|
class AstTimePrecision final : public AstNodeExpr {
|
|
// Verilog $timeprecision
|
|
public:
|
|
explicit AstTimePrecision(FileLine* fl)
|
|
: 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; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstTimeUnit final : public AstNodeExpr {
|
|
VTimescale m_timeunit; // Parent module time unit
|
|
// Verilog $timeunit
|
|
public:
|
|
explicit AstTimeUnit(FileLine* fl)
|
|
: 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; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
class AstUCFunc final : public AstNodeExpr {
|
|
// User's $c function
|
|
// @astgen op1 := exprsp : List[AstNode] // Expressions to print (some are AstText)
|
|
public:
|
|
AstUCFunc(FileLine* fl, AstNode* exprsp)
|
|
: ASTGEN_SUPER_UCFunc(fl) {
|
|
this->addExprsp(exprsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstUCFunc;
|
|
bool cleanOut() const override { return false; }
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
|
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
|
bool isOutputter() const override { return true; }
|
|
bool isGateOptimizable() const override { return false; }
|
|
bool isSubstOptimizable() const override { return false; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
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() const override { return !outp(); }
|
|
bool cleanOut() const override { return true; }
|
|
bool same(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 : AstNodeExpr
|
|
public:
|
|
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
|
|
AstNodeExpr* exprp)
|
|
: ASTGEN_SUPER_With(fl) {
|
|
this->indexArgRefp(indexArgRefp);
|
|
this->valueArgRefp(valueArgRefp);
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstWith;
|
|
bool same(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 : AstNode
|
|
// @astgen op2 := exprp : Optional[AstNodeExpr]
|
|
public:
|
|
AstWithParse(FileLine* fl, AstNode* funcrefp, AstNodeExpr* exprp)
|
|
: ASTGEN_SUPER_WithParse(fl) {
|
|
this->funcrefp(funcrefp);
|
|
this->exprp(exprp);
|
|
}
|
|
ASTGEN_MEMBERS_AstWithParse;
|
|
bool same(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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstBufIf1{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
}
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstCastDynamic{fileline(), lhsp, rhsp};
|
|
}
|
|
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; }
|
|
int instrCount() const override { return widthInstrs() * 20; }
|
|
bool isPure() const override { return true; }
|
|
};
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstCompareNN{fileline(), lhsp, rhsp, m_ignoreCase};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
|
out.opCompareNN(lhs, rhs, m_ignoreCase);
|
|
}
|
|
string name() const override { 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstConcat{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstConcatN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstDiv{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstDivD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstDivS{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEqWild{fileline(), lhsp, rhsp};
|
|
}
|
|
// 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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstFGetS{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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; }
|
|
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& out, const V3Number& lhs, const V3Number& rhs) override {
|
|
V3ERROR_NA;
|
|
}
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstFUngetC{fileline(), lhsp, rhsp};
|
|
}
|
|
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; }
|
|
int instrCount() const override { return widthInstrs() * 64; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
AstNode* filep() const { return lhsp(); }
|
|
AstNode* charp() const { return rhsp(); }
|
|
};
|
|
class AstGetcN final : public AstNodeBiop {
|
|
// Verilog string.getc()
|
|
public:
|
|
AstGetcN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) {
|
|
dtypeSetBitSized(8, VSigning::UNSIGNED);
|
|
}
|
|
ASTGEN_MEMBERS_AstGetcN;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGetcN{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
|
out.opGetcN(lhs, rhs);
|
|
}
|
|
string name() const override { 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGetcRefN{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGt{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGtD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGtN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGtS{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGte{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGteD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGteN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstGteS{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLogAnd{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLogIf{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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 {
|
|
// LOGOR with optional side effects
|
|
// Side effects currently used in some V3Width code
|
|
// TBD if this concept is generally adopted for side-effect tracking
|
|
// versus V3Const tracking it itself
|
|
bool m_sideEffect = false; // Has side effect, relies on short-circuiting
|
|
public:
|
|
AstLogOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) {
|
|
dtypeSetBit();
|
|
}
|
|
ASTGEN_MEMBERS_AstLogOr;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLogOr{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
|
out.opLogOr(lhs, rhs);
|
|
}
|
|
bool same(const AstNode* samep) const override {
|
|
const AstLogOr* const sp = static_cast<const AstLogOr*>(samep);
|
|
return m_sideEffect == sp->m_sideEffect;
|
|
}
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
string emitVerilog() override { return "%k(%l %f|| %r)"; }
|
|
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %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; }
|
|
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
|
bool isPure() const override { return !m_sideEffect; }
|
|
void sideEffect(bool flag) { m_sideEffect = flag; }
|
|
bool sideEffect() const { return m_sideEffect; }
|
|
};
|
|
class AstLt final : public AstNodeBiop {
|
|
public:
|
|
AstLt(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_Lt(fl, lhsp, rhsp) {
|
|
dtypeSetBit();
|
|
}
|
|
ASTGEN_MEMBERS_AstLt;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLt{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLtD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLtN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLtS{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLte{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLteD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLteN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLteS{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstModDiv{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstModDivS{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeqWild{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstPow{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstPowD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstPowSS{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstPowSU{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstPowUS{fileline(), lhsp, rhsp};
|
|
}
|
|
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)) {
|
|
dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED);
|
|
}
|
|
}
|
|
}
|
|
AstReplicate(FileLine* fl, AstNodeExpr* lhsp, uint32_t repCount)
|
|
: AstReplicate{fl, lhsp, new AstConst{fl, repCount}} {}
|
|
ASTGEN_MEMBERS_AstReplicate;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstReplicate{fileline(), lhsp, rhsp};
|
|
}
|
|
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)"; }
|
|
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();
|
|
}
|
|
AstReplicateN(FileLine* fl, AstNodeExpr* lhsp, uint32_t repCount)
|
|
: AstReplicateN{fl, lhsp, new AstConst{fl, repCount}} {}
|
|
ASTGEN_MEMBERS_AstReplicateN;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstReplicateN{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstShiftL{fileline(), lhsp, rhsp};
|
|
}
|
|
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 (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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstShiftR{fileline(), lhsp, rhsp};
|
|
}
|
|
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 (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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstShiftRS{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstSub{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstSubD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstURandomRange{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEq{fileline(), lhsp, rhsp};
|
|
}
|
|
// 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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEqCase{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEqD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEqN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstEqT{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstLogEq{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeq{fileline(), lhsp, 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 "!="; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeqCase{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeqD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeqN{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstNeqT{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAdd{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAddD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAnd{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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; }
|
|
};
|
|
class AstMul final : public AstNodeBiComAsv {
|
|
public:
|
|
AstMul(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_Mul(fl, lhsp, rhsp) {
|
|
dtypeFrom(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstMul;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstMul{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstMulD{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstMulS{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstOr{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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; }
|
|
};
|
|
class AstXor final : public AstNodeBiComAsv {
|
|
public:
|
|
AstXor(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_Xor(fl, lhsp, rhsp) {
|
|
dtypeFrom(lhsp);
|
|
}
|
|
ASTGEN_MEMBERS_AstXor;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstXor{fileline(), lhsp, rhsp};
|
|
}
|
|
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 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; }
|
|
};
|
|
|
|
// === 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(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)
|
|
: ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { // Need () constructor
|
|
init(fromp);
|
|
}
|
|
ASTGEN_MEMBERS_AstArraySel;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstArraySel{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
|
V3ERROR_NA; /* How can from be a const? */
|
|
}
|
|
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 true; }
|
|
bool same(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(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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAssocSel{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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 same(const AstNode* /*samep*/) const override { return true; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
};
|
|
class AstWildcardSel final : public AstNodeSel {
|
|
void init(AstNode* fromp) {
|
|
if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) {
|
|
// Strip off array to find what array references
|
|
dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep());
|
|
}
|
|
}
|
|
|
|
public:
|
|
AstWildcardSel(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
|
|
: ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) {
|
|
init(fromp);
|
|
}
|
|
ASTGEN_MEMBERS_AstWildcardSel;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstWildcardSel{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) 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 same(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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstWordSel{fileline(), lhsp, rhsp};
|
|
}
|
|
void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) 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 same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
|
|
// === AstNodeStream ===
|
|
class AstStreamL final : public AstNodeStream {
|
|
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
|
|
public:
|
|
AstStreamL(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
|
: ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {}
|
|
ASTGEN_MEMBERS_AstStreamL;
|
|
AstNodeStream* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstStreamL{fileline(), lhsp, rhsp};
|
|
}
|
|
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 true; }
|
|
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;
|
|
AstNodeStream* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstStreamR{fileline(), lhsp, rhsp};
|
|
}
|
|
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 true; }
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstAtan2D{fileline(), lhsp, rhsp};
|
|
}
|
|
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;
|
|
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
|
return new AstHypotD{fileline(), lhsp, rhsp};
|
|
}
|
|
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
|
|
string m_selfPointer; // Output code object pointer (e.g.: 'this')
|
|
|
|
public:
|
|
AstCCall(FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
|
|
: ASTGEN_SUPER_CCall(fl, funcp, argsp) {}
|
|
ASTGEN_MEMBERS_AstCCall;
|
|
|
|
string selfPointer() const { return m_selfPointer; }
|
|
void selfPointer(const string& value) { m_selfPointer = value; }
|
|
string selfPointerProtect(bool useSelfForThis) const;
|
|
};
|
|
class AstCMethodCall final : public AstNodeCCall {
|
|
// C++ method call
|
|
// @astgen op1 := fromp : AstNodeExpr
|
|
public:
|
|
AstCMethodCall(FileLine* fl, AstNodeExpr* fromp, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
|
|
: ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) {
|
|
this->fromp(fromp);
|
|
}
|
|
ASTGEN_MEMBERS_AstCMethodCall;
|
|
const char* broken() const override {
|
|
BROKEN_BASE_RTN(AstNodeCCall::broken());
|
|
BROKEN_RTN(!fromp());
|
|
return nullptr;
|
|
}
|
|
};
|
|
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
|
|
public:
|
|
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
|
|
: ASTGEN_SUPER_FuncRef(fl, (AstNode*)namep, pinsp) {}
|
|
AstFuncRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
|
|
: ASTGEN_SUPER_FuncRef(fl, name, pinsp) {}
|
|
ASTGEN_MEMBERS_AstFuncRef;
|
|
};
|
|
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;
|
|
const char* broken() const override {
|
|
BROKEN_BASE_RTN(AstNodeFTaskRef::broken());
|
|
BROKEN_RTN(!fromp());
|
|
return nullptr;
|
|
}
|
|
};
|
|
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
|
|
public:
|
|
AstNew(FileLine* fl, AstNodeExpr* pinsp)
|
|
: ASTGEN_SUPER_New(fl, "new", pinsp) {}
|
|
ASTGEN_MEMBERS_AstNew;
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
int instrCount() const override { return widthInstrs(); }
|
|
};
|
|
class AstTaskRef final : public AstNodeFTaskRef {
|
|
// A reference to a task
|
|
public:
|
|
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
|
|
: ASTGEN_SUPER_TaskRef(fl, (AstNode*)namep, pinsp) {
|
|
dtypeSetVoid();
|
|
}
|
|
AstTaskRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
|
|
: ASTGEN_SUPER_TaskRef(fl, name, pinsp) {
|
|
dtypeSetVoid();
|
|
}
|
|
ASTGEN_MEMBERS_AstTaskRef;
|
|
};
|
|
|
|
// === 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
|
|
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;
|
|
};
|
|
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 := widtph
|
|
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 := widtph
|
|
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->cloneTree(false),
|
|
ctrl1p->cloneTree(false)) {}
|
|
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p)
|
|
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(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; }
|
|
int instrCount() const override { return widthInstrs() * 16; }
|
|
};
|
|
|
|
// === AstNodeTermop ===
|
|
class AstTime final : public AstNodeTermop {
|
|
VTimescale m_timeunit; // Parent module time unit
|
|
public:
|
|
AstTime(FileLine* fl, const VTimescale& timeunit)
|
|
: ASTGEN_SUPER_Time(fl)
|
|
, m_timeunit{timeunit} {
|
|
dtypeSetUInt64();
|
|
}
|
|
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; }
|
|
int instrCount() const override { return INSTR_COUNT_TIME; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
class AstTimeD final : public AstNodeTermop {
|
|
VTimescale m_timeunit; // Parent module time unit
|
|
public:
|
|
AstTimeD(FileLine* fl, const VTimescale& timeunit)
|
|
: ASTGEN_SUPER_TimeD(fl)
|
|
, m_timeunit{timeunit} {
|
|
dtypeSetDouble();
|
|
}
|
|
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; }
|
|
int instrCount() const override { return INSTR_COUNT_TIME; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
void dump(std::ostream& str = std::cout) const override;
|
|
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
|
|
// === AstNodeTriop ===
|
|
class AstPostAdd final : public AstNodeTriop {
|
|
// Post-increment/add
|
|
// 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 { 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 true; }
|
|
bool sizeMattersRhs() const override { return true; }
|
|
bool sizeMattersThs() const override { 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 { 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 true; }
|
|
bool sizeMattersRhs() const override { return true; }
|
|
bool sizeMattersThs() const override { 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 { 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 true; }
|
|
bool sizeMattersRhs() const override { return true; }
|
|
bool sizeMattersThs() const override { 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 { 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 true; }
|
|
bool sizeMattersRhs() const override { return true; }
|
|
bool sizeMattersThs() const override { 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 { 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 AstSel final : public AstNodeTriop {
|
|
// Multiple bit range extraction
|
|
// @astgen alias op1 := fromp
|
|
// @astgen alias op2 := lsbp
|
|
// @astgen alias op3 := widthp
|
|
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
|
|
int m_declElWidth; // If a packed array, the number of bits per element
|
|
public:
|
|
AstSel(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* lsbp, AstNodeExpr* widthp)
|
|
: ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp)
|
|
, m_declElWidth{1} {
|
|
if (VN_IS(widthp, Const)) {
|
|
dtypeSetLogicSized(VN_AS(widthp, Const)->toUInt(), VSigning::UNSIGNED);
|
|
}
|
|
}
|
|
AstSel(FileLine* fl, AstNodeExpr* fromp, int lsb, int bitwidth)
|
|
: ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), // Need () constructor
|
|
new AstConst(fl, bitwidth)) // Need () constructor
|
|
, m_declElWidth{1} {
|
|
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
|
|
}
|
|
ASTGEN_MEMBERS_AstSel;
|
|
void dump(std::ostream& str) const override;
|
|
void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit,
|
|
const V3Number& width) override {
|
|
out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt());
|
|
}
|
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
|
string emitC() override {
|
|
return widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%lw, %P, %li, %ri)"
|
|
: isWide() ? "VL_SEL_%nq%lq%rq%tq(%nw,%lw, %P, %li, %ri, %ti)"
|
|
: "VL_SEL_%nq%lq%rq%tq(%lw, %P, %li, %ri, %ti)";
|
|
}
|
|
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 sizeMattersLhs() const override { return false; }
|
|
bool sizeMattersRhs() const override { return false; }
|
|
bool sizeMattersThs() const override { return false; }
|
|
bool same(const AstNode*) const override { return true; }
|
|
int instrCount() const override { return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); }
|
|
int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); }
|
|
int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); }
|
|
int msbConst() const { return lsbConst() + widthConst() - 1; }
|
|
VNumRange& declRange() { return m_declRange; }
|
|
const VNumRange& declRange() const { return m_declRange; }
|
|
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
|
int declElWidth() const { return m_declElWidth; }
|
|
void declElWidth(int flag) { m_declElWidth = flag; }
|
|
};
|
|
class AstSliceSel final : public AstNodeTriop {
|
|
// Multiple array element extraction
|
|
// @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)
|
|
: 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 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 same(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() { return m_declRange; }
|
|
const VNumRange& declRange() const { return m_declRange; }
|
|
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
|
};
|
|
class AstSubstrN final : public AstNodeTriop {
|
|
// Verilog string.substr()
|
|
public:
|
|
AstSubstrN(FileLine* fl, 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 { 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; }
|
|
};
|
|
|
|
// === AstNodeCond ===
|
|
class AstCond final : public AstNodeCond {
|
|
// Conditional ?: expression
|
|
public:
|
|
AstCond(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
|
|
: ASTGEN_SUPER_Cond(fl, condp, thenp, elsep) {}
|
|
ASTGEN_MEMBERS_AstCond;
|
|
AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) override {
|
|
return new AstCond{fileline(), condp, thenp, elsep};
|
|
}
|
|
};
|
|
class AstCondBound final : public AstNodeCond {
|
|
// Conditional ?: expression, specially made for safety checking of array bounds
|
|
public:
|
|
AstCondBound(FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep)
|
|
: ASTGEN_SUPER_CondBound(fl, condp, thenp, elsep) {}
|
|
ASTGEN_MEMBERS_AstCondBound;
|
|
AstNodeExpr* cloneType(AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) override {
|
|
return new AstCondBound{fileline(), condp, thenp, elsep};
|
|
}
|
|
};
|
|
|
|
// === 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 {
|
|
switch (m_fmt) {
|
|
case ATOI: return "atoi";
|
|
case ATOHEX: return "atohex";
|
|
case ATOOCT: return "atooct";
|
|
case ATOBIN: return "atobin";
|
|
case ATOREAL: return "atoreal";
|
|
}
|
|
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())";
|
|
}
|
|
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; }
|
|
};
|
|
class AstCAwait final : public AstNodeUniop {
|
|
// Emit C++'s co_await expression
|
|
// @astgen alias op1 := exprp
|
|
AstSenTree* m_sensesp; // Sentree related to this await
|
|
public:
|
|
AstCAwait(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sensesp = nullptr)
|
|
: ASTGEN_SUPER_CAwait(fl, exprp)
|
|
, m_sensesp{sensesp} {}
|
|
ASTGEN_MEMBERS_AstCAwait;
|
|
bool isTimingControl() const override { return true; }
|
|
const char* broken() const override;
|
|
void cloneRelink() override;
|
|
void dump(std::ostream& str) const override;
|
|
AstSenTree* sensesp() const { return m_sensesp; }
|
|
void clearSensesp() { m_sensesp = 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);
|
|
}
|
|
}
|
|
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 same(const AstNode* samep) const override {
|
|
return size() == static_cast<const AstCCast*>(samep)->size();
|
|
}
|
|
void dump(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; }
|
|
};
|
|
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; }
|
|
};
|
|
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 { return "%f$_CAST(%l)"; }
|
|
string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; }
|
|
bool cleanOut() const override { return true; }
|
|
bool cleanLhs() const override { return true; }
|
|
bool sizeMattersLhs() const override { return false; }
|
|
bool same(const AstNode* /*samep*/) const override { return true; }
|
|
};
|
|
class AstExtend final : public AstNodeUniop {
|
|
// Expand a value into a wider entity by 0 extension. Width is implied from nodep->width()
|
|
public:
|
|
AstExtend(FileLine* fl, 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)"; }
|
|
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)"; }
|
|
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; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
AstNode* filep() const { return lhsp(); }
|
|
};
|
|
class AstFGetC final : public AstNodeUniop {
|
|
public:
|
|
AstFGetC(FileLine* fl, 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; }
|
|
bool isPredictOptimizable() const override { return false; }
|
|
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
|
AstNode* filep() const { return lhsp(); }
|
|
};
|
|
class AstISToRD final : public AstNodeUniop {
|
|
// $itor where lhs is signed
|
|
public:
|
|
AstISToRD(FileLine* fl, 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; }
|
|
};
|
|
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; }
|
|
};
|
|
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; }
|
|
};
|
|
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; }
|
|
};
|
|
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 emitSimpleOperator() override { return "!"; }
|
|
bool cleanOut() const override { return true; }
|
|
bool cleanLhs() const override { return true; }
|
|
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 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 emitSimpleOperator() override { return "~"; }
|
|
bool cleanOut() const override { return false; }
|
|
bool cleanLhs() const override { return false; }
|
|
bool sizeMattersLhs() const override { return true; }
|
|
};
|
|
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 same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
|
};
|
|
class AstOneHot final : public AstNodeUniop {
|
|
// True if only single bit set in vector
|
|
public:
|
|
AstOneHot(FileLine* fl, 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; }
|
|
};
|
|
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; }
|
|
};
|
|
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; }
|
|
};
|
|
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; }
|
|
};
|
|
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; }
|
|
};
|
|
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 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; }
|
|
};
|
|
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 timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
|
VTimescale timeunit() const { return m_timeunit; }
|
|
};
|
|
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 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; }
|
|
};
|
|
|
|
// === 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)
|
|
public:
|
|
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
|
|
: ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {}
|
|
// This form only allowed post-link because output/wire compression may
|
|
// lead to deletion of AstVar's
|
|
inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access);
|
|
// This form only allowed post-link (see above)
|
|
inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access);
|
|
ASTGEN_MEMBERS_AstVarRef;
|
|
void dump(std::ostream& str) const override;
|
|
bool same(const AstNode* samep) const override;
|
|
inline bool same(const AstVarRef* samep) const;
|
|
inline bool sameNoLvalue(AstVarRef* samep) const;
|
|
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_dotted; // Dotted part of scope the name()'ed reference is under or ""
|
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
|
public:
|
|
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
|
|
: ASTGEN_SUPER_VarXRef(fl, name, nullptr, access)
|
|
, m_dotted{dotted} {}
|
|
inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access);
|
|
ASTGEN_MEMBERS_AstVarXRef;
|
|
void dump(std::ostream& str) const override;
|
|
string dotted() const { return m_dotted; }
|
|
void dotted(const string& dotted) { m_dotted = dotted; }
|
|
string inlinedDots() const { return m_inlinedDots; }
|
|
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
|
|
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 same(const AstNode* samep) const override {
|
|
const AstVarXRef* asamep = static_cast<const AstVarXRef*>(samep);
|
|
return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp()
|
|
&& name() == asamep->name() && dotted() == asamep->dotted());
|
|
}
|
|
};
|
|
|
|
#endif // Guard
|