test pass, and reformat
This commit is contained in:
parent
da3d1d9584
commit
dce9d2056c
|
|
@ -3360,8 +3360,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
uint64_t effectiveW = w;
|
||||
if (!ditemp->isWhole()) { // := weight is per-value; multiply by range size
|
||||
if (const AstInsideRange* const irp
|
||||
= VN_CAST(ditemp->rangep(), InsideRange)) {
|
||||
if (const AstInsideRange* const irp = VN_CAST(ditemp->rangep(), InsideRange)) {
|
||||
const AstConst* const lop = VN_CAST(irp->lhsp(), Const);
|
||||
const AstConst* const hip = VN_CAST(irp->rhsp(), Const);
|
||||
if (lop && hip && hip->toUQuad() >= lop->toUQuad())
|
||||
|
|
@ -3392,10 +3391,9 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
randp->dtypeSetUInt64();
|
||||
taskp->addStmtsp(new AstAssign{
|
||||
fl, new AstVarRef{fl, bucketVarp, VAccess::WRITE},
|
||||
new AstAdd{
|
||||
fl, new AstConst{fl, AstConst::Unsized64{}, 1},
|
||||
new AstModDiv{fl, randp,
|
||||
new AstConst{fl, AstConst::Unsized64{}, totalWeight}}}});
|
||||
new AstAdd{fl, new AstConst{fl, AstConst::Unsized64{}, 1},
|
||||
new AstModDiv{fl, randp,
|
||||
new AstConst{fl, AstConst::Unsized64{}, totalWeight}}}});
|
||||
|
||||
// Build AstConstraintIf chain (last-to-first so nesting is natural):
|
||||
// if (bucket <= w0) { exprp == range0 }
|
||||
|
|
@ -3428,8 +3426,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
// Scalar bucket: exprp == value
|
||||
AstNodeExpr* const exprCopyp = distp->exprp()->cloneTreePure(false);
|
||||
exprCopyp->user1(true);
|
||||
constraintExprp = new AstEq{fl, exprCopyp,
|
||||
buckets[i].rangep->cloneTreePure(false)};
|
||||
constraintExprp
|
||||
= new AstEq{fl, exprCopyp, buckets[i].rangep->cloneTreePure(false)};
|
||||
constraintExprp->user1(true);
|
||||
}
|
||||
|
||||
|
|
@ -3440,9 +3438,9 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
chainp = thenp;
|
||||
} else {
|
||||
// Bucket condition: bucketVar <= thisCumWeight (NOT rand-dependent)
|
||||
AstNodeExpr* const condp = new AstLte{
|
||||
fl, new AstVarRef{fl, bucketVarp, VAccess::READ},
|
||||
new AstConst{fl, AstConst::Unsized64{}, thisCumWeight}};
|
||||
AstNodeExpr* const condp
|
||||
= new AstLte{fl, new AstVarRef{fl, bucketVarp, VAccess::READ},
|
||||
new AstConst{fl, AstConst::Unsized64{}, thisCumWeight}};
|
||||
chainp = new AstConstraintIf{fl, condp, thenp, chainp};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3088,8 +3088,21 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheck(nodep, "Dist Item", itemp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP);
|
||||
}
|
||||
|
||||
// Inside a constraint: keep AstDist alive for V3Randomize to do weighted bucket selection
|
||||
if (m_constraintp) return;
|
||||
// Inside a constraint: keep AstDist alive for V3Randomize to do weighted bucket
|
||||
// selection, but only if all items have const weights and simple ranges (scalar or
|
||||
// InsideRange). Array/queue-based dist items are not supported by lowerDistConstraints.
|
||||
if (m_constraintp) {
|
||||
bool canLower = true;
|
||||
for (const AstDistItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), DistItem)) {
|
||||
if (!VN_IS(itemp->weightp(), Const)
|
||||
|| (!VN_IS(itemp->rangep(), Const) && !VN_IS(itemp->rangep(), InsideRange))) {
|
||||
canLower = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canLower) return;
|
||||
}
|
||||
|
||||
// Outside constraint: lower to inside expressions (ignores weights - imperfect)
|
||||
nodep->v3warn(CONSTRAINTIGN, "Constraint expression ignored (imperfect distribution)");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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')
|
||||
|
||||
if not test.have_solver:
|
||||
test.skip("No constraint solver installed")
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Test that dist constraint weights (:= and :/) produce correct distributions.
|
||||
// IEEE 1800-2017 18.5.4
|
||||
|
||||
class DistScalar;
|
||||
rand bit [7:0] x;
|
||||
// := weight is per-value: 0 has weight 1, 255 has weight 3 => ~75% should be 255
|
||||
constraint c { x dist { 8'd0 := 1, 8'd255 := 3 }; }
|
||||
endclass
|
||||
|
||||
class DistRange;
|
||||
rand bit [7:0] x;
|
||||
// :/ weight is per-range: [0:9] has total weight 1, [10:19] has total weight 3
|
||||
constraint c { x dist { [8'd0:8'd9] :/ 1, [8'd10:8'd19] :/ 3 }; }
|
||||
endclass
|
||||
|
||||
class DistZeroWeight;
|
||||
rand bit [7:0] x;
|
||||
// Weight 0 means never selected
|
||||
constraint c { x dist { 8'd0 := 0, 8'd1 := 1, 8'd2 := 1 }; }
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
DistScalar sc;
|
||||
DistRange rg;
|
||||
DistZeroWeight zw;
|
||||
int count_high;
|
||||
int count_range_high;
|
||||
int total;
|
||||
|
||||
total = 2000;
|
||||
|
||||
// Test 1: := scalar weights (expect ~75% for value 255)
|
||||
sc = new;
|
||||
count_high = 0;
|
||||
repeat (total) begin
|
||||
`checkd(sc.randomize(), 1);
|
||||
if (sc.x == 8'd255) count_high++;
|
||||
else `checkd(sc.x, 0); // Only 0 or 255 should appear
|
||||
end
|
||||
// 75% of 2000 = 1500, allow wide range for statistical test
|
||||
`check_range(count_high, 1200, 1800);
|
||||
|
||||
// Test 2: :/ range weights (expect ~75% in [10:19])
|
||||
rg = new;
|
||||
count_range_high = 0;
|
||||
repeat (total) begin
|
||||
`checkd(rg.randomize(), 1);
|
||||
if (rg.x >= 8'd10 && rg.x <= 8'd19) count_range_high++;
|
||||
else if (rg.x > 8'd9) begin
|
||||
$write("%%Error: x=%0d outside valid range [0:19]\n", rg.x);
|
||||
`stop;
|
||||
end
|
||||
end
|
||||
`check_range(count_range_high, 1200, 1800);
|
||||
|
||||
// Test 3: Zero weight exclusion (value 0 should never appear)
|
||||
zw = new;
|
||||
repeat (total) begin
|
||||
`checkd(zw.randomize(), 1);
|
||||
if (zw.x == 8'd0) begin
|
||||
$write("%%Error: zero-weight value 0 was selected\n");
|
||||
`stop;
|
||||
end
|
||||
`check_range(zw.x, 1, 2);
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue