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];
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
void insert(int32_t index, const T_Value& value) {
|
||||
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]);
|
||||
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
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
|
@ -1297,15 +1297,15 @@ private:
|
||||
if (const auto* const varp = VN_CAST(nodep->backp(), Var)) {
|
||||
if (varp->isParam()) return; // Ok, leave
|
||||
}
|
||||
// queue_slice[#:$]
|
||||
if (const auto* const selp = VN_CAST(nodep->backp(), SelExtract)) {
|
||||
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) {
|
||||
nodep->replaceWith(
|
||||
new AstConst(nodep->fileline(), AstConst::Signed32{}, 0x7FFFFFFF));
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
AstNode* backp = nodep->backp();
|
||||
if (VN_IS(backp, Sub)) backp = backp->backp();
|
||||
if (const auto* const selp = VN_CAST(backp, SelExtract)) {
|
||||
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) 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.");
|
||||
}
|
||||
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) {
|
||||
if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) {
|
||||
nodep->v3error(
|
||||
@ -250,8 +262,7 @@ private:
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
||||
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, subp};
|
||||
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, rhsp};
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
@ -259,24 +270,26 @@ private:
|
||||
} else if (const AstWildcardArrayDType* const adtypep
|
||||
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
||||
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp};
|
||||
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, rhsp};
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug() >= 9) newp->dumpTree("- SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp};
|
||||
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp};
|
||||
AstCMethodHard* newp;
|
||||
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
|
||||
if (debug() >= 9) newp->dumpTree("- SELBTq: ");
|
||||
nodep->replaceWith(newp);
|
||||
@ -338,19 +351,43 @@ private:
|
||||
V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node
|
||||
V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node
|
||||
// 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(),
|
||||
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
checkConstantOrReplace(nodep->rightp(),
|
||||
"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 lsbp = nodep->thsp()->unlinkFrBack();
|
||||
int32_t msb = VN_AS(msbp, Const)->toSInt();
|
||||
int32_t lsb = VN_AS(lsbp, Const)->toSInt();
|
||||
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)) {
|
||||
// Slice extraction
|
||||
if (fromRange.elements() == elem
|
||||
@ -453,15 +490,6 @@ private:
|
||||
// if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
|
||||
nodep->replaceWith(newp);
|
||||
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
|
||||
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
||||
<< "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