diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 9d563a687..6eab5f0d4 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -253,16 +253,33 @@ class ForceConvertVisitor final : public VNVisitor { resetRdp->rhsp()->foreach([this](AstNodeVarRef* refp) { if (refp->access() != VAccess::WRITE) return; AstVarScope* const vscp = refp->varScopep(); - AstVarScope* const newVscp - = vscp->varp()->isContinuously() ? vscp : getForceComponents(vscp).m_valVscp; - AstVarRef* const newpRefp = new AstVarRef{refp->fileline(), newVscp, VAccess::READ}; + FileLine* const flp = new FileLine{refp->fileline()}; + AstVarRef* const newpRefp = new AstVarRef{refp->fileline(), vscp, VAccess::READ}; newpRefp->user2(1); // Don't replace this read ref with the read signal - refp->replaceWith(newpRefp); + if (vscp->varp()->isContinuously()) { + refp->replaceWith(newpRefp); + } else if (isRangedDType(vscp)) { + refp->replaceWith(new AstOr{ + flp, + new AstAnd{ + flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, VAccess::READ}, + new AstVarRef{flp, getForceComponents(vscp).m_valVscp, VAccess::READ}}, + new AstAnd{ + flp, + new AstNot{flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, + VAccess::READ}}, + newpRefp}}); + } else { + refp->replaceWith(new AstCond{ + flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, VAccess::READ}, + new AstVarRef{flp, getForceComponents(vscp).m_valVscp, VAccess::READ}, + newpRefp}); + } VL_DO_DANGLING(refp->deleteTree(), refp); }); - resetEnp->addNext(resetRdp); - relinker.relink(resetEnp); + resetRdp->addNext(resetEnp); + relinker.relink(resetRdp); } void visit(AstVarScope* nodep) override { diff --git a/test_regress/t/t_clocked_release_combo.pl b/test_regress/t/t_clocked_release_combo.pl new file mode 100755 index 000000000..fcd9221f5 --- /dev/null +++ b/test_regress/t/t_clocked_release_combo.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clocked_release_combo.v b/test_regress/t/t_clocked_release_combo.v new file mode 100644 index 000000000..fe0605223 --- /dev/null +++ b/test_regress/t/t_clocked_release_combo.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +// verilator lint_off MULTIDRIVEN +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + logic [31:0] lhs1, lhs2, rhs; + logic cond = 0; + + always_comb lhs1 = rhs; + assign lhs2 = rhs; + + always @(posedge clk) rhs = '1; + + always @(negedge clk) begin + if (cond) begin + force lhs1 = 'hdeadbeef; + force lhs2 = 'hfeedface; + end + else begin + release lhs1; + release lhs2; + end + end + + int cyc = 0; + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) cond <= 1; + if (cyc == 3) cond <= 0; + if (cyc > 1 && cyc < 4) begin + if (lhs1 != 'hdeadbeef) $stop; + if (lhs2 != 'hfeedface) $stop; + end + if (cyc > 4 && cyc < 8) begin + if (lhs1 != '1) $stop; + if (lhs2 != '1) $stop; + end + if (cyc >= 8) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule