Fix force not substituted into an unpacked array index (#8002)

This commit is contained in:
BRDR LIFE 2026-07-28 21:28:06 -04:00 committed by GitHub
parent b5fa4212b0
commit 2e4dbb846c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 128 additions and 1 deletions

View File

@ -1389,7 +1389,12 @@ class ForceReplaceVisitor final : public VNVisitor {
void visit(AstVarRef* nodep) override {
if (ForceState::isNotReplaceable(nodep)) return;
if (nodep->backp() && VN_IS(nodep->backp(), ArraySel)) return;
// The array an ArraySel selects from is left to visit(AstArraySel), which builds
// the force-aware read for the whole select. The index is an ordinary read and
// must still be substituted here, so check which child this is.
if (const AstArraySel* const backSelp = VN_CAST(nodep->backp(), ArraySel)) {
if (backSelp->fromp() == nodep) return;
}
const ForceState::VarForceInfo* const varInfo = m_state.getVarInfo(nodep->varScopep());
if (!varInfo) return;

View File

@ -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()

View File

@ -0,0 +1,104 @@
// 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
// A forced signal used as the index of an unpacked array select must read as
// forced, exactly as it does everywhere else (IEEE 1800-2023 10.6.2).
//
// Before the accompanying fix the array select kept reading the unforced
// value, while arithmetic on the same signal read the forced one.
//
// Both the continuous and the procedural read of the array are checked. The
// controls are arithmetic on the same signal and a packed select on it, both
// of which were already correct.
// verilog_format: off
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
module rf (
input logic [3:0] raddr_i,
output logic [7:0] rdata_o,
output logic [7:0] plus_o,
output logic [7:0] proc_o,
output logic [7:0] packed_o
);
logic [7:0] mem[16];
logic [127:0] packed_mem;
initial begin
for (int i = 0; i < 16; ++i) mem[i] = 8'h10 + i[7:0];
packed_mem = 128'h1f1e1d1c_1b1a1918_17161514_13121110;
end
// Array select on the forced index.
assign rdata_o = mem[raddr_i];
// Arithmetic on the same forced index, as the reference.
assign plus_o = {4'h0, raddr_i} + 8'h1;
// Packed select on the same forced index, as a second reference.
assign packed_o = packed_mem[8*raddr_i+:8];
// The same array select read procedurally rather than continuously.
always_comb proc_o = mem[raddr_i];
endmodule
module t (
input clk
);
int cyc = 0;
logic [3:0] addr;
logic [7:0] rdata, plus, proc, packd;
rf u_rf (
.raddr_i(addr),
.rdata_o(rdata),
.plus_o(plus),
.proc_o(proc),
.packed_o(packd)
);
// Runtime-varying so the reads cannot be constant folded.
assign addr = cyc[3:0];
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 4) force u_rf.raddr_i = 4'h7;
if (cyc == 8) force u_rf.raddr_i = 4'ha;
if (cyc == 12) release u_rf.raddr_i;
end
always @(negedge clk) begin
case (cyc)
2: begin // Unforced: addr follows cyc.
`checkh(rdata, 8'h12)
`checkh(proc, 8'h12)
`checkh(plus, 8'h03)
`checkh(packd, 8'h12)
end
6: begin // Forced to 7 while cyc says 6.
`checkh(plus, 8'h08)
`checkh(packd, 8'h17)
`checkh(rdata, 8'h17)
`checkh(proc, 8'h17)
end
10: begin // Re-forced to 10 while cyc says 10, so only the value proves it.
`checkh(plus, 8'h0b)
`checkh(packd, 8'h1a)
`checkh(rdata, 8'h1a)
`checkh(proc, 8'h1a)
end
14: begin // Released: back to following cyc.
`checkh(plus, 8'h0f)
`checkh(packd, 8'h1e)
`checkh(rdata, 8'h1e)
`checkh(proc, 8'h1e)
$write("*-* All Finished *-*\n");
$finish;
end
default: ;
endcase
end
endmodule