mirror of
https://github.com/verilator/verilator.git
synced 2025-04-21 12:06:55 +00:00
Fix enum values of 11-16 bits wide using .next/.prev, bug1062.
This commit is contained in:
parent
e819e285e2
commit
891214fa72
2
Changes
2
Changes
@ -6,6 +6,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.885 devel
|
||||
|
||||
**** Fix enum values of 11-16 bits wide using .next/.prev, bug1062. [Brian Flachs]
|
||||
|
||||
**** Fix false warnings on non-power-2 enums using .next/.prev.
|
||||
|
||||
|
||||
|
@ -2981,20 +2981,37 @@ class AstInitArray : public AstNode {
|
||||
// Set a var to a large list of values
|
||||
// The values must be in sorted order, and not exceed the size of the var's array.
|
||||
// The first value on the initsp() list is for the lo() index of the array.
|
||||
// If default is specified, the vector may be sparse, and not provide each value.
|
||||
// Parents: ASTVAR::init()
|
||||
// Children: CONSTs...
|
||||
deque<uint32_t> m_indices; // Which array index each entry in the list is for (if defaultp)
|
||||
public:
|
||||
AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* initsp)
|
||||
AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* defaultp)
|
||||
: AstNode(fl) {
|
||||
dtypep(newDTypep);
|
||||
addNOp1p(initsp);
|
||||
addNOp1p(defaultp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(InitArray, INITARRAY)
|
||||
AstNode* initsp() const { return op1p()->castNode(); } // op1 = Initial value expressions
|
||||
void addInitsp(AstNode* newp) { addOp1p(newp); }
|
||||
AstNode* defaultp() const { return op1p()->castNode(); } // op1 = Default if sparse
|
||||
void defaultp(AstNode* newp) { setOp1p(newp); }
|
||||
AstNode* initsp() const { return op2p()->castNode(); } // op2 = Initial value expressions
|
||||
void addValuep(AstNode* newp) { addIndexValuep(m_indices.size(), newp); }
|
||||
void addIndexValuep(uint32_t index, AstNode* newp) {
|
||||
// Must insert in sorted order
|
||||
if (!m_indices.empty()) UASSERT(index > m_indices.back(), "InitArray adding index <= previous index");
|
||||
m_indices.push_back(index);
|
||||
addOp2p(newp); }
|
||||
void addFrontValuep(AstNode* newp) { // Add to front of list, e.g. index 0.
|
||||
// e.g. 0:100, 1:101 when addFront(200), get 0:200, 1:100, 2:101
|
||||
initsp()->addHereThisAsNext(newp);
|
||||
m_indices.push_back(m_indices.size());
|
||||
}
|
||||
int posIndex(int listPos) {
|
||||
UASSERT (listPos < (int)m_indices.size(), "InitArray past end of indices list");
|
||||
return m_indices[listPos]; }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual bool same(AstNode* samep) const { return m_indices==samep->castInitArray()->m_indices; }
|
||||
};
|
||||
|
||||
class AstPragma : public AstNode {
|
||||
|
@ -1464,9 +1464,21 @@ private:
|
||||
did=true;
|
||||
}
|
||||
else if (m_selp && valuep->castInitArray()) {
|
||||
int bit = m_selp->bitConst();
|
||||
AstNode* itemp = valuep->castInitArray()->initsp();
|
||||
for (int n=0; n<bit && itemp; ++n, itemp=itemp->nextp()) {}
|
||||
AstInitArray* initarp = valuep->castInitArray();
|
||||
uint32_t bit = m_selp->bitConst();
|
||||
int pos = 0;
|
||||
AstNode* itemp = initarp->initsp();
|
||||
for (; itemp; ++pos, itemp=itemp->nextp()) {
|
||||
uint32_t index = initarp->posIndex(pos);
|
||||
if (index == bit) break;
|
||||
if (index > bit) {
|
||||
if (initarp->defaultp()) {
|
||||
itemp = initarp->defaultp();
|
||||
} else {
|
||||
initarp->v3fatalSrc("Not enough values in array initalizement");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (itemp->castConst()) {
|
||||
const V3Number& num = itemp->castConst()->num();
|
||||
//UINFO(2,"constVisit "<<(void*)valuep<<" "<<num<<endl);
|
||||
|
@ -1397,12 +1397,20 @@ void EmitCImp::emitVarReset(AstVar* varp) {
|
||||
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
|
||||
}
|
||||
else if (AstInitArray* initarp = varp->valuep()->castInitArray()) {
|
||||
AstConst* constsp = initarp->initsp()->castConst();
|
||||
if (AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType()) {
|
||||
for (int i=0; i<arrayp->elementsConst(); i++) {
|
||||
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
|
||||
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
|
||||
constsp = constsp->nextp()->castConst();
|
||||
if (initarp->defaultp()) {
|
||||
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
|
||||
puts("{ int __Vi=0;");
|
||||
puts(" for (; __Vi<"+cvtToStr(arrayp->elementsConst()));
|
||||
puts("; ++__Vi) {\n");
|
||||
emitSetVarConstant(varp->name()+"[__Vi]", initarp->defaultp()->castConst());
|
||||
puts("}}\n");
|
||||
}
|
||||
int pos = 0;
|
||||
for (AstNode* itemp = initarp->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
|
||||
int index = initarp->posIndex(pos);
|
||||
if (!initarp->defaultp() && index!=pos) initarp->v3fatalSrc("Not enough values in array initalizement");
|
||||
emitSetVarConstant(varp->name()+"["+cvtToStr(index)+"]", itemp->castConst());
|
||||
}
|
||||
} else {
|
||||
varp->v3fatalSrc("InitArray under non-arrayed var");
|
||||
|
@ -448,9 +448,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep, AstNUser*) {
|
||||
putfs(nodep,"`{");
|
||||
for (AstNode* subp = nodep->initsp(); subp; subp=subp->nextp()) {
|
||||
subp->accept(*this);
|
||||
if (subp->nextp()) putbs(",");
|
||||
int pos = 0;
|
||||
for (AstNode* itemp = nodep->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
|
||||
int index = nodep->posIndex(pos);
|
||||
puts(cvtToStr(index));
|
||||
puts(":");
|
||||
itemp->accept(*this);
|
||||
if (itemp->nextp()) putbs(",");
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
|
@ -421,17 +421,19 @@ class SliceVisitor : public AstNVisitor {
|
||||
if (AstInitArray* initp = nodep->rhsp()->castInitArray()) {
|
||||
//if (debug()>=9) nodep->dumpTree(cout, "-InitArrayIn: ");
|
||||
AstNode* newp = NULL;
|
||||
int index = 0;
|
||||
while (AstNode* subp=initp->initsp()) {
|
||||
for (int pos = 0; AstNode* itemp=initp->initsp(); ++pos) {
|
||||
int index = initp->posIndex(pos);
|
||||
AstNode* lhsp = new AstArraySel(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
index++);
|
||||
newp = AstNode::addNext(newp, nodep->cloneType(lhsp, subp->unlinkFrBack()));
|
||||
index);
|
||||
newp = AstNode::addNext(newp, nodep->cloneType(lhsp, itemp->unlinkFrBack()));
|
||||
// Deleted from list of items without correcting posIndex, but that's ok as about
|
||||
// to delete the entire InitArray
|
||||
}
|
||||
//if (debug()>=9) newp->dumpTreeAndNext(cout, "-InitArrayOut: ");
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
return; // WIll iterate in a moment
|
||||
return; // Will iterate in a moment
|
||||
}
|
||||
// Hasn't been searched for implicit slices yet
|
||||
findImplicit(nodep);
|
||||
|
@ -328,7 +328,7 @@ private:
|
||||
setp = new AstConst (outnump->fileline(), *outnump);
|
||||
}
|
||||
// Note InitArray requires us to have the values in inValue order
|
||||
m_tableVarps[outnum]->varp()->valuep()->castInitArray()->addInitsp(setp);
|
||||
m_tableVarps[outnum]->varp()->valuep()->castInitArray()->addValuep(setp);
|
||||
outnum++;
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ private:
|
||||
if (inValue != inValueNextInitArray++)
|
||||
nodep->v3fatalSrc("InitArray requires us to have the values in inValue order");
|
||||
AstNode* setp = new AstConst (nodep->fileline(), outputChgMask);
|
||||
chgVscp->varp()->valuep()->castInitArray()->addInitsp(setp);
|
||||
chgVscp->varp()->valuep()->castInitArray()->addValuep(setp);
|
||||
}
|
||||
} // each value
|
||||
}
|
||||
|
@ -1504,13 +1504,13 @@ private:
|
||||
if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
|
||||
if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad();
|
||||
}
|
||||
if (adtypep->itemsp()->width() > 64 || msbdim >= 1024) {
|
||||
if (adtypep->itemsp()->width() > 64 || msbdim >= (1<<16)) {
|
||||
nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits");
|
||||
return;
|
||||
}
|
||||
}
|
||||
int selwidth = V3Number::log2b(msbdim)+1; // Width to address a bit
|
||||
AstVar* varp = enumVarp(adtypep, attrType, msbdim);
|
||||
AstVar* varp = enumVarp(adtypep, attrType, (VL_ULL(1)<<selwidth)-1);
|
||||
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp,
|
||||
@ -1703,11 +1703,13 @@ private:
|
||||
}
|
||||
if (arrayp->castUnpackArrayDType()) {
|
||||
if (!newp) {
|
||||
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
|
||||
AstInitArray* newap = new AstInitArray(nodep->fileline(), arrayp, NULL);
|
||||
newap->addValuep(valuep);
|
||||
newp = newap;
|
||||
} else {
|
||||
// We iterate hi()..lo() as that is what packed needs,
|
||||
// but INITARRAY needs lo() first
|
||||
newp->castInitArray()->initsp()->addHereThisAsNext(valuep);
|
||||
newp->castInitArray()->addFrontValuep(valuep);
|
||||
}
|
||||
} else { // Packed. Convert to concat for now.
|
||||
if (!newp) newp = valuep;
|
||||
@ -3409,9 +3411,9 @@ private:
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
// Element 0 is a non-index and has speced values
|
||||
initp->addInitsp(dimensionValue(nodep, attrType, 0));
|
||||
initp->addValuep(dimensionValue(nodep, attrType, 0));
|
||||
for (unsigned i=1; i<msbdim+1; ++i) {
|
||||
initp->addInitsp(dimensionValue(nodep, attrType, i));
|
||||
initp->addValuep(dimensionValue(nodep, attrType, i));
|
||||
}
|
||||
varp->iterate(*this); // May have already done $unit so must do this var
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
@ -3444,6 +3446,16 @@ private:
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
|
||||
// Default for all unspecified values
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
initp->defaultp(new AstConst(nodep->fileline(), AstConst::String(), ""));
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT
|
||||
|| attrType == AstAttrType::ENUM_PREV) {
|
||||
initp->defaultp(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), nodep->width(), 0)));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
|
||||
// Find valid values and populate
|
||||
if (!nodep->itemsp()) nodep->v3fatalSrc("enum without items");
|
||||
vector<AstNode*> values;
|
||||
@ -3473,20 +3485,10 @@ private:
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
// Fill in all unspecified values and add to table
|
||||
// Add all specified values to table
|
||||
for (unsigned i=0; i<(msbdim+1); ++i) {
|
||||
AstNode* valp = values[i];
|
||||
if (!valp) {
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
valp = new AstConst(nodep->fileline(), AstConst::String(), "");
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT
|
||||
|| attrType == AstAttrType::ENUM_PREV) {
|
||||
valp = new AstConst(nodep->fileline(), V3Number(nodep->fileline(), nodep->width(), 0));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
}
|
||||
initp->addInitsp(valp);
|
||||
if (valp) initp->addIndexValuep(i, valp);
|
||||
}
|
||||
varp->iterate(*this); // May have already done $unit so must do this var
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
|
18
test_regress/t/t_enum_large_methods.pl
Executable file
18
test_regress/t/t_enum_large_methods.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
55
test_regress/t/t_enum_large_methods.v
Normal file
55
test_regress/t/t_enum_large_methods.v
Normal file
@ -0,0 +1,55 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2014 by Wilson Snyder.
|
||||
|
||||
`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 {
|
||||
E01 = 'h1,
|
||||
ELARGE = 'hf00d
|
||||
} my_t;
|
||||
|
||||
integer cyc=0;
|
||||
my_t e;
|
||||
|
||||
string all;
|
||||
|
||||
// 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==20) begin
|
||||
e <= 'h11; // Unknown
|
||||
end
|
||||
else if (cyc==20) begin
|
||||
`checks(e.name, ""); // Unknown
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user