// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Ast node structure // // Code available from: http://www.veripool.org/verilator // //************************************************************************* // // Copyright 2003-2013 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. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* #ifndef _V3ASTNODES_H_ #define _V3ASTNODES_H_ 1 #ifndef _V3AST_H_ #error "Use V3Ast.h as the include" #endif //###################################################################### // Standard defines for all AstNode final classes #define ASTNODE_NODE_FUNCS(name,ucname) \ virtual ~Ast ##name() {} \ virtual AstType type() const { return AstType::at ##ucname; } \ virtual AstNode* clone() { return new Ast ##name (*this); } \ virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } \ Ast ##name * cloneTree(bool cloneNext) { return AstNode::cloneTree(cloneNext)->cast ##name(); } //###################################################################### //=== Ast* : Specific types // Netlist interconnect struct AstConst : public AstNodeMath { // A constant private: V3Number m_num; // Constant value public: AstConst(FileLine* fl, const V3Number& num) :AstNodeMath(fl) ,m_num(num) { if (m_num.isDouble()) { dtypeSetDouble(); } else { dtypeSetLogicSized(m_num.width(), m_num.sized()?0:m_num.widthMin(), m_num.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED); } } AstConst(FileLine* fl, uint32_t num) :AstNodeMath(fl) ,m_num(V3Number(fl,32,num)) { dtypeSetLogicSized(m_num.width(), m_num.sized()?0:m_num.widthMin(), AstNumeric::UNSIGNED); } class Unsized32 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value :AstNodeMath(fl) ,m_num(V3Number(fl,32,num)) { m_num.width(32,false); dtypeSetLogicSized(32,m_num.widthMin(), AstNumeric::UNSIGNED); } class RealDouble {}; // for creator type-overload selection AstConst(FileLine* fl, RealDouble, double num) :AstNodeMath(fl) ,m_num(V3Number(fl,64)) { m_num.setDouble(num); dtypeSetDouble(); } class LogicFalse {}; AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, know the dtype should be a logic of size 1 :AstNodeMath(fl) ,m_num(V3Number(fl,1,0)) { dtypeSetLogicBool(); } class LogicTrue {}; AstConst(FileLine* fl, LogicTrue) // Shorthand const 1, know the dtype should be a logic of size 1 :AstNodeMath(fl) ,m_num(V3Number(fl,1,1)) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Const, CONST) virtual string name() const { return num().ascii(); } // * = Value virtual const V3Number& num() const { return m_num; } // * = Value uint32_t toUInt() const { return num().toUInt(); } vlsint32_t toSInt() const { return num().toSInt(); } vluint64_t toUQuad() const { return num().toUQuad(); } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } virtual V3Hash sameHash() const { return V3Hash(num().toHash()); } virtual bool same(AstNode* samep) const { return num().isCaseEq(samep->castConst()->num()); } virtual int instrCount() const { return widthInstrs(); } bool isEqAllOnes() const { return num().isEqAllOnes(width()); } bool isEqAllOnesV() const { return num().isEqAllOnes(widthMin()); } }; struct AstConstString : public AstNodeMath { // A constant string private: string m_name; public: AstConstString(FileLine* fl, const string& name) : AstNodeMath(fl), m_name(name) { rewidth(); } void rewidth() { if (m_name.length()==0) { dtypeSetLogicSized(1,1,AstNumeric::UNSIGNED); // 0 width isn't allowed due to historic special cases } else { dtypeSetLogicSized(((int)m_name.length())*8, ((int)m_name.length())*8, AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(ConstString, CONSTSTRING) virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } virtual V3Hash sameHash() const { return V3Hash(name()); } virtual bool same(AstNode* samep) const { return name()==samep->castConstString()->name(); } virtual int instrCount() const { return 2; } // C just loads a pointer virtual string name() const { return m_name; } void name(const string& flag) { m_name = flag; rewidth(); } }; struct AstRange : public AstNode { // Range specification, for use under variables and cells private: bool m_littleEndian:1; // Bit vector is little endian public: AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp) :AstNode(fl) { m_littleEndian = false; setOp2p(msbp); setOp3p(lsbp); } AstRange(FileLine* fl, int msb, int lsb) :AstNode(fl) { m_littleEndian = false; setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb)); } ASTNODE_NODE_FUNCS(Range, RANGE) AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression AstNode* leftp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration AstNode* rightp() const { return littleEndian()?msbp():lsbp(); } int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); } int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); } int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; } bool littleEndian() const { return m_littleEndian; } void littleEndian(bool flag) { m_littleEndian=flag; } virtual void dump(ostream& str); virtual string emitC() { V3ERROR_NA; return ""; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; //###################################################################### //==== Data Types struct AstTypedef : public AstNode { private: string m_name; public: AstTypedef(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) : AstNode(fl), m_name(name) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve } ASTNODE_NODE_FUNCS(Typedef, TYPEDEF) AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } // METHODS virtual string name() const { return m_name; } virtual bool maybePointedTo() const { return true; } virtual bool hasDType() const { return true; } void name(const string& flag) { m_name = flag; } }; struct AstTypedefFwd : public AstNode { // Forward declaration of a type; stripped after netlist parsing is complete private: string m_name; public: AstTypedefFwd(FileLine* fl, const string& name) : AstNode(fl), m_name(name) {} ASTNODE_NODE_FUNCS(TypedefFwd, TYPEDEFFWD) // METHODS virtual string name() const { return m_name; } }; struct AstDefImplicitDType : public AstNodeDType { // For parsing enum/struct/unions that are declared with a variable rather than typedef // This allows "var enum {...} a,b" to share the enum definition for both variables // After link, these become typedefs private: string m_name; void* m_containerp; // In what scope is the name unique, so we can know what are duplicate definitions (arbitrary value) int m_uniqueNum; public: AstDefImplicitDType(FileLine* fl, const string& name, AstNode* containerp, VFlagChildDType, AstNodeDType* dtp) : AstNodeDType(fl), m_name(name), m_containerp(containerp) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(DefImplicitDType, DEFIMPLICITDTYPE) virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } void* containerp() const { return m_containerp; } // METHODS AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); } virtual string name() const { return m_name; } void name(const string& flag) { m_name = flag; } }; struct AstArrayDType : public AstNodeDType { // Array data type, ie "some_dtype var_name [2:0]" // Children: DTYPE (moved to refDTypep() in V3Width) // Children: RANGE (array bounds) private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) bool m_packed; public: AstArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep, bool isPacked=false) : AstNodeDType(fl), m_packed(isPacked) { childDTypep(dtp); // Only for parser refDTypep(NULL); setOp2p(rangep); dtypep(NULL); // V3Width will resolve widthFromSub(subDTypep()); } AstArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep, bool isPacked=false) : AstNodeDType(fl), m_packed(isPacked) { refDTypep(dtp); setOp2p(rangep); dtypep(this); widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE) virtual void dump(ostream& str); virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep())); } virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep()->castNodeDType(); }} virtual bool same(AstNode* samep) const { AstArrayDType* sp = samep->castArrayDType(); return (m_packed==sp->m_packed && msb()==sp->msb() && subDTypep()==sp->subDTypep() && rangep()->sameTree(sp->rangep())); } // HashedDT doesn't recurse, so need to check children virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } AstRange* rangep() const { return op2p()->castRange(); } // op2 = Array(s) of variable void rangep(AstRange* nodep) { setOp2p(nodep); } // METHODS virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); } int msb() const { return rangep()->msbConst(); } int lsb() const { return rangep()->lsbConst(); } int elementsConst() const { return rangep()->elementsConst(); } int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index bool isPacked() const { return m_packed; } }; struct AstBasicDType : public AstNodeDType { // Builtin atomic/vectored data type // Children: RANGE (converted to constant in V3Width) private: struct Members { AstBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) bool operator== (const Members& rhs) const { return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; } } m; // See also in AstNodeDtype: m_width, m_widthMin, m_numeric(issigned) public: AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSignedState signst=signedst_NOSIGN) : AstNodeDType(fl) { init(kwd, AstNumeric(signst), 0, -1, NULL); } AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) : AstNodeDType(fl) { init(AstBasicDTypeKwd::LOGIC, AstNumeric::NOSIGN, wantwidth, -1, NULL); } AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) : AstNodeDType(fl) { init(AstBasicDTypeKwd::BIT, AstNumeric::NOSIGN, wantwidth, -1, NULL); } AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, int widthmin) : AstNodeDType(fl) { init(kwd, numer, wantwidth, widthmin, NULL); } // See also addRange in verilog.y private: void init(AstBasicDTypeKwd kwd, AstNumeric numer, int wantwidth, int wantwidthmin, AstRange* rangep) { // wantwidth=0 means figure it out, but if a widthmin is >=0 // we allow width 0 so that {{0{x}},y} works properly // wantwidthmin=-1: default, use wantwidth if it is non zero m.m_keyword = kwd; // Implicitness: // "parameter X" is implicit and sized from initial value, "parameter reg x" not if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) { if (rangep || wantwidth) m.m_keyword = AstBasicDTypeKwd::LOGIC; } if (numer == AstNumeric::NOSIGN) { if (keyword().isSigned()) numer = AstNumeric::SIGNED; else if (keyword().isUnsigned()) numer = AstNumeric::UNSIGNED; } numeric(numer); if (!rangep && (wantwidth || wantwidthmin>=0)) { // Constant width if (wantwidth>1) m.m_nrange.init(wantwidth-1, 0, false); int wmin = wantwidthmin>=0 ? wantwidthmin : wantwidth; widthForce(wantwidth, wmin); } else if (!rangep) { // Set based on keyword properties // V3Width will pull from this width if (keyword().width() > 1 && !isOpaque()) { m.m_nrange.init(keyword().width()-1, 0, false); } widthForce(keyword().width(), keyword().width()); } else { widthForce(rangep->elementsConst(), rangep->elementsConst()); // Maybe unknown if parameters underneath it } setNOp1p(rangep); dtypep(this); } public: ASTNODE_NODE_FUNCS(BasicDType, BASICDTYPE) virtual void dump(ostream& str); virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.msb())); } virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere return samep->castBasicDType()->m == m; } virtual string name() const { return m.m_keyword.ascii(); } virtual bool broken() const { return dtypep()!=this; } AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable void rangep(AstRange* nodep) { setNOp1p(nodep); } void setSignedState(VSignedState signst) { // Note NOSIGN does NOT change the state; this is required by the parser if (signst==signedst_UNSIGNED) numeric(VSignedState(signst)); else if (signst==signedst_SIGNED) numeric(VSignedState(signst)); } // METHODS virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead bool isBitLogic() const { return keyword().isBitLogic(); } bool isDouble() const { return keyword().isDouble(); } bool isOpaque() const { return keyword().isOpaque(); } bool isSloppy() const { return keyword().isSloppy(); } bool isZeroInit() const { return keyword().isZeroInit(); } bool isRanged() const { return rangep() || m.m_nrange.ranged(); } const VNumRange& nrange() const { return m.m_nrange; } // Generally the msb/lsb/etc funcs should be used instead int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.msb()); } int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lsb()); } int left() const { return littleEndian()?lsb():msb(); } // How to show a declaration int right() const { return littleEndian()?msb():lsb(); } int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index bool littleEndian() const { return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); } bool implicit() const { return keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT; } void cvtRangeConst() { // Convert to smaller represenation if (rangep() && rangep()->msbp()->castConst() && rangep()->lsbp()->castConst()) { m.m_nrange.init(rangep()->msbConst(), rangep()->lsbConst(), rangep()->littleEndian()); rangep()->unlinkFrBackWithNext()->deleteTree(); rangep(NULL); } } }; struct AstConstDType : public AstNodeDType { // const data type, ie "const some_dtype var_name [2:0]" // ConstDType are removed in V3LinkLValue and become AstVar::isConst. // When more generic types are supported AstConstDType will be propagated further. private: AstNodeDType* m_refDTypep; // Inherit from this base data type public: AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) : AstNodeDType(fl) { childDTypep(dtp); // Only for parser refDTypep(NULL); // V3Width will resolve dtypep(NULL); // V3Width will resolve widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE) virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep())); } virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep()->castNodeDType(); }} virtual bool same(AstNode* samep) const { return (m_refDTypep==samep->castConstDType()->m_refDTypep); } virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // METHODS virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; struct AstRefDType : public AstNodeDType { private: AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef string m_name; // Name of an AstTypedef AstPackage* m_packagep; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) : AstNodeDType(fl), m_refDTypep(NULL), m_name(name), m_packagep(NULL) {} AstRefDType(FileLine* fl, AstNodeDType* defp) : AstNodeDType(fl), m_refDTypep(defp), m_packagep(NULL) { dtypeFrom(defp->dtypep()); widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(RefDType, REFDTYPE) // METHODS virtual bool broken() const { return m_refDTypep && !m_refDTypep->brokeExists(); } virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep()->castNodeDType(); }} virtual bool same(AstNode* samep) const { return (m_refDTypep==samep->castRefDType()->m_refDTypep && m_name==samep->castRefDType()->m_name && m_packagep==samep->castRefDType()->m_packagep); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(m_packagep)); } virtual void dump(ostream& str=cout); virtual string name() const { return m_name; } virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; } virtual AstNodeDType* skipRefp() const { // Skip past both the Ref and the Typedef if (defp()) return defp()->skipRefp(); else { v3fatalSrc("Typedef not linked"); return NULL; } } virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); } virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); } void name(const string& flag) { m_name = flag; } AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); } // op1 = Range of variable AstNodeDType* defp() const { return m_refDTypep; } // Code backward compatibility name for refDTypep AstNodeDType* refDTypep() const { return m_refDTypep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep=nodep; } virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } AstNodeDType* subDTypep() const { return m_refDTypep; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep=nodep; } }; struct AstStructDType : public AstNodeClassDType { AstStructDType(FileLine* fl, AstNumeric numericUnpack) : AstNodeClassDType(fl,numericUnpack) {} ASTNODE_NODE_FUNCS(StructDType, STRUCTDTYPE) virtual string verilogKwd() const { return "struct"; }; }; struct AstUnionDType : public AstNodeClassDType { //UNSUP: bool isTagged; AstUnionDType(FileLine* fl, AstNumeric numericUnpack) : AstNodeClassDType(fl,numericUnpack) {} ASTNODE_NODE_FUNCS(UnionDType, UNIONDTYPE) virtual string verilogKwd() const { return "union"; }; }; struct AstMemberDType : public AstNodeDType { // A member of a struct/union // PARENT: AstClassDType private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) string m_name; // Name of variable int m_lsb; // Within this level's packed struct, the LSB of the first bit of the member //UNSUP: int m_randType; // Randomization type (IEEE) public: AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) : AstNodeDType(fl) , m_name(name), m_lsb(-1) { childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve refDTypep(NULL); } AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) : AstNodeDType(fl) , m_name(name), m_lsb(-1) { UASSERT(dtp,"AstMember created with no dtype"); refDTypep(dtp); dtypep(this); widthFromSub(subDTypep()); } ASTNODE_NODE_FUNCS(MemberDType, MEMBERDTYPE) virtual string name() const { return m_name; } // * = Var name virtual bool hasDType() const { return true; } virtual bool maybePointedTo() const { return true; } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } // virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType) AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) virtual AstNodeDType* skipRefp() const { return dtypeSkipRefp(); } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... // METHODS virtual void name(const string& name) { m_name = name; } int lsb() const { return m_lsb; } void lsb(int lsb) { m_lsb=lsb; } }; struct AstEnumItem : public AstNode { private: string m_name; public: // Parents: ENUM AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) : AstNode(fl), m_name(name) { addNOp1p(rangep); addNOp2p(initp); } ASTNODE_NODE_FUNCS(EnumItem, ENUMITEM) virtual string name() const { return m_name; } virtual bool maybePointedTo() const { return true; } virtual bool hasDType() const { return true; } void name(const string& flag) { m_name = flag; } AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range for name appending void rangep(AstNode* nodep) { addOp1p(nodep); } AstNode* valuep() const { return op2p(); } // op2 = Value void valuep(AstNode* nodep) { addOp2p(nodep); } }; struct AstEnumItemRef : public AstNodeMath { private: AstEnumItem* m_itemp; // [AfterLink] Pointer to item AstPackage* m_packagep; // Package hierarchy public: AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstPackage* packagep) : AstNodeMath(fl), m_itemp(itemp), m_packagep(packagep) { dtypeFrom(m_itemp); } ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF) virtual void dump(ostream& str); virtual string name() const { return itemp()->name(); } virtual bool broken() const { return !itemp(); } virtual int instrCount() const { return 0; } virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); } virtual bool same(AstNode* samep) const { return itemp()==samep->castEnumItemRef()->itemp(); } AstEnumItem* itemp() const { return m_itemp; } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep=nodep; } }; struct AstEnumDType : public AstNodeDType { // Parents: TYPEDEF/MODULE // Children: ENUMVALUEs private: AstNodeDType* m_refDTypep; // Elements are of this type after V3Width int m_uniqueNum; public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) : AstNodeDType(fl) { childDTypep(dtp); // Only for parser refDTypep(NULL); addNOp2p(itemsp); dtypep(NULL); // V3Width will resolve widthFromSub(subDTypep()); m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE) virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) || (!m_refDTypep && childDTypep())); } virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep()->castNodeDType(); }} virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castEnumDType()->m_uniqueNum; } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } // op1 = Range of variable void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } AstEnumItem* itemsp() const { return op2p()->castEnumItem(); } // op2 = AstEnumItem's void addValuesp(AstNode* nodep) { addOp2p(nodep); } // METHODS virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; //###################################################################### struct AstArraySel : public AstNodeSel { // Parents: math|stmt // Children: varref|arraysel, math private: unsigned m_start; unsigned m_length; void init(AstNode* fromp) { if (fromp && fromp->dtypep()->castArrayDType()) { // Strip off array to find what array references dtypeFrom(fromp->dtypep()->castArrayDType()->subDTypep()); } } public: AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) :AstNodeSel(fl, fromp, bitp), m_start(0), m_length(1) { init(fromp); } AstArraySel(FileLine* fl, AstNode* fromp, int bit) :AstNodeSel(fl, fromp, new AstConst(fl,bit)), m_start(0), m_length(1) { init(fromp); } ASTNODE_NODE_FUNCS(ArraySel, ARRAYSEL) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; /* How can from be a const? */ } virtual string emitVerilog() { return "%k(%l%f[%r])"; } virtual string emitC() { return "%li%k[%ri]"; } virtual bool cleanOut() { return true; } virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } unsigned length() const { return m_length; } void length(unsigned length) { m_length = length; } void start(unsigned start) { m_start = start; } unsigned start() const { return m_start; } // Special operators static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable? static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? virtual void dump(ostream& str); }; struct AstWordSel : public AstNodeSel { // Select a single word from a multi-word wide value AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) :AstNodeSel(fl, fromp, bitp) { dtypeSetUInt32(); // Always used on IData arrays so returns word entities } ASTNODE_NODE_FUNCS(WordSel, WORDSEL) virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) { V3ERROR_NA; } virtual string emitVerilog() { return "%k(%l%f[%r])"; } virtual string emitC() { return "%li[%ri]"; } // Not %k, as usually it's a small constant rhsp virtual bool cleanOut() { return true; } virtual bool cleanLhs() { return true; } virtual bool cleanRhs() { return true; } virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstSelExtract : public AstNodePreSel { // Range extraction, gets replaced with AstSel AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) : AstNodePreSel(fl, fromp, msbp, lsbp) {} ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT) AstNode* msbp() const { return rhsp(); } AstNode* lsbp() const { return thsp(); } }; struct AstSelBit : public AstNodePreSel { // Single bit range extraction, perhaps with non-constant selection or array selection // Gets replaced during link with AstArraySel or AstSel AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) :AstNodePreSel(fl, fromp, bitp, NULL) { if (v3Global.assertDTypesResolved()) { v3fatalSrc("not coded to create after dtypes resolved"); } } ASTNODE_NODE_FUNCS(SelBit, SELBIT) AstNode* bitp() const { return rhsp(); } }; struct AstSelPlus : public AstNodePreSel { // +: range extraction, perhaps with non-constant selection // Gets replaced during link with AstSel AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) :AstNodePreSel(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelPlus, SELPLUS) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } }; struct AstSelMinus : public AstNodePreSel { // -: range extraction, perhaps with non-constant selection // Gets replaced during link with AstSel AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) :AstNodePreSel(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelMinus, SELMINUS) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } }; struct AstSel : public AstNodeTriop { // Multiple bit range extraction // Parents: math|stmt // Children: varref|arraysel, math, constant math AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) :AstNodeTriop(fl, fromp, lsbp, widthp) { if (widthp->castConst()) { dtypeSetLogicSized(widthp->castConst()->toUInt(), widthp->castConst()->toUInt(), AstNumeric::UNSIGNED); } } AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) :AstNodeTriop(fl, fromp, new AstConst(fl,lsb), new AstConst(fl,bitwidth)) { dtypeSetLogicSized(bitwidth,bitwidth,AstNumeric::UNSIGNED); } ASTNODE_NODE_FUNCS(Sel, SEL) virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) { out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { return this->widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri)" : "VL_SEL_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)"; } virtual bool cleanOut() { return false; } virtual bool cleanLhs() { return true;} virtual bool cleanRhs() {return true;} virtual bool cleanThs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool sizeMattersThs() {return false;} virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode*) const { return true; } virtual int instrCount() const { return widthInstrs()*(lsbp()->castConst()?3:10); } AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing) AstNode* lsbp() const { return op2p()->castNode(); } // op2 = Msb selection expression AstNode* widthp() const { return op3p()->castNode(); } // op3 = Width int widthConst() const { return widthp()->castConst()->toSInt(); } int lsbConst() const { return lsbp()->castConst()->toSInt(); } int msbConst() const { return lsbConst()+widthConst()-1; } }; struct AstMemberSel : public AstNodeMath { // Parents: math|stmt // Children: varref|arraysel, math private: // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it string m_name; public: AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) : AstNodeMath(fl), m_name(name) { setOp1p(fromp); dtypep(NULL); // V3Width will resolve } AstMemberSel(FileLine* fl, AstNode* fromp, AstMemberDType* dtp) : AstNodeMath(fl) { setOp1p(fromp); dtypep(dtp); m_name = dtp->name(); } ASTNODE_NODE_FUNCS(MemberSel, MEMBERSEL) virtual string name() const { return m_name; } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; /* How can from be a const? */ } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return false; } virtual bool same(AstNode* samep) const { return true; } // dtype comparison does it all for us virtual int instrCount() const { return widthInstrs(); } AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing) void fromp(AstNode* nodep) { setOp1p(nodep); } }; struct AstVar : public AstNode { // A variable (in/out/wire/reg/param) inside a module private: string m_name; // Name of variable AstVarType m_varType; // Type of variable bool m_input:1; // Input or inout bool m_output:1; // Output or inout bool m_tristate:1; // Inout or triwire or trireg bool m_declOutput:1; // Inout or output before tristate resolution bool m_primaryIO:1; // In/out to top level (or directly assigned from same) bool m_sc:1; // SystemC variable bool m_scClocked:1; // SystemC sc_clk<> needed bool m_scSensitive:1;// SystemC sensitive() needed bool m_sigPublic:1; // User C code accesses this signal or is top signal bool m_sigModPublic:1;// User C code accesses this signal and module bool m_sigUserRdPublic:1; // User C code accesses this signal, read only bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write bool m_usedClock:1; // Signal used as a clock bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) bool m_usedLoopIdx:1; // Variable subject of for unrolling bool m_funcLocal:1; // Local variable for a function bool m_funcReturn:1; // Return variable for a function bool m_attrClockEn:1;// User clock enable attribute bool m_attrScBv:1; // User force bit vector attribute bool m_attrIsolateAssign:1;// User isolate_assignments attribute bool m_attrSFormat:1;// User sformat attribute bool m_fileDescr:1; // File descriptor bool m_isConst:1; // Table contains constant data bool m_isStatic:1; // Static variable bool m_isPulldown:1; // Tri0 bool m_isPullup:1; // Tri1 bool m_trace:1; // Trace this variable void init() { m_input=false; m_output=false; m_tristate=false; m_declOutput=false; m_primaryIO=false; m_sc=false; m_scClocked=false; m_scSensitive=false; m_usedClock=false; m_usedParam=false; m_usedLoopIdx=false; m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false; m_funcLocal=false; m_funcReturn=false; m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false; m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false; m_trace=false; } public: AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) :AstNode(fl) , m_name(name) { init(); combineType(type); childDTypep(dtp); // Only for parser dtypep(NULL); // V3Width will resolve } AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp) :AstNode(fl) , m_name(name) { init(); combineType(type); UASSERT(dtp,"AstVar created with no dtype"); dtypep(dtp); } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth) :AstNode(fl) , m_name(name) { init(); combineType(type); dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED); } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth) :AstNode(fl) , m_name(name) { init(); combineType(type); dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED); } AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) :AstNode(fl) , m_name(name) { init(); combineType(type); if (examplep->childDTypep()) { childDTypep(examplep->childDTypep()->cloneTree(true)); } dtypeFrom(examplep); } ASTNODE_NODE_FUNCS(Var, VAR) virtual void dump(ostream& str); virtual string name() const { return m_name; } // * = Var name virtual bool hasDType() const { return true; } virtual bool maybePointedTo() const { return true; } AstVarType varType() const { return m_varType; } // * = Type of variable void varType2Out() { m_tristate=0; m_input=0; m_output=1; } void varType2In() { m_tristate=0; m_input=1; m_output=0; } string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc void combineType(AstVarType type); AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType) AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const) void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse bool hasSimpleInit() const { return (op3p() && !op3p()->castInitArray()); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } void attrClockEn(bool flag) { m_attrClockEn = flag; } void attrFileDescr(bool flag) { m_fileDescr = flag; } void attrScClocked(bool flag) { m_scClocked = flag; } void attrScBv(bool flag) { m_attrScBv = flag; } void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } void attrSFormat(bool flag) { m_attrSFormat = flag; } void usedClock(bool flag) { m_usedClock = flag; } void usedParam(bool flag) { m_usedParam = flag; } void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } void sigPublic(bool flag) { m_sigPublic = flag; } void sigModPublic(bool flag) { m_sigModPublic = flag; } void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); } void sigUserRWPublic(bool flag) { m_sigUserRWPublic = flag; if (flag) sigUserRdPublic(true); } void sc(bool flag) { m_sc = flag; } void scSensitive(bool flag) { m_scSensitive = flag; } void primaryIO(bool flag) { m_primaryIO = flag; } void isConst(bool flag) { m_isConst = flag; } void isStatic(bool flag) { m_isStatic = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } void trace(bool flag) { m_trace=flag; } // METHODS virtual void name(const string& name) { m_name = name; } bool isInput() const { return m_input; } bool isOutput() const { return m_output; } bool isInOnly() const { return m_input && !m_output; } bool isOutOnly() const { return m_output && !m_input; } bool isInout() const { return m_input && m_output; } bool isTristate() const { return m_tristate; } bool isDeclOutput() const { return m_declOutput; } bool isPrimaryIO() const { return m_primaryIO; } bool isPrimaryIn() const { return isPrimaryIO() && isInput(); } bool isIO() const { return (m_input||m_output); } bool isSignal() const { return varType().isSignal(); } bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP || varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); } bool isToggleCoverable() const { return ((isIO() || isSignal()) && (isIO() || isBitLogic()) // Wrapper would otherwise duplicate wrapped module's coverage && !isSc() && !isPrimaryIO() && !isConst()); } bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); } bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); } bool isXTemp() const { return (varType()==AstVarType::XTEMP); } bool isParam() const { return (varType()==AstVarType::LPARAM || varType()==AstVarType::GPARAM); } bool isGParam() const { return (varType()==AstVarType::GPARAM); } bool isGenVar() const { return (varType()==AstVarType::GENVAR); } bool isBitLogic() const { AstBasicDType* bdtypep = basicp(); return bdtypep && bdtypep->isBitLogic(); } bool isUsedClock() const { return m_usedClock; } bool isUsedParam() const { return m_usedParam; } bool isUsedLoopIdx() const { return m_usedLoopIdx; } bool isSc() const { return m_sc; } bool isScQuad() const; bool isScBv() const; bool isScSensitive() const { return m_scSensitive; } bool isSigPublic() const; bool isSigModPublic() const { return m_sigModPublic; } bool isSigUserRdPublic() const { return m_sigUserRdPublic; } bool isSigUserRWPublic() const { return m_sigUserRWPublic; } bool isTrace() const { return m_trace; } bool isConst() const { return m_isConst; } bool isStatic() const { return m_isStatic; } bool isFuncLocal() const { return m_funcLocal; } bool isFuncReturn() const { return m_funcReturn; } bool isPullup() const { return m_isPullup; } bool isPulldown() const { return m_isPulldown; } bool attrClockEn() const { return m_attrClockEn; } bool attrScBv() const { return m_attrScBv; } bool attrFileDescr() const { return m_fileDescr; } bool attrScClocked() const { return m_scClocked; } bool attrSFormat() const { return m_attrSFormat; } bool attrIsolateAssign() const { return m_attrIsolateAssign; } virtual string verilogKwd() const; void propagateAttrFrom(AstVar* fromp) { // This is getting connected to fromp; keep attributes // Note the method below too if (fromp->attrClockEn()) attrClockEn(true); if (fromp->attrFileDescr()) attrFileDescr(true); if (fromp->attrIsolateAssign()) attrIsolateAssign(true); } bool gateMultiInputOptimizable() const { // Ok to gate optimize; must return false if propagateAttrFrom would do anything return (!attrClockEn() && !isUsedClock()); } void combineType(AstVar* typevarp) { // This is same as typevarp (for combining input & reg decls) propagateAttrFrom(typevarp); combineType(typevarp->varType()); if (typevarp->isSigPublic()) sigPublic(true); if (typevarp->isSigModPublic()) sigModPublic(true); if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true); if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true); if (typevarp->attrScClocked()) attrScClocked(true); } void inlineAttrReset(const string& name) { m_input=m_output=false; m_name = name; if (varType()==AstVarType::INOUT) m_varType = AstVarType::TRIWIRE; if (varType()==AstVarType::INPUT || varType()==AstVarType::OUTPUT) m_varType = AstVarType::WIRE; } }; struct AstDefParam : public AstNode { // A defparam assignment // Parents: MODULE // Children: math private: string m_name; // Name of variable getting set string m_path; // Dotted cellname to set parameter of public: AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) : AstNode(fl) { setOp1p(rhsp); m_name = name; m_path = path; } virtual string name() const { return m_name; } // * = Scope name ASTNODE_NODE_FUNCS(DefParam, DEFPARAM) virtual bool cleanRhs() { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode*) const { return true; } AstNode* rhsp() const { return op1p()->castNode(); } // op1 = Assign from string path() const { return m_path; } }; struct AstImplicit : public AstNode { // Create implicit wires and do nothing else, for gates that are ignored // Parents: MODULE AstImplicit(FileLine* fl, AstNode* exprsp) : AstNode(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(Implicit, IMPLICIT) AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Assign from }; struct AstScope : public AstNode { // A particular usage of a cell // Parents: MODULE // Children: NODEBLOCK private: // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope string m_name; // Name AstScope* m_aboveScopep; // Scope above this one in the hierarchy (NULL if top) AstCell* m_aboveCellp; // Cell above this in the hierarchy (NULL if top) AstNodeModule* m_modp; // Module scope corresponds to public: AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, AstCell* aboveCellp) :AstNode(fl) ,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {} ASTNODE_NODE_FUNCS(Scope, SCOPE) virtual void cloneRelink(); virtual bool broken() const; virtual bool maybePointedTo() const { return true; } virtual string name() const { return m_name; } // * = Scope name virtual void name(const string& name) { m_name = name; } string nameDotless() const; string nameVlSym() const { return (((string)"vlSymsp->") + nameDotless()); } AstNodeModule* modp() const { return m_modp; } void addVarp(AstNode* nodep) { addOp1p(nodep); } AstNode* varsp() const { return op1p()->castNode(); } // op1 = AstVarScope's void addActivep(AstNode* nodep) { addOp2p(nodep); } AstNode* blocksp() const { return op2p()->castNode(); } // op2 = Block names void addFinalClkp(AstNode* nodep) { addOp3p(nodep); } AstNode* finalClksp() const { return op3p()->castNode(); } // op3 = Final assigns for clock correction AstScope* aboveScopep() const { return m_aboveScopep; } AstCell* aboveCellp() const { return m_aboveCellp; } bool isTop() const { return aboveScopep()==NULL; } // At top of hierarchy }; struct AstTopScope : public AstNode { // In the top level netlist, a complete scope tree // There may be two of these, when we support "rare" and "usual" splitting // Parents: topMODULE // Children: SCOPEs AstTopScope(FileLine* fl, AstScope* ascopep) :AstNode(fl) {addNOp2p(ascopep);} ASTNODE_NODE_FUNCS(TopScope, TOPSCOPE) AstNode* stmtsp() const { return op1p()->castNode(); } void addStmtsp(AstNode* nodep) { addOp1p(nodep); } AstScope* scopep() const { return op2p()->castScope(); } // op1 = AstVarScope's }; struct AstVarScope : public AstNode { // A particular scoped usage of a variable // That is, as a module is used under multiple cells, we get a different varscope for each var in the module // Parents: MODULE // Children: none private: AstScope* m_scopep; // Scope variable is underneath AstVar* m_varp; // [AfterLink] Pointer to variable itself bool m_circular:1; // Used in circular ordering dependency, need change detect public: AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) :AstNode(fl) , m_scopep(scopep), m_varp(varp) { m_circular = false; dtypeFrom(varp); } ASTNODE_NODE_FUNCS(VarScope, VARSCOPE) virtual void cloneRelink() { if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep()->castVar(); UASSERT(m_scopep->clonep(), "No clone cross link: "<clonep()->castScope(); }} virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists()) || (m_scopep && !m_scopep->brokeExists())); } virtual bool maybePointedTo() const { return true; } virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name virtual void dump(ostream& str); virtual bool hasDType() const { return true; } AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under AstNode* valuep() const { return op1p(); } // op1 = Calculation of value of variable, NULL=complicated void valuep(AstNode* valuep) { addOp1p(valuep); } bool isCircular() const { return m_circular; } void circular(bool flag) { m_circular = flag; } }; struct AstVarRef : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) AstVarRef(FileLine* fl, const string& name, bool lvalue) :AstNodeVarRef(fl, name, NULL, lvalue) {} AstVarRef(FileLine* fl, AstVar* varp, bool lvalue) // This form only allowed post-link :AstNodeVarRef(fl, varp->name(), varp, lvalue) {} // because output/wire compression may lead to deletion of AstVar's AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue) // This form only allowed post-link :AstNodeVarRef(fl, varscp->varp()->name(), varscp->varp(), lvalue) { // because output/wire compression may lead to deletion of AstVar's varScopep(varscp); } ASTNODE_NODE_FUNCS(VarRef, VARREF) virtual void dump(ostream& str); virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()->name()),V3Hash(hiername())); } virtual bool same(AstNode* samep) const { return same(samep->castVarRef()); } inline bool same(AstVarRef* samep) const { if (varScopep()) return (varScopep()==samep->varScopep() && lvalue()==samep->lvalue()); else return (hiername()==samep->hiername() && varp()->name()==samep->varp()->name() && lvalue()==samep->lvalue()); } inline bool sameNoLvalue(AstVarRef* samep) const { if (varScopep()) return (varScopep()==samep->varScopep()); else return (hiername()==samep->hiername() && varp()->name()==samep->varp()->name()); } virtual int instrCount() const { return widthInstrs()*(lvalue()?1:instrCountLd()); } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } }; struct AstVarXRef : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope private: string m_dotted; // Scope name to connected to string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue) :AstNodeVarRef(fl, name, NULL, lvalue) , m_dotted(dotted) { } AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue) :AstNodeVarRef(fl, varp->name(), varp, lvalue) , m_dotted(dotted) { dtypeFrom(varp); } ASTNODE_NODE_FUNCS(VarXRef, VARXREF) virtual void dump(ostream& str); string dotted() const { return m_dotted; } string prettyDotted() const { return prettyName(dotted()); } string inlinedDots() const { return m_inlinedDots; } void inlinedDots(const string& flag) { m_inlinedDots = flag; } virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(varp()),V3Hash(dotted())); } virtual bool same(AstNode* samep) const { return (hiername()==samep->castVarXRef()->hiername() && varp()==samep->castVarXRef()->varp() && name()==samep->castVarXRef()->name() && dotted()==samep->castVarXRef()->dotted()); } }; struct AstPin : public AstNode { // A pin on a cell private: int m_pinNum; // Pin number string m_name; // Pin name, or "" for number based interconnect AstVar* m_modVarp; // Input/output this pin connects to on submodule. bool m_svImplicit; // Pin is SystemVerilog .name'ed public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) :AstNode(fl) ,m_name(name), m_svImplicit(false) { m_pinNum = pinNum; m_modVarp = NULL; setNOp1p(exprp); } AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) :AstNode(fl), m_svImplicit(false) { m_name = varname->name(); m_pinNum = pinNum; m_modVarp = NULL; setNOp1p(exprp); } ASTNODE_NODE_FUNCS(Pin, PIN) virtual void dump(ostream& str); virtual bool broken() const { return (m_modVarp && !m_modVarp->brokeExists()); } virtual string name() const { return m_name; } // * = Pin name, ""=go by number virtual void name(const string& name) { m_name = name; } bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked int pinNum() const { return m_pinNum; } void exprp(AstNode* nodep) { addOp1p(nodep); } AstNode* exprp() const { return op1p()->castNode(); } // op1 = Expression connected to pin, NULL if unconnected AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable void modVarp(AstVar* varp) { m_modVarp=varp; } bool svImplicit() const { return m_svImplicit; } void svImplicit(bool flag) { m_svImplicit=flag; } }; struct AstModule : public AstNodeModule { // A module declaration AstModule(FileLine* fl, const string& name) : AstNodeModule (fl,name) {} ASTNODE_NODE_FUNCS(Module, MODULE) virtual string verilogKwd() const { return "module"; } }; struct AstNotFoundModule : public AstNodeModule { // A missing module declaration AstNotFoundModule(FileLine* fl, const string& name) : AstNodeModule (fl,name) {} ASTNODE_NODE_FUNCS(NotFoundModule, NOTFOUNDMODULE) virtual string verilogKwd() const { return "/*not-found-*/ module"; } }; struct AstPackage : public AstNodeModule { // A package declaration AstPackage(FileLine* fl, const string& name) : AstNodeModule (fl,name) {} ASTNODE_NODE_FUNCS(Package, PACKAGE) virtual string verilogKwd() const { return "package"; } static string dollarUnitName() { return AstNode::encodeName("$unit"); } bool isDollarUnit() const { return name() == dollarUnitName(); } }; struct AstPrimitive : public AstNodeModule { // A primitive declaration AstPrimitive(FileLine* fl, const string& name) : AstNodeModule (fl,name) {} ASTNODE_NODE_FUNCS(Primitive, PRIMITIVE) virtual string verilogKwd() const { return "primitive"; } }; struct AstPackageImport : public AstNode { private: // A package import declaration string m_name; AstPackage* m_packagep; // Package hierarchy public: AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) : AstNode (fl), m_name(name), m_packagep(packagep) {} ASTNODE_NODE_FUNCS(PackageImport, PACKAGEIMPORT) virtual bool broken() const { return (!m_packagep || !m_packagep->brokeExists()); } virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep()->castPackage(); } virtual void dump(ostream& str); virtual string name() const { return m_name; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep=nodep; } }; struct AstCell : public AstNode { // A instantiation cell or interface call (don't know which until link) private: string m_name; // Cell name string m_origName; // Original name before dot addition string m_modName; // Module the cell instances AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced public: AstCell(FileLine* fl, const string& instName, const string& modName, AstPin* pinsp, AstPin* paramsp, AstRange* rangep) : AstNode(fl) , m_name(instName), m_origName(instName), m_modName(modName) , m_modp(NULL) { addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); } ASTNODE_NODE_FUNCS(Cell, CELL) // No cloneRelink, we presume cloneee's want the same module linkages virtual void dump(ostream& str); virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); } virtual bool maybePointedTo() const { return true; } // ACCESSORS virtual string name() const { return m_name; } // * = Cell name virtual void name(const string& name) { m_name = name; } string origName() const { return m_origName; } // * = Original name void origName(const string& name) { m_origName = name; } string modName() const { return m_modName; } // * = Instance name void modName(const string& name) { m_modName = name; } AstPin* pinsp() const { return op1p()->castPin(); } // op1 = List of cell ports AstPin* paramsp() const { return op2p()->castPin(); } // op2 = List of parameter #(##) values AstRange* rangep() const { return op3p()->castRange(); } // op3 = Range of arrayed instants (NULL=not ranged) AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated void addPinsp(AstPin* nodep) { addOp1p(nodep); } void addParamsp(AstPin* nodep) { addOp2p(nodep); } void modp(AstNodeModule* nodep) { m_modp = nodep; } }; struct AstCellInline : public AstNode { // A instantiation cell that was removed by inlining // For communication between V3Inline and V3LinkDot only // Children: When 2 levels inlined, other CellInline under this private: string m_name; // Cell name, possibly {a}__DOT__{b}... string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup public: AstCellInline(FileLine* fl, const string& name, const string& origModName) : AstNode(fl) , m_name(name), m_origModName(origModName) {} ASTNODE_NODE_FUNCS(CellInline, CELLINLINE) virtual void dump(ostream& str); // ACCESSORS virtual string name() const { return m_name; } // * = Cell name string origModName() const { return m_origModName; } // * = modp()->origName() before inlining virtual void name(const string& name) { m_name = name; } }; struct AstPort : public AstNode { // A port (in/out/inout) on a module private: int m_pinNum; // Pin number string m_name; // Name of pin public: AstPort(FileLine* fl, int pinnum, const string& name) :AstNode(fl) ,m_pinNum(pinnum) ,m_name(name) {} ASTNODE_NODE_FUNCS(Port, PORT) virtual string name() const { return m_name; } // * = Port name int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation AstNode* exprp() const { return op1p()->castNode(); } // op1 = Expression connected to port }; //###################################################################### struct AstGenerate : public AstNode { // A Generate/end block // Parents: MODULE // Children: modItems AstGenerate(FileLine* fileline, AstNode* stmtsp) : AstNode(fileline) { addNOp1p(stmtsp); } ASTNODE_NODE_FUNCS(Generate, GENERATE) // op1 = Statements AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements void addStmtp(AstNode* nodep) { addOp1p(nodep); } }; struct AstParseRef : public AstNode { // A reference to a variable, function or task // We don't know which at parse time due to bison constraints // The link stages will replace this with AstVarRef, or AstTaskRef, etc. // Parents: math|stmt // Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel) private: AstParseRefExp m_expect; // Type we think it should resolve to string m_name; public: AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp) :AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); } ASTNODE_NODE_FUNCS(ParseRef, PARSEREF) virtual void dump(ostream& str); virtual string name() const { return m_name; } // * = Var name virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect),V3Hash(m_name)); } virtual bool same(AstNode* samep) const { return (expect() == samep->castParseRef()->expect() && m_name==samep->castParseRef()->m_name); } virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual void name(const string& name) { m_name = name; } AstParseRefExp expect() const { return m_expect; } void expect(AstParseRefExp exp) { m_expect=exp; } // op1 = Components AstNode* lhsp() const { return op1p(); } // op1 = List of statements AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference }; struct AstPackageRef : public AstNode { private: AstPackage* m_packagep; // Package hierarchy public: AstPackageRef(FileLine* fl, AstPackage* packagep) : AstNode(fl), m_packagep(packagep) {} ASTNODE_NODE_FUNCS(PackageRef, PACKAGEREF) // METHODS virtual bool broken() const { return !m_packagep || !m_packagep->brokeExists(); } virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) { m_packagep = m_packagep->clonep()->castPackage(); }} virtual bool same(AstNode* samep) const { return (m_packagep==samep->castPackageRef()->m_packagep); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_packagep)); } virtual void dump(ostream& str=cout); AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep=nodep; } }; struct AstDot : public AstNode { // A dot separating paths in an AstXRef, AstFuncRef or AstTaskRef // These are eliminated in the link stage public: AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) :AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); } ASTNODE_NODE_FUNCS(Dot, DOT) static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package if (!packagep) return rhsp; return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp); } virtual void dump(ostream& str); virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } }; //###################################################################### struct AstTask : public AstNodeFTask { // A task inside a module AstTask(FileLine* fl, const string& name, AstNode* stmtp) :AstNodeFTask(fl, name, stmtp) {} ASTNODE_NODE_FUNCS(Task, TASK) }; struct AstFunc : public AstNodeFTask { // A function inside a module AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) :AstNodeFTask(fl, name, stmtp) { addNOp1p(fvarsp); } ASTNODE_NODE_FUNCS(Func, FUNC) virtual bool hasDType() const { return true; } }; struct AstTaskRef : public AstNodeFTaskRef { // A reference to a task AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) :AstNodeFTaskRef(fl, namep, pinsp) {} AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) :AstNodeFTaskRef(fl, name, pinsp) {} ASTNODE_NODE_FUNCS(TaskRef, TASKREF) }; struct AstFuncRef : public AstNodeFTaskRef { // A reference to a function AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) :AstNodeFTaskRef(fl, namep, pinsp) {} AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) :AstNodeFTaskRef(fl, name, pinsp) {} ASTNODE_NODE_FUNCS(FuncRef, FUNCREF) virtual bool hasDType() const { return true; } }; struct AstDpiExport : public AstNode { // We could put an AstNodeFTaskRef instead of the verilog function name, // however we're not *calling* it, so that seems somehow wrong. // (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef) private: string m_name; // Name of function string m_cname; // Name of function on c side public: AstDpiExport(FileLine* fl, const string& vname, const string& cname) :AstNode(fl), m_name(vname), m_cname(cname) { } ASTNODE_NODE_FUNCS(DpiExport, DPIEXPORT) virtual string name() const { return m_name; } virtual void name(const string& name) { m_name = name; } string cname() const { return m_cname; } void cname(const string& cname) { m_cname = cname; } }; //###################################################################### struct AstSenItem : public AstNodeSenItem { // Parents: SENTREE // Children: (optional) VARREF SENGATE private: AstEdgeType m_edgeType; // Edge type public: class Combo {}; // for creator type-overload selection class Initial {}; // for creator type-overload selection class Settle {}; // for creator type-overload selection class Never {}; // for creator type-overload selection AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNode* varrefp) : AstNodeSenItem(fl), m_edgeType(edgeType) { setOp1p(varrefp); } AstSenItem(FileLine* fl, Combo) : AstNodeSenItem(fl) { m_edgeType = AstEdgeType::ET_COMBO; } AstSenItem(FileLine* fl, Initial) : AstNodeSenItem(fl) { m_edgeType = AstEdgeType::ET_INITIAL; } AstSenItem(FileLine* fl, Settle) : AstNodeSenItem(fl) { m_edgeType = AstEdgeType::ET_SETTLE; } AstSenItem(FileLine* fl, Never) : AstNodeSenItem(fl) { m_edgeType = AstEdgeType::ET_NEVER; } ASTNODE_NODE_FUNCS(SenItem, SENITEM) virtual void dump(ostream& str); virtual V3Hash sameHash() const { return V3Hash(V3Hash(edgeType())); } virtual bool same(AstNode* samep) const { return edgeType()==samep->castSenItem()->edgeType(); } AstEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge void edgeType(AstEdgeType type) { m_edgeType=type; editCountInc(); }// * = Posedge/negedge AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized AstNodeVarRef* varrefp() const { return op1p()->castNodeVarRef(); } // op1 = Signal sensitized // virtual bool isClocked() const { return edgeType().clockedStmt(); } virtual bool isCombo() const { return edgeType()==AstEdgeType::ET_COMBO; } virtual bool isInitial() const { return edgeType()==AstEdgeType::ET_INITIAL; } virtual bool isSettle() const { return edgeType()==AstEdgeType::ET_SETTLE; } virtual bool isNever() const { return edgeType()==AstEdgeType::ET_NEVER; } bool hasVar() const { return !(isCombo()||isInitial()||isSettle()||isNever()); } }; struct AstSenGate : public AstNodeSenItem { // Parents: SENTREE // Children: SENITEM expr // AND as applied to a sensitivity list and a gating expression // Performing this gating is optional; it may be removed by later optimizations AstSenGate(FileLine* fl, AstSenItem* sensesp, AstNode* rhsp) : AstNodeSenItem(fl) { dtypeSetLogicBool(); addOp1p(sensesp); setOp2p(rhsp); } ASTNODE_NODE_FUNCS(SenGate, SENGATE) virtual string emitVerilog() { return "(%l) %f&& (%r)"; } AstSenItem* sensesp() const { return op1p()->castSenItem(); } AstNode* rhsp() const { return op2p()->castNode(); } void sensesp(AstSenItem* nodep) { addOp1p(nodep); } void rhsp(AstNode* nodep) { setOp2p(nodep); } // virtual bool isClocked() const { return true; } virtual bool isCombo() const { return false; } virtual bool isInitial() const { return false; } virtual bool isSettle() const { return false; } virtual bool isNever() const { return false; } }; struct AstSenTree : public AstNode { // A list of senitems // Parents: MODULE | SBLOCK // Children: SENITEM list private: bool m_multi; // Created from combo logic by ORing multiple clock domains public: AstSenTree(FileLine* fl, AstNodeSenItem* sensesp) : AstNode(fl), m_multi(false) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(SenTree, SENTREE) virtual void dump(ostream& str); virtual bool maybePointedTo() const { return true; } bool isMulti() const { return m_multi; } AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); } // op1 = Sensitivity list void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); } void multi(bool flag) { m_multi = true; } // METHODS bool hasClocked(); // Includes a clocked statement bool hasSettle(); // Includes a SETTLE SenItem bool hasInitial(); // Includes a INITIAL SenItem bool hasCombo(); // Includes a COMBO SenItem }; struct AstAlways : public AstNode { AstAlways(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) : AstNode(fl) { addNOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(Always, ALWAYS) // AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate void addStmtp(AstNode* nodep) { addOp2p(nodep); } // Special accessors bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; struct AstAlwaysPublic : public AstNodeStmt { // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ // Body statements are just AstVarRefs to the public signals AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) : AstNodeStmt(fl) { addNOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPublic, ALWAYSPUBLIC) virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } // AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate void addStmtp(AstNode* nodep) { addOp2p(nodep); } // Special accessors bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; struct AstAlwaysPost : public AstNode { // Like always but post assignments for memory assignment IFs AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) : AstNode(fl) { addNOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPost, ALWAYSPOST) // AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate void addBodysp(AstNode* newp) { addOp2p(newp); } }; struct AstAssign : public AstNodeAssign { AstAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Assign, ASSIGN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssign(this->fileline(), lhsp, rhsp); } }; struct AstAssignAlias : public AstNodeAssign { // Like AstAssignW, but a true bidirect interconnection alias // If both sides are wires, there's no LHS vs RHS, AstAssignAlias(FileLine* fileline, AstVarRef* lhsp, AstVarRef* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignAlias, ASSIGNALIAS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { V3ERROR_NA; return NULL; } }; struct AstAssignDly : public AstNodeAssign { AstAssignDly(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignDly, ASSIGNDLY) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignDly(this->fileline(), lhsp, rhsp); } virtual bool isGateOptimizable() const { return false; } virtual string verilogKwd() const { return "<="; } }; struct AstAssignW : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable AstAssignW(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) { } ASTNODE_NODE_FUNCS(AssignW, ASSIGNW) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignW(this->fileline(), lhsp, rhsp); } AstAlways* convertToAlways() { AstNode* lhs1p = lhsp()->unlinkFrBack(); AstNode* rhs1p = rhsp()->unlinkFrBack(); AstAlways* newp = new AstAlways (fileline(), NULL, new AstAssign (fileline(), lhs1p, rhs1p)); replaceWith(newp); // User expected to then deleteTree(); return newp; } }; struct AstPull : public AstNode { private: bool m_direction; public: AstPull(FileLine* fileline, AstNode* lhsp, bool direction) : AstNode(fileline) { setOp1p(lhsp); m_direction = direction; } ASTNODE_NODE_FUNCS(Pull, PULL) virtual bool same(AstNode* samep) const { return direction()==samep->castPull()->direction(); } void lhsp(AstNode* np) { setOp1p(np); } AstNode* lhsp() const { return op1p()->castNode(); } // op1 = Assign to uint32_t direction() const { return (uint32_t) m_direction; } }; struct AstAssignPre : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling AstAssignPre(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPre, ASSIGNPRE) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPre(this->fileline(), lhsp, rhsp); } }; struct AstAssignPost : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling AstAssignPost(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) : AstNodeAssign(fileline, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPost, ASSIGNPOST) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPost(this->fileline(), lhsp, rhsp); } }; struct AstComment : public AstNodeStmt { // Some comment to put into the output stream // Parents: {statement list} // Children: none private: string m_name; // Name of variable public: AstComment(FileLine* fl, const string& name) : AstNodeStmt(fl) , m_name(name) {} ASTNODE_NODE_FUNCS(Comment, COMMENT) virtual string name() const { return m_name; } // * = Var name virtual V3Hash sameHash() const { return V3Hash(); } // Ignore name in comments virtual bool same(AstNode* samep) const { return true; } // Ignore name in comments }; struct AstCond : public AstNodeCond { // Conditional ?: statement // Parents: MATH // Children: MATH AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeCond(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(Cond, COND) }; struct AstCondBound : public AstNodeCond { // Conditional ?: statement, specially made for saftey checking of array bounds // Parents: MATH // Children: MATH AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeCond(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(CondBound, CONDBOUND) }; struct AstCoverDecl : public AstNodeStmt { // Coverage analysis point declaration // Parents: {statement list} // Children: none private: AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get data from instead string m_page; string m_text; string m_hier; int m_column; int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment public: AstCoverDecl(FileLine* fl, int column, const string& page, const string& comment) : AstNodeStmt(fl) { m_text = comment; m_page = page; m_column = column; m_binNum = 0; m_dataDeclp = NULL; } ASTNODE_NODE_FUNCS(CoverDecl, COVERDECL) virtual bool broken() const { if (m_dataDeclp && !m_dataDeclp->brokeExists()) return true; if (m_dataDeclp && m_dataDeclp->m_dataDeclp) v3fatalSrc("dataDeclp should point to real data, not be a list"); // Avoid O(n^2) accessing return false; } virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep()->castCoverDecl(); } virtual void dump(ostream& str); virtual int instrCount() const { return 1+2*instrCountLd(); } virtual bool maybePointedTo() const { return true; } int column() const { return m_column; } void binNum(int flag) { m_binNum = flag; } int binNum() const { return m_binNum; } const string& comment() const { return m_text; } // text to insert in code const string& page() const { return m_page; } const string& hier() const { return m_hier; } void hier(const string& flag) { m_hier=flag; } void comment(const string& flag) { m_text=flag; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return (fileline() == samep->castCoverDecl()->fileline() && hier()==samep->castCoverDecl()->hier() && comment()==samep->castCoverDecl()->comment() && column()==samep->castCoverDecl()->column()); } virtual bool isPredictOptimizable() const { return false; } void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp=nodep; } // dataDecl NULL means "use this one", but often you want "this" to indicate to get data from here AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } AstCoverDecl* dataDeclThisp() { return dataDeclNullp()?dataDeclNullp():this; } }; struct AstCoverInc : public AstNodeStmt { // Coverage analysis point; increment coverage count // Parents: {statement list} // Children: none private: AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration public: AstCoverInc(FileLine* fl, AstCoverDecl* declp) : AstNodeStmt(fl) { m_declp = declp; } ASTNODE_NODE_FUNCS(CoverInc, COVERINC) virtual bool broken() const { return !declp()->brokeExists(); } virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castCoverDecl(); } virtual void dump(ostream& str); virtual int instrCount() const { return 1+2*instrCountLd(); } virtual V3Hash sameHash() const { return V3Hash(declp()); } virtual bool same(AstNode* samep) const { return declp()==samep->castCoverInc()->declp(); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isOutputter() const { return true; } // but isPure() true AstCoverDecl* declp() const { return m_declp; } // Where defined }; struct AstCoverToggle : public AstNodeStmt { // Toggle analysis of given signal // Parents: MODULE // Children: AstCoverInc, orig var, change det var AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) : AstNodeStmt(fl) { setOp1p(incp); setOp2p(origp); setOp3p(changep); } ASTNODE_NODE_FUNCS(CoverToggle, COVERTOGGLE) virtual int instrCount() const { return 3+instrCountBranch()+instrCountLd(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode*) const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return true; } virtual bool isOutputter() const { return false; } // Though the AstCoverInc under this is an outputter // but isPure() true AstCoverInc* incp() const { return op1p()->castCoverInc(); } void incp(AstCoverInc* nodep) { setOp1p(nodep); } AstNode* origp() const { return op2p(); } AstNode* changep() const { return op3p(); } }; struct AstGenCase : public AstNodeCase { // Generate Case statement // Parents: {statement list} // exprp Children: MATHs // casesp Children: CASEITEMs AstGenCase(FileLine* fileline, AstNode* exprp, AstNode* casesp) : AstNodeCase(fileline, exprp, casesp) { } ASTNODE_NODE_FUNCS(GenCase, GENCASE) }; struct AstCase : public AstNodeCase { // Case statement // Parents: {statement list} // exprp Children: MATHs // casesp Children: CASEITEMs private: AstCaseType m_casex; // 0=case, 1=casex, 2=casez bool m_fullPragma; // Synthesis full_case bool m_parallelPragma; // Synthesis parallel_case bool m_uniquePragma; // unique case bool m_unique0Pragma; // unique0 case bool m_priorityPragma; // priority case public: AstCase(FileLine* fileline, AstCaseType casex, AstNode* exprp, AstNode* casesp) : AstNodeCase(fileline, exprp, casesp) { m_casex=casex; m_fullPragma=false; m_parallelPragma=false; m_uniquePragma=false; m_unique0Pragma=false; m_priorityPragma=false; } ASTNODE_NODE_FUNCS(Case, CASE) virtual string verilogKwd() const { return casez()?"casez":casex()?"casex":"case"; } virtual bool same(AstNode* samep) const { return m_casex==samep->castCase()->m_casex; } bool casex() const { return m_casex==AstCaseType::CT_CASEX; } bool casez() const { return m_casex==AstCaseType::CT_CASEZ; } bool fullPragma() const { return m_fullPragma; } void fullPragma(bool flag) { m_fullPragma=flag; } bool parallelPragma() const { return m_parallelPragma; } void parallelPragma(bool flag) { m_parallelPragma=flag; } bool uniquePragma() const { return m_uniquePragma; } void uniquePragma(bool flag) { m_uniquePragma=flag; } bool unique0Pragma() const { return m_unique0Pragma; } void unique0Pragma(bool flag) { m_unique0Pragma=flag; } bool priorityPragma() const { return m_priorityPragma; } void priorityPragma(bool flag) { m_priorityPragma=flag; } }; struct AstCaseItem : public AstNode { // Single item of a case statement // Parents: CASE // condsp Children: MATH (Null condition used for default block) // bodysp Children: Statements private: bool m_ignoreOverlap; // Default created by assertions; ignore overlaps public: AstCaseItem(FileLine* fileline, AstNode* condsp, AstNode* bodysp) : AstNode(fileline) { addNOp1p(condsp); addNOp2p(bodysp); m_ignoreOverlap = false; } ASTNODE_NODE_FUNCS(CaseItem, CASEITEM) virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } AstNode* condsp() const { return op1p()->castNode(); } // op1= list of possible matching expressions AstNode* bodysp() const { return op2p()->castNode(); } // op2= what to do void condsp(AstNode* nodep) { setOp1p(nodep); } void addBodysp(AstNode* newp) { addOp2p(newp); } bool isDefault() const { return condsp()==NULL; } bool ignoreOverlap() const { return m_ignoreOverlap; } void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; } }; struct AstSFormatF : public AstNode { // Convert format to string, generally under an AstDisplay or AstSFormat // Also used as "real" function for /*verilator sformat*/ functions string m_text; bool m_hidden; // Under display, etc public: AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp) : AstNode(fl), m_text(text), m_hidden(hidden) { addNOp1p(exprsp); addNOp2p(NULL); } ASTNODE_NODE_FUNCS(SFormatF, SFORMATF) virtual string name() const { return m_text; } virtual int instrCount() const { return instrCountPli(); } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(AstNode* samep) const { return text()==samep->castSFormatF()->text(); } virtual string verilogKwd() const { return "$sformatf"; } void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text=text; } AstScopeName* scopeNamep() const { return op2p()->castScopeName(); } void scopeNamep(AstNode* nodep) { setNOp2p(nodep); } bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive return (name().find("%m") != string::npos || name().find("%M") != string::npos); } bool hidden() const { return m_hidden; } }; struct AstDisplay : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref // Children: SFORMATF to generate print string private: AstDisplayType m_displayType; public: AstDisplay(FileLine* fileline, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp) : AstNodeStmt (fileline) { setOp1p(new AstSFormatF(fileline,text,true,exprsp)); setNOp3p(filep); m_displayType = dispType; } ASTNODE_NODE_FUNCS(Display, DISPLAY) virtual void dump(ostream& str); virtual bool broken() const { return !fmtp(); } virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii() : (string)"$"+(string)displayType().ascii()); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(displayType()); } virtual bool same(AstNode* samep) const { return displayType()==samep->castDisplay()->displayType(); } virtual int instrCount() const { return instrCountPli(); } AstDisplayType displayType() const { return m_displayType; } void displayType(AstDisplayType type) { m_displayType = type; } bool addNewline() const { return displayType().addNewline(); } // * = Add a newline for $display void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter AstSFormatF* fmtp() const { return op1p()->castSFormatF(); } AstNode* filep() const { return op3p(); } void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); } }; struct AstSFormat : public AstNode { // Parents: statement container // Children: string to load // Children: SFORMATF to generate print string AstSFormat(FileLine* fileline, AstNode* lhsp, const string& text, AstNode* exprsp) : AstNode (fileline) { setOp1p(new AstSFormatF(fileline,text,true,exprsp)); setOp3p(lhsp); } ASTNODE_NODE_FUNCS(SFormat, SFORMAT) virtual bool broken() const { return !fmtp(); } virtual string verilogKwd() const { return "$sformat"; } virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return true; } virtual bool isPure() const { return true; } virtual bool isOutputter() const { return false; } virtual bool cleanOut() { return false; } virtual int instrCount() const { return instrCountPli(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter AstSFormatF* fmtp() const { return op1p()->castSFormatF(); } AstNode* lhsp() const { return op3p(); } void lhsp(AstNode* nodep) { setOp3p(nodep); } }; struct AstSysIgnore : public AstNodeStmt { // Parents: stmtlist // Children: varrefs or exprs AstSysIgnore(FileLine* fileline, AstNode* exprsp) : AstNodeStmt (fileline) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(SysIgnore, SYSIGNORE) virtual string verilogKwd() const { return "$ignored"; } virtual bool isGateOptimizable() const { return false; } // Though deleted before opt virtual bool isPredictOptimizable() const { return false; } // Though deleted before opt virtual bool isPure() const { return false; } // Though deleted before opt virtual bool isOutputter() const { return true; } // Though deleted before opt virtual int instrCount() const { return instrCountPli(); } AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output }; struct AstFClose : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref AstFClose(FileLine* fileline, AstNode* filep) : AstNodeStmt (fileline) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FClose, FCLOSE) virtual string verilogKwd() const { return "$fclose"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; struct AstFOpen : public AstNodeStmt { AstFOpen(FileLine* fileline, AstNode* filep, AstNode* filenamep, AstNode* modep) : AstNodeStmt (fileline) { setOp1p(filep); setOp2p(filenamep); setOp3p(modep); } ASTNODE_NODE_FUNCS(FOpen, FOPEN) virtual string verilogKwd() const { return "$fopen"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } AstNode* modep() const { return op3p(); } }; struct AstFFlush : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref AstFFlush(FileLine* fileline, AstNode* filep) : AstNodeStmt (fileline) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FFlush, FFLUSH) virtual string verilogKwd() const { return "$fflush"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; struct AstFScanF : public AstNodeMath { // Parents: expr // Children: file which must be a varref // Children: varrefs to load private: string m_text; public: AstFScanF(FileLine* fileline, const string& text, AstNode* filep, AstNode* exprsp) : AstNodeMath (fileline), m_text(text) { addNOp1p(exprsp); setNOp2p(filep); } ASTNODE_NODE_FUNCS(FScanF, FSCANF) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$fscanf"; } virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const { return true; } // SPECIAL: makes output virtual bool cleanOut() { return false; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(AstNode* samep) const { return text()==samep->castFScanF()->text(); } AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text=text; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; struct AstSScanF : public AstNodeMath { // Parents: expr // Children: file which must be a varref // Children: varrefs to load private: string m_text; public: AstSScanF(FileLine* fileline, const string& text, AstNode* fromp, AstNode* exprsp) : AstNodeMath (fileline), m_text(text) { addNOp1p(exprsp); setOp2p(fromp); } ASTNODE_NODE_FUNCS(SScanF, SSCANF) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$sscanf"; } virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const { return true; } // SPECIAL: makes output virtual bool cleanOut() { return false; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(AstNode* samep) const { return text()==samep->castSScanF()->text(); } AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text=text; } AstNode* fromp() const { return op2p(); } void fromp(AstNode* nodep) { setOp2p(nodep); } }; struct AstReadMem : public AstNodeStmt { private: bool m_isHex; // readmemh, not readmemb public: AstReadMem(FileLine* fileline, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) : AstNodeStmt (fileline), m_isHex(hex) { setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp); } ASTNODE_NODE_FUNCS(ReadMem, READMEM) virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return isHex()==samep->castReadMem()->isHex(); } bool isHex() const { return m_isHex; } AstNode* filenamep() const { return op1p()->castNode(); } AstNode* memp() const { return op2p()->castNode(); } AstNode* lsbp() const { return op3p()->castNode(); } AstNode* msbp() const { return op4p()->castNode(); } }; struct AstSystemT : public AstNodeStmt { // $system used as task AstSystemT(FileLine* fileline, AstNode* lhsp) : AstNodeStmt (fileline) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemT, SYSTEMT) virtual string verilogKwd() const { return "$system"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* lhsp() const { return op1p(); } }; struct AstSystemF : public AstNodeMath { // $system used as function AstSystemF(FileLine* fileline, AstNode* lhsp) : AstNodeMath (fileline) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemF, SYSTEMF) virtual string verilogKwd() const { return "$system"; } virtual string emitVerilog() { return verilogKwd(); } virtual string emitC() { return "VL_SYSTEM_%nq(%lw, %P)"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual bool isUnlikely() const { return true; } virtual bool cleanOut() { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* lhsp() const { return op1p(); } }; struct AstValuePlusArgs : public AstNodeMath { // Parents: expr // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs private: string m_text; public: AstValuePlusArgs(FileLine* fileline, const string& text, AstNode* exprsp) : AstNodeMath (fileline), m_text(text) { setOp1p(exprsp); } ASTNODE_NODE_FUNCS(ValuePlusArgs, VALUEPLUSARGS) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$value$plusargs"; } virtual string emitVerilog() { return verilogKwd(); } virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool cleanOut() { return true; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(AstNode* samep) const { return text()==samep->castValuePlusArgs()->text(); } AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output void exprsp(AstNode* nodep) { setOp1p(nodep); } // op1 = Expressions to output string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text=text; } }; struct AstTestPlusArgs : public AstNodeMath { // Parents: expr // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs private: string m_text; public: AstTestPlusArgs(FileLine* fileline, const string& text) : AstNodeMath (fileline), m_text(text) { } ASTNODE_NODE_FUNCS(TestPlusArgs, TESTPLUSARGS) virtual string name() const { return m_text; } virtual string verilogKwd() const { return "$test$plusargs"; } virtual string emitVerilog() { return verilogKwd(); } virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool cleanOut() { return true; } virtual V3Hash sameHash() const { return V3Hash(text()); } virtual bool same(AstNode* samep) const { return text()==samep->castTestPlusArgs()->text(); } string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text=text; } }; struct AstGenFor : public AstNodeFor { AstGenFor(FileLine* fileline, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) : AstNodeFor(fileline, initsp, condp, incsp, bodysp) { } ASTNODE_NODE_FUNCS(GenFor, GENFOR) }; struct AstRepeat : public AstNodeStmt { AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp) : AstNodeStmt(fileline) { setOp2p(countp); addNOp3p(bodysp); } ASTNODE_NODE_FUNCS(Repeat, REPEAT) AstNode* countp() const { return op2p()->castNode(); } // op2= condition to continue AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop virtual bool isGateOptimizable() const { return false; } // Not releavant - converted to FOR virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstWhile : public AstNodeStmt { AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp, AstNode* incsp=NULL) : AstNodeStmt(fileline) { setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp); } ASTNODE_NODE_FUNCS(While, WHILE) AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop) AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop AstNode* incsp() const { return op4p()->castNode(); } // op4= increment (if from a FOR loop) void addPrecondsp(AstNode* newp) { addOp1p(newp); } void addBodysp(AstNode* newp) { addOp3p(newp); } void addIncsp(AstNode* newp) { addOp4p(newp); } virtual bool isGateOptimizable() const { return false; } virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here }; struct AstBreak : public AstNodeStmt { AstBreak(FileLine* fileline) : AstNodeStmt (fileline) {} ASTNODE_NODE_FUNCS(Break, BREAK) virtual string verilogKwd() const { return "break"; }; virtual V3Hash sameHash() const { return V3Hash(); } virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks }; struct AstContinue : public AstNodeStmt { AstContinue(FileLine* fileline) : AstNodeStmt (fileline) {} ASTNODE_NODE_FUNCS(Continue, CONTINUE) virtual string verilogKwd() const { return "continue"; }; virtual V3Hash sameHash() const { return V3Hash(); } virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks }; struct AstDisable : public AstNodeStmt { private: string m_name; // Name of block public: AstDisable(FileLine* fileline, const string& name) : AstNodeStmt(fileline), m_name(name) {} ASTNODE_NODE_FUNCS(Disable, DISABLE) virtual string name() const { return m_name; } // * = Block name void name(const string& flag) { m_name=flag; } virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks }; struct AstReturn : public AstNodeStmt { AstReturn(FileLine* fileline, AstNode* lhsp=NULL) : AstNodeStmt (fileline) { setNOp1p(lhsp); } ASTNODE_NODE_FUNCS(Return, RETURN) virtual string verilogKwd() const { return "return"; }; virtual V3Hash sameHash() const { return V3Hash(); } AstNode* lhsp() const { return op1p(); } virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks }; struct AstGenIf : public AstNodeIf { AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeIf(fileline, condp, ifsp, elsesp) { } ASTNODE_NODE_FUNCS(GenIf, GENIF) }; struct AstIf : public AstNodeIf { private: bool m_uniquePragma; // unique case bool m_unique0Pragma; // unique0 case bool m_priorityPragma; // priority case public: AstIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeIf(fileline, condp, ifsp, elsesp) { m_uniquePragma=false; m_unique0Pragma=false; m_priorityPragma=false; } ASTNODE_NODE_FUNCS(If, IF) bool uniquePragma() const { return m_uniquePragma; } void uniquePragma(bool flag) { m_uniquePragma=flag; } bool unique0Pragma() const { return m_unique0Pragma; } void unique0Pragma(bool flag) { m_unique0Pragma=flag; } bool priorityPragma() const { return m_priorityPragma; } void priorityPragma(bool flag) { m_priorityPragma=flag; } }; struct AstJumpLabel : public AstNodeStmt { // Jump point declaration // Separate from AstJumpGo; as a declaration can't be deleted // Parents: {statement list} // Children: {statement list, with JumpGo below} private: int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment public: AstJumpLabel(FileLine* fl, AstNode* stmtsp) : AstNodeStmt(fl) ,m_labelNum(0) { addNOp1p(stmtsp); } virtual int instrCount() const { return 0; } ASTNODE_NODE_FUNCS(JumpLabel, JUMPLABEL) virtual bool maybePointedTo() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } // op1 = Statements AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } int labelNum() const { return m_labelNum; } void labelNum(int flag) { m_labelNum=flag; } }; struct AstJumpGo : public AstNodeStmt { // Jump point; branch up to the JumpLabel // Parents: {statement list} private: AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration public: AstJumpGo(FileLine* fl, AstJumpLabel* labelp) : AstNodeStmt(fl) { m_labelp = labelp; } ASTNODE_NODE_FUNCS(JumpGo, JUMPGO) virtual bool broken() const { return !labelp()->brokeExistsAbove(); } virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); } virtual void dump(ostream& str); virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(labelp()); } virtual bool same(AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect return labelp()==samep->castJumpGo()->labelp(); } virtual bool isGateOptimizable() const { return false; } virtual bool isBrancher() const { return true; } // SPECIAL: We don't process code after breaks AstJumpLabel* labelp() const { return m_labelp; } }; struct AstUntilStable : public AstNodeStmt { // Quasi-while loop until given signals are stable // Parents: CFUNC (generally) // Children: VARREF, statements AstUntilStable(FileLine* fileline, AstVarRef* stablesp, AstNode* bodysp) : AstNodeStmt(fileline) { addNOp2p(stablesp); addNOp3p(bodysp); } ASTNODE_NODE_FUNCS(UntilStable, UNTILSTABLE) AstVarRef* stablesp() const { return op2p()->castVarRef(); } // op2= list of variables that must become stable AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop void addStablesp(AstVarRef* newp) { addOp2p(newp); } void addBodysp(AstNode* newp) { addOp3p(newp); } virtual bool isGateOptimizable() const { return false; } // Not relevant virtual bool isPredictOptimizable() const { return false; } // Not relevant virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstChangeXor : public AstNodeBiComAsv { // A comparison to determine change detection, common & must be fast. // Returns 32-bit or 64-bit value where 0 indicates no change. // Parents: OR or LOGOR // Children: VARREF AstChangeXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeSetUInt32(); // Always used on, and returns word entities } ASTNODE_NODE_FUNCS(ChangeXor, CHANGEXOR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opChangeXor(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f^ %r)"; } virtual string emitC() { return "VL_CHANGEXOR_%li(%lw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^"; } virtual bool cleanOut() {return false;} // Lclean && Rclean virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs(); } }; struct AstChangeDet : public AstNodeStmt { // A comparison to determine change detection, common & must be fast. private: bool m_clockReq; // Type of detection public: // Null lhs+rhs used to indicate change needed with no spec vars AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool clockReq) : AstNodeStmt(fl) { setNOp1p(lhsp); setNOp2p(rhsp); m_clockReq=clockReq; } ASTNODE_NODE_FUNCS(ChangeDet, CHANGEDET) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } bool isClockReq() const { return m_clockReq; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstBegin : public AstNode { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement // Children: statements private: string m_name; // Name of block bool m_unnamed; // Originally unnamed bool m_generate; // Underneath a generate public: // Node that simply puts name into the output stream AstBegin(FileLine* fileline, const string& name, AstNode* stmtsp, bool generate=false) : AstNode(fileline) , m_name(name) { addNOp1p(stmtsp); m_unnamed = (name==""); m_generate = generate; } ASTNODE_NODE_FUNCS(Begin, BEGIN) virtual void dump(ostream& str); virtual string name() const { return m_name; } // * = Block name virtual void name(const string& name) { m_name = name; } // op1 = Statements AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, // might NOT be a GenFor, as loop unrolling replaces with Begin void addGenforp(AstGenFor* nodep) { addOp2p(nodep); } bool unnamed() const { return m_unnamed; } void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } }; struct AstInitial : public AstNode { AstInitial(FileLine* fl, AstNode* bodysp) : AstNode(fl) { addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(Initial, INITIAL) AstNode* bodysp() const { return op1p()->castNode(); } // op1 = Expressions to evaluate // Special accessors bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; struct AstFinal : public AstNode { AstFinal(FileLine* fl, AstNode* bodysp) : AstNode(fl) { addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(Final, FINAL) AstNode* bodysp() const { return op1p()->castNode(); } // op1 = Expressions to evaluate }; struct AstInitArray : public AstNode { // Set a var to a large list of values // The values must be in sorted order, and not exceed the size of the var's array. // Parents: ASTVAR::init() // Children: CONSTs... AstInitArray(FileLine* fl, AstNode* initsp) : AstNode(fl) { addNOp1p(initsp); } ASTNODE_NODE_FUNCS(InitArray, INITARRAY) AstNode* initsp() const { return op1p()->castNode(); } // op1 = Initial value expressions void addInitsp(AstNode* newp) { addOp1p(newp); } }; struct AstPragma : public AstNode { private: AstPragmaType m_pragType; // Type of pragma public: // Pragmas don't result in any output code, they're just flags that affect // other processing in verilator. AstPragma(FileLine* fl, AstPragmaType pragType) : AstNode(fl) { m_pragType = pragType; } ASTNODE_NODE_FUNCS(Pragma, PRAGMA) AstPragmaType pragType() const { return m_pragType; } // *=type of the pragma virtual V3Hash sameHash() const { return V3Hash(pragType()); } virtual bool isPredictOptimizable() const { return false; } virtual bool same(AstNode* samep) const { return pragType()==samep->castPragma()->pragType(); } }; struct AstStop : public AstNodeStmt { AstStop(FileLine* fl) : AstNodeStmt(fl) {} ASTNODE_NODE_FUNCS(Stop, STOP) virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const { return true; } virtual int instrCount() const { return 0; } // Rarely executes virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); } virtual bool same(AstNode* samep) const { return fileline() == samep->fileline(); } }; struct AstFinish : public AstNodeStmt { AstFinish(FileLine* fl) : AstNodeStmt(fl) {} ASTNODE_NODE_FUNCS(Finish, FINISH) virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const { return true; } virtual int instrCount() const { return 0; } // Rarely executes virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); } virtual bool same(AstNode* samep) const { return fileline() == samep->fileline(); } }; struct AstTraceDecl : public AstNodeStmt { // Trace point declaration // Separate from AstTraceInc; as a declaration can't be deleted // Parents: {statement list} // Children: none private: string m_showname; // Name of variable uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines int m_right; // Property of var the trace details int m_left; // Property of var the trace details uint32_t m_arrayLsb; // Property of var the trace details uint32_t m_arrayMsb; // Property of var the trace details uint32_t m_codeInc; // Code increment public: AstTraceDecl(FileLine* fl, const string& showname, AstVar* varp) : AstNodeStmt(fl) , m_showname(showname) { dtypeFrom(varp); m_code = 0; m_codeInc = varp->dtypep()->arrayElements() * varp->dtypep()->widthWords(); AstBasicDType* bdtypep = varp->basicp(); m_left = bdtypep ? bdtypep->left() : 0; m_right = bdtypep ? bdtypep->right() : 0; if (AstArrayDType* adtypep = varp->dtypeSkipRefp()->castArrayDType()) { m_arrayLsb = adtypep->lsb(); m_arrayMsb = adtypep->msb(); } else { m_arrayLsb = 0; m_arrayMsb = 0; } } virtual int instrCount() const { return 100; } // Large... ASTNODE_NODE_FUNCS(TraceDecl, TRACEDECL) virtual string name() const { return m_showname; } virtual bool maybePointedTo() const { return true; } virtual bool hasDType() const { return true; } virtual bool same(AstNode* samep) const { return false; } string showname() const { return m_showname; } // * = Var name // Details on what we're tracing uint32_t code() const { return m_code; } void code(uint32_t code) { m_code=code; } uint32_t codeInc() const { return m_codeInc; } int left() const { return m_left; } // Note msb maybe < lsb if little endian int right() const { return m_right; } uint32_t arrayMsb() const { return m_arrayMsb; } uint32_t arrayLsb() const { return m_arrayLsb; } uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; } }; struct AstTraceInc : public AstNodeStmt { // Trace point; incremental change detect and dump // Parents: {statement list} // Children: incremental value private: AstTraceDecl* m_declp; // [After V3Trace] Pointer to declaration public: AstTraceInc(FileLine* fl, AstTraceDecl* declp, AstNode* valuep) : AstNodeStmt(fl) { dtypeFrom(declp); m_declp = declp; addNOp2p(valuep); } ASTNODE_NODE_FUNCS(TraceInc, TRACEINC) virtual bool broken() const { return !declp()->brokeExists(); } virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castTraceDecl(); } virtual void dump(ostream& str); virtual int instrCount() const { return 10+2*instrCountLd(); } virtual bool hasDType() const { return true; } virtual V3Hash sameHash() const { return V3Hash(declp()); } virtual bool same(AstNode* samep) const { return declp()==samep->castTraceInc()->declp(); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isOutputter() const { return true; } // but isPure() true // op1 = Statements before the value AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop) void addPrecondsp(AstNode* newp) { addOp1p(newp); } // op2 = Value to trace AstTraceDecl* declp() const { return m_declp; } // Where defined AstNode* valuep() const { return op2p()->castNode(); } }; struct AstActive : public AstNode { // Block of code with sensitivity activation // Parents: MODULE | CFUNC // Children: SENTREE, statements private: string m_name; AstSenTree* m_sensesp; public: AstActive(FileLine* fileline, const string& name, AstSenTree* sensesp) : AstNode(fileline) { m_name = name; // Copy it UASSERT(sensesp, "Sensesp required arg"); m_sensesp = sensesp; } ASTNODE_NODE_FUNCS(Active, ACTIVE) virtual void dump(ostream& str=cout); virtual string name() const { return m_name; } virtual bool broken() const { return (m_sensesp && !m_sensesp->brokeExists()); } virtual void cloneRelink() { if (m_sensesp->clonep()) { m_sensesp = m_sensesp->clonep()->castSenTree(); UASSERT(m_sensesp, "Bad clone cross link: "<castSenTree(); } // op2 = Combo logic AstNode* stmtsp() const { return op2p()->castNode(); } void addStmtsp(AstNode* nodep) { addOp2p(nodep); } // METHODS bool hasInitial() const { return m_sensesp->hasInitial(); } bool hasSettle() const { return m_sensesp->hasSettle(); } bool hasClocked() const { return m_sensesp->hasClocked(); } }; struct AstAttrOf : public AstNode { private: // Return a value of a attribute, for example a LSB or array LSB of a signal AstAttrType m_attrType; // What sort of extraction public: AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL) : AstNode(fl) { setNOp1p(fromp); m_attrType = attrtype; } ASTNODE_NODE_FUNCS(AttrOf, ATTROF) AstNode* fromp() const { return op1p(); } AstAttrType attrType() const { return m_attrType; } virtual void dump(ostream& str=cout); }; struct AstScopeName : public AstNodeMath { // For display %m and DPI context imports // Parents: DISPLAY // Children: TEXT private: bool m_dpiExport; // Is for dpiExport public: AstScopeName(FileLine* fl) : AstNodeMath(fl), m_dpiExport(false) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(ScopeName, SCOPENAME) virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return m_dpiExport==samep->castScopeName()->m_dpiExport; } virtual string emitVerilog() { return ""; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { return true; } AstText* scopeAttrp() const { return op1p()->castText(); } void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } string scopeSymName() const; // Name for __Vscope variable including children string scopePrettyName() const; // Name for __Vscope printing bool dpiExport() const { return m_dpiExport; } void dpiExport(bool flag) { m_dpiExport=flag; } }; struct AstUdpTable : public AstNode { AstUdpTable(FileLine* fl, AstNode* bodysp) : AstNode(fl) { addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(UdpTable, UDPTABLE) AstUdpTableLine* bodysp() const { return op1p()->castUdpTableLine(); } // op1 = List of UdpTableLines }; struct AstUdpTableLine : public AstNode { string m_text; public: AstUdpTableLine(FileLine* fl, const string& text) : AstNode(fl), m_text(text) {} ASTNODE_NODE_FUNCS(UdpTableLine, UDPTABLELINE) virtual string name() const { return m_text; } string text() const { return m_text; } }; //====================================================================== // non-ary ops struct AstRand : public AstNodeTermop { // Return a random number, based upon width() private: bool m_reset; // Random reset, versus always random public: AstRand(FileLine* fl, AstNodeDType* dtp, bool reset) : AstNodeTermop(fl) { dtypep(dtp); m_reset=reset; } AstRand(FileLine* fl) : AstNodeTermop(fl), m_reset(false) { } ASTNODE_NODE_FUNCS(Rand, RAND) virtual string emitVerilog() { return "%f$random"; } virtual string emitC() { return (m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" :"VL_RANDOM_%nq(%nw, %P)"); } virtual bool cleanOut() { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountPli(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstTime : public AstNodeTermop { AstTime(FileLine* fl) : AstNodeTermop(fl) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(Time, TIME) virtual string emitVerilog() { return "%f$time"; } virtual string emitC() { return "VL_TIME_%nq()"; } virtual bool cleanOut() { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountTime(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstTimeD : public AstNodeTermop { AstTimeD(FileLine* fl) : AstNodeTermop(fl) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(TimeD, TIMED) virtual string emitVerilog() { return "%f$realtime"; } virtual string emitC() { return "VL_TIME_D()"; } virtual bool cleanOut() { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountTime(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstUCFunc : public AstNodeMath { // User's $c function // Perhaps this should be an AstNodeListop; but there's only one list math right now AstUCFunc(FileLine* fl, AstNode* exprsp) : AstNodeMath(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCFunc, UCFUNC) virtual bool cleanOut() { return false; } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } AstNode* bodysp() const { return op1p()->castNode(); } // op1= expressions to print virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } virtual bool isGateOptimizable() const { return false; } virtual bool isSubstOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual int instrCount() const { return instrCountPli(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; //====================================================================== // Unary ops struct AstNegate : public AstNodeUniop { AstNegate(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Negate, NEGATE) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } virtual string emitC() { return "VL_NEGATE_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return true;} }; struct AstNegateD : public AstNodeUniop { AstNegateD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(NegateD, NEGATED) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegateD(lhs); } virtual string emitVerilog() { return "%f(- %l)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstRedAnd : public AstNodeUniop { AstRedAnd(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(RedAnd, REDAND) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedAnd(lhs); } virtual string emitVerilog() { return "%f(& %l)"; } virtual string emitC() { return "VL_REDAND_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} }; struct AstRedOr : public AstNodeUniop { AstRedOr(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(RedOr, REDOR) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedOr(lhs); } virtual string emitVerilog() { return "%f(| %l)"; } virtual string emitC() { return "VL_REDOR_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} }; struct AstRedXor : public AstNodeUniop { AstRedXor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(RedXor, REDXOR) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXor(lhs); } virtual string emitVerilog() { return "%f(^ %l)"; } virtual string emitC() { return "VL_REDXOR_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {int w = lhsp()->width(); return (w!=1 && w!=2 && w!=4 && w!=8 && w!=16); } virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return 1+V3Number::log2b(width()); } }; struct AstRedXnor : public AstNodeUniop { // AstRedXnors are replaced with AstRedXors in V3Const. AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(RedXnor, REDXNOR) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXnor(lhs); } virtual string emitVerilog() { return "%f(~^ %l)"; } virtual string emitC() { v3fatalSrc("REDXNOR should have became REDXOR"); return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return 1+V3Number::log2b(width()); } }; struct AstLogNot : public AstNodeUniop { AstLogNot(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LogNot, LOGNOT) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opLogNot(lhs); } virtual string emitVerilog() { return "%f(! %l)"; } virtual string emitC() { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; } virtual string emitSimpleOperator() { return "!"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} }; struct AstNot : public AstNodeUniop { AstNot(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Not, NOT) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNot(lhs); } virtual string emitVerilog() { return "%f(~ %l)"; } virtual string emitC() { return "VL_NOT_%lq(%lW, %P, %li)"; } virtual string emitSimpleOperator() { return "~"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return true;} }; struct AstExtend : public AstNodeUniop { // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() AstExtend(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} AstExtend(FileLine* fl, AstNode* lhsp, int width) : AstNodeUniop(fl, lhsp) { dtypeSetLogicSized(width,width,AstNumeric::UNSIGNED); } ASTNODE_NODE_FUNCS(Extend, EXTEND) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); } virtual string emitVerilog() { return "%l"; } virtual string emitC() { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} // Because the EXTEND operator self-casts virtual int instrCount() const { return 0; } }; struct AstExtendS : public AstNodeUniop { // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() AstExtendS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} AstExtendS(FileLine* fl, AstNode* lhsp, int width) : AstNodeUniop(fl, lhsp) { dtypeSetLogicSized(width,width,AstNumeric::UNSIGNED); } ASTNODE_NODE_FUNCS(ExtendS, EXTENDS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opExtendS(lhs); } virtual string emitVerilog() { return "%l"; } virtual string emitC() { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} // Because the EXTEND operator self-casts virtual int instrCount() const { return 0; } virtual bool signedFlavor() const { return true; } }; struct AstSigned : public AstNodeUniop { // $signed(lhs) AstSigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { if (v3Global.assertDTypesResolved()) { v3fatalSrc("not coded to create after dtypes resolved"); } } ASTNODE_NODE_FUNCS(Signed, SIGNED) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } virtual string emitVerilog() { return "%f$signed(%l)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return true;} // Eliminated before matters virtual int instrCount() const { return 0; } }; struct AstUnsigned : public AstNodeUniop { // $unsigned(lhs) AstUnsigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { if (v3Global.assertDTypesResolved()) { v3fatalSrc("not coded to create after dtypes resolved"); } } ASTNODE_NODE_FUNCS(Unsigned, UNSIGNED) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); } virtual string emitVerilog() { return "%f$unsigned(%l)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return true;} // Eliminated before matters virtual int instrCount() const { return 0; } }; struct AstRToIS : public AstNodeUniop { // $rtoi(lhs) AstRToIS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIS, RTOIS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIS(lhs); } virtual string emitVerilog() { return "%f$rtoi(%l)"; } virtual string emitC() { return "VL_RTOI_I_D(%li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return false;} // Eliminated before matters virtual int instrCount() const { return instrCountDouble(); } }; struct AstRToIRoundS : public AstNodeUniop { AstRToIRoundS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIRoundS, RTOIROUNDS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIRoundS(lhs); } virtual string emitVerilog() { return "%f$rtoi_rounded(%l)"; } virtual string emitC() { return "VL_RTOIROUND_I_D(%li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return false;} // Eliminated before matters virtual int instrCount() const { return instrCountDouble(); } }; struct AstIToRD : public AstNodeUniop { AstIToRD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(IToRD, ITORD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); } virtual string emitVerilog() { return "%f$itor(%l)"; } virtual string emitC() { return "VL_ITOR_D_I(%li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return false;} // Eliminated before matters virtual int instrCount() const { return instrCountDouble(); } }; struct AstRealToBits : public AstNodeUniop { AstRealToBits(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(RealToBits, REALTOBITS) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRealToBits(lhs); } virtual string emitVerilog() { return "%f$realtobits(%l)"; } virtual string emitC() { return "VL_CVT_Q_D(%li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return false;} // Eliminated before matters virtual int instrCount() const { return instrCountDouble(); } }; struct AstBitsToRealD : public AstNodeUniop { AstBitsToRealD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(BitsToRealD, BITSTOREALD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opBitsToRealD(lhs); } virtual string emitVerilog() { return "%f$bitstoreal(%l)"; } virtual string emitC() { return "VL_CVT_D_Q(%li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters virtual bool sizeMattersLhs() {return false;} // Eliminated before matters virtual int instrCount() const { return instrCountDouble(); } }; struct AstCLog2 : public AstNodeUniop { AstCLog2(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} ASTNODE_NODE_FUNCS(CLog2, CLOG2) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opCLog2(lhs); } virtual string emitVerilog() { return "%f$clog2(%l)"; } virtual string emitC() { return "VL_CLOG2_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*16; } }; struct AstCountOnes : public AstNodeUniop { // Number of bits set in vector AstCountOnes(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} ASTNODE_NODE_FUNCS(CountOnes, COUNTONES) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opCountOnes(lhs); } virtual string emitVerilog() { return "%f$countones(%l)"; } virtual string emitC() { return "VL_COUNTONES_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*16; } }; struct AstIsUnknown : public AstNodeUniop { // True if any unknown bits AstIsUnknown(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(IsUnknown, ISUNKNOWN) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIsUnknown(lhs); } virtual string emitVerilog() { return "%f$isunknown(%l)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} }; struct AstOneHot : public AstNodeUniop { // True if only single bit set in vector AstOneHot(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(OneHot, ONEHOT) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opOneHot(lhs); } virtual string emitVerilog() { return "%f$onehot(%l)"; } virtual string emitC() { return "VL_ONEHOT_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*4; } }; struct AstOneHot0 : public AstNodeUniop { // True if only single bit, or no bits set in vector AstOneHot0(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(OneHot0, ONEHOT0) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opOneHot0(lhs); } virtual string emitVerilog() { return "%f$onehot0(%l)"; } virtual string emitC() { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*3; } }; struct AstCast : public AstNode { // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) : AstNode(fl) { setOp1p(lhsp); setOp2p(dtp); dtypeFrom(dtp); } ASTNODE_NODE_FUNCS(Cast, CAST) virtual bool hasDType() const { return true; } virtual string emitVerilog() { return "((%d)'(%l))"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual bool cleanOut() { V3ERROR_NA; return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} AstNode* lhsp() const { return op1p(); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return op2p()->castNodeDType(); } }; struct AstCCast : public AstNodeUniop { // Cast to C-based data type private: int m_size; public: AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth=-1) : AstNodeUniop(fl, lhsp) { m_size=setwidth; if (setwidth) { if (minwidth==-1) minwidth=setwidth; dtypeSetLogicSized(setwidth,minwidth,AstNumeric::UNSIGNED); } } AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) : AstNodeUniop(fl, lhsp) { dtypeFrom(typeFromp); m_size=width(); } ASTNODE_NODE_FUNCS(CCast, CCAST) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); } virtual string emitVerilog() { return "%f$_CAST(%l)"; } virtual string emitC() { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} // Special cased in V3Cast virtual V3Hash sameHash() const { return V3Hash(size()); } virtual bool same(AstNode* samep) const { return size()==samep->castCCast()->size(); } virtual void dump(ostream& str=cout); // int size() const { return m_size; } }; struct AstCvtPackString : public AstNodeUniop { // Convert to Verilator Packed Pack (aka Pack) AstCvtPackString(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetUInt64(); } // Really, width should be dtypep -> STRING ASTNODE_NODE_FUNCS(CvtPackString, CVTPACKSTRING) virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual string emitVerilog() { return "%f$_CAST(%l)"; } virtual string emitC() { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; struct AstFEof : public AstNodeUniop { AstFEof(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} ASTNODE_NODE_FUNCS(FEof, FEOF) virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual string emitVerilog() { return "%f$feof(%l)"; } virtual string emitC() { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*16; } AstNode* filep() const { return lhsp(); } }; struct AstFGetC : public AstNodeUniop { AstFGetC(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} ASTNODE_NODE_FUNCS(FGetC, FGETC) virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual string emitVerilog() { return "%f$fgetc(%l)"; } // Non-existent filehandle returns EOF virtual string emitC() { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return widthInstrs()*64; } AstNode* filep() const { return lhsp(); } }; struct AstCeilD : public AstNodeUniop { AstCeilD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(CeilD, CEILD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(ceil(lhs.toDouble())); } virtual string emitVerilog() { return "%f$ceil(%l)"; } virtual string emitC() { return "ceil(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; struct AstExpD : public AstNodeUniop { AstExpD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(ExpD, EXPD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(exp(lhs.toDouble())); } virtual string emitVerilog() { return "%f$exp(%l)"; } virtual string emitC() { return "exp(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; struct AstFloorD : public AstNodeUniop { AstFloorD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(FloorD, FLOORD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(floor(lhs.toDouble())); } virtual string emitVerilog() { return "%f$floor(%l)"; } virtual string emitC() { return "floor(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; struct AstLogD : public AstNodeUniop { AstLogD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(LogD, LOGD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log(lhs.toDouble())); } virtual string emitVerilog() { return "%f$ln(%l)"; } virtual string emitC() { return "log(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; struct AstLog10D : public AstNodeUniop { AstLog10D(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(Log10D, LOG10D) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log10(lhs.toDouble())); } virtual string emitVerilog() { return "%f$log10(%l)"; } virtual string emitC() { return "log10(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; struct AstSqrtD : public AstNodeUniop { AstSqrtD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(SqrtD, SQRTD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sqrt(lhs.toDouble())); } virtual string emitVerilog() { return "%f$sqrt(%l)"; } virtual string emitC() { return "sqrt(%li)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual int instrCount() const { return instrCountDoubleTrig(); } virtual bool doubleFlavor() const { return true; } }; //====================================================================== // Binary ops struct AstLogOr : public AstNodeBiop { AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LogOr, LOGOR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogOr(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f|| %r)"; } virtual string emitC() { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "||"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; struct AstLogAnd : public AstNodeBiop { AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LogAnd, LOGAND) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogAnd(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f&& %r)"; } virtual string emitC() { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "&&"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; struct AstLogIf : public AstNodeBiop { AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LogIf, LOGIF) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogIf(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f-> %r)"; } virtual string emitC() { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "->"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; struct AstLogIff : public AstNodeBiCom { AstLogIff(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LogIff, LOGIFF) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLogIff(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f<-> %r)"; } virtual string emitC() { return "VL_LOGIFF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<->"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()+instrCountBranch(); } }; struct AstOr : public AstNodeBiComAsv { AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Or, OR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opOr(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f| %r)"; } virtual string emitC() { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "|"; } virtual bool cleanOut() {V3ERROR_NA; return false;} // Lclean && Rclean virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstAnd : public AstNodeBiComAsv { AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(And, AND) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAnd(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f& %r)"; } virtual string emitC() { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "&"; } virtual bool cleanOut() {V3ERROR_NA; return false;} // Lclean || Rclean virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstXor : public AstNodeBiComAsv { AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Xor, XOR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opXor(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f^ %r)"; } virtual string emitC() { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^"; } virtual bool cleanOut() {return false;} // Lclean && Rclean virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstXnor : public AstNodeBiComAsv { AstXnor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Xnor, XNOR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opXnor(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f^ ~ %r)"; } virtual string emitC() { return "VL_XNOR_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "^ ~"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} }; struct AstEq : public AstNodeBiCom { AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Eq, EQ) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f== %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstEqD : public AstNodeBiCom { AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(EqD, EQD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f== %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstNeq : public AstNodeBiCom { AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Neq, NEQ) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstNeqD : public AstNodeBiCom { AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(NeqD, NEQD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f!= %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstLt : public AstNodeBiop { AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Lt, LT) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLt(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstLtD : public AstNodeBiop { AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LtD, LTD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "<"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstLtS : public AstNodeBiop { AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LtS, LTS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f< %r)"; } virtual string emitC() { return "VL_LTS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool signedFlavor() const { return true; } }; struct AstGt : public AstNodeBiop { AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Gt, GT) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGt(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstGtD : public AstNodeBiop { AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(GtD, GTD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return ">"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstGtS : public AstNodeBiop { AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(GtS, GTS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f> %r)"; } virtual string emitC() { return "VL_GTS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool signedFlavor() const { return true; } }; struct AstGte : public AstNodeBiop { AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Gte, GTE) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGte(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstGteD : public AstNodeBiop { AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(GteD, GTED) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return ">="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstGteS : public AstNodeBiop { AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(GteS, GTES) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f>= %r)"; } virtual string emitC() { return "VL_GTES_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool signedFlavor() const { return true; } }; struct AstLte : public AstNodeBiop { AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(Lte, LTE) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLte(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstLteD : public AstNodeBiop { AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LteD, LTED) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "<="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstLteS : public AstNodeBiop { AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(LteS, LTES) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f<= %r)"; } virtual string emitC() { return "VL_LTES_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool signedFlavor() const { return true; } }; struct AstShiftL : public AstNodeBiop { AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) : AstNodeBiop(fl, lhsp, rhsp) { if (setwidth) { dtypeSetLogicSized(setwidth,setwidth,AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftL, SHIFTL) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftL(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f<< %r)"; } virtual string emitC() { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "<<"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;} }; struct AstShiftR : public AstNodeBiop { AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) : AstNodeBiop(fl, lhsp, rhsp) { if (setwidth) { dtypeSetLogicSized(setwidth,setwidth,AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(ShiftR, SHIFTR) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftR(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f>> %r)"; } virtual string emitC() { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ">>"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} // LHS size might be > output size, so don't want to force size }; struct AstShiftRS : public AstNodeBiop { AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) : AstNodeBiop(fl, lhsp, rhsp) { if (setwidth) { dtypeSetLogicSized(setwidth,setwidth,AstNumeric::SIGNED); } } ASTNODE_NODE_FUNCS(ShiftRS, SHIFTRS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftRS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f>>> %r)"; } virtual string emitC() { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool signedFlavor() const { return true; } }; struct AstAdd : public AstNodeBiComAsv { AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Add, ADD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAdd(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f+ %r)"; } virtual string emitC() { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "+"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} }; struct AstAddD : public AstNodeBiComAsv { AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(AddD, ADDD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAddD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f+ %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "+"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstSub : public AstNodeBiop { AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Sub, SUB) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSub(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f- %r)"; } virtual string emitC() { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} }; struct AstSubD : public AstNodeBiop { AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(SubD, SUBD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSubD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f- %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "-"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstMul : public AstNodeBiComAsv { AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Mul, MUL) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMul(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "*"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountMul(); } }; struct AstMulD : public AstNodeBiComAsv { AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(MulD, MULD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "*"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return instrCountDouble(); } virtual bool doubleFlavor() const { return true; } }; struct AstMulS : public AstNodeBiComAsv { AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(MulS, MULS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { return "VL_MULS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountMul(); } virtual bool signedFlavor() const { return true; } }; struct AstDiv : public AstNodeBiop { AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Div, DIV) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDiv(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } }; struct AstDivD : public AstNodeBiop { AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(DivD, DIVD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitSimpleOperator() { return "/"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDoubleDiv(); } virtual bool doubleFlavor() const { return true; } }; struct AstDivS : public AstNodeBiop { AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(DivS, DIVS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f/ %r)"; } virtual string emitC() { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } virtual bool signedFlavor() const { return true; } }; struct AstModDiv : public AstNodeBiop { AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDiv, MODDIV) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDiv(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f%% %r)"; } virtual string emitC() { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } }; struct AstModDivS : public AstNodeBiop { AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDivS, MODDIVS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDivS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f%% %r)"; } virtual string emitC() { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;} virtual int instrCount() const { return widthInstrs()*instrCountDiv(); } virtual bool signedFlavor() const { return true; } }; struct AstPow : public AstNodeBiop { AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Pow, POW) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPow(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()*instrCountMul(); } }; struct AstPowD : public AstNodeBiop { AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(PowD, POWD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowD(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "pow(%li,%ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return instrCountDoubleDiv(); } virtual bool doubleFlavor() const { return true; } }; struct AstPowS : public AstNodeBiop { AstPowS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowS, POWS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowS(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()*instrCountMul(); } virtual bool signedFlavor() const { return true; } }; struct AstEqCase : public AstNodeBiCom { AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(EqCase, EQCASE) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opCaseEq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f=== %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstNeqCase : public AstNodeBiCom { AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(NeqCase, NEQCASE) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opCaseNeq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f!== %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstEqWild : public AstNodeBiop { // Note wildcard operator rhs differs from lhs AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(EqWild, EQWILD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f==? %r)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "=="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstNeqWild : public AstNodeBiop { AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeSetLogicBool(); } ASTNODE_NODE_FUNCS(NeqWild, NEQWILD) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildNeq(lhs,rhs); } virtual string emitVerilog() { return "%k(%l %f!=? %r)"; } virtual string emitC() { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return "!="; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstConcat : public AstNodeBiop { // If you're looking for {#{}}, see AstReplicate AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { if (lhsp->dtypep() && rhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width()+rhsp->dtypep()->width(), lhsp->dtypep()->width()+rhsp->dtypep()->width(), AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(Concat, CONCAT) virtual string emitVerilog() { return "%f{%l, %k%r}"; } virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opConcat(lhs,rhs); } virtual string emitC() { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()*2; } }; struct AstReplicate : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { if (AstConst* constp=rhsp->castConst()) { dtypeSetLogicSized(lhsp->width()*constp->toUInt(), lhsp->width()*constp->toUInt(), AstNumeric::UNSIGNED); } } AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) : AstNodeBiop(fl, lhsp, new AstConst(fl, repCount)) {} ASTNODE_NODE_FUNCS(Replicate, REPLICATE) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opRepl(lhs,rhs); } virtual string emitVerilog() { return "%f{%r{%k%l}}"; } virtual string emitC() { return "VL_REPLICATE_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()*2; } }; struct AstBufIf1 : 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 AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(BufIf1, BUFIF1) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opBufIf1(lhs,rhs); } virtual string emitVerilog() { return "bufif(%r,%l)"; } virtual string emitC() { V3ERROR_NA; return "";} // Lclean || Rclean virtual string emitSimpleOperator() { V3ERROR_NA; return "";} // Lclean || Rclean virtual bool cleanOut() {V3ERROR_NA; return "";} // Lclean || Rclean virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} }; struct AstFGetS : public AstNodeBiop { AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FGetS, FGETS) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } virtual string emitVerilog() { return "%f$fgets(%l,%r)"; } virtual string emitC() { return "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual int instrCount() const { return widthInstrs()*64; } AstNode* strgp() const { return lhsp(); } AstNode* filep() const { return rhsp(); } }; struct AstPattern : public AstNodeMath { // Verilog '{a,b,c,d...} // Parents: AstNodeAssign, AstPattern, ... // Children: expression, AstPattern, AstPatReplicate AstPattern(FileLine* fl, AstNode* itemsp) : AstNodeMath(fl) { addNOp1p(itemsp); } ASTNODE_NODE_FUNCS(Pattern, PATTERN) virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } virtual string emitC() { V3ERROR_NA; return "";} virtual string emitSimpleOperator() { V3ERROR_NA; return "";} virtual bool cleanOut() {V3ERROR_NA; return "";} virtual int instrCount() const { return widthInstrs(); } AstNode* itemsp() const { return op1p(); } // op1 = AstPatReplicate, AstPatMember, etc }; struct AstPatMember : public AstNodeMath { // Verilog '{a} or '{a{b}} // Parents: AstPattern // Children: expression, AstPattern, replication count private: bool m_default; public: AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) : AstNodeMath(fl) { setOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; } ASTNODE_NODE_FUNCS(PatMember, PATMEMBER) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; } virtual string emitVerilog() { return lhsp()?"%f{%r{%k%l}}":"%l"; } virtual string emitC() { V3ERROR_NA; return "";} virtual string emitSimpleOperator() { V3ERROR_NA; return "";} virtual bool cleanOut() {V3ERROR_NA; return "";} virtual int instrCount() const { return widthInstrs()*2; } AstNode* lhsp() const { return op1p(); } // op1 = expression to assign or another AstPattern AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) AstNode* repp() const { return op3p(); } // op3 = replication count, or NULL for count 1 bool isDefault() const { return m_default; } void isDefault(bool flag) { m_default = flag; } }; //====================================================================== // SysVerilog assertions struct AstVAssert : public AstNodeStmt { // Verilog Assertion // Parents: {statement list} // Children: expression, if pass statements, if fail statements AstVAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp) : AstNodeStmt(fl) { addOp1p(propp); addNOp2p(passsp); addNOp3p(failsp); } ASTNODE_NODE_FUNCS(VAssert, VASSERT) virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } AstNode* propp() const { return op1p(); } // op1 = property AstNode* passsp() const { return op2p(); } // op2 = if passes AstNode* failsp() const { return op3p(); } // op3 = if fails }; //====================================================================== // Assertions struct AstClocking : public AstNode { // Set default clock region // Parents: MODULE // Children: Assertions AstClocking(FileLine* fl, AstNodeSenItem* sensesp, AstNode* bodysp) : AstNode(fl) { addOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(Clocking, CLOCKING) AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); } // op1 = Sensitivity list AstNode* bodysp() const { return op2p(); } // op2 = Body }; //====================================================================== // PSL struct AstPslDefClock : public AstNode { // Set default PSL clock // Parents: MODULE // Children: SENITEM AstPslDefClock(FileLine* fl, AstNodeSenItem* sensesp) : AstNode(fl) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(PslDefClock, PSLDEFCLOCK) AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); } // op1 = Sensitivity list }; struct AstPslClocked : public AstNode { // A clocked property // Parents: ASSERT|COVER (property) // Children: SENITEM, Properties AstPslClocked(FileLine* fl, AstNodeSenItem* sensesp, AstNode* disablep, AstNode* propp) : AstNode(fl) { addNOp1p(sensesp); addNOp2p(disablep); addOp3p(propp); } ASTNODE_NODE_FUNCS(PslClocked, PSLCLOCKED) virtual bool hasDType() const { return true; } // Used under PslCover, which expects a bool child AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); } // op1 = Sensitivity list AstNode* disablep() const { return op2p(); } // op2 = disable AstNode* propp() const { return op3p(); } // op3 = property }; struct AstPslAssert : public AstNodeStmt { // Psl Assertion // Parents: {statement list} // Children: expression, report string private: string m_name; // Name to report public: AstPslAssert(FileLine* fl, AstNode* propp, const string& name="") : AstNodeStmt(fl) , m_name(name) { addOp1p(propp); } ASTNODE_NODE_FUNCS(PslAssert, PSLASSERT) virtual string name() const { return m_name; } // * = Var name virtual V3Hash sameHash() const { return V3Hash(name()); } virtual bool same(AstNode* samep) const { return samep->name() == name(); } AstNode* propp() const { return op1p(); } // op1 = property AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain }; struct AstPslCover : public AstNodeStmt { // Psl Cover // Parents: {statement list} // Children: expression, report string private: string m_name; // Name to report public: AstPslCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="") : AstNodeStmt(fl) , m_name(name) { addOp1p(propp); addNOp4p(stmtsp); } ASTNODE_NODE_FUNCS(PslCover, PSLCOVER) virtual string name() const { return m_name; } // * = Var name virtual V3Hash sameHash() const { return V3Hash(name()); } virtual bool same(AstNode* samep) const { return samep->name() == name(); } virtual void name(const string& name) { m_name = name; } AstNode* propp() const { return op1p(); } // op1 = property AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain AstNode* coverincp() const { return op3p(); } // op3 = coverage node void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node AstNode* stmtsp() const { return op4p(); } // op4 = statements }; //====================================================================== // PSL Expressions struct AstPslBool : public AstNode { // Separates PSL Sere/sequences from the normal expression boolean layer below. // Note this excludes next() and similar functions; they are time domain, so not under AstPslBool. // Parents: Sequences, etc. // Children: math AstPslBool(FileLine* fileline, AstNode* exprp) : AstNode(fileline) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(PslBool, PSLBOOL) AstNode* exprp() const { return op1p()->castNode(); } // op1= expression virtual bool hasDType() const { return true; } virtual bool isGateOptimizable() const { return false; } // Not relevant virtual bool isPredictOptimizable() const { return false; } // Not relevant virtual int instrCount() const { return 0; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; //====================================================================== // Text based nodes struct AstText : public AstNodeText { private: bool m_tracking; // When emit, it's ok to parse the string to do indentation public: AstText(FileLine* fl, const string& textp, bool tracking=false) : AstNodeText(fl, textp), m_tracking(tracking) {} ASTNODE_NODE_FUNCS(Text, TEXT) void tracking(bool flag) { m_tracking = flag; } bool tracking() const { return m_tracking; } }; struct AstScCtor : public AstNodeText { AstScCtor(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScCtor, SCCTOR) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstScDtor : public AstNodeText { AstScDtor(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScDtor, SCDTOR) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstScHdr : public AstNodeText { AstScHdr(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScHdr, SCHDR) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstScImp : public AstNodeText { AstScImp(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScImp, SCIMP) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstScImpHdr : public AstNodeText { AstScImpHdr(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScImpHdr, SCIMPHDR) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstScInt : public AstNodeText { AstScInt(FileLine* fl, const string& textp) : AstNodeText(fl, textp) {} ASTNODE_NODE_FUNCS(ScInt, SCINT) virtual bool isPure() const { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const { return true; } }; struct AstUCStmt : public AstNodeStmt { // User $c statement AstUCStmt(FileLine* fl, AstNode* exprsp) : AstNodeStmt(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCStmt, UCSTMT) AstNode* bodysp() const { return op1p()->castNode(); } // op1= expressions to print virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } virtual bool isOutputter() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } }; //====================================================================== // Emit C nodes struct AstCFile : public AstNode { // C++ output file // Parents: NETLIST // Children: nothing yet private: string m_name; ///< Filename bool m_slow:1; ///< Compile w/o optimization bool m_source:1; ///< Source file (vs header file) bool m_support:1; ///< Support file (non systemc) public: AstCFile(FileLine* fl, const string& name) : AstNode(fl) { m_name = name; m_slow = false; m_source = false; m_support = false; } ASTNODE_NODE_FUNCS(CFile, CFILE) virtual string name() const { return m_name; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } virtual void dump(ostream& str=cout); bool slow() const { return m_slow; } void slow(bool flag) { m_slow = flag; } bool source() const { return m_source; } void source(bool flag) { m_source = flag; } bool support() const { return m_support; } void support(bool flag) { m_support = flag; } }; struct AstCFunc : public AstNode { // C++ function // Parents: MODULE/SCOPE // Children: VAR/statements private: AstCFuncType m_funcType; AstScope* m_scopep; string m_name; string m_cname; // C name, for dpiExports string m_rtnType; // void, bool, or other return type string m_argTypes; bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special bool m_skipDecl:1; // Don't declare it bool m_declPrivate:1; // Declare it private bool m_formCallTree:1; // Make a global function to call entire tree of functions bool m_slow:1; // Slow routine, called once or just at init time bool m_funcPublic:1; // From user public task/function bool m_isStatic:1; // Function is declared static (no this) bool m_symProlog:1; // Setup symbol table for later instructions bool m_entryPoint:1; // User may call into this top level function bool m_pure:1; // Pure function bool m_dpiExport:1; // From dpi export bool m_dpiExportWrapper:1; // From dpi export; static function with dispatch table bool m_dpiImport:1; // From dpi import public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="") : AstNode(fl) { m_funcType = AstCFuncType::FT_NORMAL; m_scopep = scopep; m_name = name; m_rtnType = rtnType; m_dontCombine = false; m_skipDecl = false; m_declPrivate = false; m_formCallTree = false; m_slow = false; m_funcPublic = false; m_isStatic = true; // Note defaults to static, later we see where thisp is needed m_symProlog = false; m_entryPoint = false; m_pure = false; m_dpiExport = false; m_dpiExportWrapper = false; m_dpiImport = false; } ASTNODE_NODE_FUNCS(CFunc, CFUNC) virtual string name() const { return m_name; } virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); } virtual bool maybePointedTo() const { return true; } virtual void dump(ostream& str=cout); virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType()) && (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid()) && (argTypes()==samep->castCFunc()->argTypes()) && (!(dpiImport() || dpiExport()) || name()==samep->castCFunc()->name())); } // virtual void name(const string& name) { m_name = name; } virtual int instrCount() const { return dpiImport() ? instrCountDpi() : 0; } void cname(const string& name) { m_cname = name; } string cname() const { return m_cname; } AstScope* scopep() const { return m_scopep; } void scopep(AstScope* nodep) { m_scopep = nodep; } string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); } bool dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; } void dontCombine(bool flag) { m_dontCombine = flag; } bool skipDecl() const { return m_skipDecl; } void skipDecl(bool flag) { m_skipDecl = flag; } bool declPrivate() const { return m_declPrivate; } void declPrivate(bool flag) { m_declPrivate = flag; } bool formCallTree() const { return m_formCallTree; } void formCallTree(bool flag) { m_formCallTree = flag; } bool slow() const { return m_slow; } void slow(bool flag) { m_slow = flag; } bool funcPublic() const { return m_funcPublic; } void funcPublic(bool flag) { m_funcPublic = flag; } void argTypes(const string& str) { m_argTypes = str; } string argTypes() const { return m_argTypes; } void funcType(AstCFuncType flag) { m_funcType = flag; } AstCFuncType funcType() const { return m_funcType; } bool isStatic() const { return m_isStatic; } void isStatic(bool flag) { m_isStatic = flag; } bool symProlog() const { return m_symProlog; } void symProlog(bool flag) { m_symProlog = flag; } bool entryPoint() const { return m_entryPoint; } void entryPoint(bool flag) { m_entryPoint = flag; } bool pure() const { return m_pure; } void pure(bool flag) { m_pure = flag; } bool dpiExport() const { return m_dpiExport; } void dpiExport(bool flag) { m_dpiExport = flag; } bool dpiExportWrapper() const { return m_dpiExportWrapper; } void dpiExportWrapper(bool flag) { m_dpiExportWrapper = flag; } bool dpiImport() const { return m_dpiImport; } void dpiImport(bool flag) { m_dpiImport = flag; } // // If adding node accessors, see below emptyBody AstNode* argsp() const { return op1p()->castNode(); } void addArgsp(AstNode* nodep) { addOp1p(nodep); } AstNode* initsp() const { return op2p()->castNode(); } void addInitsp(AstNode* nodep) { addOp2p(nodep); } AstNode* stmtsp() const { return op3p()->castNode(); } void addStmtsp(AstNode* nodep) { addOp3p(nodep); } AstNode* finalsp() const { return op4p()->castNode(); } void addFinalsp(AstNode* nodep) { addOp4p(nodep); } // Special methods bool emptyBody() const { return argsp()==NULL && initsp()==NULL && stmtsp()==NULL && finalsp()==NULL; } }; struct AstCCall : public AstNodeStmt { // C++ function call // Parents: Anything above a statement // Children: Args to the function private: AstCFunc* m_funcp; string m_hiername; string m_argTypes; public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp=NULL) : AstNodeStmt(fl) { m_funcp = funcp; addNOp1p(argsp); } AstCCall(AstCCall* oldp, AstCFunc* funcp) // Replacement form for V3Combine // Note this removes old attachments from the oldp : AstNodeStmt(oldp->fileline()) { m_funcp = funcp; m_hiername = oldp->hiername(); m_argTypes = oldp->argTypes(); if (oldp->argsp()) addNOp1p(oldp->argsp()->unlinkFrBackWithNext()); } ASTNODE_NODE_FUNCS(CCall, CCALL) virtual void dump(ostream& str=cout); virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep()->castCFunc(); }} virtual bool broken() const { return (m_funcp && !m_funcp->brokeExists()); } virtual int instrCount() const { return instrCountCall(); } virtual V3Hash sameHash() const { return V3Hash(funcp()); } virtual bool same(AstNode* samep) const { return (funcp()==samep->castCCall()->funcp() && argTypes()==samep->castCCall()->argTypes()); } AstNode* exprsp() const { return op1p()->castNode(); } // op1= expressions to print virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return funcp()->pure(); } virtual bool isOutputter() const { return !(funcp()->pure()); } AstCFunc* funcp() const { return m_funcp; } string hiername() const { return m_hiername; } void hiername(const string& hn) { m_hiername = hn; } void argTypes(const string& str) { m_argTypes = str; } string argTypes() const { return m_argTypes; } // AstNode* argsp() const { return op1p()->castNode(); } void addArgsp(AstNode* nodep) { addOp1p(nodep); } }; struct AstCReturn : public AstNodeStmt { // C++ return from a function // Parents: CFUNC/statement // Children: Math AstCReturn(FileLine* fl, AstNode* lhsp) : AstNodeStmt(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(CReturn, CRETURN) virtual int instrCount() const { return widthInstrs(); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode*) const { return true; } // AstNode* lhsp() const { return op1p(); } }; struct AstCMath : public AstNodeMath { private: bool m_cleanOut; public: // Emit C textual math function (like AstUCFunc) AstCMath(FileLine* fl, AstNode* exprsp) : AstNodeMath(fl), m_cleanOut(true) { addOp1p(exprsp); dtypeFrom(exprsp); } AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut=true) : AstNodeMath(fl), m_cleanOut(cleanOut) { addNOp1p(new AstText(fl, textStmt, true)); if (setwidth) { dtypeSetLogicSized(setwidth,setwidth,AstNumeric::UNSIGNED); } } ASTNODE_NODE_FUNCS(CMath, CMATH) virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool cleanOut() { return m_cleanOut; } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p()->castNode(); } // op1= expressions to print }; struct AstCStmt : public AstNodeStmt { // Emit C statement AstCStmt(FileLine* fl, AstNode* exprsp) : AstNodeStmt(fl) { addNOp1p(exprsp); } AstCStmt(FileLine* fl, const string& textStmt) : AstNodeStmt(fl) { addNOp1p(new AstText(fl, textStmt, true)); } ASTNODE_NODE_FUNCS(CStmt, CSTMT) virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p()->castNode(); } // op1= expressions to print }; //###################################################################### // Right below top struct AstTypeTable : public AstNode { // Container for hash of standard data types // Children: NODEDTYPEs typedef map,AstBasicDType*> LogicMap; AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX]; // enum { IDX0_LOGIC, IDX0_BIT, _IDX0_MAX }; LogicMap m_logicMap[_IDX0_MAX][AstNumeric::_ENUM_MAX]; // uses above IDX enums // typedef map DetailedMap; DetailedMap m_detailedMap; public: AstTypeTable(FileLine* fl) : AstNode(fl) { for (int i=0; icastNodeDType();} // op1 = List of dtypes void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); } AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd); AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin, AstNumeric numeric); AstBasicDType* findInsertSameDType(AstBasicDType* nodep); void clearCache(); void repairCache(); virtual void dump(ostream& str=cout); }; //###################################################################### // Top struct AstNetlist : public AstNode { // All modules are under this single top node. // Parents: none // Children: MODULEs & CFILEs private: AstTypeTable* m_typeTablep; // Reference to top type table, for faster lookup public: AstNetlist() : AstNode(new FileLine("AstRoot",0)) { m_typeTablep = NULL; } ASTNODE_NODE_FUNCS(Netlist, NETLIST) AstNodeModule* modulesp() const { return op1p()->castNodeModule();} // op1 = List of modules AstNodeModule* topModulep() const { return op1p()->castNodeModule(); } // * = Top module in hierarchy (first one added, for now) void addModulep(AstNodeModule* modulep) { addOp1p(modulep); } AstCFile* filesp() const { return op2p()->castCFile();} // op2 = List of files void addFilesp(AstCFile* filep) { addOp2p(filep); } AstNode* miscsp() const { return op3p();} // op3 = List of dtypes etc void addMiscsp(AstNode* nodep) { addOp3p(nodep); } AstTypeTable* typeTablep() { return m_typeTablep; } void addTypeTablep(AstTypeTable* nodep) { m_typeTablep = nodep; addMiscsp(nodep); } }; //###################################################################### #endif // Guard