forked from github/verilator
Support up to 64 bit enums for .next/.prev/.name (#3244).
This commit is contained in:
parent
9a722ccf62
commit
59d170c6f8
1
Changes
1
Changes
@ -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]
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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, [=]() { //
|
||||
|
103
src/V3Width.cpp
103
src/V3Width.cpp
@ -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);
|
||||
|
21
test_regress/t/t_enum_huge_methods.pl
Executable file
21
test_regress/t/t_enum_huge_methods.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 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;
|
73
test_regress/t/t_enum_huge_methods.v
Normal file
73
test_regress/t/t_enum_huge_methods.v
Normal 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
|
@ -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);
|
||||
| ^~~~
|
||||
|
Loading…
Reference in New Issue
Block a user