Compare commits
15 Commits
7e88f79837
...
fd59f49f52
| Author | SHA1 | Date |
|---|---|---|
|
|
fd59f49f52 | |
|
|
2ef979a39c | |
|
|
23ea3d7f11 | |
|
|
94e3f387a7 | |
|
|
cd30c22d1c | |
|
|
81f6cdc32c | |
|
|
23ca23b7b5 | |
|
|
f3c63d017a | |
|
|
ffd2c5c69e | |
|
|
93d7d9c417 | |
|
|
c20a6f4396 | |
|
|
419f3192c5 | |
|
|
e9f42fdfbd | |
|
|
fee71d420c | |
|
|
d4613ed1a4 |
|
|
@ -48,7 +48,7 @@ jobs:
|
|||
ls -lsha
|
||||
tree -L 3 pages
|
||||
- name: Upload pages artifact
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: pages
|
||||
|
||||
|
|
|
|||
12
Changes
12
Changes
|
|
@ -65,9 +65,11 @@ Verilator 5.047 devel
|
|||
* Improve assignment-compatibility type check (#2843) (#5666) (#7052). [Pawel Kojma, Antmicro Ltd.]
|
||||
* Improve error message when variable used as data type (#7318). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Improve E_UNSUPPORTED warning messages (#7329). [Eunseo Song]
|
||||
* Improve NFA-based multi-cycle SVA evaluation engine (#7430). [Yilou Wang]
|
||||
* Change array tracing to dump left index to right index (#7205). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Change `--converge-limit` default to 10000 (#7209).
|
||||
* Remove DFG extract optimization pass (#7394). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Remove multi-threaded FST tracing (#7443). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize trace code for faster compiles on repeated types (#6707) (#6832). [Todd Strader]
|
||||
* Optimize size of trace declaration object code (#7150). [Szymon Gizler, Antmicro Ltd.]
|
||||
* Optimize function call return value temporaries (#7152). [Geza Lore, Testorrent USA, Inc.]
|
||||
|
|
@ -80,11 +82,15 @@ Verilator 5.047 devel
|
|||
* Optimize more patterns in DfgPeephole (#7332). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize read references in DFG (#7354). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize DFG only once, after scoping (#7362). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize more DFG peephole patterns (#7423). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize more DFG peephole patterns (#7423) (#7452). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize DfgBreakCycles IndependentBits analysis ordering (#7446). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize select patterns in DfgPeephole. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize temporary insertion in DfgPeephole. [Geza Lore, Testorrent USA, Inc.]
|
||||
* Optimize arithmetic right shift (>>>) in DfgBreakCycles (#7447). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Fix recursive default assignment for sub-arrays (#4589) (#7202). [Julian Carrier]
|
||||
* Fix virtual interface member trigger convergence (#5116) (#7323). [Yilou Wang]
|
||||
* Fix shift width mismatch in constraint solver SMT emission (#5420) (#7265). [Yilou Wang]
|
||||
* Fix returning wrong type from static function in parameterized class (#5479) (#7387) (#7411) (#7418). [em2machine]
|
||||
* Fix returning wrong type from static function in parameterized class (#5479) (#7387) (#7411) (#7418) (#7445) (#7450). [em2machine]
|
||||
* Fix randomize size+element queue constraints (#5582) (#7225). [Rahul Behl, Testorrent USA, Inc.]
|
||||
* Fix null assignment to virtual interfaces (#5974) (#5990). [Maxim Fonarev]
|
||||
* Fix typedef scope resolution for parameterized class aliases (#5977) (#7319). [Nick Brereton]
|
||||
|
|
@ -151,8 +157,10 @@ Verilator 5.047 devel
|
|||
* Fix delete inside foreach skipping elements (#7407) (#7410)
|
||||
* Fix std::randomize in parameterized-derived class (#7409) (#7416). [Yilou Wang]
|
||||
* Fix virtual interface implied comparison with null (#7421). [Alex Solomatnikov]
|
||||
* Fix uvm_hdl_release_and_read to release value and check success (#7425). [Christian Hecken, Heidelberg University]
|
||||
* Fix inline constraint on array-indexed randomize target (#7431) (#7434). [Yilou Wang]
|
||||
* Fix modification of members of object with const handle (#7433). [Kamil Danecki, Antmicro Ltd.]
|
||||
* Fix `dist` under implication in constraints (#7440) (#7442). [Alex Solomatnikov] [Yilou Wang]
|
||||
|
||||
|
||||
Verilator 5.046 2026-02-28
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ Drew Ranck
|
|||
Drew Taussig
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Mejdrich
|
||||
Eric Müller
|
||||
Eric Rippey
|
||||
Eunseo Song
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ include directories and link to the SystemC libraries.
|
|||
|
||||
Deprecated and has no effect.
|
||||
|
||||
Before Verialtor 5.048: Optional. Enable multithreaded FST trace; see
|
||||
In versions before 5.048: Optional. Enable multithreaded FST trace; see
|
||||
:vlopt:`--trace-threads`.
|
||||
|
||||
.. describe:: TRACE_VCD
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ Muhlestein
|
|||
Multithreaded
|
||||
Multithreading
|
||||
Mykyta
|
||||
NFA
|
||||
NOUNOPTFLAT
|
||||
NaN
|
||||
Nalbantis
|
||||
|
|
@ -837,6 +838,7 @@ gotFinish
|
|||
goto
|
||||
gprof
|
||||
gtkwave
|
||||
hdl
|
||||
hdr
|
||||
hdzhangdoc
|
||||
hh
|
||||
|
|
@ -1211,6 +1213,7 @@ upcasting
|
|||
urandom
|
||||
uselib
|
||||
utimes
|
||||
uvm
|
||||
uwire
|
||||
uwires
|
||||
valgrind
|
||||
|
|
|
|||
|
|
@ -329,8 +329,12 @@ class DeadVisitor final : public VNVisitor {
|
|||
void visit(AstNodeFTask* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (!nodep->taskPublic() && !nodep->dpiExport() && !nodep->dpiImport())
|
||||
if (nodep->taskPublic() || nodep->dpiExport() || nodep->dpiImport()) {
|
||||
if (m_modp && !m_modp->dead() && !m_modp->verilatorLib())
|
||||
m_modp->user1Inc(); // Keep container
|
||||
} else {
|
||||
m_tasksp.push(nodep);
|
||||
}
|
||||
if (nodep->classOrPackagep()) {
|
||||
if (m_elimCells) {
|
||||
nodep->classOrPackagep(nullptr);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,8 @@ public:
|
|||
// Thanks to the interning, equality is identity
|
||||
bool operator==(const DfgDataType& that) const { return this == &that; }
|
||||
bool operator!=(const DfgDataType& that) const { return this != &that; }
|
||||
// Similarly for hash
|
||||
V3Hash hash() const { return V3Hash{this}; }
|
||||
|
||||
// Type of elements, for arrays only
|
||||
const DfgDataType& elemDtype() const {
|
||||
|
|
@ -132,13 +134,6 @@ public:
|
|||
return *m_elemDtypep;
|
||||
}
|
||||
|
||||
V3Hash hash() const {
|
||||
V3Hash hash{static_cast<uint32_t>(m_kind)};
|
||||
hash += m_size;
|
||||
if (m_elemDtypep) hash += m_elemDtypep->hash();
|
||||
return hash;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Static factory and management functions
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
size_t m_currentGeneration = 0; // Current generation number
|
||||
size_t m_lastId = 0; // Last unique vertex ID assigned
|
||||
size_t m_nTemps = 0; // Number of temporary variables created
|
||||
// Scope for transient temporariy variables cerated in this pass. They should all be
|
||||
// eliminated wihtin this pass, so anything should be ok, pick the top scope as easy to find.
|
||||
AstScope* const m_tmpScopep = v3Global.rootp()->topScopep()->scopep();
|
||||
|
||||
// STATIC STATE
|
||||
static V3DebugBisect s_debugBisect; // Debug aid
|
||||
|
|
@ -404,6 +407,12 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
return make<Vertex>(examplep->fileline(), examplep->dtype(), operands...);
|
||||
}
|
||||
|
||||
// Replicate 'bitp' to 'vtxp->width()' bits
|
||||
DfgVertex* replicate(DfgVertex* vtxp, DfgVertex* bitp) {
|
||||
if (vtxp->dtype() == m_bitDType) return bitp;
|
||||
return make<DfgReplicate>(vtxp, bitp, makeI32(vtxp->fileline(), vtxp->width()));
|
||||
}
|
||||
|
||||
// Check two vertex are the same, or the same constant value
|
||||
static bool isSame(const DfgVertex* ap, const DfgVertex* bp) {
|
||||
if (ap == bp) return true;
|
||||
|
|
@ -561,15 +570,25 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Attempt to reuse associative binary expressions if hey already exist, e.g.:
|
||||
// '(a OP (b OP c))' -> '(a OP b) OP c', iff '(a OP b)' already exists, or
|
||||
// '(a OP c) OP b' iff '(a OP c)' already exists and the vertex is commutative.
|
||||
// Only do this is 'b OP c' has a single use and can subsequently be removed,
|
||||
// otherwise there is no improvement.
|
||||
if (rSamep && !rSamep->hasMultipleSinks()) {
|
||||
DfgVertex* const rlVtxp = rSamep->lhsp();
|
||||
DfgVertex* const rrVtxp = rSamep->rhsp();
|
||||
|
||||
if VL_CONSTEXPR_CXX17 (IsCommutative<Vertex>::value) {
|
||||
if (!lhsp->hasMultipleSinks() && rlVtxp->hasMultipleSinks()) {
|
||||
APPLYING(ROTATE_ASSOC_COMM_MULTIUSE) {
|
||||
replace(make<Vertex>(vtxp, rlVtxp, make<Vertex>(vtxp, lhsp, rrVtxp)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to reuse associative binary expressions if hey already exist, e.g.:
|
||||
// '(a OP (b OP c))' -> '(a OP b) OP c', iff '(a OP b)' already exists, or
|
||||
// '(a OP c) OP b' iff '(a OP c)' already exists and the vertex is commutative.
|
||||
// Only do this if 'b OP c' has a single use and can subsequently be removed,
|
||||
// otherwise there is no improvement.
|
||||
|
||||
// '(a OP (b OP c))' -> '(a OP b) OP c'
|
||||
if (Vertex* const existingp
|
||||
= m_cache.get<Vertex>(resultDType<Vertex>(lhsp, rlVtxp), lhsp, rlVtxp)) {
|
||||
|
|
@ -700,10 +719,10 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
tryPushBitwiseOpThroughConcat(Vertex* const vtxp, DfgConst* constp, DfgConcat* concatp) {
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
|
||||
// If at least one of the sides of the Concat constant, or width 1 (i.e.: can be
|
||||
// further simplified), then push the Vertex past the Concat
|
||||
if (concatp->lhsp()->is<DfgConst>() || concatp->rhsp()->is<DfgConst>() //
|
||||
|| concatp->lhsp()->dtype() == m_bitDType || concatp->rhsp()->dtype() == m_bitDType) {
|
||||
// If at least one of the sides of the Concat constant, then push Vertex past Concat
|
||||
DfgConst* const catLConstp = concatp->lhsp()->cast<DfgConst>();
|
||||
DfgConst* const catRConstp = concatp->rhsp()->cast<DfgConst>();
|
||||
if (catLConstp || catRConstp) {
|
||||
APPLYING(PUSH_BITWISE_OP_THROUGH_CONCAT) {
|
||||
const uint32_t width = concatp->width();
|
||||
const DfgDataType& lDtype = concatp->lhsp()->dtype();
|
||||
|
|
@ -712,14 +731,30 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
const uint32_t rWidth = rDtype.size();
|
||||
|
||||
// The new Lhs vertex
|
||||
DfgConst* const newLhsConstp = makeZero(constp->fileline(), lWidth);
|
||||
newLhsConstp->num().opSel(constp->num(), width - 1, rWidth);
|
||||
Vertex* const newLhsp = make<Vertex>(flp, lDtype, newLhsConstp, concatp->lhsp());
|
||||
DfgVertex* const newLhsp = [&]() -> DfgVertex* {
|
||||
DfgConst* const newLhsConstp = makeZero(constp->fileline(), lWidth);
|
||||
if (catLConstp) {
|
||||
V3Number num{constp->fileline(), static_cast<int>(lWidth), 0u};
|
||||
num.opSel(constp->num(), width - 1, rWidth);
|
||||
foldOp<Vertex>(newLhsConstp->num(), num, catLConstp->num());
|
||||
return newLhsConstp;
|
||||
}
|
||||
newLhsConstp->num().opSel(constp->num(), width - 1, rWidth);
|
||||
return make<Vertex>(flp, lDtype, newLhsConstp, concatp->lhsp());
|
||||
}();
|
||||
|
||||
// The new Rhs vertex
|
||||
DfgConst* const newRhsConstp = makeZero(constp->fileline(), rWidth);
|
||||
newRhsConstp->num().opSel(constp->num(), rWidth - 1, 0);
|
||||
Vertex* const newRhsp = make<Vertex>(flp, rDtype, newRhsConstp, concatp->rhsp());
|
||||
DfgVertex* const newRhsp = [&]() -> DfgVertex* {
|
||||
DfgConst* const newRhsConstp = makeZero(constp->fileline(), rWidth);
|
||||
if (catRConstp) {
|
||||
V3Number num{constp->fileline(), static_cast<int>(rWidth), 0u};
|
||||
num.opSel(constp->num(), rWidth - 1, 0);
|
||||
foldOp<Vertex>(newRhsConstp->num(), num, catRConstp->num());
|
||||
return newRhsConstp;
|
||||
}
|
||||
newRhsConstp->num().opSel(constp->num(), rWidth - 1, 0);
|
||||
return make<Vertex>(flp, rDtype, newRhsConstp, concatp->rhsp());
|
||||
}();
|
||||
|
||||
// Replace this vertex
|
||||
replace(make<DfgConcat>(concatp, newLhsp, newRhsp));
|
||||
|
|
@ -794,6 +829,46 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
return false;
|
||||
}
|
||||
|
||||
template <typename Bitwise>
|
||||
VL_ATTR_WARN_UNUSED_RESULT bool tryPushBitwiseOpThrougSel(Bitwise* const vtxp) {
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
|
||||
if (DfgSel* const lSelp = lhsp->cast<DfgSel>()) {
|
||||
DfgSel* rSelp = nullptr;
|
||||
DfgVertex* extrap = nullptr;
|
||||
if (DfgSel* const selp = rhsp->cast<DfgSel>()) {
|
||||
rSelp = selp;
|
||||
} else if (Bitwise* const bitwisep = rhsp->cast<Bitwise>()) {
|
||||
if (DfgSel* const rlSelp = bitwisep->lhsp()->template cast<DfgSel>()) {
|
||||
rSelp = rlSelp;
|
||||
extrap = bitwisep->rhsp();
|
||||
} else if (DfgSel* const rrSelp = bitwisep->rhsp()->template cast<DfgSel>()) {
|
||||
rSelp = rrSelp;
|
||||
extrap = bitwisep->lhsp();
|
||||
}
|
||||
}
|
||||
if (rSelp) {
|
||||
DfgVertex* const lFromp = lSelp->fromp();
|
||||
DfgVertex* const rFromp = rSelp->fromp();
|
||||
if (lFromp->dtype() == rFromp->dtype() && lFromp->width() <= VL_QUADSIZE //
|
||||
&& lSelp->lsb() == rSelp->lsb()) {
|
||||
APPLYING(PUSH_BITWISE_THROUGH_SEL) {
|
||||
Bitwise* const bwp
|
||||
= make<Bitwise>(vtxp->fileline(), lSelp->fromp()->dtype(),
|
||||
lSelp->fromp(), rSelp->fromp());
|
||||
DfgVertex* resp = make<DfgSel>(vtxp, bwp, lSelp->lsb());
|
||||
if (extrap) resp = make<Bitwise>(vtxp, resp, extrap);
|
||||
replace(resp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Bitwise>
|
||||
VL_ATTR_WARN_UNUSED_RESULT bool tryReplaceBitwiseWithReduction(Bitwise* vtxp) {
|
||||
UASSERT_OBJ(vtxp->width() == 1, vtxp, "Width must be 1");
|
||||
|
|
@ -803,13 +878,15 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
|
||||
if (DfgSel* const lSelp = lhsp->template cast<DfgSel>()) {
|
||||
DfgSel* rSelp = rhsp->template cast<DfgSel>();
|
||||
DfgSel* rSelp = nullptr;
|
||||
DfgVertex* extrap = nullptr;
|
||||
if (!rSelp) {
|
||||
if (Bitwise* const rBitwisep = rhsp->template cast<Bitwise>()) {
|
||||
rSelp = rBitwisep->lhsp()->template cast<DfgSel>();
|
||||
extrap = rBitwisep->rhsp();
|
||||
}
|
||||
if (DfgSel* const selp = rhsp->template cast<DfgSel>()) {
|
||||
rSelp = selp;
|
||||
} else if (Bitwise* const rBitwisep = rhsp->template cast<Bitwise>()) {
|
||||
rSelp = rBitwisep->lhsp()->template cast<DfgSel>();
|
||||
extrap = rBitwisep->rhsp();
|
||||
} else if (Reduction* const rRedp = rhsp->template cast<Reduction>()) {
|
||||
rSelp = rRedp->srcp()->template cast<DfgSel>();
|
||||
}
|
||||
if (rSelp) {
|
||||
uint32_t lsb = 0;
|
||||
|
|
@ -1021,6 +1098,94 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
return {nullptr, 0, 0};
|
||||
}
|
||||
|
||||
// The following patterns all unwind a Sel throgh it's source and replace it with
|
||||
// another single Sel. Doing this one at a time can take a long time with nested
|
||||
// concatenations/selects/etc, so instead unwind as much as possible in one go.
|
||||
std::pair<DfgVertex*, uint32_t> unwindSel(DfgVertex* fromp, uint32_t lsb,
|
||||
const uint32_t width) {
|
||||
while (true) {
|
||||
const uint32_t msb = lsb + width - 1;
|
||||
|
||||
// Sel from Concat
|
||||
if (DfgConcat* const concatp = fromp->cast<DfgConcat>()) {
|
||||
DfgVertex* const lhsp = concatp->lhsp();
|
||||
DfgVertex* const rhsp = concatp->rhsp();
|
||||
|
||||
if (msb < rhsp->width()) {
|
||||
// If the select is entirely from rhs, then replace with sel from rhs
|
||||
APPLYING(REMOVE_SEL_FROM_RHS_OF_CONCAT) {
|
||||
fromp = rhsp;
|
||||
continue;
|
||||
}
|
||||
} else if (lsb >= rhsp->width()) {
|
||||
// If the select is entirely from the lhs, then replace with sel from lhs
|
||||
APPLYING(REMOVE_SEL_FROM_LHS_OF_CONCAT) {
|
||||
fromp = lhsp;
|
||||
lsb -= rhsp->width();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DfgReplicate* const repp = fromp->cast<DfgReplicate>()) {
|
||||
// If the Sel is wholly into the source of the Replicate, push the Sel through
|
||||
// the Replicate and apply it directly to the source of the Replicate.
|
||||
const uint32_t srcWidth = repp->srcp()->width();
|
||||
if (width <= srcWidth) {
|
||||
const uint32_t newLsb = lsb % srcWidth;
|
||||
const uint32_t newMsb = newLsb + width - 1;
|
||||
if (newMsb < srcWidth) {
|
||||
APPLYING(PUSH_SEL_THROUGH_REPLICATE) {
|
||||
fromp = repp->srcp();
|
||||
lsb = newLsb;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sel from Sel
|
||||
if (DfgSel* const selp = fromp->cast<DfgSel>()) {
|
||||
APPLYING(REPLACE_SEL_FROM_SEL) {
|
||||
// Select from the source of the source Sel with adjusted LSB
|
||||
fromp = selp->fromp();
|
||||
lsb += selp->lsb();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Sel from a partial variable (including narrowed vertex)
|
||||
if (DfgVarPacked* const varp = fromp->cast<DfgVarPacked>()) {
|
||||
if (varp->srcp() && !varp->isVolatile()) {
|
||||
// Must be a splice, otherwise it would have been inlined
|
||||
DfgSplicePacked* splicep = varp->srcp()->as<DfgSplicePacked>();
|
||||
DfgVertex* driverp = nullptr;
|
||||
uint32_t driverLsb = 0;
|
||||
splicep->foreachDriver([&](DfgVertex& src, const uint32_t dLsb) {
|
||||
const uint32_t dMsb = dLsb + src.width() - 1;
|
||||
// If it does not cover the whole searched bit range, move on
|
||||
if (lsb < dLsb || dMsb < msb) return false;
|
||||
// Save the driver
|
||||
driverp = &src;
|
||||
driverLsb = dLsb;
|
||||
return true;
|
||||
});
|
||||
if (driverp) {
|
||||
APPLYING(PUSH_SEL_THROUGH_SPLICE) {
|
||||
fromp = driverp;
|
||||
lsb -= driverLsb;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No patterns matched, stop
|
||||
break;
|
||||
}
|
||||
return {fromp, lsb};
|
||||
}
|
||||
|
||||
// VISIT methods
|
||||
|
||||
void visit(DfgVertex*) override {}
|
||||
|
|
@ -1148,38 +1313,12 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Sel from Concat
|
||||
if (DfgConcat* const concatp = fromp->cast<DfgConcat>()) {
|
||||
DfgVertex* const lhsp = concatp->lhsp();
|
||||
DfgVertex* const rhsp = concatp->rhsp();
|
||||
|
||||
if (msb < rhsp->width()) {
|
||||
// If the select is entirely from rhs, then replace with sel from rhs
|
||||
APPLYING(REMOVE_SEL_FROM_RHS_OF_CONCAT) { //
|
||||
replace(make<DfgSel>(vtxp, rhsp, vtxp->lsb()));
|
||||
return;
|
||||
}
|
||||
} else if (lsb >= rhsp->width()) {
|
||||
// If the select is entirely from the lhs, then replace with sel from lhs
|
||||
APPLYING(REMOVE_SEL_FROM_LHS_OF_CONCAT) {
|
||||
replace(make<DfgSel>(vtxp, lhsp, lsb - rhsp->width()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DfgReplicate* const repp = fromp->cast<DfgReplicate>()) {
|
||||
// If the Sel is wholly into the source of the Replicate, push the Sel through the
|
||||
// Replicate and apply it directly to the source of the Replicate.
|
||||
const uint32_t srcWidth = repp->srcp()->width();
|
||||
if (width <= srcWidth) {
|
||||
const uint32_t newLsb = lsb % srcWidth;
|
||||
if (newLsb + width <= srcWidth) {
|
||||
APPLYING(PUSH_SEL_THROUGH_REPLICATE) {
|
||||
replace(make<DfgSel>(vtxp, repp->srcp(), newLsb));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Unwind through bit packing in one go
|
||||
{
|
||||
const auto res = unwindSel(fromp, lsb, width);
|
||||
if (res.first != fromp || res.second != lsb) {
|
||||
replace(make<DfgSel>(vtxp, res.first, res.second));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1197,15 +1336,6 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Sel from Sel
|
||||
if (DfgSel* const selp = fromp->cast<DfgSel>()) {
|
||||
APPLYING(REPLACE_SEL_FROM_SEL) {
|
||||
// Select from the source of the source Sel with adjusted LSB
|
||||
replace(make<DfgSel>(vtxp, selp->fromp(), lsb + selp->lsb()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sel from Cond
|
||||
if (DfgCond* const condp = fromp->cast<DfgCond>()) {
|
||||
if (!condp->hasMultipleSinks()) {
|
||||
|
|
@ -1239,31 +1369,6 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sel from a partial variable (including narrowed vertex)
|
||||
if (DfgVarPacked* const varp = fromp->cast<DfgVarPacked>()) {
|
||||
if (varp->srcp() && !varp->isVolatile()) {
|
||||
// Must be a splice, otherwise it would have been inlined
|
||||
DfgSplicePacked* splicep = varp->srcp()->as<DfgSplicePacked>();
|
||||
DfgVertex* driverp = nullptr;
|
||||
uint32_t driverLsb = 0;
|
||||
splicep->foreachDriver([&](DfgVertex& src, const uint32_t dLsb) {
|
||||
const uint32_t dMsb = dLsb + src.width() - 1;
|
||||
// If it does not cover the whole searched bit range, move on
|
||||
if (lsb < dLsb || dMsb < msb) return false;
|
||||
// Save the driver
|
||||
driverp = &src;
|
||||
driverLsb = dLsb;
|
||||
return true;
|
||||
});
|
||||
if (driverp) {
|
||||
APPLYING(PUSH_SEL_THROUGH_SPLICE) {
|
||||
replace(make<DfgSel>(vtxp, driverp, lsb - driverLsb));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(DfgMux* const vtxp) override {
|
||||
|
|
@ -1349,18 +1454,27 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
if (tryPushBitwiseOpThroughReductions(vtxp)) return;
|
||||
|
||||
if (DfgNot* const lhsNotp = lhsp->cast<DfgNot>()) {
|
||||
if (tryPushBitwiseOpThrougSel(vtxp)) return;
|
||||
|
||||
{
|
||||
DfgNot* const lNotp = lhsp->cast<DfgNot>();
|
||||
DfgNot* const rNotp = rhsp->cast<DfgNot>();
|
||||
// ~A & A is all zeroes
|
||||
if (lhsNotp->srcp() == rhsp) {
|
||||
if ((lNotp && isSame(lNotp->srcp(), rhsp)) || (rNotp && isSame(lhsp, rNotp->srcp()))) {
|
||||
APPLYING(REPLACE_CONTRADICTORY_AND) {
|
||||
replace(makeZero(flp, vtxp->width()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ~A & (A & _) or ~A & (_ & A) is all zeroes
|
||||
if (DfgAnd* const rhsAndp = rhsp->cast<DfgAnd>()) {
|
||||
if (lhsNotp->srcp() == rhsAndp->lhsp() || lhsNotp->srcp() == rhsAndp->rhsp()) {
|
||||
if (DfgAnd* const rSamep = rhsp->cast<DfgAnd>()) {
|
||||
DfgNot* const rlNotp = rSamep->lhsp()->cast<DfgNot>();
|
||||
DfgNot* const rrNotp = rSamep->rhsp()->cast<DfgNot>();
|
||||
// ~A & (A & _) or ~A & (_ & A) is all zeroes
|
||||
if ((lNotp && isSame(lNotp->srcp(), rSamep->lhsp()))
|
||||
|| (lNotp && isSame(lNotp->srcp(), rSamep->rhsp()))
|
||||
|| (rlNotp && isSame(lhsp, rlNotp->srcp()))
|
||||
|| (rrNotp && isSame(lhsp, rrNotp->srcp()))) {
|
||||
APPLYING(REPLACE_CONTRADICTORY_AND_3) {
|
||||
replace(makeZero(flp, vtxp->width()));
|
||||
return;
|
||||
|
|
@ -1463,24 +1577,29 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
if (tryPushBitwiseOpThroughReductions(vtxp)) return;
|
||||
|
||||
if (DfgNot* const lhsNotp = lhsp->cast<DfgNot>()) {
|
||||
if (tryPushBitwiseOpThrougSel(vtxp)) return;
|
||||
|
||||
{
|
||||
DfgNot* const lNotp = lhsp->cast<DfgNot>();
|
||||
DfgNot* const rNotp = rhsp->cast<DfgNot>();
|
||||
// ~A | A is all ones
|
||||
if (lhsNotp->srcp() == rhsp) {
|
||||
if ((lNotp && isSame(lNotp->srcp(), rhsp)) || (rNotp && isSame(lhsp, rNotp->srcp()))) {
|
||||
APPLYING(REPLACE_TAUTOLOGICAL_OR) {
|
||||
DfgConst* const resp = makeZero(flp, vtxp->width());
|
||||
resp->num().setAllBits1();
|
||||
replace(resp);
|
||||
replace(makeOnes(flp, vtxp->width()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ~A | (A | _) or ~A | (_ | A) is all ones
|
||||
if (DfgOr* const rhsOrp = rhsp->cast<DfgOr>()) {
|
||||
if (lhsNotp->srcp() == rhsOrp->lhsp() || lhsNotp->srcp() == rhsOrp->rhsp()) {
|
||||
if (DfgOr* const rSamep = rhsp->cast<DfgOr>()) {
|
||||
DfgNot* const rlNotp = rSamep->lhsp()->cast<DfgNot>();
|
||||
DfgNot* const rrNotp = rSamep->rhsp()->cast<DfgNot>();
|
||||
// ~A | (A | _) or ~A | (_ | A) is all ones
|
||||
if ((lNotp && isSame(lNotp->srcp(), rSamep->lhsp()))
|
||||
|| (lNotp && isSame(lNotp->srcp(), rSamep->rhsp()))
|
||||
|| (rlNotp && isSame(lhsp, rlNotp->srcp()))
|
||||
|| (rrNotp && isSame(lhsp, rrNotp->srcp()))) {
|
||||
APPLYING(REPLACE_TAUTOLOGICAL_OR_3) {
|
||||
DfgConst* const resp = makeZero(flp, vtxp->width());
|
||||
resp->num().setAllBits1();
|
||||
replace(resp);
|
||||
replace(makeOnes(flp, vtxp->width()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1525,6 +1644,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
if (tryPushBitwiseOpThroughReductions(vtxp)) return;
|
||||
|
||||
if (tryPushBitwiseOpThrougSel(vtxp)) return;
|
||||
|
||||
if (vtxp->dtype() == m_bitDType) {
|
||||
if (tryReplaceBitwiseWithReduction(vtxp)) return;
|
||||
}
|
||||
|
|
@ -1847,10 +1968,9 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
DfgSplicePacked* const sp = new DfgSplicePacked{m_dfg, flp, vtxp->dtype()};
|
||||
m_vInfo[sp].m_id = ++m_lastId;
|
||||
sp->addDriver(catp, lsb, flp);
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
AstScope* const scopep = vtxp->scopep(scopeCache, true);
|
||||
const std::string name = m_dfg.makeUniqueName("PeepholeNarrow", m_nTemps++);
|
||||
DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep);
|
||||
DfgVertexVar* const varp
|
||||
= m_dfg.makeNewVar(flp, name, vtxp->dtype(), m_tmpScopep);
|
||||
varp->tmpForp(varp->vscp());
|
||||
m_vInfo[varp].m_id = ++m_lastId;
|
||||
varp->vscp()->varp()->isInternal(true);
|
||||
|
|
@ -2511,53 +2631,63 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
if (vtxp->dtype() == m_bitDType) {
|
||||
if (isZero(thenp)) { // a ? 0 : b becomes ~a & b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) {
|
||||
replace(make<DfgAnd>(vtxp, make<DfgNot>(vtxp, condp), elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (thenp == condp) { // a ? a : b becomes a | b
|
||||
if (isSame(condp, thenp)) { // a ? a : b becomes a | b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_COND) {
|
||||
replace(make<DfgOr>(vtxp, condp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (elsep == condp) { // a ? b : a becomes a & b
|
||||
if (isSame(condp, elsep)) { // a ? b : a becomes a & b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_COND) {
|
||||
replace(make<DfgAnd>(vtxp, condp, thenp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vtxp->width() <= VL_QUADSIZE) {
|
||||
if (isZero(thenp)) { // a ? 0 : b becomes ~a & b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) {
|
||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||
replace(make<DfgAnd>(vtxp, maskp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isOnes(thenp)) { // a ? 1 : b becomes a | b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ONES) {
|
||||
replace(make<DfgOr>(vtxp, condp, elsep));
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
replace(make<DfgOr>(vtxp, maskp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isZero(elsep)) { // a ? b : 0 becomes a & b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ZERO) {
|
||||
replace(make<DfgAnd>(vtxp, condp, thenp));
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
replace(make<DfgAnd>(vtxp, maskp, thenp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isOnes(elsep)) { // a ? b : 1 becomes ~a | b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ONES) {
|
||||
replace(make<DfgOr>(vtxp, make<DfgNot>(vtxp, condp), thenp));
|
||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||
replace(make<DfgOr>(vtxp, maskp, thenp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (DfgOr* const tOrp = thenp->cast<DfgOr>()) {
|
||||
if (isSame(tOrp->lhsp(), elsep)) { // a ? b | c : b becomes b | (a & c)
|
||||
APPLYING(REPLACE_COND_THEN_OR_LHS) {
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, condp, tOrp->rhsp());
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->rhsp());
|
||||
replace(make<DfgOr>(vtxp, tOrp->lhsp(), andp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isSame(tOrp->rhsp(), elsep)) { // a ? b | c : c becomes c | (a & b)
|
||||
APPLYING(REPLACE_COND_THEN_OR_RHS) {
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, condp, tOrp->lhsp());
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->lhsp());
|
||||
replace(make<DfgOr>(vtxp, tOrp->rhsp(), andp));
|
||||
return;
|
||||
}
|
||||
|
|
@ -2590,6 +2720,33 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tConcatp->hasMultipleSinks()) {
|
||||
if (DfgConcat* const tRCatp = tConcatp->rhsp()->cast<DfgConcat>()) {
|
||||
if (!tRCatp->hasMultipleSinks()) {
|
||||
if (DfgSel* const tLSelp = tConcatp->lhsp()->cast<DfgSel>()) {
|
||||
if (DfgSel* const tRRSelp = tRCatp->rhsp()->cast<DfgSel>()) {
|
||||
if (tLSelp->lsb() == tRCatp->width() //
|
||||
&& tRRSelp->lsb() == 0 //
|
||||
&& isSame(tLSelp->fromp(), elsep) //
|
||||
&& isSame(tRRSelp->fromp(), elsep)) {
|
||||
APPLYING(REPLACE_COND_INSERT) {
|
||||
DfgVertex* const newTp = tRCatp->lhsp();
|
||||
DfgVertex* const newEp = make<DfgSel>(
|
||||
flp, newTp->dtype(), elsep, tRRSelp->width());
|
||||
DfgCond* const newCp = make<DfgCond>(flp, newTp->dtype(),
|
||||
condp, newTp, newEp);
|
||||
replace(make<DfgConcat>(
|
||||
vtxp, tLSelp,
|
||||
make<DfgConcat>(tRCatp, newCp, tRRSelp)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isEqOne(thenp) && isZero(elsep)) {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PULL_NOTS_THROUGH_COND) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_BITWISE_OP_THROUGH_CONCAT) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_BITWISE_THROUGH_REDUCTION) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_BITWISE_THROUGH_SEL) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_COMMUTATIVE_BINARY_THROUGH_COND) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_COMPARE_OP_THROUGH_CONCAT) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_CONCAT_THROUGH_COND_LHS) \
|
||||
|
|
@ -110,6 +111,7 @@
|
|||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_CONST_ZERO_ONES) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_DEC) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_INC) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_INSERT) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_OR_THEN_COND_LHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_OR_THEN_COND_RHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_SAME_CAT_LHS) \
|
||||
|
|
@ -160,6 +162,7 @@
|
|||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REUSE_ASSOC_BINARY_LHS_WITH_LHS_OF_RHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REUSE_ASSOC_BINARY_LHS_WITH_RHS_OF_RHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, RIGHT_LEANING_ASSOC) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, ROTATE_ASSOC_COMM_MULTIUSE) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NEQ_CONDITION) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NOT_CONDITION) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_SIDES_IN_BINARY)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
// Changes user() and weight()
|
||||
|
||||
class GraphRemoveRedundant final : GraphAlg<> {
|
||||
const bool m_sumWeights; ///< Sum, rather then maximize weights
|
||||
const bool m_sumWeights; // Sum, rather then maximize weights
|
||||
private:
|
||||
void main() {
|
||||
for (V3GraphVertex& vertex : m_graphp->vertices()) vertexIterate(&vertex);
|
||||
|
|
|
|||
|
|
@ -2295,7 +2295,10 @@ void V3Options::setDebugMode(int level) {
|
|||
if (!m_dumpLevel.count("tree")) m_dumpLevel["tree"] = 3; // Don't override if already set.
|
||||
m_stats = true;
|
||||
m_debugCheck = true;
|
||||
if (level) cout << "Starting " << version() << "\n";
|
||||
if (level) {
|
||||
cout << "- Starting " << version() << "\n";
|
||||
UINFO(1, "Current working directory (CWD) is " << V3Os::cwd());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned V3Options::debugLevel(const string& tag) const VL_MT_SAFE {
|
||||
|
|
|
|||
|
|
@ -1406,13 +1406,16 @@ class ParamProcessor final {
|
|||
}
|
||||
cloneVarp->valuep(exprp->cloneTree(false));
|
||||
if (AstNodeDType* const origDTypep = modvarp->subDTypep()) {
|
||||
AstNodeDType* const dtypeClonep = origDTypep->cloneTree(false);
|
||||
// Inline every param ref so widthing doesn't reach back into the template
|
||||
// (#7411). Cycle detector for dependent parameters in the same module.
|
||||
// Attach clone under cloneVarp so the root has a back pointer.
|
||||
if (cloneVarp->childDTypep())
|
||||
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
|
||||
cloneVarp->childDTypep(origDTypep->cloneTree(false));
|
||||
cloneVarp->dtypep(nullptr);
|
||||
// Inline param refs so widthing doesn't touch the template (#7411).
|
||||
constexpr int maxSubstIters = 1000;
|
||||
for (int it = 0; it < maxSubstIters; ++it) {
|
||||
bool any = false;
|
||||
dtypeClonep->foreach([&](AstVarRef* varrefp) {
|
||||
cloneVarp->foreach([&](AstVarRef* varrefp) {
|
||||
AstVar* const targetp = varrefp->varp();
|
||||
AstNode* replacep = nullptr;
|
||||
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
|
||||
|
|
@ -1432,19 +1435,40 @@ class ParamProcessor final {
|
|||
any = true;
|
||||
}
|
||||
});
|
||||
// Substitute RefDType to an overridden paramtype. RefDType is
|
||||
// not a foreach leaf, so collect matches and replace after the
|
||||
// walk. Reverse order so descendants are replaced before
|
||||
// ancestors -- replacing an ancestor would free its descendants.
|
||||
std::vector<std::pair<AstRefDType*, AstNodeDType*>> toReplace;
|
||||
cloneVarp->foreach([&](AstRefDType* refp) {
|
||||
AstParamTypeDType* const ptdp
|
||||
= VN_CAST(refp->refDTypep(), ParamTypeDType);
|
||||
if (!ptdp) return;
|
||||
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
|
||||
if (pp->modPTypep() == ptdp) {
|
||||
if (AstNodeDType* const overDtp
|
||||
= VN_CAST(pp->exprp(), NodeDType)) {
|
||||
toReplace.emplace_back(refp, overDtp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (auto it = toReplace.rbegin(); it != toReplace.rend(); ++it) {
|
||||
AstRefDType* const refp = it->first;
|
||||
refp->replaceWith(it->second->cloneTree(false));
|
||||
VL_DO_DANGLING(refp->deleteTree(), refp);
|
||||
any = true;
|
||||
}
|
||||
if (!any) break;
|
||||
}
|
||||
// Bail if anything still points at the template.
|
||||
dtypeClonep->foreach([&](AstVarRef* varrefp) {
|
||||
cloneVarp->foreach([&](AstVarRef* varrefp) {
|
||||
varrefp->v3fatalSrc(
|
||||
"Unresolved VarRef '"
|
||||
<< varrefp->prettyName() << "' in pin dtype clone. Pin: "
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
});
|
||||
if (cloneVarp->childDTypep())
|
||||
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
|
||||
cloneVarp->childDTypep(dtypeClonep);
|
||||
cloneVarp->dtypep(nullptr);
|
||||
}
|
||||
V3Const::constifyParamsEdit(cloneVarp);
|
||||
if (AstConst* const widthedp = VN_CAST(cloneVarp->valuep(), Const)) {
|
||||
|
|
|
|||
|
|
@ -5517,8 +5517,6 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
if (patp) {
|
||||
// Don't want the RHS an array
|
||||
allConstant &= VN_IS(patp->lhssp(), Const);
|
||||
patp->dtypep(arrayDtp->subDTypep());
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
||||
|
|
@ -5527,7 +5525,50 @@ class WidthVisitor final : public VNVisitor {
|
|||
= new AstInitArray{nodep->fileline(), arrayDtp, nullptr};
|
||||
newp = newap;
|
||||
}
|
||||
VN_AS(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep);
|
||||
// If valuep is a reference to an array constant (or a
|
||||
// slice of one), flatten its elements into the target
|
||||
// array. Width resolution has already run (including
|
||||
// early resolution in patVectorMap), so slices appear
|
||||
// as AstSliceSel.
|
||||
const AstInitArray* subInitp = nullptr;
|
||||
int flattenLo = 0;
|
||||
int flattenElements = 0;
|
||||
if (const auto* vrp = VN_CAST(valuep, NodeVarRef)) {
|
||||
subInitp = VN_CAST(vrp->varp()->valuep(), InitArray);
|
||||
if (subInitp) {
|
||||
if (const auto* adtp
|
||||
= VN_CAST(vrp->varp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
flattenElements = adtp->declRange().elements();
|
||||
}
|
||||
}
|
||||
} else if (const auto* slicep = VN_CAST(valuep, SliceSel)) {
|
||||
if (const auto* vrp = VN_CAST(slicep->fromp(), NodeVarRef)) {
|
||||
subInitp = VN_CAST(vrp->varp()->valuep(), InitArray);
|
||||
if (subInitp) {
|
||||
flattenLo = slicep->declRange().lo();
|
||||
flattenElements = slicep->declRange().elements();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subInitp && flattenElements > 0) {
|
||||
// Sub-array values are always constant
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
for (int sn = 0; sn < flattenElements; ++sn) {
|
||||
UASSERT_OBJ(entn < range.elements(), nodep,
|
||||
"Flattened sub-array overflows target array");
|
||||
VN_AS(newp, InitArray)
|
||||
->addIndexValuep(ent - range.lo(),
|
||||
subInitp->getIndexDefaultedValuep(flattenLo + sn)
|
||||
->cloneTree(false));
|
||||
if (sn < flattenElements - 1) {
|
||||
++entn;
|
||||
ent += range.leftToRightInc();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allConstant &= VN_IS(valuep, Const);
|
||||
VN_AS(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep);
|
||||
}
|
||||
} else { // Packed. Convert to concat for now.
|
||||
if (!newp) {
|
||||
newp = valuep;
|
||||
|
|
@ -9549,7 +9590,29 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (!newEntry) {
|
||||
patp->v3error("Assignment pattern key used multiple times: " << element);
|
||||
}
|
||||
element += range.leftToRightInc();
|
||||
// For positional members that reference an array (or a slice
|
||||
// of one), advance by that array/slice's element count so
|
||||
// subsequent members are mapped correctly. Width-resolve the
|
||||
// value expression so its dtype is set
|
||||
int elementAdvance = 1;
|
||||
if (!patp->keyp()
|
||||
&& (VN_IS(patp->lhssp(), NodeVarRef) || VN_IS(patp->lhssp(), SelExtract))) {
|
||||
userIterateAndNext(patp->lhssp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
AstNodeExpr* const exprp = patp->lhssp();
|
||||
if (const AstNodeDType* const dtypep = exprp->dtypep()) {
|
||||
if (const auto* adtp = VN_CAST(dtypep->skipRefp(), UnpackArrayDType)) {
|
||||
// Only flatten constant arrays backed by InitArray
|
||||
const AstNodeVarRef* vrp = VN_CAST(exprp, NodeVarRef);
|
||||
if (!vrp) {
|
||||
if (const auto* slicep = VN_CAST(exprp, SliceSel))
|
||||
vrp = VN_CAST(slicep->fromp(), NodeVarRef);
|
||||
}
|
||||
if (vrp && VN_IS(vrp->varp()->valuep(), InitArray))
|
||||
elementAdvance = adtp->declRange().elements();
|
||||
}
|
||||
}
|
||||
}
|
||||
element += range.leftToRightInc() * elementAdvance;
|
||||
}
|
||||
return patmap;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# 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,159 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Greg Davill
|
||||
// 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);
|
||||
|
||||
package arr_pkg;
|
||||
localparam logic [31:0] PKG_ADDRS[3] = '{32'hAA001000, 32'hAA002000, 32'hAA003000};
|
||||
endpackage
|
||||
|
||||
module t ( /*AUTOARG*/);
|
||||
|
||||
// Test: array concatenation in pattern initialization
|
||||
// An array localparam used as a value in another array's pattern
|
||||
// should have its elements "flattened" into the target array.
|
||||
|
||||
localparam logic [31:0] BASE_ADDRS[3] = '{32'h80001000, 32'h80002000, 32'h80003000};
|
||||
|
||||
// Sub-array slice at the start
|
||||
localparam logic [31:0] ALL_ADDRS[4] = '{BASE_ADDRS[0:1], 32'h80003000, 32'h80004000};
|
||||
|
||||
// Sub-array slice in the middle
|
||||
localparam logic [31:0] MID[5] = '{32'hFF, BASE_ADDRS[0:1], 32'hAA, 32'hBB};
|
||||
|
||||
// Multiple full sub-arrays
|
||||
localparam logic [31:0] EXTRA[2] = '{32'hC0, 32'hD0};
|
||||
localparam logic [31:0] MULTI[5] = '{BASE_ADDRS, EXTRA};
|
||||
|
||||
// Sub-array with default (sparse InitArray)
|
||||
localparam logic [31:0] DFLT[3] = '{default: 32'hDD};
|
||||
localparam logic [31:0] WITH_DFLT[4] = '{DFLT, 32'hEE};
|
||||
|
||||
// Slice at the end
|
||||
localparam logic [31:0] TAIL[4] = '{32'hAA, 32'hBB, BASE_ADDRS[1:2]};
|
||||
|
||||
// Multiple slices combined
|
||||
localparam logic [31:0] MULTI_SLICE[4] = '{BASE_ADDRS[0:1], BASE_ADDRS[1:2]};
|
||||
|
||||
// Single-element slice
|
||||
localparam logic [31:0] SINGLE[3] = '{BASE_ADDRS[0:0], 32'hAA, 32'hBB};
|
||||
|
||||
// Descending-range source array
|
||||
localparam logic [31:0] DESC[2:0] = '{32'hD0, 32'hD1, 32'hD2};
|
||||
localparam logic [31:0] WITH_DESC[4] = '{DESC[1:0], 32'hAA, 32'hBB};
|
||||
|
||||
// Slice bounds from parameter expressions
|
||||
localparam int unsigned N = 2;
|
||||
localparam logic [31:0] PARAM_SLICE[4] = '{BASE_ADDRS[0:N-1], 32'hAA, 32'hBB};
|
||||
|
||||
// Multiple param-bounded slices composing a larger array
|
||||
localparam logic [31:0] SRC_A[4] = '{32'hA0, 32'hA1, 32'hA2, 32'hA3};
|
||||
localparam logic [31:0] SRC_B[4] = '{32'hB0, 32'hB1, 32'hB2, 32'hB3};
|
||||
localparam int unsigned NA = 2;
|
||||
localparam int unsigned NB = 3;
|
||||
localparam int unsigned TOTAL = NA + NB;
|
||||
localparam logic [31:0] COMPOSED[TOTAL] = '{SRC_A[0:NA-1], SRC_B[0:NB-1]};
|
||||
|
||||
// Test key'd associative array initialisations
|
||||
localparam logic [31:0] KEY_ARR_A[4] = '{0: BASE_ADDRS[0:1], 2: 32'hF2, 3: 32'hF3};
|
||||
localparam logic [31:0] KEY_ARR_B[4] = '{2: ALL_ADDRS[1:2], default: 32'h00};
|
||||
|
||||
// Keyed pattern where values are indexed from another array param
|
||||
// the key determines position, not the source array's element count.
|
||||
localparam logic [31:0] KEYED_FROM_ARR[3] = '{
|
||||
0: BASE_ADDRS[2], 1: BASE_ADDRS[0], 2: BASE_ADDRS[1]
|
||||
};
|
||||
|
||||
// Package-scoped array as a positional pattern member
|
||||
localparam logic [31:0] WITH_PKG[4] = '{arr_pkg::PKG_ADDRS, 32'hFF};
|
||||
|
||||
// Package-scoped array slice
|
||||
localparam logic [31:0] PKG_SLICE[4] = '{arr_pkg::PKG_ADDRS[0:1], 32'hAA, 32'hBB};
|
||||
|
||||
initial begin
|
||||
`checkh(ALL_ADDRS[0], 32'h80001000);
|
||||
`checkh(ALL_ADDRS[1], 32'h80002000);
|
||||
`checkh(ALL_ADDRS[2], 32'h80003000);
|
||||
`checkh(ALL_ADDRS[3], 32'h80004000);
|
||||
|
||||
`checkh(MID[0], 32'hFF);
|
||||
`checkh(MID[1], 32'h80001000);
|
||||
`checkh(MID[2], 32'h80002000);
|
||||
`checkh(MID[3], 32'hAA);
|
||||
`checkh(MID[4], 32'hBB);
|
||||
|
||||
`checkh(MULTI[0], 32'h80001000);
|
||||
`checkh(MULTI[1], 32'h80002000);
|
||||
`checkh(MULTI[2], 32'h80003000);
|
||||
`checkh(MULTI[3], 32'hC0);
|
||||
`checkh(MULTI[4], 32'hD0);
|
||||
|
||||
`checkh(WITH_DFLT[0], 32'hDD);
|
||||
`checkh(WITH_DFLT[1], 32'hDD);
|
||||
`checkh(WITH_DFLT[2], 32'hDD);
|
||||
`checkh(WITH_DFLT[3], 32'hEE);
|
||||
|
||||
`checkh(TAIL[0], 32'hAA);
|
||||
`checkh(TAIL[1], 32'hBB);
|
||||
`checkh(TAIL[2], 32'h80002000);
|
||||
`checkh(TAIL[3], 32'h80003000);
|
||||
|
||||
`checkh(MULTI_SLICE[0], 32'h80001000);
|
||||
`checkh(MULTI_SLICE[1], 32'h80002000);
|
||||
`checkh(MULTI_SLICE[2], 32'h80002000);
|
||||
`checkh(MULTI_SLICE[3], 32'h80003000);
|
||||
|
||||
`checkh(SINGLE[0], 32'h80001000);
|
||||
`checkh(SINGLE[1], 32'hAA);
|
||||
`checkh(SINGLE[2], 32'hBB);
|
||||
|
||||
`checkh(WITH_DESC[0], 32'hD2);
|
||||
`checkh(WITH_DESC[1], 32'hD1);
|
||||
`checkh(WITH_DESC[2], 32'hAA);
|
||||
`checkh(WITH_DESC[3], 32'hBB);
|
||||
|
||||
`checkh(PARAM_SLICE[0], 32'h80001000);
|
||||
`checkh(PARAM_SLICE[1], 32'h80002000);
|
||||
`checkh(PARAM_SLICE[2], 32'hAA);
|
||||
`checkh(PARAM_SLICE[3], 32'hBB);
|
||||
|
||||
`checkh(COMPOSED[0], 32'hA0);
|
||||
`checkh(COMPOSED[1], 32'hA1);
|
||||
`checkh(COMPOSED[2], 32'hB0);
|
||||
`checkh(COMPOSED[3], 32'hB1);
|
||||
`checkh(COMPOSED[4], 32'hB2);
|
||||
|
||||
`checkh(KEY_ARR_A[0], 32'h80001000);
|
||||
`checkh(KEY_ARR_A[1], 32'h80002000);
|
||||
`checkh(KEY_ARR_A[2], 32'hF2);
|
||||
`checkh(KEY_ARR_A[3], 32'hF3);
|
||||
|
||||
`checkh(KEY_ARR_B[0], 32'h00);
|
||||
`checkh(KEY_ARR_B[1], 32'h00);
|
||||
`checkh(KEY_ARR_B[2], 32'h80002000);
|
||||
`checkh(KEY_ARR_B[3], 32'h80003000);
|
||||
|
||||
`checkh(KEYED_FROM_ARR[0], 32'h80003000);
|
||||
`checkh(KEYED_FROM_ARR[1], 32'h80001000);
|
||||
`checkh(KEYED_FROM_ARR[2], 32'h80002000);
|
||||
|
||||
`checkh(WITH_PKG[0], 32'hAA001000);
|
||||
`checkh(WITH_PKG[1], 32'hAA002000);
|
||||
`checkh(WITH_PKG[2], 32'hAA003000);
|
||||
`checkh(WITH_PKG[3], 32'hFF);
|
||||
|
||||
`checkh(PKG_SLICE[0], 32'hAA001000);
|
||||
`checkh(PKG_SLICE[1], 32'hAA002000);
|
||||
`checkh(PKG_SLICE[2], 32'hAA);
|
||||
`checkh(PKG_SLICE[3], 32'hBB);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
%Error-UNSUPPORTED: t/t_assert_consec_rep_unsup.v:11:45: Unsupported: multi-cycle sequence expression inside consecutive repetition (IEEE 1800-2023 16.9.2)
|
||||
%Error-UNSUPPORTED: t/t_assert_consec_rep_unsup.v:13:45: Unsupported: multi-cycle sequence expression inside consecutive repetition (IEEE 1800-2023 16.9.2)
|
||||
: ... note: In instance 't'
|
||||
11 | assert property (@(posedge clk) (a ##1 b) [* 2] |-> a);
|
||||
13 | assert property (@(posedge clk) (a ##1 b) [* 2] |-> a);
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (input clk);
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
logic a, b;
|
||||
|
||||
// Unsupported: multi-cycle sequence expression inside consecutive repetition
|
||||
|
|
|
|||
|
|
@ -250,10 +250,10 @@ module t (
|
|||
`signal(REUSE_ASSOC_LHS_WITH_RHS_OF_RHS_XOR_COMMON, rand_a[23:4] ^ rand_a[39:20]);
|
||||
`signal(REUSE_ASSOC_LHS_WITH_RHS_OF_RHS_XOR, rand_a[23:4] ^ (~rand_b[24:5] ^ rand_a[39:20]));
|
||||
|
||||
`signal(REPLACE_COND_CONST_ONE_ZERO, rand_a[0] ? 8'b1 : 8'b0);
|
||||
`signal(REPLACE_COND_CONST_ZERO_ONE, rand_a[0] ? 8'b0 : 8'b1);
|
||||
`signal(REPLACE_COND_CONST_ONES_ZERO, rand_a[0] ? 8'hff : 8'b0);
|
||||
`signal(REPLACE_COND_CONST_ZERO_ONAE, rand_a[0] ? 8'b0 : 8'hff);
|
||||
`signal(REPLACE_COND_CONST_ONE_ZERO, rand_a[0] ? 80'b1 : 80'b0);
|
||||
`signal(REPLACE_COND_CONST_ZERO_ONE, rand_a[0] ? 80'b0 : 80'b1);
|
||||
`signal(REPLACE_COND_CONST_ONES_ZERO, rand_a[0] ? -80'b1 : 80'b0);
|
||||
`signal(REPLACE_COND_CONST_ZERO_ONAE, rand_a[0] ? 80'b0 : -80'b1);
|
||||
`signal(REPLACE_COND_CAT_LHS_CONST_ONE_ZERO, rand_a[0] ? {8'b1, rand_b[0]} : {8'b0, rand_b[1]});
|
||||
`signal(REPLACE_COND_CAT_LHS_CONST_ZERO_ONE, rand_a[0] ? {8'b0, rand_b[0]} : {8'b1, rand_b[1]});
|
||||
`signal(REPLACE_COND_SAME_CAT_LHS, rand_a[0] ? {8'd0, rand_b[0]} : {8'd0, rand_b[1]});
|
||||
|
|
@ -325,6 +325,7 @@ module t (
|
|||
`signal(REMOVE_EQ_BIT_1, 1'b1 == rand_a[0]);
|
||||
`signal(REMOVE_NEQ_BIT_0, 1'b0 != rand_a[0]);
|
||||
`signal(REPLACE_NEQ_BIT_1, 1'b1 != rand_a[0]);
|
||||
`signal(REPLACE_COND_INSERT, rand_a[0] ? {rand_b[63:40], {1'd0, rand_b[38:0]}} : rand_b);
|
||||
|
||||
// Operators that should work wiht mismatched widths
|
||||
`signal(MISMATCHED_ShiftL,const_a << 4'd2);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename
|
|||
test.execute()
|
||||
|
||||
if test.vlt:
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 41)
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 38)
|
||||
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//*************************************************************************
|
||||
|
||||
#include "Vt_opt_dead__Dpi.h"
|
||||
|
||||
void dpii_Keep() {}
|
||||
|
|
@ -11,13 +11,16 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
test.compile(verilator_flags2=[test.pli_filename])
|
||||
|
||||
test.execute()
|
||||
|
||||
# bug2227, Verilator unsupported, class dead
|
||||
# This is what we really want:
|
||||
# test.file_grep_not(test.obj_dir + "/V"+test.name+"__Syms.h", r'dead')
|
||||
test.file_grep(test.obj_dir + "/V" + test.name + "__Syms.h", r'dead')
|
||||
# test.file_grep_not(test.obj_dir + "/V"+test.name+"__Syms.h", r'Dead')
|
||||
# test.file_grep_not(test.obj_dir + "/V" + test.name + "_classes.mk", r'Dead');
|
||||
test.file_grep(test.obj_dir + "/V" + test.name + "__Dpi.h", r'dpii_Keep')
|
||||
test.file_grep(test.obj_dir + "/V" + test.name + "__Dpi.h", r'dpix_Keep')
|
||||
test.file_grep(test.obj_dir + "/V" + test.name + "_Pkg_public_kpt.h", r'public_int_Keep')
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -4,26 +4,95 @@
|
|||
// SPDX-FileCopyrightText: 2020 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class EmptyClass_Dead;
|
||||
// Tests look for magic string "Dead" not to exist; V3Dead should remove these
|
||||
|
||||
class BaseClass_Dead;
|
||||
endclass
|
||||
|
||||
class EmptyClass_Dead extends BaseClass_Dead;
|
||||
endclass
|
||||
|
||||
package Pack_Dead;
|
||||
typedef bit typedef_Dead;
|
||||
endpackage
|
||||
|
||||
module Mod_Dead;
|
||||
typedef class ModClass_Co_Dead;
|
||||
class ModClass_Dead;
|
||||
int memberb_dead;
|
||||
int m_b_Dead;
|
||||
ModClass_Co_Dead m_co_dead;
|
||||
task method_Dead;
|
||||
endtask
|
||||
static task method_static_Dead;
|
||||
endtask
|
||||
endclass
|
||||
class ModClass_Co_Dead;
|
||||
ModClass_Dead m_dead; // Check that ModClass_Dead<->ModClass_Co_Dead link gets Deadified
|
||||
endclass
|
||||
endmodule
|
||||
|
||||
//TODO dead check with class extends
|
||||
module Mod_Empty_Dead;
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
module Mod_Parent_Empty_Dead;
|
||||
Mod_Empty_Dead sub ();
|
||||
endmodule
|
||||
|
||||
interface If_Dead;
|
||||
function void if_func_Dead;
|
||||
endfunction
|
||||
modport modport_Dead(import if_func_Dead);
|
||||
endinterface
|
||||
|
||||
package Pkg_public_kpt;
|
||||
parameter int public_int_Keep /*verilator public_flat_rd*/ = 5;
|
||||
endpackage
|
||||
|
||||
package Pkg_Keep;
|
||||
import "DPI-C" function void dpii_Keep();
|
||||
|
||||
export "DPI-C" function dpix_Keep;
|
||||
function void dpix_Keep;
|
||||
endfunction
|
||||
endpackage
|
||||
|
||||
module t ( /*AUTOARG*/);
|
||||
|
||||
typedef struct {int struct_member_Dead;} struct_Dead_t;
|
||||
struct_Dead_t var_struct_Dead;
|
||||
|
||||
typedef int typedef_Dead1_t;
|
||||
typedef typedef_Dead1_t typedef_Dead2_t;
|
||||
|
||||
function void func_Dead;
|
||||
endfunction
|
||||
|
||||
generate
|
||||
if (0) begin
|
||||
Mod_Dead cell_dead ();
|
||||
Mod_Dead cell_nogen_Dead ();
|
||||
If_Dead if_nogen_Dead ();
|
||||
end
|
||||
endgenerate
|
||||
|
||||
Mod_Empty_Dead cell_empty_Dead ();
|
||||
Mod_Parent_Empty_Dead cell_parent_empty_Dead ();
|
||||
|
||||
typedef_Dead1_t assigned_to_Dead1;
|
||||
typedef_Dead2_t assigned_to_Dead2;
|
||||
typedef_Dead2_t assigned_to_Dead3;
|
||||
typedef_Dead2_t assigned_to_Dead4;
|
||||
typedef_Dead2_t assigned_to_Dead5;
|
||||
typedef_Dead2_t assigned_to_Dead6;
|
||||
|
||||
always_comb assigned_to_Dead6 = assigned_to_Dead5;
|
||||
always_comb assigned_to_Dead5 = assigned_to_Dead4;
|
||||
always_comb assigned_to_Dead4 = assigned_to_Dead3;
|
||||
always_comb assigned_to_Dead3 = assigned_to_Dead2;
|
||||
always_comb assigned_to_Dead2 = assigned_to_Dead1;
|
||||
|
||||
initial begin
|
||||
assigned_to_Dead1 = 1;
|
||||
assigned_to_Dead1 = 2;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Method/member access on a value-parameter whose type is
|
||||
// the enclosing module's type-parameter.
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] S_TIMER;
|
||||
logic [7:0] M_TIMER;
|
||||
logic [7:0] M_EXT;
|
||||
} my_irq_t;
|
||||
|
||||
module leaf #(
|
||||
parameter type interrupts_t = logic,
|
||||
parameter interrupts_t INTERRUPTS = '0
|
||||
) ();
|
||||
logic [7:0] observed;
|
||||
always_comb observed = INTERRUPTS.M_TIMER;
|
||||
endmodule
|
||||
|
||||
module mid #(
|
||||
parameter type interrupts_t = logic,
|
||||
parameter interrupts_t INTERRUPTS = '0
|
||||
) ();
|
||||
leaf #(
|
||||
.interrupts_t(interrupts_t),
|
||||
.INTERRUPTS(INTERRUPTS)
|
||||
) l ();
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
localparam type irq_t = my_irq_t;
|
||||
localparam irq_t IRQ = '{S_TIMER: 8'hAA, M_TIMER: 8'h55, M_EXT: 8'hCC};
|
||||
mid #(
|
||||
.interrupts_t(irq_t),
|
||||
.INTERRUPTS(IRQ)
|
||||
) m ();
|
||||
initial begin
|
||||
#1;
|
||||
if (m.l.observed !== 8'h55) begin
|
||||
$write("%%Error: observed=%h expected 55\n", m.l.observed);
|
||||
$stop;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`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);
|
||||
// verilog_format: on
|
||||
|
||||
package pkg;
|
||||
typedef struct packed {logic [1:0][31:0] bar;} T;
|
||||
localparam T t = 64'h87654321_deadbeef;
|
||||
endpackage
|
||||
|
||||
module foo #(
|
||||
parameter type T = int,
|
||||
parameter T t = 0
|
||||
) ();
|
||||
initial begin
|
||||
`checkh(t.bar[0], 32'hdeadbeef);
|
||||
`checkh(t.bar[1], 32'h87654321);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
foo #(
|
||||
.T(pkg::T),
|
||||
.t(pkg::t)
|
||||
) u_foo ();
|
||||
endmodule
|
||||
Loading…
Reference in New Issue