Fix force not substituted into an unpacked array index (#8002)
This commit is contained in:
parent
b5fa4212b0
commit
2e4dbb846c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,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
|
||||
Loading…
Reference in New Issue