forked from github/verilator
Support queue[$-1] selects.
This commit is contained in:
parent
90e049c674
commit
9ffd0a4e70
@ -413,6 +413,10 @@ public:
|
|||||||
return m_deque[index];
|
return m_deque[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Access with an index counted from end (e.g. q[$])
|
||||||
|
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
|
||||||
|
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||||
|
|
||||||
// function void q.insert(index, value);
|
// function void q.insert(index, value);
|
||||||
void insert(int32_t index, const T_Value& value) {
|
void insert(int32_t index, const T_Value& value) {
|
||||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
||||||
@ -428,6 +432,12 @@ public:
|
|||||||
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const {
|
||||||
|
return slice(lsb, m_deque.size() - 1 - msb);
|
||||||
|
}
|
||||||
|
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
|
||||||
|
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
|
||||||
|
}
|
||||||
|
|
||||||
// For save/restore
|
// For save/restore
|
||||||
const_iterator begin() const { return m_deque.begin(); }
|
const_iterator begin() const { return m_deque.begin(); }
|
||||||
|
@ -1297,15 +1297,15 @@ private:
|
|||||||
if (const auto* const varp = VN_CAST(nodep->backp(), Var)) {
|
if (const auto* const varp = VN_CAST(nodep->backp(), Var)) {
|
||||||
if (varp->isParam()) return; // Ok, leave
|
if (varp->isParam()) return; // Ok, leave
|
||||||
}
|
}
|
||||||
// queue_slice[#:$]
|
AstNode* backp = nodep->backp();
|
||||||
if (const auto* const selp = VN_CAST(nodep->backp(), SelExtract)) {
|
if (VN_IS(backp, Sub)) backp = backp->backp();
|
||||||
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) {
|
if (const auto* const selp = VN_CAST(backp, SelExtract)) {
|
||||||
nodep->replaceWith(
|
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return;
|
||||||
new AstConst(nodep->fileline(), AstConst::Signed32{}, 0x7FFFFFFF));
|
|
||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (const auto* const selp = VN_CAST(backp, SelBit)) {
|
||||||
|
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return;
|
||||||
|
}
|
||||||
|
// queue_slice[#:$] and queue_bitsel[$] etc handled in V3WidthSel
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
|
||||||
}
|
}
|
||||||
void visit(AstIsUnbounded* nodep) override {
|
void visit(AstIsUnbounded* nodep) override {
|
||||||
|
@ -190,6 +190,18 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNodeExpr* selQueueBackness(AstNode* nodep) {
|
||||||
|
if (VN_IS(nodep, Unbounded)) { // e.g. "[$]"
|
||||||
|
return new AstConst{nodep->fileline(), AstConst::Signed32{}, 0};
|
||||||
|
} else if (VN_IS(nodep, Sub) && VN_IS(VN_CAST(nodep, Sub)->lhsp(), Unbounded)) {
|
||||||
|
// e.g. "q[$ - 1]", where 1 is subnodep
|
||||||
|
AstNodeExpr* subrhsp = VN_CAST(nodep, Sub)->rhsp()->unlinkFrBack();
|
||||||
|
return subrhsp;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void warnTri(AstNode* nodep) {
|
void warnTri(AstNode* nodep) {
|
||||||
if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) {
|
if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) {
|
||||||
nodep->v3error(
|
nodep->v3error(
|
||||||
@ -250,8 +262,7 @@ private:
|
|||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
||||||
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
||||||
AstNodeExpr* const subp = rhsp;
|
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, rhsp};
|
||||||
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, subp};
|
|
||||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||||
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
@ -259,24 +270,26 @@ private:
|
|||||||
} else if (const AstWildcardArrayDType* const adtypep
|
} else if (const AstWildcardArrayDType* const adtypep
|
||||||
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
||||||
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
||||||
AstNodeExpr* const subp = rhsp;
|
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, rhsp};
|
||||||
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp};
|
|
||||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||||
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||||
AstNodeExpr* const subp = rhsp;
|
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
|
||||||
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp};
|
|
||||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||||
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
|
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||||
AstNodeExpr* const subp = rhsp;
|
AstCMethodHard* newp;
|
||||||
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp};
|
if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) {
|
||||||
|
newp = new AstCMethodHard{nodep->fileline(), fromp, "atBack", backnessp};
|
||||||
|
} else {
|
||||||
|
newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
|
||||||
|
}
|
||||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||||
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
@ -338,19 +351,43 @@ private:
|
|||||||
V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node
|
V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node
|
||||||
V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node
|
V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node
|
||||||
// if (debug() >= 9) nodep->dumpTree("- SELEX3: ");
|
// if (debug() >= 9) nodep->dumpTree("- SELEX3: ");
|
||||||
|
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
||||||
|
const FromData fromdata = fromDataForArray(nodep, fromp);
|
||||||
|
AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
||||||
|
const VNumRange fromRange = fromdata.m_fromRange;
|
||||||
|
if (VN_IS(ddtypep, QueueDType)) {
|
||||||
|
AstNodeExpr* const qleftp = nodep->rhsp()->unlinkFrBack();
|
||||||
|
AstNodeExpr* const qrightp = nodep->thsp()->unlinkFrBack();
|
||||||
|
AstNodeExpr* const qleftBacknessp = selQueueBackness(qleftp);
|
||||||
|
AstNodeExpr* const qrightBacknessp = selQueueBackness(qrightp);
|
||||||
|
// Use special methods to refer to back rather than math using
|
||||||
|
// queue size, this allows a single queue reference, to support
|
||||||
|
// for equations in side effects that select the queue to
|
||||||
|
// operate upon.
|
||||||
|
std::string name = (qleftBacknessp ? "sliceBackBack"
|
||||||
|
: qrightBacknessp ? "sliceFrontBack"
|
||||||
|
: "slice");
|
||||||
|
auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, name,
|
||||||
|
qleftBacknessp ? qleftBacknessp : qleftp};
|
||||||
|
newp->addPinsp(qrightBacknessp ? qrightBacknessp : qrightp);
|
||||||
|
newp->dtypep(ddtypep);
|
||||||
|
newp->didWidth(true);
|
||||||
|
newp->protect(false);
|
||||||
|
UINFO(6, " new " << newp << endl);
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Non-queue
|
||||||
checkConstantOrReplace(nodep->leftp(),
|
checkConstantOrReplace(nodep->leftp(),
|
||||||
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||||
checkConstantOrReplace(nodep->rightp(),
|
checkConstantOrReplace(nodep->rightp(),
|
||||||
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||||
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
|
||||||
AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack();
|
AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack();
|
AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack();
|
||||||
int32_t msb = VN_AS(msbp, Const)->toSInt();
|
int32_t msb = VN_AS(msbp, Const)->toSInt();
|
||||||
int32_t lsb = VN_AS(lsbp, Const)->toSInt();
|
int32_t lsb = VN_AS(lsbp, Const)->toSInt();
|
||||||
const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
|
const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
|
||||||
const FromData fromdata = fromDataForArray(nodep, fromp);
|
|
||||||
AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
|
||||||
const VNumRange fromRange = fromdata.m_fromRange;
|
|
||||||
if (VN_IS(ddtypep, UnpackArrayDType)) {
|
if (VN_IS(ddtypep, UnpackArrayDType)) {
|
||||||
// Slice extraction
|
// Slice extraction
|
||||||
if (fromRange.elements() == elem
|
if (fromRange.elements() == elem
|
||||||
@ -453,15 +490,6 @@ private:
|
|||||||
// if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
|
// if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
} else if (VN_IS(ddtypep, QueueDType)) {
|
|
||||||
auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, "slice", msbp};
|
|
||||||
msbp->addNext(lsbp);
|
|
||||||
newp->dtypep(ddtypep);
|
|
||||||
newp->didWidth(true);
|
|
||||||
newp->protect(false);
|
|
||||||
UINFO(6, " new " << newp << endl);
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
} else { // nullptr=bad extract, or unknown node type
|
} else { // nullptr=bad extract, or unknown node type
|
||||||
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
||||||
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
||||||
|
21
test_regress/t/t_queue_back.pl
Executable file
21
test_regress/t/t_queue_back.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 2022 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;
|
36
test_regress/t/t_queue_back.v
Normal file
36
test_regress/t/t_queue_back.v
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
|
||||||
|
int q[$];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
q = { 20, 30, 40 };
|
||||||
|
|
||||||
|
r = q[$];
|
||||||
|
if (r != 40) $stop;
|
||||||
|
|
||||||
|
r = q[$-1];
|
||||||
|
if (r != 30) $stop;
|
||||||
|
|
||||||
|
q = q[0:$-1]; // void'(q.pop_back()) or q.delete(q.size-1)
|
||||||
|
if (q.size != 2) $stop;
|
||||||
|
if (q[0] != 20) $stop;
|
||||||
|
if (q[1] != 30) $stop;
|
||||||
|
|
||||||
|
q = { 20, 30, 40 };
|
||||||
|
q = q[$-1:$];
|
||||||
|
if (q.size != 2) $stop;
|
||||||
|
if (q[0] != 30) $stop;
|
||||||
|
if (q[1] != 40) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue
Block a user