mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support type case and type equality comparisons.
This commit is contained in:
parent
4f19eeaffa
commit
5064ec2806
1
Changes
1
Changes
@ -60,6 +60,7 @@ Verilator 5.006 2023-01-22
|
||||
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support import/export lists in modport (#3886). [Gökçe Aydos]
|
||||
* Support class queue equality (#3895). [Ilya Barkov]
|
||||
* Support type case and type equality comparisons.
|
||||
* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte]
|
||||
* Optimize expansion of extend operators.
|
||||
|
@ -379,6 +379,7 @@ public:
|
||||
ENUM_NAME, // V3Width processes
|
||||
ENUM_VALID, // V3Width processes
|
||||
//
|
||||
TYPEID, // V3Width processes
|
||||
TYPENAME, // V3Width processes
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
@ -406,7 +407,7 @@ public:
|
||||
"DT_PUBLIC",
|
||||
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
||||
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
|
||||
"TYPENAME",
|
||||
"TYPEID", "TYPENAME",
|
||||
"VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
||||
|
@ -3352,6 +3352,30 @@ public:
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
bool stringFlavor() const override { return true; }
|
||||
};
|
||||
class AstEqT final : public AstNodeBiCom {
|
||||
// Equal (==) for data types
|
||||
public:
|
||||
AstEqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_EqT(fl, lhsp, rhsp) {
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEqT;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstEqT{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f== %r)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
};
|
||||
class AstLogEq final : public AstNodeBiCom {
|
||||
public:
|
||||
AstLogEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
@ -3467,6 +3491,30 @@ public:
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
bool stringFlavor() const override { return true; }
|
||||
};
|
||||
class AstNeqT final : public AstNodeBiCom {
|
||||
// Not-equal (!=) for data types
|
||||
public:
|
||||
AstNeqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_NeqT(fl, lhsp, rhsp) {
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstNeqT;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstNeqT{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f!= %r)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSimpleOperator() override { return "!="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_STR; }
|
||||
};
|
||||
|
||||
// === AstNodeBiComAsv ===
|
||||
class AstAdd final : public AstNodeBiComAsv {
|
||||
|
@ -374,6 +374,32 @@ size_t V3ParseImp::tokenPipeScanParam(size_t depth) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
size_t V3ParseImp::tokenPipeScanType(size_t depth) {
|
||||
// Search around IEEE type_reference to see if is expression
|
||||
// Return location of following token, or input if not found
|
||||
// yTYPE__ETC '(' ... ')' ['==' '===' '!=' '!===']
|
||||
if (tokenPeekp(depth)->token != '(') return depth;
|
||||
depth += 1; // Past the (
|
||||
int parens = 1; // Count first (
|
||||
while (true) {
|
||||
const int tok = tokenPeekp(depth)->token;
|
||||
if (tok == 0) {
|
||||
UINFO(9, "tokenPipeScanType hit EOF; probably syntax error to come");
|
||||
break;
|
||||
} else if (tok == '(') {
|
||||
++parens;
|
||||
} else if (tok == ')') {
|
||||
--parens;
|
||||
if (parens == 0) {
|
||||
++depth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++depth;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
void V3ParseImp::tokenPipeline() {
|
||||
// called from bison's "yylex", has a "this"
|
||||
if (m_tokensAhead.empty()) tokenPull(); // corrupts yylval
|
||||
@ -388,6 +414,7 @@ void V3ParseImp::tokenPipeline() {
|
||||
|| token == yLOCAL__LEX //
|
||||
|| token == yNEW__LEX //
|
||||
|| token == ySTATIC__LEX //
|
||||
|| token == yTYPE__LEX //
|
||||
|| token == yVIRTUAL__LEX //
|
||||
|| token == yWITH__LEX //
|
||||
|| token == yaID__LEX //
|
||||
@ -443,6 +470,18 @@ void V3ParseImp::tokenPipeline() {
|
||||
} else {
|
||||
token = ySTATIC__ETC;
|
||||
}
|
||||
} else if (token == yTYPE__LEX) {
|
||||
VL_RESTORER(yylval); // Remember value, as about to read ahead
|
||||
const size_t depth = tokenPipeScanType(0);
|
||||
const int postToken = tokenPeekp(depth)->token;
|
||||
if ( // v-- token v-- postToken
|
||||
// yTYPE__EQ '(' .... ')' EQ_OPERATOR yTYPE_ETC '(' ... ')'
|
||||
postToken == yP_EQUAL || postToken == yP_NOTEQUAL || postToken == yP_CASEEQUAL
|
||||
|| postToken == yP_CASENOTEQUAL) {
|
||||
token = yTYPE__EQ;
|
||||
} else {
|
||||
token = yTYPE__ETC;
|
||||
}
|
||||
} else if (token == yVIRTUAL__LEX) {
|
||||
if (nexttok == yCLASS) {
|
||||
token = yVIRTUAL__CLASS;
|
||||
|
@ -303,6 +303,7 @@ private:
|
||||
void tokenPipeline(); // Internal; called from tokenToBison
|
||||
void tokenPipelineSym();
|
||||
size_t tokenPipeScanParam(size_t depth);
|
||||
size_t tokenPipeScanType(size_t depth);
|
||||
const V3ParseBisonYYSType* tokenPeekp(size_t depth);
|
||||
void preprocDumps(std::ostream& os);
|
||||
};
|
||||
|
@ -106,6 +106,7 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) {
|
||||
|
||||
enum Castable : uint8_t {
|
||||
UNSUPPORTED,
|
||||
SAMEISH,
|
||||
COMPATIBLE,
|
||||
ENUM_EXPLICIT,
|
||||
ENUM_IMPLICIT,
|
||||
@ -114,7 +115,7 @@ enum Castable : uint8_t {
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& str, const Castable& rhs) {
|
||||
static const char* const s_det[]
|
||||
= {"UNSUP", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"};
|
||||
= {"UNSUP", "IDENT", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"};
|
||||
return str << s_det[rhs];
|
||||
}
|
||||
|
||||
@ -314,6 +315,9 @@ private:
|
||||
void visit(AstLteN* nodep) override { visit_cmp_string(nodep); }
|
||||
void visit(AstGtN* nodep) override { visit_cmp_string(nodep); }
|
||||
void visit(AstGteN* nodep) override { visit_cmp_string(nodep); }
|
||||
// ... Data type compares
|
||||
void visit(AstEqT* nodep) override { visit_cmp_type(nodep); }
|
||||
void visit(AstNeqT* nodep) override { visit_cmp_type(nodep); }
|
||||
|
||||
// Widths: out width = lhs width = rhs width
|
||||
// Signed: Output signed iff LHS & RHS signed.
|
||||
@ -1569,6 +1573,10 @@ private:
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
break;
|
||||
}
|
||||
case VAttrType::TYPEID:
|
||||
// Soon to be handled in AstEqT
|
||||
nodep->dtypeSetSigned32();
|
||||
break;
|
||||
default: {
|
||||
// Everything else resolved earlier
|
||||
nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // Approximation, unsized 32
|
||||
@ -1841,7 +1849,7 @@ private:
|
||||
nodep->fromp()->unlinkFrBack()},
|
||||
new AstConst{fl, AstConst::Signed32{}, 1}},
|
||||
new AstConst{fl, AstConst::Signed32{}, 0}};
|
||||
} else if (castable == COMPATIBLE) {
|
||||
} else if (castable == SAMEISH || castable == COMPATIBLE) {
|
||||
nodep->v3warn(CASTCONST, "$cast will always return one as "
|
||||
<< toDtp->prettyDTypeNameQ()
|
||||
<< " is always castable from "
|
||||
@ -1904,7 +1912,7 @@ private:
|
||||
<< toDtp->prettyDTypeNameQ() << " from "
|
||||
<< fromDtp->prettyDTypeNameQ());
|
||||
bad = true;
|
||||
} else if (castable == COMPATIBLE || castable == ENUM_IMPLICIT
|
||||
} else if (castable == SAMEISH || castable == COMPATIBLE || castable == ENUM_IMPLICIT
|
||||
|| castable == ENUM_EXPLICIT) {
|
||||
; // Continue
|
||||
} else if (castable == DYNAMIC_CLASS) {
|
||||
@ -4246,6 +4254,45 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with case(type(data_type))
|
||||
if (AstAttrOf* const exprap = VN_CAST(nodep->exprp(), AttrOf)) {
|
||||
if (exprap->attrType() == VAttrType::TYPEID) {
|
||||
AstNodeDType* const exprDtp = VN_AS(exprap->fromp(), NodeDType);
|
||||
UINFO(9, "case type exprDtp " << exprDtp << endl);
|
||||
// V3Param may have a pointer to this case statement, and we need
|
||||
// dotted references to remain properly named, so rather than
|
||||
// removing we convert it to a "normal" expression "case (1) ..."
|
||||
FileLine* const newfl = nodep->fileline();
|
||||
newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform
|
||||
newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform
|
||||
nodep->fileline(newfl);
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->isDefault()) {
|
||||
bool hit = false;
|
||||
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
|
||||
const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf);
|
||||
if (!condAttrp) {
|
||||
condp->v3error(
|
||||
"Case(type) statement requires items that have type() items");
|
||||
} else {
|
||||
AstNodeDType* const condDtp = VN_AS(condAttrp->fromp(), NodeDType);
|
||||
if (computeCastable(exprDtp, condDtp, nodep) == SAMEISH) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushDeletep(itemp->condsp()->unlinkFrBackWithNext());
|
||||
// Item condition becomes constant 1 if hits else 0
|
||||
itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit});
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(exprap->unlinkFrBack()), exprap);
|
||||
nodep->exprp(new AstConst{newfl, AstConst::BitTrue{}});
|
||||
}
|
||||
}
|
||||
|
||||
// Take width as maximum across all items, if any is real whole thing is real
|
||||
AstNodeDType* subDTypep = nodep->exprp()->dtypep();
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
@ -5729,6 +5776,32 @@ private:
|
||||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit_cmp_type(AstNodeBiop* nodep) {
|
||||
// CALLER: EqT, LtT
|
||||
// Widths: 1 bit out
|
||||
// Data type compare (not output)
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{SELF, BOTH}.p());
|
||||
const AstAttrOf* const lhsap = VN_AS(nodep->lhsp(), AttrOf);
|
||||
const AstAttrOf* const rhsap = VN_AS(nodep->rhsp(), AttrOf);
|
||||
UASSERT_OBJ(lhsap->attrType() == VAttrType::TYPEID, lhsap,
|
||||
"Type compare expects type reference");
|
||||
UASSERT_OBJ(rhsap->attrType() == VAttrType::TYPEID, rhsap,
|
||||
"Type compare expects type reference");
|
||||
AstNodeDType* const lhsDtp = VN_AS(lhsap->fromp(), NodeDType);
|
||||
AstNodeDType* const rhsDtp = VN_AS(rhsap->fromp(), NodeDType);
|
||||
UINFO(9, "==type lhsDtp " << lhsDtp << endl);
|
||||
UINFO(9, "==type rhsDtp " << lhsDtp << endl);
|
||||
const bool invert = VN_IS(nodep, NeqT);
|
||||
const bool identical = computeCastable(lhsDtp, rhsDtp, nodep) == SAMEISH;
|
||||
UINFO(9, "== " << identical << endl);
|
||||
const bool eq = invert ^ identical;
|
||||
AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitTrue{}, eq};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
|
||||
// CALLER: (real_ok=false) Not
|
||||
@ -6346,8 +6419,8 @@ private:
|
||||
if (const AstEnumDType* const expEnump
|
||||
= VN_CAST(expDTypep->skipRefToEnump(), EnumDType)) {
|
||||
const auto castable = computeCastable(expEnump, underp->dtypep(), underp);
|
||||
if (castable != COMPATIBLE && castable != ENUM_IMPLICIT && !VN_IS(underp, Cast)
|
||||
&& !VN_IS(underp, CastDynamic) && !m_enumItemp
|
||||
if (castable != SAMEISH && castable != COMPATIBLE && castable != ENUM_IMPLICIT
|
||||
&& !VN_IS(underp, Cast) && !VN_IS(underp, CastDynamic) && !m_enumItemp
|
||||
&& !nodep->fileline()->warnIsOff(V3ErrorCode::ENUMVALUE) && warnOn) {
|
||||
underp->v3warn(ENUMVALUE,
|
||||
"Implicit conversion to enum "
|
||||
@ -7080,10 +7153,11 @@ private:
|
||||
const Castable castable = UNSUPPORTED;
|
||||
toDtp = toDtp->skipRefToEnump();
|
||||
fromDtp = fromDtp->skipRefToEnump();
|
||||
if (toDtp == fromDtp) return COMPATIBLE;
|
||||
|
||||
if (toDtp == fromDtp) return SAMEISH;
|
||||
if (toDtp->similarDType(fromDtp)) return SAMEISH;
|
||||
// UNSUP unpacked struct/unions (treated like BasicDType)
|
||||
const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp);
|
||||
|
||||
const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType)
|
||||
|| VN_IS(fromBaseDtp, EnumDType)
|
||||
|| VN_IS(fromBaseDtp, NodeUOrStructDType);
|
||||
|
@ -577,7 +577,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
|
||||
"timeprecision" { FL; return yTIMEPRECISION; }
|
||||
"timeunit" { FL; return yTIMEUNIT; }
|
||||
"type" { FL; return yTYPE; }
|
||||
"type" { FL; return yTYPE__LEX; }
|
||||
"typedef" { FL; return yTYPEDEF; }
|
||||
"union" { FL; return yUNION; }
|
||||
"unique" { FL; return yUNIQUE; }
|
||||
|
@ -757,8 +757,10 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
||||
%token<fl> yTRIOR "trior"
|
||||
%token<fl> yTRIREG "trireg"
|
||||
%token<fl> yTRUE "true"
|
||||
%token<fl> yTYPE "type"
|
||||
%token<fl> yTYPEDEF "typedef"
|
||||
%token<fl> yTYPE__EQ "type-then-eqneq"
|
||||
%token<fl> yTYPE__ETC "type"
|
||||
%token<fl> yTYPE__LEX "type-in-lex"
|
||||
%token<fl> yUNION "union"
|
||||
%token<fl> yUNIQUE "unique"
|
||||
%token<fl> yUNIQUE0 "unique0"
|
||||
@ -1865,7 +1867,7 @@ parameter_declarationFront: // IEEE: local_ or parameter_declaration w/o ass
|
||||
|
||||
parameter_declarationTypeFront: // IEEE: local_ or parameter_declaration w/o assignment
|
||||
// // Front must execute first so VARDTYPE is ready before list of vars
|
||||
varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); }
|
||||
varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); }
|
||||
;
|
||||
|
||||
parameter_port_declarationFrontE: // IEEE: local_ or parameter_port_declaration w/o assignment
|
||||
@ -1882,8 +1884,8 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as
|
||||
// // IEEE: parameter_declaration (minus assignment)
|
||||
// // IEEE: local_parameter_declaration (minus assignment)
|
||||
// // Front must execute first so VARDTYPE is ready before list of vars
|
||||
varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); }
|
||||
| yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); }
|
||||
varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); }
|
||||
| yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); }
|
||||
;
|
||||
|
||||
net_declaration<nodep>: // IEEE: net_declaration - excluding implict
|
||||
@ -2105,7 +2107,7 @@ data_typeNoRef<nodeDTypep>: // ==IEEE: data_type, excluding class_ty
|
||||
{ $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; }
|
||||
| yEVENT
|
||||
{ $$ = new AstBasicDType{$1, VBasicDTypeKwd::EVENT}; v3Global.setHasEvents(); }
|
||||
| type_reference { $$ = $1; }
|
||||
| type_referenceDecl { $$ = $1; }
|
||||
// // IEEE: class_scope: see data_type above
|
||||
// // IEEE: class_type: see data_type above
|
||||
// // IEEE: ps_covergroup: see data_type above
|
||||
@ -2137,11 +2139,21 @@ var_data_type<nodeDTypep>: // ==IEEE: var_data_type
|
||||
| yVAR implicit_typeE { $$ = $2; }
|
||||
;
|
||||
|
||||
type_reference<nodeDTypep>: // ==IEEE: type_reference
|
||||
yTYPE '(' exprOrDataType ')'
|
||||
type_referenceBoth<nodeExprp>: // IEEE: type_reference
|
||||
yTYPE__ETC '(' exprOrDataType ')'
|
||||
{ $$ = new AstAttrOf{$1, VAttrType::TYPEID, $3}; }
|
||||
;
|
||||
|
||||
type_referenceDecl<nodeDTypep>: // IEEE: type_reference (as a data type for declaration)
|
||||
yTYPE__ETC '(' exprOrDataType ')'
|
||||
{ $$ = new AstRefDType{$1, AstRefDType::FlagTypeOfExpr{}, $3}; }
|
||||
;
|
||||
|
||||
type_referenceEq<nodeExprp>: // IEEE: type_reference (as an ==/!== expression)
|
||||
yTYPE__EQ '(' exprOrDataType ')'
|
||||
{ $$ = new AstAttrOf{$1, VAttrType::TYPEID, $3}; }
|
||||
;
|
||||
|
||||
struct_unionDecl<nodeUOrStructDTypep>: // IEEE: part of data_type
|
||||
// // packedSigningE is NOP for unpacked
|
||||
ySTRUCT packedSigningE '{'
|
||||
@ -2768,11 +2780,11 @@ c_generate_item<nodep>: // IEEE: generate_item (for checkers)
|
||||
;
|
||||
|
||||
conditional_generate_construct<nodep>: // ==IEEE: conditional_generate_construct
|
||||
yCASE '(' expr ')' ~c~case_generate_itemListE yENDCASE
|
||||
yCASE '(' exprTypeCompare ')' ~c~case_generate_itemListE yENDCASE
|
||||
{ $$ = new AstGenCase{$1, $3, $5}; }
|
||||
| yIF '(' expr ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE
|
||||
| yIF '(' exprTypeCompare ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE
|
||||
{ $$ = new AstGenIf{$1, $3, $5, nullptr}; }
|
||||
| yIF '(' expr ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null
|
||||
| yIF '(' exprTypeCompare ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null
|
||||
{ $$ = new AstGenIf{$1, $3, $5, $7}; }
|
||||
;
|
||||
|
||||
@ -3691,11 +3703,11 @@ unique_priorityE<uniqstate>: // IEEE: unique_priority + empty
|
||||
;
|
||||
|
||||
caseStart<casep>: // IEEE: part of case_statement
|
||||
yCASE '(' expr ')'
|
||||
yCASE '(' exprTypeCompare ')'
|
||||
{ $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASE, $3, nullptr}; }
|
||||
| yCASEX '(' expr ')'
|
||||
| yCASEX '(' exprTypeCompare ')'
|
||||
{ $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASEX, $3, nullptr}; }
|
||||
| yCASEZ '(' expr ')'
|
||||
| yCASEZ '(' exprTypeCompare ')'
|
||||
{ $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASEZ, $3, nullptr}; }
|
||||
;
|
||||
|
||||
@ -3764,8 +3776,8 @@ value_range<nodeExprp>: // ==IEEE: value_range
|
||||
//UNSUP ;
|
||||
|
||||
caseCondList<nodeExprp>: // IEEE: part of case_item
|
||||
expr { $$ = $1; }
|
||||
| caseCondList ',' expr { $$ = $1->addNext($3); }
|
||||
exprTypeCompare { $$ = $1; }
|
||||
| caseCondList ',' exprTypeCompare { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
patternNoExpr<nodep>: // IEEE: pattern **Excluding Expr*
|
||||
@ -4709,6 +4721,11 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
|
||||
| ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS{$2, $1, $3}; }
|
||||
| ~l~expr yP_LTMINUSGT ~r~expr { $$ = new AstLogEq{$2, $1, $3}; }
|
||||
//
|
||||
// // IEEE: expression binary_operator expression (type compare see IEEE footnote)
|
||||
| type_referenceEq yP_CASEEQUAL type_referenceBoth { $$ = new AstEqT{$2, $1, $3}; }
|
||||
| type_referenceEq yP_CASENOTEQUAL type_referenceBoth { $$ = new AstNeqT{$2, $1, $3}; }
|
||||
| type_referenceEq yP_EQUAL type_referenceBoth { $$ = new AstEqT{$2, $1, $3}; }
|
||||
| type_referenceEq yP_NOTEQUAL type_referenceBoth { $$ = new AstNeqT{$2, $1, $3}; }
|
||||
// // IEEE: expr yP_MINUSGT expr (1800-2009)
|
||||
// // Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set"
|
||||
// // To duplicating expr for constraints, just allow the more general form
|
||||
@ -4771,7 +4788,7 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
|
||||
// // expanded from casting_type
|
||||
| simple_type yP_TICK '(' expr ')'
|
||||
{ $$ = new AstCast{$1->fileline(), $4, VFlagChildDType{}, $1}; }
|
||||
| yTYPE '(' exprOrDataType ')' yP_TICK '(' expr ')'
|
||||
| yTYPE__ETC '(' exprOrDataType ')' yP_TICK '(' expr ')'
|
||||
{ $$ = new AstCast{$1, $7, VFlagChildDType{},
|
||||
new AstRefDType{$1, AstRefDType::FlagTypeOfExpr{}, $3}}; }
|
||||
| ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned{$1, $4}; }
|
||||
@ -4946,6 +4963,11 @@ exprStrText<nodep>:
|
||||
| strAsText { $$ = $1; }
|
||||
;
|
||||
|
||||
exprTypeCompare<nodeExprp>:
|
||||
expr { $$ = $1; }
|
||||
| type_referenceBoth { $$ = $1; }
|
||||
;
|
||||
|
||||
cStrList<nodep>:
|
||||
exprStrText { $$ = $1; }
|
||||
| exprStrText ',' cStrList { $$ = $1->addNext($3); }
|
||||
|
21
test_regress/t/t_type_compare.pl
Executable file
21
test_regress/t/t_type_compare.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2004 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
68
test_regress/t/t_type_compare.v
Normal file
68
test_regress/t/t_type_compare.v
Normal file
@ -0,0 +1,68 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module Sub #(parameter type T = type(logic[11:0]));
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
|
||||
int case_ok;
|
||||
|
||||
Sub #(.T(int)) sub();
|
||||
|
||||
typedef logic [12:0] logic12_t;
|
||||
|
||||
// Generate if
|
||||
if (type(logic[12:0]) !== type(logic[12:0])) initial $stop;
|
||||
if (type(logic[12:0]) != type(logic12_t)) initial $stop;
|
||||
if (type(logic[12:0]) !== type(logic12_t)) initial $stop;
|
||||
if (type(logic[22:0]) == type(logic12_t)) initial $stop;
|
||||
if (type(logic[22:0]) === type(logic12_t)) initial $stop;
|
||||
// Generate case
|
||||
case (type(real))
|
||||
type(int): initial $stop;
|
||||
type(real): ;
|
||||
default: initial $stop;
|
||||
endcase
|
||||
|
||||
initial begin
|
||||
if (type(real) == type(logic[12:0])) $stop;
|
||||
if (type(real) === type(logic[12:0])) $stop;
|
||||
if (type(real) != type(real)) $stop;
|
||||
if (type(real) !== type(real)) $stop;
|
||||
if (type(logic[12:0]) !== type(logic[12:0])) $stop;
|
||||
if (type(logic[12:0]) != type(logic12_t)) $stop;
|
||||
if (type(logic[12:0]) !== type(logic12_t)) $stop;
|
||||
if (type(logic[22:0]) == type(logic12_t)) $stop;
|
||||
if (type(logic[22:0]) === type(logic12_t)) $stop;
|
||||
|
||||
// Item selected
|
||||
case (type(real))
|
||||
type(real): case_ok = 1;
|
||||
type(int): $stop;
|
||||
type(chandle): $stop;
|
||||
default: $stop;
|
||||
endcase
|
||||
if (case_ok != 1) $stop;
|
||||
|
||||
// Default selected
|
||||
case (type(real))
|
||||
type(int): $stop;
|
||||
default: case_ok = 2;
|
||||
endcase
|
||||
if (case_ok != 2) $stop;
|
||||
|
||||
// No body selected
|
||||
case (type(real))
|
||||
type(int): $stop;
|
||||
endcase
|
||||
if (case_ok != 2) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
5
test_regress/t/t_type_compare_bad.out
Normal file
5
test_regress/t/t_type_compare_bad.out
Normal file
@ -0,0 +1,5 @@
|
||||
%Error: t/t_type_compare_bad.v:12:9: Case(type) statement requires items that have type() items
|
||||
: ... In instance t
|
||||
12 | 1: $stop;
|
||||
| ^
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_type_compare_bad.pl
Executable file
19
test_regress/t/t_type_compare_bad.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
20
test_regress/t/t_type_compare_bad.v
Normal file
20
test_regress/t/t_type_compare_bad.v
Normal file
@ -0,0 +1,20 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
// Syntax error, so not checking: if (type(real) == 1)) $stop; // Bad
|
||||
|
||||
case (type(real))
|
||||
1: $stop; // Bad
|
||||
default: $finish;
|
||||
endcase
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user