Support type case and type equality comparisons.

This commit is contained in:
Wilson Snyder 2023-02-12 20:09:10 -05:00
parent 4f19eeaffa
commit 5064ec2806
13 changed files with 344 additions and 25 deletions

View File

@ -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.

View File

@ -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",

View File

@ -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 {

View File

@ -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;

View File

@ -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);
};

View File

@ -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);

View File

@ -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; }

View File

@ -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); }

View 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;

View 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

View 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

View 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;

View 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