Support '{} assignment pattern on arrays, bug355.

This commit is contained in:
Wilson Snyder 2014-03-30 20:41:20 -04:00
parent 6e3e8318d0
commit 446b0e4e5e
7 changed files with 132 additions and 14 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
** PSL is no longer supported, please use System Verilog assertions.
** Support '{} assignment pattern on arrays, bug355.
*** Add --no-trace-params.
*** Add assertions on 'unique if', bug725. [Jeff Bush]

View File

@ -408,6 +408,22 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (!nodep->user1()) {
// Cleanup initArrays
if (AstInitArray* initp = nodep->rhsp()->castInitArray()) {
//if (debug()>=9) nodep->dumpTree(cout, "-InitArrayIn: ");
AstNode* newp = NULL;
int index = 0;
while (AstNode* subp=initp->initsp()) {
AstNode* lhsp = new AstArraySel(nodep->fileline(),
nodep->lhsp()->cloneTree(false),
index++);
newp = newp->addNext(nodep->cloneType(lhsp, subp->unlinkFrBack()));
}
//if (debug()>=9) newp->dumpTreeAndNext(cout, "-InitArrayOut: ");
nodep->replaceWith(newp);
pushDeletep(nodep); nodep=NULL;
return; // WIll iterate in a moment
}
// Hasn't been searched for implicit slices yet
findImplicit(nodep);
}

View File

@ -911,7 +911,7 @@ private:
}
if (nodep->valuep()) {
//if (debug()) nodep->dumpTree(cout," final: ");
if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep()->width(),0,BOTH).p());
if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep(),BOTH).p());
if (!nodep->valuep()->castInitArray()) { // No dtype at present, perhaps TODO
widthCheck(nodep,"Initial value",nodep->valuep(),nodep->width(),nodep->widthMin());
}
@ -1020,8 +1020,15 @@ private:
nodep->dtypeFrom(nodep->itemp());
}
virtual void visit(AstInitArray* nodep, AstNUser* vup) {
// Should be correct by construction, so we'll just loop through all types
nodep->iterateChildren(*this, vup);
// InitArray has type of the array; children are array values
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("InitArray type not assigned by AstPattern visitor");
nodep->dtypep(vdtypep);
if (AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType()) {
nodep->iterateChildren(*this,WidthVP(arrayp->subDTypep(),BOTH).p());
} else {
nodep->v3fatalSrc("InitArray on non-array");
}
}
virtual void visit(AstInside* nodep, AstNUser* vup) {
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
@ -1269,19 +1276,95 @@ private:
patp->dtypep(memp);
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
if (!newp) newp = patp->lhssp()->unlinkFrBack();
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, patp->lhssp()->unlinkFrBack());
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
if (newpatp) pushDeletep(newpatp);
if (newpatp) { pushDeletep(newpatp); newpatp=NULL; }
}
if (newp) nodep->replaceWith(newp);
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
}
else if (AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType()) {
typedef map<int,AstPatMember*> PatMap;
PatMap patmap;
{
int element = arrayp->declRange().left();
for (AstPatMember* patp = nodep->itemsp()->castPatMember();
patp; patp = patp->nextp()->castPatMember()) {
if (patp->keyp()) {
if (AstConst* constp = patp->keyp()->castConst()) {
element = constp->toSInt();
} else {
patp->keyp()->v3error("Assignment pattern key not supported/understood: "<<patp->keyp()->prettyTypeName());
}
}
if (patmap.find(element) != patmap.end()) {
patp->v3error("Assignment pattern key used multiple times: "<<element);
} else {
patmap.insert(make_pair(element, patp));
}
element += arrayp->declRange().leftToRightInc();
}
}
UINFO(9,"ent "<<arrayp->declRange().hi()<<" to "<<arrayp->declRange().lo()<<endl);
AstNode* newp = NULL;
for (int ent=arrayp->declRange().hi(); ent>=arrayp->declRange().lo(); --ent) {
AstPatMember* newpatp = NULL;
AstPatMember* patp = NULL;
PatMap::iterator it=patmap.find(ent);
if (it == patmap.end()) {
if (defaultp) {
newpatp = defaultp->cloneTree(false);
patp = newpatp;
}
else {
nodep->v3error("Assignment pattern missed initializing elements: "<<ent);
}
} else {
patp = it->second;
patmap.erase(it);
}
// Determine initial values
vdtypep = arrayp->subDTypep();
// Don't want the RHS an array
patp->dtypep(arrayp->subDTypep());
// Determine values - might be another InitArray
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
// Convert to InitArray or constify immediately
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (arrayp->castUnpackArrayDType()) {
if (!newp) {
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
} else {
// We iterate hi()..lo() as that is what packed needs,
// but INITARRAY needs lo() first
newp->castInitArray()->initsp()->addHereThisAsNext(valuep);
}
} else { // Packed. Convert to concat for now.
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
}
if (newpatp) { pushDeletep(newpatp); newpatp=NULL; }
}
if (patmap.size()) nodep->v3error("Assignment pattern with too many elements");
if (newp) nodep->replaceWith(newp);
else nodep->v3error("Assignment pattern with no members");
//if (debug()>=9) newp->dumpTree("-apat-out: ");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
} else {
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<vdtypep->prettyTypeName());
}
@ -1291,10 +1374,11 @@ private:
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
nodep->dtypep(vdtypep);
UINFO(9," PATMEMBER "<<nodep<<endl);
if (nodep->lhssp()->nextp()) nodep->v3fatalSrc("PatMember value should be singular w/replicates removed");
nodep->lhssp()->dtypeFrom(nodep);
nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p());
widthCheck(nodep,"LHS",nodep->lhssp(),nodep->width(),nodep->width());
widthCheck(nodep,"Value",nodep->lhssp(),vdtypep);
}
int visitPatMemberRep(AstPatMember* nodep) {
uint32_t times = 1;

View File

@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug355");
compile (
);

View File

@ -26,11 +26,21 @@ module t (/*AUTOARG*/
//array_simp[0] = '{ 1:4'd3, default:13};
//if (array_simp[0] !== 16'hDD3D) $stop;
array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }};
array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }};
if (array_simp !== 32'h3210_1234) $stop;
// IEEE says '{} allowed only on assignments, not !=, ==.
// Doesn't seem to work for unpacked arrays in other simulators
array_simp = '{2 { '{4 { 4'd3, 4'd2, 4'd1, 4'd0 }} } };
array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }};
if (array_simp !== 32'h3210_3210) $stop;
array_simp = '{2{ '{4{ 4'd3 }} }};
if (array_simp !== 32'h3333_3333) $stop;
// Not legal in other simulators - replication doesn't match
// However IEEE suggests this is legal.
//array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2}
$write("*-* All Finished *-*\n");
$finish;

View File

@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug355");
compile (
);

View File

@ -25,7 +25,17 @@ module t (/*AUTOARG*/);
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_1234) $stop;
// Doesn't seem to work for unpacked arrays in other simulators
array_simp = '{2 { '{4 { 4'd3, 4'd2, 4'd1, 4'd0 }} } };
array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }};
if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0],
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_3210) $stop;
array_simp = '{2{ '{4{ 4'd3 }} }};
if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0],
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3333_3333) $stop;
// Not legal in other simulators - replication doesn't match
// However IEEE suggests this is legal.
//array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2}
$write("*-* All Finished *-*\n");
$finish;