parent
bed0456eca
commit
25cb31c38b
|
@ -205,6 +205,7 @@ Sean Cross
|
|||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
Seth Pellegrino
|
||||
Shou-Li Hsu
|
||||
Srinivasan Venkataramanan
|
||||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
|
|
|
@ -124,6 +124,7 @@ public:
|
|||
// Iff has a non-null subDTypep(), as generic node function
|
||||
virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return nullptr; }
|
||||
virtual AstNodeDType* subDType2p() const VL_MT_STABLE { return nullptr; }
|
||||
virtual bool isAggregateType() const { return false; }
|
||||
virtual bool isFourstate() const;
|
||||
// Ideally an IEEE $typename
|
||||
virtual string prettyDTypeName(bool) const { return prettyTypeName(); }
|
||||
|
@ -366,6 +367,7 @@ public:
|
|||
AstNodeDType* subDType2p() const override VL_MT_STABLE {
|
||||
return m_keyDTypep ? m_keyDTypep : keyChildDTypep();
|
||||
}
|
||||
bool isAggregateType() const override { return true; }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
|
@ -742,6 +744,7 @@ public:
|
|||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
bool isAggregateType() const override { return true; }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
|
@ -1108,6 +1111,7 @@ public:
|
|||
AstNodeDType* subDTypep() const override VL_MT_STABLE {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
bool isAggregateType() const override { return true; }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
inline int boundConst() const VL_MT_STABLE;
|
||||
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
|
@ -1404,6 +1408,7 @@ public:
|
|||
const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType);
|
||||
return m_isCompound == sp->m_isCompound;
|
||||
}
|
||||
bool isAggregateType() const override { return true; }
|
||||
// Outer dimension comes first. The first element is this node.
|
||||
std::vector<AstUnpackArrayDType*> unpackDimensions();
|
||||
void isCompound(bool flag) { m_isCompound = flag; }
|
||||
|
|
|
@ -319,69 +319,58 @@ class SliceVisitor final : public VNVisitor {
|
|||
|
||||
void expandBiOp(AstNodeBiop* nodep) {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
// If it's an unpacked array, blow it up into comparing each element
|
||||
AstNodeDType* const fromDtp = nodep->lhsp()->dtypep()->skipRefp();
|
||||
UINFO(9, " Bi-Eq/Neq expansion " << nodep << endl);
|
||||
|
||||
// Only expand if lhs is an unpacked array (we assume type checks already passed)
|
||||
const AstNodeDType* const fromDtp = nodep->lhsp()->dtypep()->skipRefp();
|
||||
if (const AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
|
||||
AstNodeBiop* logp = nullptr;
|
||||
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
nodep->lhsp()->v3error(
|
||||
"Slice operator "
|
||||
<< nodep->lhsp()->prettyTypeName()
|
||||
<< " on non-slicable (e.g. non-vector) left-hand-side operand");
|
||||
} else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
nodep->rhsp()->v3error(
|
||||
"Slice operator "
|
||||
<< nodep->rhsp()->prettyTypeName()
|
||||
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
|
||||
} else {
|
||||
const int elements = adtypep->rangep()->elementsConst();
|
||||
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
||||
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
||||
// Original node is replaced, so it is safe to copy it one time even if it is
|
||||
// impure.
|
||||
AstNodeBiop* const clonep
|
||||
= VN_AS(nodep->cloneType(
|
||||
cloneAndSel(nodep->lhsp(), elements, elemIdx, elemIdx != 0),
|
||||
cloneAndSel(nodep->rhsp(), elements, elemIdx, elemIdx != 0)),
|
||||
NodeBiop);
|
||||
if (elemIdx == 0) {
|
||||
nodep->foreach([this](AstExprStmt* const exprp) {
|
||||
// Result expression is always evaluated to the same value, so the
|
||||
// statements can be removed once they were included in the expression
|
||||
// created for the 1st element.
|
||||
AstNodeExpr* const resultp = exprp->resultp()->unlinkFrBack();
|
||||
exprp->replaceWith(resultp);
|
||||
VL_DO_DANGLING(pushDeletep(exprp), exprp);
|
||||
});
|
||||
}
|
||||
|
||||
if (!logp) {
|
||||
logp = clonep;
|
||||
} else {
|
||||
switch (nodep->type()) {
|
||||
case VNType::atEq: // FALLTHRU
|
||||
case VNType::atEqCase:
|
||||
logp = new AstLogAnd{nodep->fileline(), logp, clonep};
|
||||
break;
|
||||
case VNType::atNeq: // FALLTHRU
|
||||
case VNType::atNeqCase:
|
||||
logp = new AstLogOr{nodep->fileline(), logp, clonep};
|
||||
break;
|
||||
default:
|
||||
nodep->v3fatalSrc("Unknown node type processing array slice");
|
||||
break;
|
||||
}
|
||||
const int elements = adtypep->rangep()->elementsConst();
|
||||
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
||||
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
||||
// Original node is replaced, so it is safe to copy it one time even if it is
|
||||
// impure.
|
||||
AstNodeBiop* const clonep = VN_AS(
|
||||
nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx, elemIdx != 0),
|
||||
cloneAndSel(nodep->rhsp(), elements, elemIdx, elemIdx != 0)),
|
||||
NodeBiop);
|
||||
if (elemIdx == 0) {
|
||||
nodep->foreach([this](AstExprStmt* const exprp) {
|
||||
// Result expression is always evaluated to the same value, so the
|
||||
// statements can be removed once they were included in the expression
|
||||
// created for the 1st element.
|
||||
AstNodeExpr* const resultp = exprp->resultp()->unlinkFrBack();
|
||||
exprp->replaceWith(resultp);
|
||||
VL_DO_DANGLING(pushDeletep(exprp), exprp);
|
||||
});
|
||||
}
|
||||
|
||||
if (!logp) {
|
||||
logp = clonep;
|
||||
} else {
|
||||
switch (nodep->type()) {
|
||||
case VNType::atEq: // FALLTHRU
|
||||
case VNType::atEqCase:
|
||||
logp = new AstLogAnd{nodep->fileline(), logp, clonep};
|
||||
break;
|
||||
case VNType::atNeq: // FALLTHRU
|
||||
case VNType::atNeqCase:
|
||||
logp = new AstLogOr{nodep->fileline(), logp, clonep};
|
||||
break;
|
||||
default: nodep->v3fatalSrc("Unknown node type processing array slice"); break;
|
||||
}
|
||||
}
|
||||
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
|
||||
nodep->replaceWith(logp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep = logp;
|
||||
}
|
||||
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
|
||||
nodep->replaceWith(logp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep = logp;
|
||||
}
|
||||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstEq* nodep) override { expandBiOp(nodep); }
|
||||
void visit(AstNeq* nodep) override { expandBiOp(nodep); }
|
||||
void visit(AstEqCase* nodep) override { expandBiOp(nodep); }
|
||||
|
|
108
src/V3Width.cpp
108
src/V3Width.cpp
|
@ -6551,6 +6551,93 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// LRM 6.22.2 Equivalent types
|
||||
bool isEquivalentDType(const AstNodeDType* lhs, const AstNodeDType* rhs) {
|
||||
// a) If two types match, they are equivalent.
|
||||
if (!lhs || !rhs) return false;
|
||||
lhs = lhs->skipRefp();
|
||||
rhs = rhs->skipRefp();
|
||||
if (lhs == rhs) return true;
|
||||
// If both are basic types, check if they are the same type
|
||||
if (VN_IS(lhs, BasicDType) && VN_IS(rhs, BasicDType)) {
|
||||
const auto* lb = VN_CAST(lhs, BasicDType);
|
||||
const auto* rb = VN_CAST(rhs, BasicDType);
|
||||
if (lb->isString() != rb->isString()) return false;
|
||||
}
|
||||
|
||||
// d) Unpacked fixed-size array types are equivalent if they have equivalent element types
|
||||
// and equal size; the actual range bounds may differ. Note that the element type of a
|
||||
// multidimensional array is itself an array type.
|
||||
const bool lhsIsUnpackArray = VN_IS(lhs, UnpackArrayDType);
|
||||
const bool rhsIsUnpackArray = VN_IS(rhs, UnpackArrayDType);
|
||||
if (lhsIsUnpackArray || rhsIsUnpackArray) {
|
||||
if (VN_IS(lhs, UnpackArrayDType) && VN_IS(rhs, UnpackArrayDType)) {
|
||||
const AstUnpackArrayDType* const lhsp = VN_CAST(lhs, UnpackArrayDType);
|
||||
const AstUnpackArrayDType* const rhsp = VN_CAST(rhs, UnpackArrayDType);
|
||||
const int lsz = lhsp->elementsConst();
|
||||
const int rsz = rhsp->elementsConst();
|
||||
if (lsz >= 0 && rsz >= 0 && lsz != rsz) return false;
|
||||
return isEquivalentDType(lhsp->subDTypep(), rhsp->subDTypep());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// e) Dynamic array, associative array, and queue types are equivalent if they are the same
|
||||
// kind of array (dynamic, associative, or queue), have equivalent index types (for
|
||||
// associative arrays), and have equivalent element types.
|
||||
const bool lhsIsDynArray = VN_IS(lhs, DynArrayDType);
|
||||
const bool rhsIsDynArray = VN_IS(rhs, DynArrayDType);
|
||||
const bool lhsIsQueue = VN_IS(lhs, QueueDType);
|
||||
const bool rhsIsQueue = VN_IS(rhs, QueueDType);
|
||||
const bool lhsIsAssocArray = VN_IS(lhs, AssocArrayDType);
|
||||
const bool rhsIsAssocArray = VN_IS(rhs, AssocArrayDType);
|
||||
|
||||
if (lhsIsDynArray || rhsIsDynArray || lhsIsQueue || rhsIsQueue || lhsIsAssocArray
|
||||
|| rhsIsAssocArray) {
|
||||
if (const AstDynArrayDType* const lhsp = VN_CAST(lhs, DynArrayDType)) {
|
||||
if (const AstDynArrayDType* const rhsp = VN_CAST(rhs, DynArrayDType)) {
|
||||
return isEquivalentDType(lhsp->subDTypep(), rhsp->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
if (const AstQueueDType* const lhsp = VN_CAST(lhs, QueueDType)) {
|
||||
if (const AstQueueDType* const rhsp = VN_CAST(rhs, QueueDType)) {
|
||||
return isEquivalentDType(lhsp->subDTypep(), rhsp->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
if (const AstAssocArrayDType* const lhsp = VN_CAST(lhs, AssocArrayDType)) {
|
||||
if (const AstAssocArrayDType* const rhsp = VN_CAST(rhs, AssocArrayDType)) {
|
||||
return isEquivalentDType(lhsp->subDTypep(), rhsp->subDTypep())
|
||||
&& isEquivalentDType(lhsp->keyDTypep(), rhsp->keyDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// c) Packed arrays, packed structures, packed unions, and built-in integral
|
||||
// types are equivalent if they contain the same number of total bits, are either all
|
||||
// 2-state or all 4-state, and are either all signed or all unsigned.
|
||||
if (lhs->isIntegralOrPacked() && rhs->isIntegralOrPacked()) {
|
||||
if (lhs->width() != rhs->width()) return false;
|
||||
if (lhs->isFourstate() != rhs->isFourstate()) return false;
|
||||
if (lhs->isSigned() != rhs->isSigned()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isAggregateType(const AstNode* nodep) {
|
||||
if (!nodep) return false;
|
||||
const AstNodeDType* dtypep = nodep->dtypep();
|
||||
if (!dtypep) return false;
|
||||
dtypep = dtypep->skipRefp();
|
||||
if (!dtypep) return false;
|
||||
return dtypep->isAggregateType();
|
||||
}
|
||||
|
||||
void visit_cmp_eq_gt(AstNodeBiop* nodep, bool realok) {
|
||||
// CALLER: AstEq, AstGt, ..., AstLtS
|
||||
// Real allowed if and only if real_lhs set
|
||||
|
@ -6567,7 +6654,26 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
|
||||
|
||||
const bool isAggrLhs = isAggregateType(nodep->lhsp());
|
||||
const bool isAggrRhs = isAggregateType(nodep->rhsp());
|
||||
|
||||
if ((isAggrLhs || isAggrRhs) && nodep->lhsp() && nodep->rhsp()) {
|
||||
const AstNodeDType* const lhsDType = nodep->lhsp()->dtypep();
|
||||
const AstNodeDType* const rhsDType = nodep->rhsp()->dtypep();
|
||||
|
||||
if (lhsDType && rhsDType && !isEquivalentDType(lhsDType, rhsDType)) {
|
||||
nodep->v3error("Comparison requires matching data types\n"
|
||||
<< nodep->warnMore() << "... Left-hand data type: "
|
||||
<< lhsDType->prettyDTypeNameQ() << "\n"
|
||||
<< nodep->warnMore() << "... Right-hand data type: "
|
||||
<< rhsDType->prettyDTypeNameQ());
|
||||
AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
} else if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
|
||||
if (!realok) {
|
||||
nodep->v3error("Real is illegal operand to ?== operator");
|
||||
AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
%Error: t/t_fuzz_eqne_bad.v:12:23: Slice operator VARREF 't.b' on non-slicable (e.g. non-vector) right-hand-side operand
|
||||
%Error: t/t_fuzz_eqne_bad.v:12:19: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'logic$[0:-1]'
|
||||
: ... Right-hand data type: 'logic'
|
||||
12 | initial c = (a != &b);
|
||||
| ^
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
|
@ -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()
|
|
@ -0,0 +1,78 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
// Typedefs
|
||||
typedef int myint_t;
|
||||
typedef int myint2_t;
|
||||
typedef int myq_t[$];
|
||||
typedef int myval_t;
|
||||
typedef string mykey_t;
|
||||
|
||||
initial begin
|
||||
// Scalar
|
||||
int a = 1, b = 1;
|
||||
|
||||
// Unpacked array
|
||||
int u1[2] = '{1, 2};
|
||||
int u2[2] = '{1, 2};
|
||||
|
||||
int m1[2][2] = '{{1, 2}, {3, 4}};
|
||||
int m2[2][2] = '{{1, 2}, {3, 4}};
|
||||
|
||||
// Dynamic array
|
||||
int d1[] = new[2];
|
||||
int d2[] = new[2];
|
||||
|
||||
// Queue
|
||||
int q1[$] = '{10, 20};
|
||||
int q2[$] = '{10, 20};
|
||||
|
||||
// Associative array
|
||||
int aa1[string];
|
||||
int aa2[string];
|
||||
|
||||
// Typedef array
|
||||
myint_t t1[2] = '{1, 2};
|
||||
myint2_t t2[2] = '{1, 2};
|
||||
|
||||
// Typedef queue
|
||||
myq_t tq1 = '{1, 2};
|
||||
int tq2[$] = '{1, 2};
|
||||
|
||||
// Typedef associative array
|
||||
myval_t aa_typedef1[mykey_t];
|
||||
int aa_typedef2[string];
|
||||
|
||||
// Typedef scalar
|
||||
bit signed [31:0] b1 = 1;
|
||||
int i1 = 1;
|
||||
|
||||
d1[0] = 5; d1[1] = 6;
|
||||
d2[0] = 5; d2[1] = 6;
|
||||
|
||||
aa1["a"] = 1; aa2["a"] = 1;
|
||||
aa1["b"] = 2; aa2["b"] = 2;
|
||||
|
||||
aa_typedef1["foo"] = 123;
|
||||
aa_typedef2["foo"] = 123;
|
||||
|
||||
if (a != b) $fatal(0, "Scalar comparison failed");
|
||||
if (u1 != u2) $fatal(0, "Unpacked 1D array comparison failed");
|
||||
if (m1 != m2) $fatal(0, "Unpacked multi-dimensional array comparison failed");
|
||||
if (d1 != d2) $fatal(0, "Dynamic array comparison failed");
|
||||
if (q1 != q2) $fatal(0, "Queue comparison failed");
|
||||
if (aa1 != aa2) $fatal(0, "Associative array comparison failed");
|
||||
if (t1 != t2) $fatal(0, "Typedef unpacked array comparison failed");
|
||||
if (tq1 != tq2) $fatal(0, "Typedef queue comparison failed");
|
||||
if (aa_typedef1 != aa_typedef2)
|
||||
$fatal(0, "Typedef associative array comparison failed");
|
||||
if (b1 != i1) $fatal(0, "bit[31:0] vs int comparison failed");
|
||||
|
||||
$display("*-* All Finished *-*");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,68 @@
|
|||
%Error: t/t_lint_dtype_compare_bad.v:52:19: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[$]'
|
||||
: ... Right-hand data type: 'logic[31:0]'
|
||||
52 | if (queue_var == 1) begin end
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_lint_dtype_compare_bad.v:55:11: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'logic[31:0]'
|
||||
: ... Right-hand data type: 'int$[$]'
|
||||
55 | if (1 == queue_var) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:58:12: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[$]'
|
||||
: ... Right-hand data type: 'bit$[$]'
|
||||
58 | if (q1 == q2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:61:12: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[]'
|
||||
: ... Right-hand data type: 'bit$[]'
|
||||
61 | if (d1 == d2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:64:12: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[0:1]'
|
||||
: ... Right-hand data type: 'int$[0:1][0:0]'
|
||||
64 | if (u1 == u2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:67:12: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[0:1]'
|
||||
: ... Right-hand data type: 'int$[0:2]'
|
||||
67 | if (a1 == a2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:70:13: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[string]'
|
||||
: ... Right-hand data type: 'int$[int]'
|
||||
70 | if (aa1 == aa2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:73:13: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[string]'
|
||||
: ... Right-hand data type: 'logic[3:0]$[string]'
|
||||
73 | if (aa3 == aa4) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:76:14: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[0:1]'
|
||||
: ... Right-hand data type: 'bit$[0:1]'
|
||||
76 | if (bad1 == bad2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:79:14: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[string]'
|
||||
: ... Right-hand data type: 'logic[31:0]$[string]'
|
||||
79 | if (val1 == val2) begin end
|
||||
| ^~
|
||||
%Error: t/t_lint_dtype_compare_bad.v:82:13: Comparison requires matching data types
|
||||
: ... note: In instance 't'
|
||||
: ... Left-hand data type: 'int$[string]'
|
||||
: ... Right-hand data type: 'int$[int]'
|
||||
82 | if (aa5 == aa6) begin end
|
||||
| ^~
|
||||
%Error: Exiting due to
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,84 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// DESCRIPTION: Verilator: Invalid aggregate dtype comparisons
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Shou-Li Hsu.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
typedef int myint_t;
|
||||
typedef bit mybit_t;
|
||||
typedef string mystr_t;
|
||||
typedef int myval_t;
|
||||
typedef logic [31:0] mylogic_t;
|
||||
|
||||
initial begin
|
||||
int queue_var[$] = '{1, 2, 3};
|
||||
int q1[$] = '{1, 2};
|
||||
bit q2[$] = '{1'b1, 1'b0};
|
||||
|
||||
int d1[] = new[2];
|
||||
bit d2[] = new[2];
|
||||
|
||||
int u1[2] = '{1, 2};
|
||||
int u2[2][1] = '{{1}, {2}};
|
||||
|
||||
int a1[2] = '{1, 2};
|
||||
int a2[3] = '{1, 2, 3};
|
||||
|
||||
int aa1[string];
|
||||
int aa2[int];
|
||||
|
||||
int aa3[string];
|
||||
logic [3:0] aa4[string];
|
||||
|
||||
myint_t bad1[2] = '{1, 2};
|
||||
mybit_t bad2[2] = '{1, 0};
|
||||
|
||||
myval_t val1[mystr_t] = '{"foo": 123};
|
||||
mylogic_t val2[string] = '{"foo": 32'h12345678};
|
||||
|
||||
myint_t aa5[string];
|
||||
myint_t aa6[int];
|
||||
aa5["a"] = 1;
|
||||
aa6[1] = 1;
|
||||
|
||||
// queue vs scalar
|
||||
if (queue_var == 1) begin end
|
||||
|
||||
// scalar vs queue
|
||||
if (1 == queue_var) begin end
|
||||
|
||||
// queue with diff type
|
||||
if (q1 == q2) begin end
|
||||
|
||||
// dyn array with diff type
|
||||
if (d1 == d2) begin end
|
||||
|
||||
// unpacked diff dim
|
||||
if (u1 == u2) begin end
|
||||
|
||||
// unpacked diff size
|
||||
if (a1 == a2) begin end
|
||||
|
||||
// assoc array diff key type
|
||||
if (aa1 == aa2) begin end
|
||||
|
||||
// assoc array diff value type
|
||||
if (aa3 == aa4) begin end
|
||||
|
||||
// typedef mismatch in unpacked array
|
||||
if (bad1 == bad2) begin end
|
||||
|
||||
// typedef mismatch in assoc array value
|
||||
if (val1 == val2) begin end
|
||||
|
||||
// typedef mismatch in assoc array key
|
||||
if (aa5 == aa6) begin end
|
||||
end
|
||||
endmodule
|
|
@ -18,7 +18,7 @@ module t;
|
|||
initial begin
|
||||
begin // integers
|
||||
int q1[$];
|
||||
bit[31:0] q2[$];
|
||||
bit signed [31:0] q2[$];
|
||||
q1.push_back(1);
|
||||
q2.push_back(1);
|
||||
q1.push_back(-2);
|
||||
|
|
|
@ -3,8 +3,20 @@
|
|||
113 | if (unpacked_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Internal Error: t/t_stream_unpack_lhs.v:113:35: ../V3Width.cpp:#: Node has no type
|
||||
%Error-UNSUPPORTED: t/t_stream_unpack_lhs.v:114:38: Unsupported/Illegal: Assignment pattern member not underneath a supported construct: NEQ
|
||||
: ... note: In instance 't'
|
||||
114 | if (unpacked_asc_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_stream_unpack_lhs.v:115:38: Unsupported/Illegal: Assignment pattern member not underneath a supported construct: NEQ
|
||||
: ... note: In instance 't'
|
||||
115 | if (unpacked_des_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_stream_unpack_lhs.v:117:36: Unsupported/Illegal: Assignment pattern member not underneath a supported construct: NEQ
|
||||
: ... note: In instance 't'
|
||||
117 | if (packed_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
|
||||
| ^~
|
||||
%Error: Internal Error: t/t_stream_unpack_lhs.v:117:33: ../V3Width.cpp:#: Node has no type
|
||||
: ... note: In instance 't'
|
||||
113 | if (unpacked_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
|
||||
| ^~
|
||||
117 | if (packed_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
|
||||
| ^~
|
||||
... This fatal error may be caused by the earlier error(s); resolve those first.
|
||||
|
|
Loading…
Reference in New Issue