This commit is contained in:
parent
6c1cfc68cf
commit
218659f4e8
|
|
@ -161,6 +161,7 @@ Martin Stadler
|
|||
Mateusz Gancarz
|
||||
Matthew Ballance
|
||||
Max Wipfli
|
||||
Michael Bedford Taylor
|
||||
Michael Bikovitsky
|
||||
Michael Killough
|
||||
Michal Czyz
|
||||
|
|
|
|||
|
|
@ -2787,6 +2787,18 @@ class ConstVisitor final : public VNVisitor {
|
|||
}
|
||||
m_selp = nullptr;
|
||||
}
|
||||
|
||||
// Evaluate a slice of an unpacked array. If constantification is
|
||||
// required (m_required=true), call replaceWithSimulation() to compute
|
||||
// the slice via simulation. Otherwise just iterate the children.
|
||||
void visit(AstSliceSel* nodep) override {
|
||||
// First constify or width any child nodes
|
||||
iterateChildren(nodep);
|
||||
if (!m_required) return; // Do nothing unless we are in parameter mode
|
||||
// Fallback to simulation: this will invoke SimulateVisitor::visit(AstSliceSel*)
|
||||
replaceWithSimulation(nodep);
|
||||
}
|
||||
|
||||
void visit(AstCAwait* nodep) override {
|
||||
m_hasJumpDelay = true;
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -732,6 +732,14 @@ class ParamProcessor final {
|
|||
AstNode* const exprp = pinp->exprp();
|
||||
longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
|
||||
any_overridesr = true;
|
||||
} else if (VN_IS(pinp->exprp(), InitArray)) {
|
||||
// Array assigned to scalar parameter. Treat the InitArray as a constant
|
||||
// integer array and include it in the module name. Constantify nested
|
||||
// expressions before mangling the value number.
|
||||
V3Const::constifyParamsEdit(pinp->exprp());
|
||||
longnamer += "_" + paramSmallName(srcModp, modvarp)
|
||||
+ paramValueNumber(pinp->exprp());
|
||||
any_overridesr = true;
|
||||
} else {
|
||||
V3Const::constifyParamsEdit(pinp->exprp());
|
||||
// String constants are parsed as logic arrays and converted to strings in V3Const.
|
||||
|
|
|
|||
|
|
@ -894,6 +894,40 @@ private:
|
|||
clearOptimizable(nodep, "Array select of non-array");
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate a slice of an unpacked array. If the base value is a constant
|
||||
// AstInitArray, build a new AstInitArray representing the slice and assign
|
||||
// it as this node's value. New index 0 corresponds to the lowest index of
|
||||
// the slice. Otherwise, mark this node as unoptimizable.
|
||||
void visit(AstSliceSel* nodep) override {
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_checkOnly || !optimizable()) return;
|
||||
// Fetch the base constant array
|
||||
if (AstInitArray* const initp = VN_CAST(fetchValueNull(nodep->fromp()), InitArray)) {
|
||||
const VNumRange& sliceRange = nodep->declRange();
|
||||
const uint32_t sliceElements = sliceRange.elements();
|
||||
const int sliceLo = sliceRange.lo();
|
||||
// Use this node's dtype for the slice array
|
||||
AstNodeDType* const dtypep = nodep->dtypep()->skipRefp();
|
||||
// Clone the default value from the base array, if present
|
||||
AstNodeExpr* defaultp = nullptr;
|
||||
if (initp->defaultp()) defaultp = initp->defaultp()->cloneTree(false);
|
||||
AstInitArray* const newInitp = new AstInitArray{nodep->fileline(), dtypep, defaultp};
|
||||
// Copy slice elements in ascending order
|
||||
for (uint32_t idx = 0; idx < sliceElements; ++idx) {
|
||||
const uint32_t baseIdx = sliceLo + idx;
|
||||
AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(baseIdx);
|
||||
if (itemp) newInitp->addIndexValuep(idx, itemp->cloneTree(false));
|
||||
}
|
||||
// Assign the new constant array and track it for later deletion
|
||||
setValue(nodep, newInitp);
|
||||
m_reclaimValuesp.push_back(newInitp);
|
||||
} else {
|
||||
clearOptimizable(nodep, "Slice select of non-array");
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstBegin* nodep) override {
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test constant parameter slicing of unpacked arrays (issue #6257)
|
||||
#
|
||||
# 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('vlt')
|
||||
|
||||
test.compile(verilator_flags2=['--exe','--main','--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`timescale 1ns/1ps
|
||||
// Test constant parameter slicing of unpacked arrays with various slice ranges.
|
||||
|
||||
module issue_desc #(
|
||||
parameter int els_p = 1,
|
||||
parameter int val_p [els_p+1:2],
|
||||
parameter int orig_els = 1
|
||||
) ();
|
||||
// Drop the lowest index (2) in each recursion: slice [high:3]
|
||||
if (els_p > 1) begin : r
|
||||
issue_desc #(
|
||||
.els_p(els_p-1),
|
||||
.val_p(val_p[els_p+1:3]),
|
||||
.orig_els(orig_els)
|
||||
) x();
|
||||
end
|
||||
initial begin
|
||||
int expected = orig_els - els_p + 1;
|
||||
if (val_p[2] !== expected) begin
|
||||
$error("DESC wrong value %0d expected %0d in %m", val_p[2], expected);
|
||||
$finish;
|
||||
end
|
||||
$display("%08x (desc %m)", val_p[2]);
|
||||
end
|
||||
endmodule
|
||||
|
||||
module issue_rev #(
|
||||
parameter int els_p = 1,
|
||||
parameter int val_p [2:els_p+1],
|
||||
parameter int orig_els = 1
|
||||
) ();
|
||||
// Drop the lowest index (2) in each recursion: slice [3:high]
|
||||
if (els_p > 1) begin : r
|
||||
issue_rev #(
|
||||
.els_p(els_p-1),
|
||||
.val_p(val_p[3:els_p+1]),
|
||||
.orig_els(orig_els)
|
||||
) x();
|
||||
end
|
||||
initial begin
|
||||
int expected = orig_els - els_p + 1;
|
||||
if (val_p[2] !== expected) begin
|
||||
$error("REV wrong value %0d expected %0d in %m", val_p[2], expected);
|
||||
$finish;
|
||||
end
|
||||
$display("%08x (rev %m)", val_p[2]);
|
||||
end
|
||||
endmodule
|
||||
|
||||
module issue_def #(
|
||||
parameter int els_p = 1,
|
||||
// Internal default fill is zero; the test overrides this with DEADBEEF.
|
||||
parameter int val_p [els_p+1:2] = '{default:0},
|
||||
parameter int orig_els = 1
|
||||
) ();
|
||||
// Recursively slice off the lowest index (2)
|
||||
if (els_p > 1) begin : r
|
||||
issue_def #(
|
||||
.els_p(els_p-1),
|
||||
.val_p(val_p[els_p+1:3]),
|
||||
.orig_els(orig_els)
|
||||
) x();
|
||||
end
|
||||
initial begin
|
||||
// Expect 32'hDEADBEEF when overridden by the top-level test.
|
||||
if (val_p[2] !== 32'hDEADBEEF) begin
|
||||
$error("DEF wrong value %0x expected DEADBEEF in %m", val_p[2]);
|
||||
$finish;
|
||||
end
|
||||
$display("%08x (def %m)", val_p[2]);
|
||||
end
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
// For els_p=5, the range [els_p+1:2] is [6:2].
|
||||
// Descending initializer: index 6=5,5=4,4=3,3=2,2=1.
|
||||
parameter int val_desc [6:2] = '{5,4,3,2,1};
|
||||
// Reverse slice initializer: ascending values on [2:6].
|
||||
parameter int val_rev [2:6] = '{1,2,3,4,5};
|
||||
// Override for default-array test: all elements set to 32'hDEADBEEF on [6:2].
|
||||
parameter int val_def [6:2] = '{default: 32'hDEADBEEF};
|
||||
|
||||
issue_desc #(.els_p(5), .val_p(val_desc), .orig_els(5)) iss_desc();
|
||||
issue_rev #(.els_p(5), .val_p(val_rev), .orig_els(5)) iss_rev();
|
||||
issue_def #(.els_p(5), .val_p(val_def), .orig_els(5)) iss_def();
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue