mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Fix queue element access (#5551)
This commit is contained in:
parent
4e5c7f4568
commit
4cd69f9feb
@ -4424,6 +4424,8 @@ class AstSelBit final : public AstNodePreSel {
|
|||||||
// Single bit range extraction, perhaps with non-constant selection or array selection
|
// Single bit range extraction, perhaps with non-constant selection or array selection
|
||||||
// Gets replaced during link with AstArraySel or AstSel
|
// Gets replaced during link with AstArraySel or AstSel
|
||||||
// @astgen alias op2 := bitp
|
// @astgen alias op2 := bitp
|
||||||
|
private:
|
||||||
|
VAccess m_access; // Left hand side assignment
|
||||||
public:
|
public:
|
||||||
AstSelBit(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
|
AstSelBit(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* bitp)
|
||||||
: ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) {
|
: ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) {
|
||||||
@ -4431,6 +4433,8 @@ public:
|
|||||||
"not coded to create after dtypes resolved");
|
"not coded to create after dtypes resolved");
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstSelBit;
|
ASTGEN_MEMBERS_AstSelBit;
|
||||||
|
VAccess access() const { return m_access; }
|
||||||
|
void access(const VAccess& flag) { m_access = flag; }
|
||||||
};
|
};
|
||||||
class AstSelExtract final : public AstNodePreSel {
|
class AstSelExtract final : public AstNodePreSel {
|
||||||
// Range extraction, gets replaced with AstSel
|
// Range extraction, gets replaced with AstSel
|
||||||
|
@ -311,6 +311,7 @@ class LinkLValueVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstNodePreSel* nodep) override {
|
void visit(AstNodePreSel* nodep) override {
|
||||||
|
if (AstSelBit* const selbitp = VN_CAST(nodep, SelBit)) selbitp->access(m_setRefLvalue);
|
||||||
VL_RESTORER(m_setRefLvalue);
|
VL_RESTORER(m_setRefLvalue);
|
||||||
{ // Only set lvalues on the from
|
{ // Only set lvalues on the from
|
||||||
iterateAndNextNull(nodep->fromp());
|
iterateAndNextNull(nodep->fromp());
|
||||||
|
@ -493,10 +493,11 @@ class TaskVisitor final : public VNVisitor {
|
|||||||
|| VN_IS(pinp, ArraySel)) {
|
|| VN_IS(pinp, ArraySel)) {
|
||||||
refArgOk = true;
|
refArgOk = true;
|
||||||
} else if (AstCMethodHard* const cMethodp = VN_CAST(pinp, CMethodHard)) {
|
} else if (AstCMethodHard* const cMethodp = VN_CAST(pinp, CMethodHard)) {
|
||||||
refArgOk = cMethodp->name() == "at" || cMethodp->name() == "atBack";
|
|
||||||
if (VN_IS(cMethodp->fromp()->dtypep()->skipRefp(), QueueDType)) {
|
if (VN_IS(cMethodp->fromp()->dtypep()->skipRefp(), QueueDType)) {
|
||||||
cMethodp->name(cMethodp->name() == "at" ? "atWriteAppend"
|
refArgOk = cMethodp->name() == "atWriteAppend"
|
||||||
: "atWriteAppendBack");
|
|| cMethodp->name() == "atWriteAppendBack";
|
||||||
|
} else {
|
||||||
|
refArgOk = cMethodp->name() == "at" || cMethodp->name() == "atBack";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (refArgOk) {
|
if (refArgOk) {
|
||||||
|
@ -3520,9 +3520,19 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||||
}
|
}
|
||||||
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
|
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
|
||||||
if (const AstCMethodHard* const ichildp = VN_CAST(childp, CMethodHard)) {
|
if (AstCMethodHard* const ichildp = VN_CAST(childp, CMethodHard)) {
|
||||||
if (ichildp->name() == "at" || ichildp->name() == "atWrite"
|
const std::string name = ichildp->name();
|
||||||
|| ichildp->name() == "atWriteAppend" || ichildp->name() == "atWriteAppendBack") {
|
if (name == "at" || name == "atWrite" || name == "atBack" || name == "atWriteAppend"
|
||||||
|
|| name == "atWriteAppendBack") {
|
||||||
|
const AstNodeDType* const fromDtypep = ichildp->fromp()->dtypep()->skipRefp();
|
||||||
|
if (VN_IS(fromDtypep, QueueDType) || VN_IS(fromDtypep, DynArrayDType)) {
|
||||||
|
// Change access methods to writable ones
|
||||||
|
if (name == "at") {
|
||||||
|
ichildp->name("atWrite");
|
||||||
|
} else if (name == "atBack") {
|
||||||
|
ichildp->name("atWriteAppendBack");
|
||||||
|
}
|
||||||
|
}
|
||||||
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
|
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -215,24 +215,6 @@ class WidthSelVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isPossibleWrite(AstNodeExpr* nodep) {
|
|
||||||
AstNode* abovep = nodep->firstAbovep();
|
|
||||||
if (AstNodeAssign* const assignp = VN_CAST(abovep, NodeAssign)) {
|
|
||||||
// On an assign LHS, assume a write
|
|
||||||
return assignp->lhsp() == nodep;
|
|
||||||
}
|
|
||||||
if (AstMethodCall* const methodCallp = VN_CAST(abovep, MethodCall)) {
|
|
||||||
// A method call can write
|
|
||||||
return methodCallp->fromp() == nodep;
|
|
||||||
}
|
|
||||||
if (AstNodePreSel* const preSelp = VN_CAST(abovep, NodePreSel)) {
|
|
||||||
// If we're not selected from, it's not a write (we're the index)
|
|
||||||
if (preSelp->fromp() != nodep) return false;
|
|
||||||
}
|
|
||||||
AstNodeExpr* exprp = VN_CAST(abovep, NodeExpr);
|
|
||||||
return exprp ? isPossibleWrite(exprp) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
|
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
|
||||||
|
|
||||||
@ -300,7 +282,7 @@ class WidthSelVisitor final : public VNVisitor {
|
|||||||
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)
|
||||||
const char* methodName = isPossibleWrite(nodep) ? "atWrite" : "at";
|
const char* methodName = nodep->access().isWriteOrRW() ? "atWrite" : "at";
|
||||||
AstCMethodHard* const newp
|
AstCMethodHard* const newp
|
||||||
= new AstCMethodHard{nodep->fileline(), fromp, methodName, rhsp};
|
= new AstCMethodHard{nodep->fileline(), fromp, methodName, rhsp};
|
||||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||||
@ -310,7 +292,7 @@ class WidthSelVisitor final : public VNVisitor {
|
|||||||
} 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)
|
||||||
AstCMethodHard* newp;
|
AstCMethodHard* newp;
|
||||||
const char* methodName = isPossibleWrite(nodep) ? "atWriteAppend" : "at";
|
const char* methodName = nodep->access().isWriteOrRW() ? "atWriteAppend" : "at";
|
||||||
if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) {
|
if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) {
|
||||||
newp = new AstCMethodHard{nodep->fileline(), fromp,
|
newp = new AstCMethodHard{nodep->fileline(), fromp,
|
||||||
std::string(methodName) + "Back", backnessp};
|
std::string(methodName) + "Back", backnessp};
|
||||||
|
18
test_regress/t/t_dynarray_cast_write.py
Executable file
18
test_regress/t/t_dynarray_cast_write.py
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
39
test_regress/t/t_dynarray_cast_write.v
Normal file
39
test_regress/t/t_dynarray_cast_write.v
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
int x = 1;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar extends Foo;
|
||||||
|
function new;
|
||||||
|
x = 2;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
int sel_bit = 3;
|
||||||
|
Bar bar = new;
|
||||||
|
Foo foo = bar;
|
||||||
|
Bar bars[] = new[4];
|
||||||
|
$cast(bars[0], foo);
|
||||||
|
if (bars[0].x != 2) $stop;
|
||||||
|
|
||||||
|
$cast(bars[sel_bit[0]], foo);
|
||||||
|
if (bars[1].x != 2) $stop;
|
||||||
|
|
||||||
|
$cast(bars[bars[0].x], foo);
|
||||||
|
if (bars[2].x != 2) $stop;
|
||||||
|
|
||||||
|
$cast(bars[sel_bit[1:0]], foo);
|
||||||
|
if (bars[3].x != 2) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
18
test_regress/t/t_queue_output_func.py
Executable file
18
test_regress/t/t_queue_output_func.py
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
27
test_regress/t/t_queue_output_func.v
Normal file
27
test_regress/t/t_queue_output_func.v
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
int x = 1;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
task init_set_2 (output Cls c);
|
||||||
|
c = new;
|
||||||
|
c.x = 2;
|
||||||
|
endtask
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Cls cls_q[$];
|
||||||
|
init_set_2(cls_q[0]);
|
||||||
|
if (cls_q[0].x != 2) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue
Block a user