Support up to 64 bit enums for .next/.prev/.name (#3244).

This commit is contained in:
Wilson Snyder 2021-12-11 11:29:01 -05:00
parent 9a722ccf62
commit 59d170c6f8
10 changed files with 288 additions and 88 deletions

View File

@ -19,6 +19,7 @@ Verilator 4.217 devel
**Minor:**
* Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman]
* Fix MSWIN compile error (#2681). [Unai Martinez-Corral]
* Fix VL_STREAML_FAST_QQI with 64 bit left-hand-side (#3232) (#3235)
* Fix $sformat of inputs/outputs (#3236). [Adrien Le Masle]

View File

@ -1017,21 +1017,41 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
// - the default/inititem children might be in different order yet still yield the same table
// See note in AstInitArray::same about the same. This function instead compares by initializer
// value, rather than by tree structure.
const AstUnpackArrayDType* const aDTypep = VN_AS(ap->dtypep(), UnpackArrayDType);
const AstUnpackArrayDType* const bDTypep = VN_AS(bp->dtypep(), UnpackArrayDType);
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) { // Element types differ
return false;
}
if (!aDTypep->rangep()->sameTree(bDTypep->rangep())) { // Ranges differ
return false;
}
// Compare initializer arrays by value. Note this is only called when they hash the same,
// so they likely run at most once per call to 'AstConstPool::findTable'.
const uint32_t size = aDTypep->elementsConst();
for (uint32_t n = 0; n < size; ++n) {
const AstNode* const valAp = ap->getIndexDefaultedValuep(n);
const AstNode* const valBp = bp->getIndexDefaultedValuep(n);
if (!valAp->sameTree(valBp)) { return false; }
if (const AstAssocArrayDType* const aDTypep = VN_CAST(ap->dtypep(), AssocArrayDType)) {
const AstAssocArrayDType* const bDTypep = VN_CAST(bp->dtypep(), AssocArrayDType);
if (!bDTypep) return false;
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
if (!aDTypep->keyDTypep()->sameTree(bDTypep->keyDTypep())) return false;
UASSERT_OBJ(ap->defaultp(), ap, "Assoc InitArray should have a default");
UASSERT_OBJ(bp->defaultp(), bp, "Assoc InitArray should have a default");
if (!ap->defaultp()->sameTree(bp->defaultp())) return false;
// Compare initializer arrays by value. Note this is only called when they hash the same,
// so they likely run at most once per call to 'AstConstPool::findTable'.
// This assumes that the defaults are used in the same way.
// TODO when buinding the AstInitArray, remove any values matching the default
const auto& amapr = ap->map();
const auto& bmapr = bp->map();
const auto ait = amapr.cbegin();
const auto bit = bmapr.cbegin();
while (ait != amapr.cend() || bit != bmapr.cend()) {
if (ait == amapr.cend() || bit == bmapr.cend()) return false; // Different size
if (ait->first != bit->first) return false; // Different key
if (ait->second->sameTree(bit->second)) return false; // Different value
}
} else if (const AstUnpackArrayDType* const aDTypep
= VN_CAST(ap->dtypep(), UnpackArrayDType)) {
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
if (!bDTypep) return false;
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
if (!aDTypep->rangep()->sameTree(bDTypep->rangep())) return false;
// Compare initializer arrays by value. Note this is only called when they hash the same,
// so they likely run at most once per call to 'AstConstPool::findTable'.
const vluint64_t size = aDTypep->elementsConst();
for (vluint64_t n = 0; n < size; ++n) {
const AstNode* const valAp = ap->getIndexDefaultedValuep(n);
const AstNode* const valBp = bp->getIndexDefaultedValuep(n);
if (!valAp->sameTree(valBp)) return false;
}
}
return true;
}
@ -1039,8 +1059,9 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
const AstNode* const defaultp = initp->defaultp();
// Verify initializer is well formed
UASSERT_OBJ(VN_IS(initp->dtypep(), UnpackArrayDType), initp,
"Const pool table must have AstUnpackArrayDType dtype");
UASSERT_OBJ(VN_IS(initp->dtypep(), AssocArrayDType)
|| VN_IS(initp->dtypep(), UnpackArrayDType),
initp, "Const pool table must have array dtype");
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
"Const pool table default must be Const");
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {

View File

@ -538,6 +538,12 @@ public:
keyDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
}
AstAssocArrayDType(FileLine* fl, AstNodeDType* dtp, AstNodeDType* keyDtp)
: ASTGEN_SUPER_AssocArrayDType(fl) {
refDTypep(dtp);
keyDTypep(keyDtp);
dtypep(dtp);
}
ASTNODE_NODE_FUNCS(AssocArrayDType)
virtual const char* broken() const override {
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
@ -4953,12 +4959,12 @@ class AstInitArray final : public AstNode {
// Parents: ASTVAR::init()
// Children: AstInitItem
public:
using KeyItemMap = std::map<uint32_t, AstInitItem*>;
using KeyItemMap = std::map<vluint64_t, AstInitItem*>;
private:
KeyItemMap m_map; // Node value for each array index
public:
AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* defaultp)
AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp)
: ASTGEN_SUPER_InitArray(fl) {
dtypep(newDTypep);
addNOp1p(defaultp);
@ -4988,7 +4994,7 @@ public:
AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions
void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); }
const KeyItemMap& map() const { return m_map; }
AstNode* addIndexValuep(uint32_t index, AstNode* newp) {
AstNode* addIndexValuep(vluint64_t index, AstNode* newp) {
// Returns old value, caller must garbage collect
AstNode* oldp = nullptr;
const auto it = m_map.find(index);
@ -5002,7 +5008,7 @@ public:
}
return oldp;
}
AstNode* getIndexValuep(uint32_t index) const {
AstNode* getIndexValuep(vluint64_t index) const {
const auto it = m_map.find(index);
if (it == m_map.end()) {
return nullptr;
@ -5010,7 +5016,7 @@ public:
return it->second->valuep();
}
}
AstNode* getIndexDefaultedValuep(uint32_t index) const {
AstNode* getIndexDefaultedValuep(vluint64_t index) const {
AstNode* valuep = getIndexValuep(index);
if (!valuep) valuep = defaultp();
return valuep;

View File

@ -46,27 +46,52 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor {
protected:
// VISITORS
virtual void visit(AstInitArray* nodep) override {
const AstUnpackArrayDType* const dtypep
= VN_AS(nodep->dtypep()->skipRefp(), UnpackArrayDType);
UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype");
const uint32_t size = dtypep->elementsConst();
const uint32_t tabMod = tabModulus(dtypep->subDTypep());
VL_RESTORER(m_inUnpacked);
VL_RESTORER(m_unpackedWord);
m_inUnpacked = true;
// Note the double {{ initializer. The first { starts the initializer of the VlUnpacked,
// and the second starts the initializer of m_storage within the VlUnpacked.
puts("{");
ofp()->putsNoTracking("{");
puts("\n");
for (uint32_t n = 0; n < size; ++n) {
m_unpackedWord = n;
if (n) puts((n % tabMod) ? ", " : ",\n");
iterate(nodep->getIndexDefaultedValuep(n));
if (const AstAssocArrayDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), AssocArrayDType)) {
// Note the double {{ initializer. The first { starts the initializer of the
// VlUnpacked, and the second starts the initializer of m_storage within the
// VlUnpacked.
puts("{");
ofp()->putsNoTracking("{");
puts("\n");
int comma = 0;
const auto& mapr = nodep->map();
for (const auto& itr : mapr) {
if (comma++) putbs(",\n");
puts(cvtToStr(itr.first));
ofp()->printf("%" PRIx64 "ULL", itr.first);
ofp()->putsNoTracking(":");
ofp()->putsNoTracking("{");
iterate(nodep->getIndexValuep(itr.first));
ofp()->putsNoTracking("}");
}
puts("\n");
puts("}");
ofp()->putsNoTracking("}");
} else if (const AstUnpackArrayDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
const vluint64_t size = dtypep->elementsConst();
const uint32_t tabMod = tabModulus(dtypep->subDTypep());
// Note the double {{ initializer. The first { starts the initializer of the
// VlUnpacked, and the second starts the initializer of m_storage within the
// VlUnpacked.
puts("{");
ofp()->putsNoTracking("{");
puts("\n");
for (vluint64_t n = 0; n < size; ++n) {
m_unpackedWord = n;
if (n) puts((n % tabMod) ? ", " : ",\n");
iterate(nodep->getIndexDefaultedValuep(n));
}
puts("\n");
puts("}");
ofp()->putsNoTracking("}");
} else {
nodep->v3fatalSrc("Array initializer has non-array dtype");
}
puts("\n");
puts("}");
ofp()->putsNoTracking("}");
}
virtual void visit(AstInitItem* nodep) override { // LCOV_EXCL_START

View File

@ -622,7 +622,18 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
// If an ARRAYINIT we initialize it using an initial block similar to a signal
// puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
} else if (const AstInitArray* const initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (AstAssocArrayDType* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
if (initarp->defaultp()) {
emitSetVarConstant(varNameProtected + ".atDefault()",
VN_AS(initarp->defaultp(), Const));
}
const auto& mapr = initarp->map();
for (const auto& itr : mapr) {
AstNode* const valuep = itr.second->valuep();
emitSetVarConstant(varNameProtected + ".at(" + cvtToStr(itr.first) + ")",
VN_AS(valuep, Const));
}
} else if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");

View File

@ -351,17 +351,30 @@ private:
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
}
virtual void visit(AstInitArray* nodep) override {
// Hash unpacked array initializers by value, as the order of initializer nodes does not
// matter, and we want semantically equivalent initializers to map to the same hash.
const AstUnpackArrayDType* const dtypep = VN_CAST(nodep->dtypep(), UnpackArrayDType);
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, /* hashChildren: */ !dtypep, [=]() {
if (dtypep) {
const uint32_t size = dtypep->elementsConst();
for (uint32_t n = 0; n < size; ++n) { //
iterateNull(nodep->getIndexDefaultedValuep(n));
}
if (const AstAssocArrayDType* const dtypep = VN_CAST(nodep->dtypep(), AssocArrayDType)) {
if (nodep->defaultp()) {
m_hash
+= hashNodeAndIterate(nodep->defaultp(), HASH_DTYPE, HASH_CHILDREN, [=]() {});
}
});
const auto& mapr = nodep->map();
for (const auto& itr : mapr) { // mapr is sorted, so hash should get stable results
m_hash += itr.first;
m_hash += hashNodeAndIterate(itr.second, HASH_DTYPE, HASH_CHILDREN, [=]() {});
}
} else if (const AstUnpackArrayDType* const dtypep
= VN_CAST(nodep->dtypep(), UnpackArrayDType)) {
// Hash unpacked array initializers by value, as the order of initializer nodes does
// not matter, and we want semantically equivalent initializers to map to the same
// hash.
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, /* hashChildren: */ !dtypep, [=]() {
if (dtypep) {
const uint32_t size = dtypep->elementsConst();
for (uint32_t n = 0; n < size; ++n) { //
iterateNull(nodep->getIndexDefaultedValuep(n));
}
}
});
}
}
virtual void visit(AstPragma* nodep) override {
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //

View File

@ -1675,20 +1675,30 @@ private:
auto* const enumDtp = VN_AS(toDtp, EnumDType);
UASSERT_OBJ(enumDtp, nodep, "$cast determined as enum, but not enum type");
const uint64_t maxval = enumMaxValue(nodep, enumDtp);
const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit
AstVar* const varp
= enumVarp(enumDtp, AstAttrType::ENUM_VALID, (1ULL << selwidth) - 1);
AstVarRef* const varrefp = new AstVarRef(fl, varp, VAccess::READ);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
FileLine* const fl_nowarn = new FileLine(fl);
fl_nowarn->warnOff(V3ErrorCode::WIDTH, true);
auto* const testp = new AstCond{
fl,
new AstGt{fl_nowarn, nodep->fromp()->cloneTree(false),
new AstConst{fl_nowarn, AstConst::Unsized64{}, maxval}},
new AstConst{fl, AstConst::BitFalse{}},
new AstArraySel{fl, varrefp,
new AstSel{fl, nodep->fromp()->cloneTree(false), 0, selwidth}}};
const bool assoc = maxval > ENUM_LOOKUP_BITS;
AstNode* testp = nullptr;
if (assoc) {
AstVar* const varp = enumVarp(enumDtp, AstAttrType::ENUM_VALID, true, 0);
AstVarRef* const varrefp = new AstVarRef{fl, varp, VAccess::READ};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
testp = new AstAssocSel{fl, varrefp, nodep->fromp()->cloneTree(false)};
} else {
const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit
AstVar* const varp
= enumVarp(enumDtp, AstAttrType::ENUM_VALID, false, (1ULL << selwidth) - 1);
AstVarRef* const varrefp = new AstVarRef(fl, varp, VAccess::READ);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
FileLine* const fl_nowarn = new FileLine(fl);
fl_nowarn->warnOff(V3ErrorCode::WIDTH, true);
testp = new AstCond{
fl,
new AstGt{fl_nowarn, nodep->fromp()->cloneTree(false),
new AstConst{fl_nowarn, AstConst::Unsized64{}, maxval}},
new AstConst{fl, AstConst::BitFalse{}},
new AstArraySel{
fl, varrefp,
new AstSel{fl, nodep->fromp()->cloneTree(false), 0, selwidth}}};
}
newp = new AstCond{fl, testp,
new AstExprStmt{fl,
new AstAssign{fl, nodep->top()->unlinkFrBack(),
@ -2224,8 +2234,8 @@ private:
AstNodeDType* const vdtypep = m_vup->dtypeNullp();
UASSERT_OBJ(vdtypep, nodep, "InitArray type not assigned by AstPattern/Var visitor");
nodep->dtypep(vdtypep);
if (const AstNodeArrayDType* const arrayp
= VN_CAST(vdtypep->skipRefp(), NodeArrayDType)) {
const AstNodeDType* const arrayp = vdtypep->skipRefp();
if (VN_IS(arrayp, NodeArrayDType) || VN_IS(arrayp, AssocArrayDType)) {
userIterateChildren(nodep, WidthVP(arrayp->subDTypep(), BOTH).p());
} else {
UINFO(1, "dtype object " << vdtypep->skipRefp() << endl);
@ -2635,17 +2645,27 @@ private:
}
// Need a runtime lookup table. Yuk.
const uint64_t msbdim = enumMaxValue(nodep, adtypep);
const int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit
AstVar* const varp = enumVarp(adtypep, attrType, (1ULL << selwidth) - 1);
AstVarRef* const varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* const newp = new AstArraySel(
nodep->fileline(), varrefp,
// Select in case widths are off due to msblen!=width
// We return "random" values if outside the range, which is fine
// as next/previous on illegal values just need something good out
new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth));
nodep->replaceWith(newp);
const bool assoc = msbdim > ENUM_LOOKUP_BITS;
if (assoc) {
AstVar* const varp = enumVarp(adtypep, attrType, true, 0);
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), varp, VAccess::READ};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* const newp
= new AstAssocSel{nodep->fileline(), varrefp, nodep->fromp()->unlinkFrBack()};
nodep->replaceWith(newp);
} else {
const int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit
AstVar* const varp = enumVarp(adtypep, attrType, false, (1ULL << selwidth) - 1);
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), varp, VAccess::READ};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* const newp = new AstArraySel(
nodep->fileline(), varrefp,
// Select in case widths are off due to msblen!=width
// We return "random" values if outside the range, which is fine
// as next/previous on illegal values just need something good out
new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth));
nodep->replaceWith(newp);
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
nodep->v3error("Unknown built-in enum method " << nodep->prettyNameQ());
@ -5912,19 +5932,19 @@ private:
UASSERT_OBJ(vconstp, errNodep, "Enum item without constified value");
if (vconstp->toUQuad() >= maxval) maxval = vconstp->toUQuad();
}
if (adtypep->itemsp()->width() > 64 || maxval >= (1 << ENUM_LOOKUP_BITS)) {
if (adtypep->itemsp()->width() > 64) {
errNodep->v3warn(E_UNSUPPORTED,
"Unsupported: enum next/prev method on enum with > 10 bits");
return ENUM_LOOKUP_BITS;
"Unsupported: enum next/prev/name method on enum with > 64 bits");
return 64;
}
return maxval;
}
AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) {
AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, bool assoc, uint32_t msbdim) {
// Return a variable table which has specified dimension properties for this variable
const auto pos = m_tableMap.find(std::make_pair(nodep, attrType));
if (pos != m_tableMap.end()) return pos->second;
UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " max=" << msbdim << " for "
<< nodep << endl);
UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " assoc=" << assoc
<< " max=" << msbdim << " for " << nodep << endl);
AstNodeDType* basep;
if (attrType == AstAttrType::ENUM_NAME) {
basep = nodep->findStringDType();
@ -5937,8 +5957,13 @@ private:
} else {
basep = nodep->dtypep();
}
AstNodeArrayDType* const vardtypep = new AstUnpackArrayDType(
nodep->fileline(), basep, new AstRange(nodep->fileline(), msbdim, 0));
AstNodeDType* vardtypep;
if (assoc) {
vardtypep = new AstAssocArrayDType{nodep->fileline(), basep, nodep};
} else {
vardtypep = new AstUnpackArrayDType{nodep->fileline(), basep,
new AstRange(nodep->fileline(), msbdim, 0)};
}
AstInitArray* const initp = new AstInitArray(nodep->fileline(), vardtypep, nullptr);
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
AstVar* const varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
@ -5990,8 +6015,12 @@ private:
}
}
// Add all specified values to table
for (vluint64_t i = 0; i < (msbdim + 1); ++i) {
if (values[i]) initp->addIndexValuep(i, values[i]);
if (assoc) {
for (const auto& itr : values) initp->addIndexValuep(itr.first, itr.second);
} else {
for (vluint64_t i = 0; i < (msbdim + 1); ++i) {
if (values[i]) initp->addIndexValuep(i, values[i]);
}
}
userIterate(varp, nullptr); // May have already done $unit so must do this var
m_tableMap.emplace(std::make_pair(nodep, attrType), varp);

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 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(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,73 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2014 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef enum logic [59:0] {
E01 = 60'h1,
ELARGE = 60'h1234_4567_abcd
} my_t;
integer cyc = 0;
my_t e;
string all;
int i_cast;
// Check runtime
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc == 0) begin
// Setup
e <= E01;
end
else if (cyc == 1) begin
`checks(e.name, "E01");
`checkh(e.next, ELARGE);
e <= ELARGE;
end
else if (cyc == 3) begin
`checks(e.name, "ELARGE");
`checkh(e.next, E01);
`checkh(e.prev, E01);
e <= E01;
end
//
else if (cyc == 10) begin
i_cast <= $cast(e, 60'h1234);
end
else if (cyc == 11) begin
`checkh(i_cast, 0);
i_cast <= $cast(e, 60'h1);
end
else if (cyc == 12) begin
`checkh(i_cast, 1);
i_cast <= $cast(e, 60'h1234_4567_abcd);
end
else if (cyc == 13) begin
`checkh(i_cast, 1);
end
//
else if (cyc == 20) begin
e <= 'h11; // Unknown
end
else if (cyc == 21) begin
`checks(e.name, ""); // Unknown
end
else if (cyc == 99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -1,7 +1,7 @@
%Error: t/t_enum_huge_methods_bad.v:15:11: Value too wide for 64-bits expected in this context 160'h12344567abcd12344567abcd
15 | ELARGE = 160'h1234_4567_abcd_1234_4567_abcd
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%Error-UNSUPPORTED: t/t_enum_huge_methods_bad.v:30:14: Unsupported: enum next/prev method on enum with > 10 bits
%Error-UNSUPPORTED: t/t_enum_huge_methods_bad.v:30:14: Unsupported: enum next/prev/name method on enum with > 64 bits
: ... In instance t
30 | $display(e.name);
| ^~~~