Fix enum values of 11-16 bits wide using .next/.prev, bug1062.

This commit is contained in:
Wilson Snyder 2016-06-15 22:46:34 -04:00
parent e819e285e2
commit 891214fa72
10 changed files with 161 additions and 41 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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