Support force assignments to array elements of real type (#7048)

This commit is contained in:
Ryszard Rozak 2026-03-05 14:37:20 +01:00 committed by GitHub
parent e5ad9b3a4b
commit 258629634c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 169 additions and 29 deletions

View File

@ -574,6 +574,7 @@ public:
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64
|| m_e == TIME);
}
bool isBit() const { return m_e == BIT; }
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
return (m_e == LOGIC || m_e == BIT);
}

View File

@ -459,6 +459,7 @@ public:
return m.m_keyword;
}
bool isBitLogic() const { return keyword().isBitLogic(); }
bool isBit() const { return keyword().isBit(); }
bool isCHandle() const VL_MT_STABLE { return keyword().isCHandle(); }
bool isDouble() const VL_MT_STABLE { return keyword().isDouble(); }
bool isEvent() const VL_MT_STABLE { return keyword() == VBasicDTypeKwd::EVENT; }

View File

@ -1778,6 +1778,15 @@ public:
addAttrsp(attrsp);
dtypep(nullptr); // V3Width will resolve
}
AstTypedef(FileLine* fl, const string& name, AstNodeDType* dtp, bool underClass)
: ASTGEN_SUPER_Typedef(fl)
, m_name{name}
, m_declTokenNum{fl->tokenNum()}
, m_isHideLocal{false}
, m_isHideProtected{false}
, m_isUnderClass{underClass} {
dtypep(dtp);
}
ASTGEN_MEMBERS_AstTypedef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;

View File

@ -241,6 +241,7 @@ public:
private:
// NODE STATE
// AstNodeDType::user1p -> AstNodeDType*, dtype created for __En variables
// AstVar::user1p -> ForceComponentsVar* instance (via m_forceComponentsVar)
// AstVarScope::user1p -> ForceComponentsVarScope* instance (via m_forceComponentsVarScope)
// AstVarRef::user2 -> Flag indicating not to replace reference
@ -264,7 +265,7 @@ private:
if (const AstUnpackArrayDType* const udtp = VN_CAST(dtp, UnpackArrayDType)) {
const size_t elemsInSubDType = checkIfDTypeSupportedRecurse(udtp->subDTypep(), varp);
return udtp->elementsConst() * elemsInSubDType;
} else if (const AstNodeUOrStructDType* const sdtp = VN_CAST(dtp, NodeUOrStructDType)) {
} else if (const AstStructDType* const sdtp = VN_CAST(dtp, StructDType)) {
size_t elemCount = 0;
for (const AstMemberDType* mdtp = sdtp->membersp(); mdtp;
mdtp = VN_AS(mdtp->nextp(), MemberDType)) {
@ -287,26 +288,117 @@ private:
return 1;
}
}
static AstNodeDType* getEnVarpDTypep(const AstVar* const varp) {
static AstNodeDType* getEnVarpDTypep(AstVar* const varp) {
AstNodeDType* const origDTypep = varp->dtypep()->skipRefp();
if (origDTypep->user1p()) return VN_AS(origDTypep->user1p(), NodeDType);
const size_t unpackElemNum = checkIfDTypeSupportedRecurse(origDTypep, varp);
if (unpackElemNum > ELEMENTS_MAX) {
varp->v3warn(E_UNSUPPORTED, "Unsupported: Force of variable with "
">= "
<< ELEMENTS_MAX << " unpacked elements");
}
if (VN_IS(origDTypep, UnpackArrayDType)) {
return origDTypep;
} else if (VN_IS(origDTypep, BasicDType)) {
return isRangedDType(varp) ? origDTypep : varp->findBitDType();
} else if (VN_IS(origDTypep, PackArrayDType)) {
return origDTypep;
} else if (VN_IS(origDTypep, NodeUOrStructDType)) {
return origDTypep;
} else {
varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type");
return origDTypep;
}
return getEnVarpDTypeRecursep(varp, origDTypep);
}
static AstNodeDType* getEnVarpDTypeRecursep(AstVar* const varp, AstNodeDType* const dtypep) {
if (dtypep->user1p()) return VN_AS(dtypep->user1p(), NodeDType);
if (AstNodeArrayDType* const arrp = VN_CAST(dtypep, NodeArrayDType)) {
AstNodeDType* const subDTypep = arrp->subDTypep()->skipRefp();
AstNodeDType* const enSubDTypep = getEnVarpDTypeRecursep(varp, subDTypep);
if (subDTypep != enSubDTypep) {
AstNodeArrayDType* enArrp;
if (VN_IS(arrp, UnpackArrayDType)) {
enArrp = new AstUnpackArrayDType{arrp->fileline(), enSubDTypep,
arrp->rangep()->cloneTree(false)};
} else if (VN_IS(arrp, PackArrayDType)) {
enArrp = new AstPackArrayDType{arrp->fileline(), enSubDTypep,
arrp->rangep()->cloneTree(false)};
} else {
varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type");
return dtypep;
}
dtypep->user1p(enArrp);
v3Global.rootp()->typeTablep()->addTypesp(enArrp);
return enArrp;
} else {
dtypep->user1p(dtypep);
return dtypep;
}
} else if (AstBasicDType* const basicp = VN_CAST(dtypep, BasicDType)) {
if (basicp->isBit()) {
dtypep->user1p(dtypep);
return dtypep;
} else {
AstNodeDType* const bitDtp = varp->findBitRangeDType(
basicp->declRange(), basicp->elements(), VSigning::UNSIGNED);
dtypep->user1p(bitDtp);
return bitDtp;
}
} else if (AstNodeUOrStructDType* const structp = VN_CAST(dtypep, NodeUOrStructDType)) {
std::vector<AstMemberDType*> enMemberDTypes;
bool changed = false;
for (AstMemberDType* mdtp = structp->membersp(); mdtp;
mdtp = VN_AS(mdtp->nextp(), MemberDType)) {
AstNodeDType* const subMdtp = mdtp->subDTypep()->skipRefp();
AstNodeDType* const enSubMdtp = getEnVarpDTypeRecursep(varp, subMdtp);
if (subMdtp != enSubMdtp) {
changed = true;
AstMemberDType* const enMdtp
= new AstMemberDType{mdtp->fileline(), mdtp->name(), enSubMdtp};
enMdtp->dtypep(enSubMdtp);
enMemberDTypes.push_back(enMdtp);
} else {
enMemberDTypes.push_back(mdtp->cloneTreePure(false));
}
}
if (changed) {
const bool packed = structp->packed();
AstNodeUOrStructDType* enStructp;
if (VN_IS(structp, StructDType)) {
enStructp = new AstStructDType{structp->fileline(),
packed ? VSigning::SIGNED : VSigning::NOSIGN};
} else if (VN_IS(structp, UnionDType) && packed) {
const AstUnionDType* const unionp = VN_AS(structp, UnionDType);
enStructp = new AstUnionDType{unionp->fileline(), unionp->isSoft(),
unionp->isTagged(), VSigning::SIGNED};
} else {
varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type");
return dtypep;
}
int width = 0;
if (packed) {
for (const auto& memberp : enMemberDTypes) {
enStructp->addMembersp(memberp);
const int memberWidth = memberp->width();
if (VN_IS(structp, StructDType)) {
width += memberWidth;
} else {
width = std::max(width, memberWidth);
}
}
} else {
for (const auto& memberp : enMemberDTypes) enStructp->addMembersp(memberp);
width = 1;
}
v3Global.rootp()->typeTablep()->addTypesp(enStructp);
enStructp->name(structp->name() + "__VforceEn_t");
enStructp->dtypep(enStructp);
enStructp->widthForce(width, width);
enStructp->classOrPackagep(structp->classOrPackagep());
dtypep->user1p(enStructp);
AstTypedef* const typedefp
= new AstTypedef{enStructp->fileline(), enStructp->name(), enStructp,
VN_IS(enStructp->classOrPackagep(), Class)};
varp->addNextHere(typedefp);
return enStructp;
} else {
for (const auto& memberp : enMemberDTypes) memberp->deleteTree();
dtypep->user1p(dtypep);
return dtypep;
}
}
varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type");
return dtypep;
}
public:

View File

@ -25,6 +25,7 @@ module t (
int int_arr[-1:2][1][3];
bit [5:0] bit_arr[5];
union_t union_arr[4];
real real_arr[2][1][3];
assign bit_arr[2][3] = 1;
@ -35,18 +36,21 @@ module t (
logic_arr[0][2][-4] <= 1;
int_arr[0][0][2] <= 1;
union_arr[1].x <= 1;
real_arr[0][0][1] <= 1;
end
else if (cyc == 1) begin
`checkh(logic_arr[0][2][-4], 1);
`checkh(int_arr[0][0][2], 1);
`checkh(bit_arr[2][3], 1);
`checkh(union_arr[1].x, 1);
`checkr(real_arr[0][0][1], 1);
end
else if (cyc == 2) begin
force logic_arr[0][2][-4] = 0;
force int_arr[0][0][2] = 0;
force bit_arr[2][3] = 0;
force union_arr[1].y = 2;
force real_arr[0][0][1] = 0;
end
else if (cyc == 3) begin
`checkh(logic_arr[0][2][-4], 0);
@ -56,11 +60,14 @@ module t (
`checkh(bit_arr[2][3], 0);
`checkh(union_arr[1].x, 2);
union_arr[1].x <= 3;
`checkr(real_arr[0][0][1], 0);
real_arr[0][0][1] <= 2;
end
else if (cyc == 4) begin
`checkh(logic_arr[0][2][-4], 0);
`checkh(int_arr[0][0][2], 0);
`checkh(union_arr[1].y, 2);
`checkr(real_arr[0][0][1], 0);
end
else if (cyc == 5) begin
release logic_arr[0][2][-4];
@ -68,6 +75,7 @@ module t (
release bit_arr[2][3];
`checkh(bit_arr[2][3], 1);
release union_arr[1].x;
release real_arr[0][0][1];
end
else if (cyc == 6) begin
`checkh(logic_arr[0][2][-4], 0);
@ -77,11 +85,14 @@ module t (
`checkh(bit_arr[2][3], 1);
`checkh(union_arr[1].x, 2);
union_arr[1].y <= 4;
`checkr(real_arr[0][0][1], 0);
real_arr[0][0][1] <= 3;
end
else if (cyc == 7) begin
`checkh(logic_arr[0][2][-4], 1);
`checkh(int_arr[0][0][2], 1);
`checkh(union_arr[1].x, 4);
`checkr(real_arr[0][0][1], 3);
end
else if (cyc == 8) begin
$write("*-* All Finished *-*\n");

View File

@ -16,10 +16,16 @@ module t (
integer cyc = 0;
typedef struct packed {
bit a;
bit b;
} packed_t;
typedef struct {
int x;
logic y;
int arr[5];
packed_t pt;
} struct_t;
struct_t s_array[3];
@ -32,16 +38,19 @@ module t (
s_array[1].x = 1;
s_array[1].arr[2] = 1;
my_struct.x <= 1;
my_struct.pt.b <= 1;
end
else if (cyc == 1) begin
`checkh(s_array[1].x, 1);
`checkh(s_array[1].arr[2], 1);
`checkh(my_struct.x, 1);
`checkh(my_struct.pt.b, 1);
end
else if (cyc == 2) begin
force s_array[1].x = 0;
force s_array[1].arr[2] = 2;
force my_struct.x = 0;
force my_struct.pt.b = 0;
end
else if (cyc == 3) begin
`checkh(s_array[1].x, 0);
@ -50,16 +59,20 @@ module t (
s_array[1].arr[2] = 3;
`checkh(my_struct.x, 0);
my_struct.x <= 1;
`checkh(my_struct.pt.b, 0);
my_struct.pt.b <= 1;
end
else if (cyc == 4) begin
`checkh(s_array[1].x, 0);
`checkh(s_array[1].arr[2], 2);
`checkh(my_struct.x, 0);
`checkh(my_struct.pt.b, 0);
end
else if (cyc == 5) begin
release s_array[1].x;
release s_array[1].arr[2];
release my_struct.x;
release my_struct.pt.b;
end
else if (cyc == 6) begin
`checkh(s_array[1].x, 0);
@ -68,11 +81,14 @@ module t (
s_array[1].arr[2] = 4;
`checkh(my_struct.x, 0);
my_struct.x <= 1;
`checkh(my_struct.pt.b, 0);
my_struct.pt.b <= 1;
end
else if (cyc == 7) begin
`checkh(s_array[1].x, 1);
`checkh(s_array[1].arr[2], 4);
`checkh(my_struct.x, 1);
`checkh(my_struct.pt.b, 1);
end
else if (cyc == 8) begin
$write("*-* All Finished *-*\n");

View File

@ -1,8 +1,14 @@
%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:22:7: Unsupported: Force of variable with >= 1000 unpacked elements
22 | bit big_array[40][40][40];
%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:26:7: Unsupported: Force of variable with >= 1000 unpacked elements
26 | bit big_array[40][40][40];
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:21:12: Unsupported: Force of variable with >= 1000 unpacked elements
21 | struct_t s_array[3000];
%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:25:12: Unsupported: Force of variable with >= 1000 unpacked elements
25 | struct_t s_array[3000];
| ^~~~~~~
%Error: Exiting due to
%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:27:11: Forcing variable of unsupported type: REFDTYPE 'union_t'
27 | union_t my_union;
| ^~~~~~~~
%Error: Internal Error: t/t_force_unpacked_unsup.v:27:11: ../V3Force.cpp:#: Unsupported: Force of variable of unhandled data type
27 | union_t my_union;
| ^~~~~~~~
... This fatal error may be caused by the earlier error(s); resolve those first.

View File

@ -17,59 +17,63 @@ module t (
integer cyc = 0;
typedef struct {int x;} struct_t;
typedef union {
int x;
logic y;
} union_t;
struct_t s_array[3000];
bit big_array[40][40][40];
real r_array[2];
union_t my_union;
// Test loop
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 0) begin
r_array[0] <= 1;
big_array[1][2][3] <= 1;
s_array[1].x <= 1;
my_union.x <= 1;
end
else if (cyc == 1) begin
`checkr(r_array[0], 1);
`checkr(big_array[1][2][3], 1);
`checkh(s_array[1].x, 1);
`checkh(my_union.x, 1);
end
else if (cyc == 2) begin
force r_array[0] = 0;
force big_array[1][2][3] = 0;
force s_array[1].x = 0;
force my_union.x = 0;
end
else if (cyc == 3) begin
`checkr(r_array[0], 0);
`checkr(big_array[1][2][3], 0);
r_array[0] <= 1;
big_array[1][2][3] <= 1;
`checkh(s_array[1].x, 0);
s_array[1].x <= 1;
`checkh(my_union.x, 0);
my_union.x <= 1;
end
else if (cyc == 4) begin
`checkr(r_array[0], 0);
`checkr(big_array[1][2][3], 0);
`checkh(s_array[1].x, 0);
`checkh(my_union.x, 0);
end
else if (cyc == 5) begin
release r_array[0];
release big_array[1][2][3];
release s_array[1].x;
release my_union.x;
end
else if (cyc == 6) begin
`checkr(r_array[0], 0);
`checkr(big_array[1][2][3], 0);
r_array[0] <= 1;
big_array[1][2][3] <= 1;
`checkh(s_array[1].x, 0);
s_array[1].x <= 1;
`checkh(my_union.x, 0);
my_union.x <= 1;
end
else if (cyc == 7) begin
`checkr(r_array[0], 1);
`checkr(big_array[1][2][3], 1);
`checkh(s_array[1].x, 1);
`checkh(my_union.x, 1);
end
else if (cyc == 8) begin
$write("*-* All Finished *-*\n");