diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 51cf61090..2a9488edf 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -480,13 +480,13 @@ class UndrivenVisitor final : public VNVisitorConst { // EOM //&& entryp->getNodep()) { && (entryp->getNodep() - || (V3UndrivenCapture::enableWriteSummary && entryp->getCallNodep()))) { + || (m_enableWriteSummary && entryp->getCallNodep()))) { // EOM const AstNode* const otherWritep = entryp->getNodep() ? static_cast(entryp->getNodep()) - : (V3UndrivenCapture::enableWriteSummary ? entryp->getCallNodep() + : (m_enableWriteSummary ? entryp->getCallNodep() : nullptr); if (m_alwaysCombp diff --git a/src/V3UndrivenCapture.cpp b/src/V3UndrivenCapture.cpp index 795fd69de..935e03eb0 100644 --- a/src/V3UndrivenCapture.cpp +++ b/src/V3UndrivenCapture.cpp @@ -69,7 +69,13 @@ private: UINFO(DBG, "UndrivenCapture: direct write in " << taskNameQ(m_curTaskp) << " var=" << nodep->varp()->prettyNameQ() << " at " << nodep->fileline()); - m_cap.info(m_curTaskp).directWrites.push_back(nodep->varp()); + //m_cap.info(m_curTaskp).directWrites.push_back(nodep->varp()); + AstVar* const retVarp = VN_CAST(m_curTaskp->fvarp(), Var); + if (retVarp && nodep->varp() == retVarp) { + // Skip: function return variable is local, not a side-effect + } else { + m_cap.info(m_curTaskp).directWrites.push_back(nodep->varp()); + } } iterateChildrenConst(nodep); } diff --git a/test_regress/t/t_multidriven_funcret0.py b/test_regress/t/t_multidriven_funcret0.py new file mode 100644 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_multidriven_funcret0.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_multidriven_funcret0.v b/test_regress/t/t_multidriven_funcret0.v new file mode 100644 index 000000000..792164033 --- /dev/null +++ b/test_regress/t/t_multidriven_funcret0.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: MULTIDRIVEN false positive - package function return var +// +// Minimal reproducer for: package function with "return expr" used in always_comb expression. +// The function return variable must not be treated as a side-effect "writeSummary" target. + +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); + +package p; + function automatic int num_bytes(input int size); + return 1 << size; + endfunction +endpackage + +module t; + typedef struct packed { + logic [31:0] addr; + logic [2:0] size; + } meta_t; + + meta_t rd_meta_q; + meta_t rd_meta; + + always_comb begin + rd_meta = rd_meta_q; + rd_meta.addr = rd_meta_q.addr + p::num_bytes(int'(rd_meta_q.size)); + end + + initial begin + rd_meta_q.addr = 32'h100; + rd_meta_q.size = 3'd2; // num_bytes = 4 + #1; + `checkd(rd_meta.addr, 32'h104); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule