Fix enum.next(0) and enum.prev(0).

This commit is contained in:
Wilson Snyder 2023-02-26 15:24:24 -05:00
parent 4703fc39be
commit c03affa544
3 changed files with 38 additions and 20 deletions

View File

@ -50,6 +50,7 @@ Verilator 5.007 devel
* Fix build on HP PA architecture (#3954). [John David Anglin]
* Fix missing error on negative replicate (#3963). [Benjamin Menküc]
* Fix packed array structure replication.
* Fix enum.next(0) and enum.prev(0).
Verilator 5.006 2023-01-22

View File

@ -2920,34 +2920,47 @@ private:
VAttrType attrType;
if (nodep->name() == "name") {
attrType = VAttrType::ENUM_NAME;
methodOkArguments(nodep, 0, 0);
} else if (nodep->name() == "next") {
attrType = VAttrType::ENUM_NEXT;
methodOkArguments(nodep, 0, 1);
} else if (nodep->name() == "prev") {
attrType = VAttrType::ENUM_PREV;
methodOkArguments(nodep, 0, 1);
} else {
nodep->v3fatalSrc("Bad case");
}
if (nodep->name() == "name") {
methodOkArguments(nodep, 0, 0);
} else if (nodep->pinsp() && !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const))) {
nodep->pinsp()->v3fatalSrc("Unsupported: enum next/prev with non-const argument");
} else if (nodep->pinsp()
&& !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)
&& VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt() == 1
&& !nodep->pinsp()->nextp())) {
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
AstMethodCall* const clonep = nodep->cloneTree(false);
VN_AS(VN_AS(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1);
const uint32_t stepWidth
= VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt();
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
AstArg* const argp = new AstArg{nodep->fileline(), "", constp};
AstMethodCall* const newp
= new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp};
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
if (nodep->name() != "name" && nodep->pinsp()) {
if (!VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)) {
nodep->pinsp()->v3fatalSrc(
"Unsupported: enum next/prev with non-const argument");
} else {
const uint32_t stepWidth
= VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt();
if (stepWidth == 0) {
// Step of 0 "legalizes" like $cast, use .next.prev
AstMethodCall* const newp = new AstMethodCall{
nodep->fileline(),
new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"next", nullptr},
"prev", nullptr};
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
} else if (stepWidth != 1) {
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
AstMethodCall* const clonep = nodep->cloneTree(false);
VN_AS(VN_AS(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1);
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
AstArg* const argp = new AstArg{nodep->fileline(), "", constp};
AstMethodCall* const newp
= new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp};
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
}
}
}
// Need a runtime lookup table. Yuk.
const uint64_t msbdim = enumMaxValue(nodep, adtypep);

View File

@ -34,12 +34,16 @@ module t (/*AUTOARG*/
else if (cyc == 1) begin
`checks(e.name, "E01");
`checkh(e.next, ELARGE);
`checkh(e.next(0), E01);
`checkh(e.prev(0), E01);
e <= ELARGE;
end
else if (cyc == 3) begin
`checks(e.name, "ELARGE");
`checkh(e.next, E01);
`checkh(e.prev, E01);
`checkh(e.next(0), ELARGE);
`checkh(e.prev(0), ELARGE);
e <= E01;
end
//