forked from github/verilator
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2de586e678 | ||
|
14285f24cd | ||
|
6c6f7f8ae9 | ||
|
42962bf5ee | ||
|
61394bdece | ||
|
240c4e98ac | ||
|
9bd94be5d2 | ||
|
8744ce85d0 | ||
|
87e8e219dd | ||
|
7997ba08cb | ||
|
bfe2760098 | ||
|
a105fdf731 | ||
|
fd175de17e | ||
|
e17f6ed030 | ||
|
5d8d0585c1 | ||
|
d3ac16d6d9 | ||
|
6dd4ff021f | ||
|
693d52b57c | ||
|
67c18ada59 | ||
|
d08d07e89b | ||
|
089fe9ae0f | ||
|
dc517c8335 | ||
|
862892c9bd | ||
|
fce1fa0953 | ||
|
3dcf14ec56 | ||
|
d3a787698b | ||
|
6727a41d7f | ||
|
8535fad052 |
17
src/V3Ast.h
17
src/V3Ast.h
@ -2094,6 +2094,15 @@ public:
|
||||
uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions
|
||||
static int uniqueNumInc() { return ++s_uniqueNum; }
|
||||
const char* charIQWN() const { return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); }
|
||||
bool matching(const AstNodeDType* typep) const {
|
||||
if (VN_IS(typep, RefDType) || VN_IS(typep, ConstDType)) {
|
||||
// Unwrap type wrappers
|
||||
return typep->match(this);
|
||||
} else {
|
||||
return match(typep);
|
||||
}
|
||||
}
|
||||
virtual bool match(const AstNodeDType* typep) const = 0;
|
||||
};
|
||||
|
||||
class AstNodeUOrStructDType : public AstNodeDType {
|
||||
@ -2148,6 +2157,7 @@ public:
|
||||
int lsb() const { return 0; }
|
||||
int msb() const { return dtypep()->width()-1; } // Packed classes look like arrays
|
||||
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return typep == this; }
|
||||
};
|
||||
|
||||
class AstNodeArrayDType : public AstNodeDType {
|
||||
@ -2205,6 +2215,13 @@ public:
|
||||
int lsb() const;
|
||||
int elementsConst() const;
|
||||
VNumRange declRange() const;
|
||||
virtual bool matchingArrayType(const AstNodeArrayDType* matchp) const = 0;
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstNodeArrayDType* arrayp = VN_CAST_CONST(typep, NodeArrayDType);
|
||||
if (!arrayp) return typep->matching(this);
|
||||
return arrayp && matchingArrayType(arrayp) && declRange() == arrayp->declRange()
|
||||
&& subDTypep()->matching(arrayp->subDTypep());
|
||||
}
|
||||
};
|
||||
|
||||
class AstNodeSel : public AstNodeBiop {
|
||||
|
@ -305,6 +305,7 @@ public:
|
||||
AstVarType varType() const { return m_varType; } // * = Type of variable
|
||||
bool isParam() const { return true; }
|
||||
bool isGParam() const { return (varType()==AstVarType::GPARAM); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return childDTypep()->matching(typep); }
|
||||
};
|
||||
|
||||
class AstTypedef : public AstNode {
|
||||
@ -389,6 +390,7 @@ public:
|
||||
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
|
||||
virtual string name() const { return m_name; }
|
||||
void name(const string& flag) { m_name = flag; }
|
||||
virtual bool match(const AstNodeDType* typep) const { return typep == this; }
|
||||
};
|
||||
|
||||
class AstAssocArrayDType : public AstNodeDType {
|
||||
@ -449,6 +451,11 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstAssocArrayDType* arrayp = VN_CAST_CONST(typep, AssocArrayDType);
|
||||
return arrayp && subDTypep()->matching(arrayp->subDTypep())
|
||||
&& keyDTypep()->matching(arrayp->keyDTypep());
|
||||
}
|
||||
};
|
||||
|
||||
class AstDynArrayDType : public AstNodeDType {
|
||||
@ -499,6 +506,10 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstDynArrayDType* arrayp = VN_CAST_CONST(typep, DynArrayDType);
|
||||
return arrayp && subDTypep()->matching(arrayp->subDTypep());
|
||||
}
|
||||
};
|
||||
|
||||
class AstPackArrayDType : public AstNodeArrayDType {
|
||||
@ -525,6 +536,9 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PackArrayDType)
|
||||
virtual string prettyDTypeName() const;
|
||||
virtual bool matchingArrayType(const AstNodeArrayDType* matchp) const {
|
||||
return VN_IS(matchp, PackArrayDType);
|
||||
}
|
||||
};
|
||||
|
||||
class AstUnpackArrayDType : public AstNodeArrayDType {
|
||||
@ -553,6 +567,9 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(UnpackArrayDType)
|
||||
virtual string prettyDTypeName() const;
|
||||
virtual bool matchingArrayType(const AstNodeArrayDType* matchp) const {
|
||||
return VN_IS(matchp, UnpackArrayDType);
|
||||
}
|
||||
};
|
||||
|
||||
class AstUnsizedArrayDType : public AstNodeDType {
|
||||
@ -596,6 +613,10 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstUnsizedArrayDType* arrayp = VN_CAST_CONST(typep, UnsizedArrayDType);
|
||||
return arrayp && subDTypep()->matching(arrayp->subDTypep());
|
||||
}
|
||||
};
|
||||
|
||||
class AstBasicDType : public AstNodeDType {
|
||||
@ -673,6 +694,14 @@ public:
|
||||
virtual bool same(const AstNode* samep) const { // width/widthMin/numeric compared elsewhere
|
||||
const AstBasicDType* sp = static_cast<const AstBasicDType*>(samep);
|
||||
return m == sp->m; }
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstBasicDType* matchp = VN_CAST_CONST(typep, BasicDType);
|
||||
return matchp && isSigned() == matchp->isSigned()
|
||||
&& (same(matchp) ||
|
||||
(isIntNumeric() && matchp->isIntNumeric()
|
||||
&& isFourstate() == matchp->isFourstate()
|
||||
&& nrange() == matchp->nrange()));
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return type()==samep->type() && same(samep); }
|
||||
virtual string name() const { return m.m_keyword.ascii(); }
|
||||
@ -700,6 +729,7 @@ public:
|
||||
bool isString() const { return keyword().isString(); }
|
||||
bool isSloppy() const { return keyword().isSloppy(); }
|
||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||
bool isIntNumeric() const { return keyword().isIntNumeric(); }
|
||||
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.hi()); }
|
||||
@ -759,6 +789,7 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return subDTypep()->matching(typep); }
|
||||
};
|
||||
|
||||
class AstClassRefDType : public AstNodeDType {
|
||||
@ -798,6 +829,7 @@ public:
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
AstClass* classp() const { return m_classp; }
|
||||
void classp(AstClass* nodep) { m_classp = nodep; }
|
||||
virtual bool match(const AstNodeDType* typep) const { return typep == this; }
|
||||
};
|
||||
|
||||
class AstIfaceRefDType : public AstNodeDType {
|
||||
@ -850,6 +882,8 @@ public:
|
||||
AstModport* modportp() const { return m_modportp; }
|
||||
void modportp(AstModport* modportp) { m_modportp = modportp; }
|
||||
bool isModport() { return !m_modportName.empty(); }
|
||||
// Cannot take type() of interface
|
||||
virtual bool match(const AstNodeDType* typep) const { return false; }
|
||||
};
|
||||
|
||||
class AstQueueDType : public AstNodeDType {
|
||||
@ -899,6 +933,10 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const {
|
||||
const AstQueueDType* queuep = VN_CAST_CONST(typep, QueueDType);
|
||||
return queuep && subDTypep()->matching(queuep->subDTypep());
|
||||
}
|
||||
};
|
||||
|
||||
class AstRefDType : public AstNodeDType {
|
||||
@ -964,6 +1002,7 @@ public:
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep = nodep; }
|
||||
AstNode* typeofp() const { return op2p(); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return refDTypep()->matching(typep); }
|
||||
};
|
||||
|
||||
class AstStructDType : public AstNodeUOrStructDType {
|
||||
@ -1041,6 +1080,7 @@ public:
|
||||
virtual string tag() const { return m_tag; }
|
||||
int lsb() const { return m_lsb; }
|
||||
void lsb(int lsb) { m_lsb = lsb; }
|
||||
virtual bool match(const AstNodeDType* typep) const { return subDTypep()->matching(typep); }
|
||||
};
|
||||
|
||||
class AstVoidDType : public AstNodeDType {
|
||||
@ -1063,6 +1103,7 @@ public:
|
||||
virtual int widthAlignBytes() const { return 1; }
|
||||
virtual int widthTotalBytes() const { return 1; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return false; }
|
||||
};
|
||||
|
||||
class AstEnumItem : public AstNode {
|
||||
@ -1156,6 +1197,7 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool match(const AstNodeDType* typep) const { return typep == this; }
|
||||
};
|
||||
|
||||
class AstParseTypeDType : public AstNodeDType {
|
||||
@ -1175,6 +1217,7 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return 0; }
|
||||
virtual int widthTotalBytes() const { return 0; }
|
||||
virtual bool match(const AstNodeDType* typep) const { return false; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@ -2981,6 +3024,18 @@ public:
|
||||
void priorityPragma(bool flag) { m_priorityPragma = flag; }
|
||||
};
|
||||
|
||||
class AstTypeCase : public AstNodeCase {
|
||||
// Case statement for type references
|
||||
// Parents: {statement list}
|
||||
// exprp Children: MATHs
|
||||
// casesp Children: CASEITEMs
|
||||
public:
|
||||
AstTypeCase(FileLine* fl, AstNodeDType* typep, AstNode* casesp)
|
||||
: ASTGEN_SUPER(fl, typep, casesp) { }
|
||||
ASTNODE_NODE_FUNCS(TypeCase)
|
||||
virtual string verilogKwd() const { return "case"; }
|
||||
};
|
||||
|
||||
class AstCaseItem : public AstNode {
|
||||
// Single item of a case statement
|
||||
// Parents: CASE
|
||||
@ -5647,6 +5702,39 @@ public:
|
||||
virtual int instrCount() const { return instrCountString(); }
|
||||
virtual bool stringFlavor() const { return true; }
|
||||
};
|
||||
class AstEqT : public AstNodeBiCom {
|
||||
public:
|
||||
AstEqT(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(EqT)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqT(this->fileline(), lhsp, rhsp); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEq(lhs, rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f== %r)"; }
|
||||
// TOOD -- if we can't even emit C, should this be a child of AstNodeMath?
|
||||
virtual string emitC() { return ""; }
|
||||
virtual string emitSimpleOperator() { return "=="; }
|
||||
virtual bool cleanOut() const { return false; }
|
||||
virtual bool cleanLhs() const { return false; }
|
||||
virtual bool cleanRhs() const { return false; }
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
virtual bool sizeMattersRhs() const { return false; }
|
||||
};
|
||||
class AstNeqT : public AstNodeBiCom {
|
||||
public:
|
||||
AstNeqT(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(NeqT)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstNeqT(this->fileline(), lhsp, rhsp); }
|
||||
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 ""; }
|
||||
virtual string emitSimpleOperator() { return "!="; }
|
||||
virtual bool cleanOut() const { return false; }
|
||||
virtual bool cleanLhs() const { return false; }
|
||||
virtual bool cleanRhs() const { return false; }
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
virtual bool sizeMattersRhs() const { return false; }
|
||||
};
|
||||
class AstShiftL : public AstNodeBiop {
|
||||
public:
|
||||
AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0)
|
||||
|
@ -197,6 +197,7 @@ private:
|
||||
bool m_doGenerate; // Do errors later inside generate statement
|
||||
int m_dtTables; // Number of created data type tables
|
||||
TableMap m_tableMap; // Created tables so can remove duplicates
|
||||
bool m_leaveTypeof; // Don't clean up type-of children
|
||||
|
||||
// ENUMS
|
||||
enum ExtendRule {
|
||||
@ -254,6 +255,9 @@ private:
|
||||
// ... These comparisons don't allow reals
|
||||
virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); }
|
||||
virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visit_cmp_eq_gt(nodep, false); }
|
||||
// ... Type compares
|
||||
virtual void visit(AstEqT* nodep) VL_OVERRIDE { visit_cmp_eq_type(nodep); }
|
||||
virtual void visit(AstNeqT* nodep) VL_OVERRIDE { visit_cmp_eq_type(nodep); }
|
||||
// ... Real compares
|
||||
virtual void visit(AstEqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); }
|
||||
virtual void visit(AstNeqD* nodep) VL_OVERRIDE { visit_cmp_real(nodep); }
|
||||
@ -1301,7 +1305,8 @@ private:
|
||||
userIterateAndNext(nodep->typeofp(), WidthVP(SELF, BOTH).p());
|
||||
AstNode* typeofp = nodep->typeofp();
|
||||
nodep->refDTypep(typeofp->dtypep());
|
||||
VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp);
|
||||
if (!m_leaveTypeof)
|
||||
VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp);
|
||||
// We had to use AstRefDType for this construct as pointers to this type
|
||||
// in type table are still correct (which they wouldn't be if we replaced the node)
|
||||
}
|
||||
@ -3571,6 +3576,35 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void visit_cmp_eq_type(AstNodeBiop* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
// don't clean up types which may not be in the type table
|
||||
// we're going to remove this whole sub-tree anyway
|
||||
m_leaveTypeof = true;
|
||||
userIterateChildren(nodep, WidthVP(CONTEXT, PRELIM).p());
|
||||
m_leaveTypeof = false;
|
||||
bool equal = false;
|
||||
// TODO -- remove
|
||||
nodep->dumpTree(cout, "typeCompare: ");
|
||||
AstRefDType* refLhsp = VN_CAST(nodep->lhsp(), RefDType);
|
||||
AstRefDType* refRhsp = VN_CAST(nodep->rhsp(), RefDType);
|
||||
if (refLhsp && refRhsp) {
|
||||
if (refLhsp->matching(refRhsp)
|
||||
// TODO -- is this even necessary in the end?
|
||||
|| refLhsp->dtypep() == refRhsp->dtypep()) {
|
||||
equal = true;
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Expected two types for type comparison");
|
||||
}
|
||||
bool isNot = VN_IS(nodep, NeqT);
|
||||
uint32_t value = equal ^ isNot ? 1 : 0;
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
1, value));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
void visit_cmp_eq_gt(AstNodeBiop* nodep, bool realok) {
|
||||
// CALLER: AstEq, AstGt, ..., AstLtS
|
||||
// Real allowed if and only if real_lhs set
|
||||
@ -4901,6 +4935,7 @@ public:
|
||||
m_doGenerate = doGenerate;
|
||||
m_dtTables = 0;
|
||||
m_vup = NULL;
|
||||
m_leaveTypeof = false;
|
||||
}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
return userIterateSubtreeReturnEdits(nodep, WidthVP(SELF, BOTH).p());
|
||||
|
@ -2708,6 +2708,7 @@ statement_item<nodep>: // IEEE: statement_item
|
||||
if ($1 == uniq_UNIQUE) $2->uniquePragma(true);
|
||||
if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true);
|
||||
if ($1 == uniq_PRIORITY) $2->priorityPragma(true); }
|
||||
| typeCaseStart typeCase_itemListE yENDCASE { $$ = $1; if ($2) $1->addItemsp($2); }
|
||||
//
|
||||
// // IEEE: conditional_statement
|
||||
| unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE
|
||||
@ -2929,6 +2930,10 @@ caseStart<casep>: // IEEE: part of case_statement
|
||||
| yCASEZ '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEZ,$3,NULL); }
|
||||
;
|
||||
|
||||
typeCaseStart<casep>: // IEEE: part of case_statement
|
||||
yCASE '(' type_reference ')' { $$ = new AstTypeCase($1,$3,NULL); }
|
||||
;
|
||||
|
||||
caseAttrE:
|
||||
/*empty*/ { }
|
||||
| caseAttrE yVL_FULL_CASE { GRAMMARP->m_caseAttrp->fullPragma(true); }
|
||||
@ -2945,6 +2950,11 @@ case_itemListE<caseitemp>: // IEEE: [ { case_item } ]
|
||||
| case_itemList { $$ = $1; }
|
||||
;
|
||||
|
||||
typeCase_itemListE<caseitemp>: // IEEE: [ { case_item } ]
|
||||
/* empty */ { $$ = NULL; }
|
||||
| typeCase_itemList { $$ = $1; }
|
||||
;
|
||||
|
||||
case_insideListE<caseitemp>: // IEEE: [ { case_inside_item } ]
|
||||
/* empty */ { $$ = NULL; }
|
||||
| case_inside_itemList { $$ = $1; }
|
||||
@ -2952,11 +2962,21 @@ case_insideListE<caseitemp>: // IEEE: [ { case_inside_item } ]
|
||||
|
||||
case_itemList<caseitemp>: // IEEE: { case_item + ... }
|
||||
caseCondList ':' stmtBlock { $$ = new AstCaseItem($2,$1,$3); }
|
||||
| yDEFAULT ':' stmtBlock { $$ = new AstCaseItem($1,NULL,$3); }
|
||||
| yDEFAULT stmtBlock { $$ = new AstCaseItem($1,NULL,$2); }
|
||||
| case_defaultItem { $$ = $1; }
|
||||
| case_itemList caseCondList ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
|
||||
| case_itemList yDEFAULT stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$3)); }
|
||||
| case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($2,NULL,$4)); }
|
||||
| case_itemList case_defaultItem { $$ = $1;$1->addNext($2); }
|
||||
;
|
||||
|
||||
case_defaultItem<caseitemp>:
|
||||
yDEFAULT ':' stmtBlock { $$ = new AstCaseItem($1,NULL,$3); }
|
||||
| yDEFAULT stmtBlock { $$ = new AstCaseItem($1,NULL,$2); }
|
||||
;
|
||||
|
||||
typeCase_itemList<caseitemp>: // IEEE: { case_item + ... } but for type references
|
||||
typeCaseCondList ':' stmtBlock { $$ = new AstCaseItem($2,$1,$3); }
|
||||
| case_defaultItem { $$ = $1; }
|
||||
| typeCase_itemList typeCaseCondList ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,$2,$4)); }
|
||||
| typeCase_itemList case_defaultItem { $$ = $1;$1->addNext($2); }
|
||||
;
|
||||
|
||||
case_inside_itemList<caseitemp>: // IEEE: { case_inside_item + open_range_list ... }
|
||||
@ -2992,6 +3012,11 @@ caseCondList<nodep>: // IEEE: part of case_item
|
||||
| caseCondList ',' expr { $$ = $1;$1->addNext($3); }
|
||||
;
|
||||
|
||||
typeCaseCondList<nodep>: // IEEE: also part of case_item
|
||||
type_reference { $$ = $1; }
|
||||
| typeCaseCondList ',' type_reference { $$ = $1;$1->addNext($3); }
|
||||
;
|
||||
|
||||
patternNoExpr<nodep>: // IEEE: pattern **Excluding Expr*
|
||||
'.' id/*variable*/ { $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); }
|
||||
| yP_DOTSTAR { $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); }
|
||||
@ -3695,6 +3720,10 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
||||
| ~l~expr '*' ~r~expr { $$ = new AstMul ($2,$1,$3); }
|
||||
| ~l~expr '/' ~r~expr { $$ = new AstDiv ($2,$1,$3); }
|
||||
| ~l~expr '%' ~r~expr { $$ = new AstModDiv ($2,$1,$3); }
|
||||
| type_reference yP_EQUAL type_reference { $$ = new AstEqT ($2,$1,$3); }
|
||||
| type_reference yP_NOTEQUAL type_reference { $$ = new AstNeqT ($2,$1,$3); }
|
||||
| type_reference yP_CASEEQUAL type_reference { $$ = new AstEqT ($2,$1,$3); }
|
||||
| type_reference yP_CASENOTEQUAL type_reference { $$ = new AstNeqT ($2,$1,$3); }
|
||||
| ~l~expr yP_EQUAL ~r~expr { $$ = new AstEq ($2,$1,$3); }
|
||||
| ~l~expr yP_NOTEQUAL ~r~expr { $$ = new AstNeq ($2,$1,$3); }
|
||||
| ~l~expr yP_CASEEQUAL ~r~expr { $$ = new AstEqCase ($2,$1,$3); }
|
||||
|
20
test_regress/t/t_type_comparison.pl
Executable file
20
test_regress/t/t_type_comparison.pl
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 by Todd Strader. 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.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
191
test_regress/t/t_type_comparison.v
Normal file
191
test_regress/t/t_type_comparison.v
Normal file
@ -0,0 +1,191 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Todd Strader.
|
||||
|
||||
module foo
|
||||
#(parameter type a_type = logic,
|
||||
parameter type b_type = int)
|
||||
();
|
||||
|
||||
initial begin
|
||||
if (type(a_type) != type(logic[7:0])) begin
|
||||
$display("%%Error: a_type is wrong");
|
||||
$stop();
|
||||
end
|
||||
|
||||
if (type(b_type) != type(real)) begin
|
||||
$display("%%Error: b_type is wrong");
|
||||
$stop();
|
||||
end
|
||||
|
||||
if (type(a_type) == type(logic)) begin
|
||||
$display("%%Error: a_type is the default value");
|
||||
$stop();
|
||||
end
|
||||
|
||||
if (type(b_type) == type(int)) begin
|
||||
$display("%%Error: b_type is the default value");
|
||||
$stop();
|
||||
end
|
||||
|
||||
if (type(a_type) == type(b_type)) begin
|
||||
$display("%%Error: a_type equals b_type");
|
||||
$stop();
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
package pkg;
|
||||
typedef struct packed {logic foo;} struct_t;
|
||||
typedef enum {A_VAL, B_VAL, C_VAL} enum_t;
|
||||
typedef union packed {
|
||||
logic [7:0] foo;
|
||||
logic [3:0] bar;
|
||||
} union_t;
|
||||
endpackage
|
||||
|
||||
module t();
|
||||
|
||||
foo #(
|
||||
.a_type (logic[7:0]),
|
||||
.b_type (real)) the_foo ();
|
||||
|
||||
shortint shortint_v;
|
||||
int int_v;
|
||||
longint longint_v;
|
||||
byte byte_v;
|
||||
bit bit_v;
|
||||
logic logic_v;
|
||||
reg reg_v;
|
||||
integer integer_v;
|
||||
time time_v;
|
||||
|
||||
const int int_c;
|
||||
|
||||
integer string_to_integer_1[string];
|
||||
integer string_to_integer_2[string];
|
||||
integer int_to_integer[int];
|
||||
|
||||
int dyn_1 [];
|
||||
int dyn_2 [];
|
||||
real dyn_3 [];
|
||||
int dyn_4 [] [];
|
||||
int dyn_5 [] [];
|
||||
|
||||
int queue_1 [$];
|
||||
int queue_2 [$];
|
||||
real queue_3 [$];
|
||||
|
||||
// From 6.22.1 (mostly)
|
||||
typedef bit node; // 'bit' and 'node' are matching types
|
||||
typedef node type1;
|
||||
typedef type1 type2; // 'type1' and 'type2' are matching types
|
||||
|
||||
struct packed {int A; int B;} AB1, AB2; // AB1, AB2 have matching types
|
||||
struct packed {int A; int B;} AB3; // the type of AB3 does not match
|
||||
// the type of AB1
|
||||
|
||||
typedef struct packed {int A; int B;} AB_t;
|
||||
AB_t AB4; AB_t AB5; // AB4 and AB5 have matching types
|
||||
typedef struct packed {int A; int B;} otherAB_t;
|
||||
otherAB_t AB6; // the type of AB6 does not match the type of AB4 or AB5
|
||||
|
||||
typedef bit signed [7:0] BYTE; // matches the byte type
|
||||
/* verilator lint_off LITENDIAN */
|
||||
typedef bit signed [0:7] ETYB; // does not match the byte type
|
||||
/* verilator lint_on LITENDIAN */
|
||||
typedef bit [7:0] UNSIGNED_BYTE; // also does not match the byte type
|
||||
|
||||
typedef byte MEM_BYTES [256];
|
||||
typedef bit signed [7:0] MY_MEM_BYTES [256]; // MY_MEM_BYTES matches
|
||||
// MEM_BYTES
|
||||
typedef bit signed [7:0] [255:0] MEM_BYTES_PACKED;
|
||||
typedef bit signed [7:0] [255:0] MY_MEM_BYTES_PACKED;
|
||||
typedef logic [1:0] [3:0] NIBBLES;
|
||||
typedef logic [7:0] MY_BYTE; // MY_BYTE and NIBBLES are not matching types
|
||||
typedef logic MD_ARY [][2:0];
|
||||
typedef logic MD_ARY_TOO [][0:2]; // Does not match MD_ARY
|
||||
|
||||
typedef byte signed MY_CHAR; // MY_CHAR matches the byte type
|
||||
|
||||
// 6.22.1 h
|
||||
import pkg::*;
|
||||
struct_t struct_v;
|
||||
enum_t enum_v;
|
||||
union_t union_v;
|
||||
|
||||
bit should_be_true;
|
||||
|
||||
initial begin
|
||||
// size of non-fixed-length arrays does not matter for type matching
|
||||
string_to_integer_2["foo"] = 5;
|
||||
dyn_1 = new[100];
|
||||
dyn_2[3] = 7;
|
||||
queue_1.push_front(8);
|
||||
|
||||
if (type(shortint) != type(shortint_v)) $stop();
|
||||
if (type(int) != type(int_v)) $stop();
|
||||
if (type(longint) != type(longint_v)) $stop();
|
||||
if (type(byte) != type(byte_v)) $stop();
|
||||
if (type(bit) != type(bit_v)) $stop();
|
||||
if (type(logic) != type(logic_v)) $stop();
|
||||
if (type(reg) != type(reg_v)) $stop();
|
||||
if (type(integer) != type(integer_v)) $stop();
|
||||
if (type(time) != type(time_v)) $stop();
|
||||
if (type(string_to_integer_1) != type(string_to_integer_2)) $stop();
|
||||
if (type(string_to_integer_1) == type(int_to_integer)) $stop();
|
||||
if (type(dyn_1) != type(dyn_2)) $stop();
|
||||
if (type(dyn_1) == type(dyn_3)) $stop();
|
||||
if (type(dyn_1) == type(dyn_4)) $stop();
|
||||
if (type(dyn_4) != type(dyn_5)) $stop();
|
||||
if (type(queue_1) != type(queue_2)) $stop();
|
||||
if (type(queue_1) == type(queue_3)) $stop();
|
||||
if (type(bit) != type(node)) $stop();
|
||||
if (type(type1) != type(type2)) $stop();
|
||||
if (type(AB1) != type(AB2)) $stop();
|
||||
if (type(AB3) == type(AB1)) $stop();
|
||||
if (type(AB4) != type(AB5)) $stop();
|
||||
if (type(AB6) == type(AB4)) $stop();
|
||||
if (type(AB6) == type(AB5)) $stop();
|
||||
if (type(BYTE) != type(byte)) $stop();
|
||||
if (type(ETYB) == type(byte)) $stop();
|
||||
if (type(BYTE) == type(UNSIGNED_BYTE)) $stop();
|
||||
if (type(MEM_BYTES) != type(MY_MEM_BYTES)) $stop();
|
||||
if (type(MEM_BYTES_PACKED) != type(MY_MEM_BYTES_PACKED)) $stop();
|
||||
if (type(NIBBLES) == type(MY_BYTE)) $stop();
|
||||
if (type(MD_ARY) == type(MD_ARY_TOO)) $stop();
|
||||
if (type(MY_CHAR) != type(byte)) $stop();
|
||||
if (type(struct_v) != type(struct_t)) $stop();
|
||||
if (type(struct_v) != type(pkg::struct_t)) $stop();
|
||||
if (type(struct_t) != type(pkg::struct_t)) $stop();
|
||||
if (type(struct_v.foo) != type(logic)) $stop();
|
||||
if (type(logic) != type(struct_v.foo)) $stop();
|
||||
if (type(enum_v) != type(enum_t)) $stop();
|
||||
if (type(union_v) != type(union_t)) $stop();
|
||||
// TODO -- the rest
|
||||
// TODO -- case statement
|
||||
// TODO -- generate case
|
||||
|
||||
if (type(shortint) !== type(shortint_v)) $stop();
|
||||
if (type(int) === type(shortint_v)) $stop();
|
||||
|
||||
if (type(int_c) != type(int_v)) $stop();
|
||||
if (type(int_v) != type(int_c)) $stop();
|
||||
|
||||
should_be_true = '0;
|
||||
// case (type(shortint_v))
|
||||
// type(shortint): should_be_true = '1;
|
||||
// type(int): $stop();
|
||||
// default: $stop();
|
||||
// endcase
|
||||
//
|
||||
// if (!should_be_true) $stop();
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user