mirror of
https://github.com/verilator/verilator.git
synced 2025-04-04 19:52:39 +00:00
* Support 2D dynamic array initialization (#4700) - new[] on sub arrays (as per original issue) - Built-in methods for sub-arrays - Initialization and literals assignmensts - Dynamic array as an element for other arrays and queues
This commit is contained in:
parent
5363d89870
commit
4babba16d6
@ -192,6 +192,7 @@ Tudor Timi
|
||||
Tymoteusz Blazejczyk
|
||||
Udi Finkelstein
|
||||
Unai Martinez-Corral
|
||||
Valentin Atepalikhin
|
||||
Varun Koyyalagunta
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
|
@ -1292,6 +1292,11 @@ public:
|
||||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
AstUnsizedArrayDType(FileLine* fl, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_UnsizedArrayDType(fl) {
|
||||
refDTypep(dtp);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_AstUnsizedArrayDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep()) || (!m_refDTypep && childDTypep())));
|
||||
|
@ -903,9 +903,12 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
||||
}
|
||||
dtypep = adtypep->subDTypep();
|
||||
continue;
|
||||
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
} else if (VN_IS(dtypep, QueueDType)
|
||||
|| VN_IS(dtypep, DynArrayDType)
|
||||
|| VN_IS(dtypep, AssocArrayDType)
|
||||
|| VN_IS(dtypep, WildcardArrayDType)) {
|
||||
unpacked++;
|
||||
dtypep = qdtypep->subDTypep();
|
||||
dtypep = dtypep->subDTypep();
|
||||
continue;
|
||||
} else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
|
||||
|
@ -140,7 +140,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
||||
arrayp = new AstUnpackArrayDType{rangep->fileline(), VFlagChildDType{}, arrayp,
|
||||
rangep};
|
||||
} else if (VN_IS(nrangep, UnsizedRange)) {
|
||||
arrayp = new AstUnsizedArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
||||
arrayp = new AstDynArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
||||
VL_DO_DANGLING(nrangep->deleteTree(), nrangep);
|
||||
} else if (VN_IS(nrangep, BracketRange)) {
|
||||
const AstBracketRange* const arangep = VN_AS(nrangep, BracketRange);
|
||||
|
@ -1528,7 +1528,8 @@ class WidthVisitor final : public VNVisitor {
|
||||
case VAttrType::DIM_SIZE: {
|
||||
UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression");
|
||||
AstNodeDType* const dtypep = nodep->fromp()->dtypep();
|
||||
if (VN_IS(dtypep, QueueDType)) {
|
||||
if (VN_IS(dtypep, QueueDType)
|
||||
|| VN_IS(dtypep, DynArrayDType)) {
|
||||
switch (nodep->attrType()) {
|
||||
case VAttrType::DIM_SIZE: {
|
||||
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
|
||||
@ -1570,7 +1571,11 @@ class WidthVisitor final : public VNVisitor {
|
||||
break;
|
||||
}
|
||||
case VAttrType::DIM_BITS: {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue");
|
||||
if (VN_IS(dtypep, DynArrayDType)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for dynamic array");
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: nodep->v3fatalSrc("Unhandled attribute type");
|
||||
@ -2151,14 +2156,32 @@ class WidthVisitor final : public VNVisitor {
|
||||
// Make sure dtype is sized
|
||||
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
|
||||
if (const AstUnsizedArrayDType* const unsizedp
|
||||
= VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
|
||||
if (!(m_ftaskp && m_ftaskp->dpiImport())) {
|
||||
UINFO(9, "Unsized becomes dynamic array " << nodep << endl);
|
||||
AstDynArrayDType* const newp
|
||||
= new AstDynArrayDType{unsizedp->fileline(), unsizedp->subDTypep()};
|
||||
nodep->dtypep(newp);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
if (m_ftaskp && m_ftaskp->dpiImport()) {
|
||||
AstNodeDType *dtp = nodep->dtypep();
|
||||
AstNodeDType *np = nullptr;
|
||||
while (VN_IS(dtp->skipRefp(), DynArrayDType)
|
||||
|| VN_IS(dtp->skipRefp(), UnpackArrayDType)) {
|
||||
if (const AstDynArrayDType* const unsizedp
|
||||
= VN_CAST(dtp->skipRefp(), DynArrayDType)) {
|
||||
if (!np) {
|
||||
UINFO(9, "Dynamic becomes unsized array (var itself) " << nodep << endl);
|
||||
} else {
|
||||
UINFO(9, "Dynamic becomes unsized array (subDType) " << dtp << endl);
|
||||
}
|
||||
AstUnsizedArrayDType* const newp
|
||||
= new AstUnsizedArrayDType{unsizedp->fileline(), unsizedp->subDTypep()};
|
||||
newp->dtypep(newp);
|
||||
if (!np) { // for Var itself
|
||||
nodep->dtypep(newp);
|
||||
} else { // for subDType
|
||||
np->virtRefDTypep(newp);
|
||||
}
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
np = newp;
|
||||
} else {
|
||||
np = dtp->skipRefp();
|
||||
}
|
||||
dtp = np->virtRefDTypep();
|
||||
}
|
||||
}
|
||||
if (AstWildcardArrayDType* const wildp
|
||||
@ -2458,6 +2481,7 @@ class WidthVisitor final : public VNVisitor {
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, PRELIM}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, PRELIM}.p());
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
}
|
||||
if (m_vup->final()) {
|
||||
@ -2480,6 +2504,7 @@ class WidthVisitor final : public VNVisitor {
|
||||
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
|
||||
}
|
||||
}
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
}
|
||||
}
|
||||
@ -3348,6 +3373,12 @@ class WidthVisitor final : public VNVisitor {
|
||||
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||
}
|
||||
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
|
||||
if (const AstCMethodHard* const ichildp = VN_CAST(childp, CMethodHard)) {
|
||||
if (ichildp->name() == "at") {
|
||||
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (AstNodeVarRef* const varrefp = VN_CAST(childp, NodeVarRef)) {
|
||||
varrefp->access(access);
|
||||
} else if (const AstMemberSel* const ichildp = VN_CAST(childp, MemberSel)) {
|
||||
|
@ -20,8 +20,6 @@ module Vt_debug_emitv_t;
|
||||
signed int [31:0] string
|
||||
???? // ASSOCARRAYDTYPE
|
||||
signed int [31:0]
|
||||
???? // UNSIZEDARRAYDTYPE
|
||||
|
||||
???? // DYNARRAYDTYPE
|
||||
signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] e_t;
|
||||
typedef struct packed
|
||||
@ -37,8 +35,6 @@ module Vt_debug_emitv_t;
|
||||
signed int [31:0] string
|
||||
???? // ASSOCARRAYDTYPE
|
||||
signed int [31:0]
|
||||
???? // UNSIZEDARRAYDTYPE
|
||||
|
||||
???? // DYNARRAYDTYPE
|
||||
signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] ps_t;
|
||||
typedef struct
|
||||
@ -53,8 +49,6 @@ module Vt_debug_emitv_t;
|
||||
signed int [31:0] string
|
||||
???? // ASSOCARRAYDTYPE
|
||||
signed int [31:0]
|
||||
???? // UNSIZEDARRAYDTYPE
|
||||
|
||||
???? // DYNARRAYDTYPE
|
||||
signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] us_t;
|
||||
typedef union
|
||||
@ -68,8 +62,6 @@ module Vt_debug_emitv_t;
|
||||
signed int [31:0] string
|
||||
???? // ASSOCARRAYDTYPE
|
||||
signed int [31:0]
|
||||
???? // UNSIZEDARRAYDTYPE
|
||||
|
||||
???? // DYNARRAYDTYPE
|
||||
signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] union_t;
|
||||
struct packed
|
||||
|
10
test_regress/t/t_dynarray_bits.out
Normal file
10
test_regress/t/t_dynarray_bits.out
Normal file
@ -0,0 +1,10 @@
|
||||
%Error-UNSUPPORTED: t/t_dynarray_bits.v:12:11: Unsupported: $bits for dynamic array
|
||||
: ... note: In instance 't'
|
||||
12 | if ($bits(a) != 0) $stop;
|
||||
| ^~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Internal Error: t/t_dynarray_bits.v:12:20: ../V3Width.cpp:#: Node has no type
|
||||
: ... note: In instance 't'
|
||||
12 | if ($bits(a) != 0) $stop;
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html for more assistance.
|
19
test_regress/t/t_dynarray_bits.pl
Executable file
19
test_regress/t/t_dynarray_bits.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 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(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
17
test_regress/t/t_dynarray_bits.v
Normal file
17
test_regress/t/t_dynarray_bits.v
Normal file
@ -0,0 +1,17 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
integer a[];
|
||||
|
||||
initial begin
|
||||
if ($bits(a) != 0) $stop;
|
||||
a = new [10];
|
||||
if ($bits(a) != 10*32) $stop;
|
||||
end
|
||||
|
||||
endmodule
|
21
test_regress/t/t_dynarray_multid.pl
Executable file
21
test_regress/t/t_dynarray_multid.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 2019 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;
|
222
test_regress/t/t_dynarray_multid.v
Normal file
222
test_regress/t/t_dynarray_multid.v
Normal file
@ -0,0 +1,222 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
integer a1 [][];
|
||||
integer a2 [2][];
|
||||
|
||||
integer a3 [][] = '{'{1, 2, 3}, '{4, 5, 6}};
|
||||
integer a4 [][] = '{{7, 8, 9}, {10, 11, 12}};
|
||||
integer a5 [][] = '{3{'{13, 14}}};
|
||||
|
||||
integer aa1 [string][];
|
||||
integer wa1 [*][];
|
||||
integer qa1 [$][];
|
||||
struct {
|
||||
integer i;
|
||||
integer a[];
|
||||
} s1;
|
||||
|
||||
integer a[] = '{1,2,3};
|
||||
|
||||
logic [7:0][3:0] a6 [][];
|
||||
|
||||
initial begin
|
||||
`checkh(a1.size, 0);
|
||||
a1 = new [3];
|
||||
`checkh(a1.size, 3);
|
||||
`checkh($size(a1), 3);
|
||||
`checkh($high(a1), 2);
|
||||
`checkh($right(a1), 2);
|
||||
|
||||
foreach (a1[i]) a1[i] = new [i + 1];
|
||||
|
||||
foreach (a1[i]) begin
|
||||
`checkh(a1[i].size, i + 1);
|
||||
`checkh($size(a1[i]), i + 1);
|
||||
`checkh($high(a1[i]), i);
|
||||
`checkh($right(a1[i]), i);
|
||||
end
|
||||
|
||||
foreach (a1[i, j]) a1[i][j] = i * 10 + j;
|
||||
|
||||
`checkh(a1[0][0], 0);
|
||||
`checkh(a1[1][0], 10);
|
||||
`checkh(a1[1][1], 11);
|
||||
`checkh(a1[2][0], 20);
|
||||
`checkh(a1[2][1], 21);
|
||||
`checkh(a1[2][2], 22);
|
||||
|
||||
`checkh(a1[2].sum, 63);
|
||||
|
||||
foreach (a1[i]) a1[i].delete;
|
||||
foreach (a1[i]) begin
|
||||
`checkh(a1[i].size, 0);
|
||||
end
|
||||
|
||||
a1.delete;
|
||||
`checkh(a1.size, 0);
|
||||
|
||||
a1 = new [2];
|
||||
`checkh(a1.size, 2);
|
||||
|
||||
foreach (a1[i]) a1[i] = new [i + 2];
|
||||
foreach (a1[i]) begin
|
||||
`checkh(a1[i].size, i + 2);
|
||||
end
|
||||
|
||||
foreach (a2[i]) begin
|
||||
`checkh(a2[i].size, 0);
|
||||
end
|
||||
foreach (a2[i]) a2[i] = new [i + 1];
|
||||
foreach (a2[i]) begin
|
||||
`checkh(a2[i].size, i + 1);
|
||||
end
|
||||
|
||||
foreach (a2[i]) a2[i].delete;
|
||||
foreach (a2[i]) begin
|
||||
`checkh(a2[i].size, 0);
|
||||
end
|
||||
|
||||
`checkh(a3.size, 2);
|
||||
foreach (a3[i]) begin
|
||||
`checkh(a3[i].size, 3);
|
||||
end
|
||||
|
||||
`checkh(a3[0][0], 1);
|
||||
`checkh(a3[0][1], 2);
|
||||
`checkh(a3[0][2], 3);
|
||||
`checkh(a3[1][0], 4);
|
||||
`checkh(a3[1][1], 5);
|
||||
`checkh(a3[1][2], 6);
|
||||
|
||||
`checkh(a4.size, 2);
|
||||
foreach (a4[i]) begin
|
||||
`checkh(a4[i].size, 3);
|
||||
end
|
||||
|
||||
`checkh(a4[0][0], 7);
|
||||
`checkh(a4[0][1], 8);
|
||||
`checkh(a4[0][2], 9);
|
||||
`checkh(a4[1][0], 10);
|
||||
`checkh(a4[1][1], 11);
|
||||
`checkh(a4[1][2], 12);
|
||||
|
||||
`checkh(a5.size, 3);
|
||||
foreach (a5[i]) begin
|
||||
`checkh(a5[i].size, 2);
|
||||
end
|
||||
|
||||
`checkh(a5[0][0], 13);
|
||||
`checkh(a5[0][1], 14);
|
||||
`checkh(a5[1][0], 13);
|
||||
`checkh(a5[1][1], 14);
|
||||
`checkh(a5[2][0], 13);
|
||||
`checkh(a5[2][1], 14);
|
||||
|
||||
a5 = a4;
|
||||
`checkh(a5.size, 2);
|
||||
foreach (a5[i]) begin
|
||||
`checkh(a5[i].size, 3);
|
||||
end
|
||||
|
||||
`checkh(a5[0][0], 7);
|
||||
`checkh(a5[0][1], 8);
|
||||
`checkh(a5[0][2], 9);
|
||||
`checkh(a5[1][0], 10);
|
||||
`checkh(a5[1][1], 11);
|
||||
`checkh(a5[1][2], 12);
|
||||
|
||||
a4 = '{'{15, 16}, '{17, 18}};
|
||||
|
||||
`checkh(a4.size, 2);
|
||||
foreach (a4[i]) begin
|
||||
`checkh(a4[i].size, 2);
|
||||
end
|
||||
|
||||
`checkh(a4[0][0], 15);
|
||||
`checkh(a4[0][1], 16);
|
||||
`checkh(a4[1][0], 17);
|
||||
`checkh(a4[1][1], 18);
|
||||
|
||||
a4 = '{{19}, {20}, {21, 22}};
|
||||
|
||||
`checkh(a4.size, 3);
|
||||
`checkh(a4[0].size, 1);
|
||||
`checkh(a4[1].size, 1);
|
||||
`checkh(a4[2].size, 2);
|
||||
|
||||
`checkh(a4[0][0], 19);
|
||||
`checkh(a4[1][0], 20);
|
||||
`checkh(a4[2][0], 21);
|
||||
`checkh(a4[2][1], 22);
|
||||
|
||||
a5 = '{2{a}};
|
||||
|
||||
`checkh(a5.size, 2);
|
||||
foreach (a5[i]) begin
|
||||
`checkh(a5[i].size, 3);
|
||||
end
|
||||
|
||||
`checkh(a5[0][0], 1);
|
||||
`checkh(a5[0][1], 2);
|
||||
`checkh(a5[0][2], 3);
|
||||
`checkh(a5[1][0], 1);
|
||||
`checkh(a5[1][1], 2);
|
||||
`checkh(a5[1][2], 3);
|
||||
|
||||
a5 = '{};
|
||||
`checkh(a5.size, 0);
|
||||
|
||||
a5 = '{2{'{}}};
|
||||
|
||||
`checkh(a5.size, 2);
|
||||
foreach (a5[i]) begin
|
||||
`checkh(a5[i].size, 0);
|
||||
end
|
||||
|
||||
aa1["k1"] = new [3];
|
||||
`checkh(aa1["k1"].size, 3);
|
||||
aa1["k1"].delete;
|
||||
|
||||
wa1[1] = new [3];
|
||||
`checkh(wa1[1].size, 3);
|
||||
wa1[1].delete;
|
||||
|
||||
qa1.push_back(a);
|
||||
`checkh(qa1[0].size, 3);
|
||||
qa1[0] = new [4];
|
||||
`checkh(qa1[0].size, 4);
|
||||
qa1[0].delete;
|
||||
|
||||
s1.a = new [4];
|
||||
`checkh(s1.a.size, 4);
|
||||
s1.a.delete;
|
||||
|
||||
`checkh($dimensions(a1), 3);
|
||||
`checkh($dimensions(a2), 3);
|
||||
`checkh($dimensions(aa1), 3);
|
||||
`checkh($dimensions(wa1), 3);
|
||||
`checkh($dimensions(qa1), 3);
|
||||
`checkh($dimensions(a), 2);
|
||||
`checkh($dimensions(a6), 4);
|
||||
`checkh($unpacked_dimensions(a1), 2);
|
||||
`checkh($unpacked_dimensions(a2), 2);
|
||||
`checkh($unpacked_dimensions(aa1), 2);
|
||||
`checkh($unpacked_dimensions(wa1), 2);
|
||||
`checkh($unpacked_dimensions(qa1), 2);
|
||||
`checkh($unpacked_dimensions(a), 1);
|
||||
`checkh($unpacked_dimensions(a6), 2);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user