mirror of
https://github.com/verilator/verilator.git
synced 2025-01-31 18:54:03 +00:00
Support concatenation of unpacked arrays (#4558)
This commit is contained in:
parent
afecde87d8
commit
4e2c63c8cb
146
src/V3Slice.cpp
146
src/V3Slice.cpp
@ -56,6 +56,9 @@ class SliceVisitor final : public VNVisitor {
|
|||||||
// AstNodeUniop::user1() -> bool. True if find is complete
|
// AstNodeUniop::user1() -> bool. True if find is complete
|
||||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
// AstInitArray::user2() -> Previously accessed itemIdx
|
||||||
|
// AstInitItem::user2() -> Corresponding first elemIdx
|
||||||
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNode* m_assignp = nullptr; // Assignment we are under
|
AstNode* m_assignp = nullptr; // Assignment we are under
|
||||||
@ -63,7 +66,8 @@ class SliceVisitor final : public VNVisitor {
|
|||||||
bool m_okInitArray = false; // Allow InitArray children
|
bool m_okInitArray = false; // Allow InitArray children
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int offset) {
|
|
||||||
|
AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int elemIdx) {
|
||||||
// Insert an ArraySel, except for a few special cases
|
// Insert an ArraySel, except for a few special cases
|
||||||
const AstUnpackArrayDType* const arrayp
|
const AstUnpackArrayDType* const arrayp
|
||||||
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
||||||
@ -87,40 +91,126 @@ class SliceVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
m_assignError = true;
|
m_assignError = true;
|
||||||
elements = 1;
|
elements = 1;
|
||||||
offset = 0;
|
elemIdx = 0;
|
||||||
}
|
}
|
||||||
AstNodeExpr* newp;
|
AstNodeExpr* newp;
|
||||||
if (const AstInitArray* const initp = VN_CAST(nodep, InitArray)) {
|
if (AstInitArray* const initp = VN_CAST(nodep, InitArray)) {
|
||||||
UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl);
|
UINFO(9, " cloneInitArray(" << elements << "," << elemIdx << ") " << nodep << endl);
|
||||||
const int leOffset = !arrayp->rangep()->ascending()
|
|
||||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
auto considerOrder = [](const auto* nodep, int idxFromLeft) -> int {
|
||||||
: offset;
|
return !nodep->rangep()->ascending()
|
||||||
AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(leOffset);
|
? nodep->rangep()->elementsConst() - 1 - idxFromLeft
|
||||||
if (!itemp) {
|
: idxFromLeft;
|
||||||
nodep->v3error("Array initialization has too few elements, need element "
|
};
|
||||||
<< offset);
|
newp = nullptr;
|
||||||
|
int itemIdx = 0;
|
||||||
|
int i = 0;
|
||||||
|
if (const int prevItemIdx = initp->user2()) {
|
||||||
|
const AstInitArray::KeyItemMap& itemMap = initp->map();
|
||||||
|
const auto it = itemMap.find(considerOrder(arrayp, prevItemIdx));
|
||||||
|
if (it != itemMap.end()) {
|
||||||
|
const AstInitItem* itemp = it->second;
|
||||||
|
if (itemp->user2() && itemp->user2() < elemIdx) {
|
||||||
|
// Let's resume traversal from the previous position
|
||||||
|
itemIdx = prevItemIdx;
|
||||||
|
i = itemp->user2();
|
||||||
}
|
}
|
||||||
newp = itemp ? itemp->cloneTreePure(false) : new AstConst{nodep->fileline(), 0};
|
}
|
||||||
|
}
|
||||||
|
const AstNodeDType* const expectedItemDTypep = arrayp->subDTypep()->skipRefp();
|
||||||
|
while (i <= elemIdx) {
|
||||||
|
AstNodeExpr* const itemp
|
||||||
|
= initp->getIndexDefaultedValuep(considerOrder(arrayp, itemIdx));
|
||||||
|
if (!itemp && !m_assignError) {
|
||||||
|
nodep->v3error("Array initialization has too few elements, need element "
|
||||||
|
<< elemIdx);
|
||||||
|
m_assignError = true;
|
||||||
|
}
|
||||||
|
const AstNodeDType* itemRawDTypep = itemp->dtypep()->skipRefp();
|
||||||
|
const VCastable castable
|
||||||
|
= AstNode::computeCastable(expectedItemDTypep, itemRawDTypep, itemp);
|
||||||
|
if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
|
||||||
|
if (i == elemIdx) {
|
||||||
|
newp = itemp->cloneTreePure(false);
|
||||||
|
break;
|
||||||
|
} else { // Check the next item
|
||||||
|
++i;
|
||||||
|
++itemIdx;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const AstUnpackArrayDType* const itemDTypep
|
||||||
|
= VN_CAST(itemRawDTypep, UnpackArrayDType);
|
||||||
|
if (!itemDTypep
|
||||||
|
|| !expectedItemDTypep->same(itemDTypep->subDTypep()->skipRefp())) {
|
||||||
|
if (!m_assignError) {
|
||||||
|
itemp->v3error("Item is incompatible with the array type.");
|
||||||
|
}
|
||||||
|
m_assignError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i + itemDTypep->elementsConst()
|
||||||
|
> elemIdx) { // This item contains the element
|
||||||
|
int offset = considerOrder(itemDTypep, elemIdx - i);
|
||||||
|
if (AstSliceSel* const slicep = VN_CAST(itemp, SliceSel)) {
|
||||||
|
offset += slicep->declRange().lo();
|
||||||
|
newp = new AstArraySel{nodep->fileline(),
|
||||||
|
slicep->lhsp()->cloneTreePure(false), offset};
|
||||||
|
} else {
|
||||||
|
newp = new AstArraySel{nodep->fileline(), itemp->cloneTreePure(false),
|
||||||
|
offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_assignError && elemIdx + 1 == elements
|
||||||
|
&& i + itemDTypep->elementsConst() > elements) {
|
||||||
|
nodep->v3error("Array initialization has too many elements. "
|
||||||
|
<< elements << " elements are expected, but at least "
|
||||||
|
<< i + itemDTypep->elementsConst()
|
||||||
|
<< " elements exist.");
|
||||||
|
m_assignError = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else { // Check the next item
|
||||||
|
i += itemDTypep->elementsConst();
|
||||||
|
++itemIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (elemIdx + 1 == elements && static_cast<size_t>(itemIdx) + 1 < initp->map().size()
|
||||||
|
&& !m_assignError) {
|
||||||
|
nodep->v3error("Array initialization has too many elements. "
|
||||||
|
<< elements << " elements are expected, but at least "
|
||||||
|
<< i + initp->map().size() - itemIdx << " elements exist.");
|
||||||
|
m_assignError = true;
|
||||||
|
}
|
||||||
|
if (newp) {
|
||||||
|
const AstInitArray::KeyItemMap& itemMap = initp->map();
|
||||||
|
const auto it = itemMap.find(considerOrder(arrayp, itemIdx));
|
||||||
|
if (it != itemMap.end()) { // Remember current position for the next invocation.
|
||||||
|
initp->user2(itemIdx);
|
||||||
|
it->second->user2(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newp) newp = new AstConst{nodep->fileline(), 0};
|
||||||
} else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) {
|
} else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) {
|
||||||
UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl);
|
UINFO(9, " cloneCond(" << elements << "," << elemIdx << ") " << nodep << endl);
|
||||||
return snodep->cloneType(snodep->condp()->cloneTreePure(false),
|
return snodep->cloneType(snodep->condp()->cloneTreePure(false),
|
||||||
cloneAndSel(snodep->thenp(), elements, offset),
|
cloneAndSel(snodep->thenp(), elements, elemIdx),
|
||||||
cloneAndSel(snodep->elsep(), elements, offset));
|
cloneAndSel(snodep->elsep(), elements, elemIdx));
|
||||||
} else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) {
|
} else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) {
|
||||||
UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl);
|
UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep << endl);
|
||||||
const int leOffset = (snodep->declRange().lo()
|
const int leOffset = (snodep->declRange().lo()
|
||||||
+ (!snodep->declRange().ascending()
|
+ (!snodep->declRange().ascending()
|
||||||
? snodep->declRange().elements() - 1 - offset
|
? snodep->declRange().elements() - 1 - elemIdx
|
||||||
: offset));
|
: elemIdx));
|
||||||
newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false),
|
newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false),
|
||||||
leOffset};
|
leOffset};
|
||||||
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)
|
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)
|
||||||
|| VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel)
|
|| VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel)
|
||||||
|| VN_IS(nodep, ExprStmt)) {
|
|| VN_IS(nodep, ExprStmt)) {
|
||||||
UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl);
|
UINFO(9, " cloneSel(" << elements << "," << elemIdx << ") " << nodep << endl);
|
||||||
const int leOffset = !arrayp->rangep()->ascending()
|
const int leOffset = !arrayp->rangep()->ascending()
|
||||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
? arrayp->rangep()->elementsConst() - 1 - elemIdx
|
||||||
: offset;
|
: elemIdx;
|
||||||
newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false),
|
newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false),
|
||||||
leOffset};
|
leOffset};
|
||||||
} else {
|
} else {
|
||||||
@ -149,10 +239,10 @@ class SliceVisitor final : public VNVisitor {
|
|||||||
// elements
|
// elements
|
||||||
AstNodeAssign* newlistp = nullptr;
|
AstNodeAssign* newlistp = nullptr;
|
||||||
const int elements = arrayp->rangep()->elementsConst();
|
const int elements = arrayp->rangep()->elementsConst();
|
||||||
for (int offset = 0; offset < elements; ++offset) {
|
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
||||||
AstNodeAssign* const newp
|
AstNodeAssign* const newp
|
||||||
= nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset),
|
= nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx),
|
||||||
cloneAndSel(nodep->rhsp(), elements, offset));
|
cloneAndSel(nodep->rhsp(), elements, elemIdx));
|
||||||
if (debug() >= 9) newp->dumpTree("- new: ");
|
if (debug() >= 9) newp->dumpTree("- new: ");
|
||||||
newlistp = AstNode::addNext(newlistp, newp);
|
newlistp = AstNode::addNext(newlistp, newp);
|
||||||
}
|
}
|
||||||
@ -199,11 +289,11 @@ class SliceVisitor final : public VNVisitor {
|
|||||||
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
|
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
|
||||||
} else {
|
} else {
|
||||||
const int elements = adtypep->rangep()->elementsConst();
|
const int elements = adtypep->rangep()->elementsConst();
|
||||||
for (int offset = 0; offset < elements; ++offset) {
|
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
||||||
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
||||||
AstNodeBiop* const clonep
|
AstNodeBiop* const clonep = VN_AS(
|
||||||
= VN_AS(nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset),
|
nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx),
|
||||||
cloneAndSel(nodep->rhsp(), elements, offset)),
|
cloneAndSel(nodep->rhsp(), elements, elemIdx)),
|
||||||
NodeBiop);
|
NodeBiop);
|
||||||
if (!logp) {
|
if (!logp) {
|
||||||
logp = clonep;
|
logp = clonep;
|
||||||
|
@ -4120,6 +4120,7 @@ private:
|
|||||||
PatVecMap patmap = patVectorMap(nodep, range);
|
PatVecMap patmap = patVectorMap(nodep, range);
|
||||||
UINFO(9, "ent " << range.left() << " to " << range.right() << endl);
|
UINFO(9, "ent " << range.left() << " to " << range.right() << endl);
|
||||||
AstNode* newp = nullptr;
|
AstNode* newp = nullptr;
|
||||||
|
bool allConstant = true;
|
||||||
for (int entn = 0, ent = range.left(); entn < range.elements();
|
for (int entn = 0, ent = range.left(); entn < range.elements();
|
||||||
++entn, ent += range.leftToRightInc()) {
|
++entn, ent += range.leftToRightInc()) {
|
||||||
AstPatMember* newpatp = nullptr;
|
AstPatMember* newpatp = nullptr;
|
||||||
@ -4129,7 +4130,10 @@ private:
|
|||||||
if (defaultp) {
|
if (defaultp) {
|
||||||
newpatp = defaultp->cloneTree(false);
|
newpatp = defaultp->cloneTree(false);
|
||||||
patp = newpatp;
|
patp = newpatp;
|
||||||
} else {
|
} else if (!(VN_IS(arrayDtp, UnpackArrayDType) && !allConstant)) {
|
||||||
|
// If arrayDtp is an unpacked array and item is not constant,
|
||||||
|
// the number of elemnt cannot be determined here as the dtype of each element
|
||||||
|
// is not set yet. V3Slice checks for such cases.
|
||||||
nodep->v3error("Assignment pattern missed initializing elements: " << ent);
|
nodep->v3error("Assignment pattern missed initializing elements: " << ent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4140,6 +4144,7 @@ private:
|
|||||||
if (patp) {
|
if (patp) {
|
||||||
// Don't want the RHS an array
|
// Don't want the RHS an array
|
||||||
patp->dtypep(arrayDtp->subDTypep());
|
patp->dtypep(arrayDtp->subDTypep());
|
||||||
|
allConstant &= VN_IS(patp->lhssp(), Const);
|
||||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||||
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
||||||
if (!newp) {
|
if (!newp) {
|
||||||
|
21
test_regress/t/t_unpacked_concat.pl
Executable file
21
test_regress/t/t_unpacked_concat.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;
|
102
test_regress/t/t_unpacked_concat.v
Normal file
102
test_regress/t/t_unpacked_concat.v
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2023 by Yutetsu TAKATSUKASA.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
typedef int AI3[1:3];
|
||||||
|
AI3 A3;
|
||||||
|
int A9[1:9];
|
||||||
|
|
||||||
|
logic [2:0] s0;
|
||||||
|
logic [2:0] s1[1:3];
|
||||||
|
logic [2:0] s2[3:1];
|
||||||
|
logic [2:0] s3[2:8];
|
||||||
|
logic [2:0] s4[8:2];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
s0 = 3'd1;
|
||||||
|
s1[1] = 3'd2;
|
||||||
|
s1[2] = 3'd3;
|
||||||
|
s1[3] = 3'd4;
|
||||||
|
s2[1] = 3'd5;
|
||||||
|
s2[2] = 3'd6;
|
||||||
|
s2[3] = 3'd7;
|
||||||
|
|
||||||
|
A3 = '{1, 2, 3};
|
||||||
|
A9 = {A3, 4, 5, A3, 6};
|
||||||
|
if (A9[1] != 1) $stop;
|
||||||
|
if (A9[2] != 2) $stop;
|
||||||
|
if (A9[3] != 3) $stop;
|
||||||
|
if (A9[4] != 4) $stop;
|
||||||
|
if (A9[5] != 5) $stop;
|
||||||
|
if (A9[6] != 1) $stop;
|
||||||
|
if (A9[7] != 2) $stop;
|
||||||
|
if (A9[8] != 3) $stop;
|
||||||
|
if (A9[9] != 6) $stop;
|
||||||
|
|
||||||
|
s3 = {s0, s1, s2};
|
||||||
|
if (s3[2] != s0) $stop;
|
||||||
|
if (s3[3] != s1[1]) $stop;
|
||||||
|
if (s3[4] != s1[2]) $stop;
|
||||||
|
if (s3[5] != s1[3]) $stop;
|
||||||
|
if (s3[6] != s2[3]) $stop;
|
||||||
|
if (s3[7] != s2[2]) $stop;
|
||||||
|
if (s3[8] != s2[1]) $stop;
|
||||||
|
|
||||||
|
s3[2:8] = {s0, s1[1:2], s1[3], s2[3], s2[2:1]};
|
||||||
|
if (s3[2] != s0) $stop;
|
||||||
|
if (s3[3] != s1[1]) $stop;
|
||||||
|
if (s3[4] != s1[2]) $stop;
|
||||||
|
if (s3[5] != s1[3]) $stop;
|
||||||
|
if (s3[6] != s2[3]) $stop;
|
||||||
|
if (s3[7] != s2[2]) $stop;
|
||||||
|
if (s3[8] != s2[1]) $stop;
|
||||||
|
|
||||||
|
s3 = {s0, s1[1], s1[2:3], s2[3:2], s2[1]};
|
||||||
|
if (s3[2] != s0) $stop;
|
||||||
|
if (s3[3] != s1[1]) $stop;
|
||||||
|
if (s3[4] != s1[2]) $stop;
|
||||||
|
if (s3[5] != s1[3]) $stop;
|
||||||
|
if (s3[6] != s2[3]) $stop;
|
||||||
|
if (s3[7] != s2[2]) $stop;
|
||||||
|
if (s3[8] != s2[1]) $stop;
|
||||||
|
|
||||||
|
s4 = {s0, s1, s2};
|
||||||
|
if (s4[8] != s0) $stop;
|
||||||
|
if (s4[7] != s1[1]) $stop;
|
||||||
|
if (s4[6] != s1[2]) $stop;
|
||||||
|
if (s4[5] != s1[3]) $stop;
|
||||||
|
if (s4[4] != s2[3]) $stop;
|
||||||
|
if (s4[3] != s2[2]) $stop;
|
||||||
|
if (s4[2] != s2[1]) $stop;
|
||||||
|
|
||||||
|
s4[8:2] = {s0, s1[1:2], s1[3], s2[3], s2[2:1]};
|
||||||
|
if (s4[8] != s0) $stop;
|
||||||
|
if (s4[7] != s1[1]) $stop;
|
||||||
|
if (s4[6] != s1[2]) $stop;
|
||||||
|
if (s4[5] != s1[3]) $stop;
|
||||||
|
if (s4[4] != s2[3]) $stop;
|
||||||
|
if (s4[3] != s2[2]) $stop;
|
||||||
|
if (s4[2] != s2[1]) $stop;
|
||||||
|
|
||||||
|
s4 = {s0, s1[1], s1[2:3], s2[3:2], s2[1]};
|
||||||
|
if (s4[8] != s0) $stop;
|
||||||
|
if (s4[7] != s1[1]) $stop;
|
||||||
|
if (s4[6] != s1[2]) $stop;
|
||||||
|
if (s4[5] != s1[3]) $stop;
|
||||||
|
if (s4[4] != s2[3]) $stop;
|
||||||
|
if (s4[3] != s2[2]) $stop;
|
||||||
|
if (s4[2] != s2[1]) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
@ -3,8 +3,4 @@
|
|||||||
17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}};
|
17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}};
|
||||||
| ^
|
| ^
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||||
%Error: t/t_unpacked_concat_bad.v:17:46: Assignment pattern missed initializing elements: 0
|
|
||||||
: ... note: In instance 't'
|
|
||||||
17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}};
|
|
||||||
| ^
|
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
13
test_regress/t/t_unpacked_concat_bad2.out
Normal file
13
test_regress/t/t_unpacked_concat_bad2.out
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
%Error: t/t_unpacked_concat_bad2.v:25:15: Array initialization has too many elements. 2 elements are expected, but at least 5 elements exist.
|
||||||
|
25 | s1 = {s0, s2};
|
||||||
|
| ^
|
||||||
|
%Error: t/t_unpacked_concat_bad2.v:26:23: Array initialization has too many elements. 4 elements are expected, but at least 5 elements exist.
|
||||||
|
26 | s2 = {s1, s0, s0, s0};
|
||||||
|
| ^
|
||||||
|
%Error: t/t_unpacked_concat_bad2.v:28:17: Item is incompatible with the array type.
|
||||||
|
28 | s2 = {s0, s3};
|
||||||
|
| ^~
|
||||||
|
%Error: t/t_unpacked_concat_bad2.v:30:19: Item is incompatible with the array type.
|
||||||
|
30 | A9_logic = {A3, 4, 5, A3, 6};
|
||||||
|
| ^~
|
||||||
|
%Error: Exiting due to
|
19
test_regress/t/t_unpacked_concat_bad2.pl
Executable file
19
test_regress/t/t_unpacked_concat_bad2.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(vlt => 1);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
fails => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
34
test_regress/t/t_unpacked_concat_bad2.v
Normal file
34
test_regress/t/t_unpacked_concat_bad2.v
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2023 by Yutetsu TAKATSUKASA.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
logic [7:0] s0;
|
||||||
|
logic [7:0] s1[1:2];
|
||||||
|
logic [7:0] s2[1:4];
|
||||||
|
logic [7:0] s3[2][2];
|
||||||
|
|
||||||
|
typedef int AI3[1:3];
|
||||||
|
AI3 A3;
|
||||||
|
logic [31:0] A9_logic[1:9];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// RHS has too many elements.
|
||||||
|
s1 = {s0, s2};
|
||||||
|
s2 = {s1, s0, s0, s0};
|
||||||
|
// Incompatible type
|
||||||
|
s2 = {s0, s3};
|
||||||
|
|
||||||
|
A9_logic = {A3, 4, 5, A3, 6};
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
Loading…
Reference in New Issue
Block a user