This commit is contained in:
parent
4357aee09a
commit
ed3aa43657
|
|
@ -3338,6 +3338,34 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
|
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
|
||||||
|
|
||||||
|
// Restrict enum variables in solver to valid members only
|
||||||
|
{
|
||||||
|
AstNodeModule* const genModp = VN_AS(genp->user2p(), NodeModule);
|
||||||
|
nodep->foreachMember([&](AstClass*, AstVar* memberVarp) {
|
||||||
|
if (!memberVarp->user3()) return;
|
||||||
|
AstEnumDType* const enumDtp
|
||||||
|
= VN_CAST(memberVarp->dtypep()->skipRefToEnump(), EnumDType);
|
||||||
|
if (!enumDtp) return;
|
||||||
|
const int width = enumDtp->width();
|
||||||
|
const std::string smtName = memberVarp->name();
|
||||||
|
std::string constraint = "(__Vbv (or";
|
||||||
|
for (AstEnumItem* itemp = enumDtp->itemsp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
||||||
|
const AstConst* const vconstp = VN_AS(itemp->valuep(), Const);
|
||||||
|
constraint += " (= " + smtName + " (_ bv" + cvtToStr(vconstp->toUInt())
|
||||||
|
+ " " + cvtToStr(width) + "))";
|
||||||
|
}
|
||||||
|
constraint += "))";
|
||||||
|
AstCMethodHard* const callp = new AstCMethodHard{
|
||||||
|
fl, new AstVarRef{fl, genModp, genp, VAccess::READWRITE},
|
||||||
|
VCMethod::RANDOMIZER_HARD,
|
||||||
|
new AstCExpr{fl, AstCExpr::Pure{}, "\"" + constraint + "\""}};
|
||||||
|
callp->dtypeSetVoid();
|
||||||
|
randomizep->addStmtsp(callp->makeStmt());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
|
||||||
AstTaskRef* const setupTaskRefp = new AstTaskRef{fl, setupAllTaskp, nullptr};
|
AstTaskRef* const setupTaskRefp = new AstTaskRef{fl, setupAllTaskp, nullptr};
|
||||||
randomizep->addStmtsp(setupTaskRefp->makeStmt());
|
randomizep->addStmtsp(setupTaskRefp->makeStmt());
|
||||||
|
|
|
||||||
|
|
@ -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,82 @@
|
||||||
|
// 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);
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
// Test that randc enum variables with user constraints only produce
|
||||||
|
// valid enum members (not arbitrary bitvector values).
|
||||||
|
|
||||||
|
module t;
|
||||||
|
|
||||||
|
typedef enum bit [2:0] {
|
||||||
|
RED = 0,
|
||||||
|
GREEN = 1,
|
||||||
|
BLUE = 2,
|
||||||
|
WHITE = 3,
|
||||||
|
BLACK = 4
|
||||||
|
} color_t;
|
||||||
|
|
||||||
|
class ColorClass;
|
||||||
|
randc color_t color;
|
||||||
|
constraint c_no_dark { color != BLACK; }
|
||||||
|
endclass
|
||||||
|
|
||||||
|
// Test with all enum values allowed (no exclusion constraint)
|
||||||
|
class AllColorsClass;
|
||||||
|
randc color_t color;
|
||||||
|
constraint c_range { color <= WHITE; }
|
||||||
|
endclass
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
ColorClass c;
|
||||||
|
AllColorsClass ac;
|
||||||
|
int color_seen[5];
|
||||||
|
int first_seq, all_same, this_seq;
|
||||||
|
|
||||||
|
// Test 1: randc enum with exclusion constraint
|
||||||
|
// Values must be valid enum members (0-4) and not BLACK (4)
|
||||||
|
c = new;
|
||||||
|
repeat (40) begin
|
||||||
|
`checkd(c.randomize(), 1);
|
||||||
|
`checkd(c.color <= BLACK, 1);
|
||||||
|
`checkd(c.color == BLACK, 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test 2: randc enum with range constraint - run multiple trials,
|
||||||
|
// verify only valid enum members produced and sequence varies
|
||||||
|
all_same = 1;
|
||||||
|
first_seq = 0;
|
||||||
|
for (int trial = 0; trial < 3; trial++) begin
|
||||||
|
ac = new;
|
||||||
|
this_seq = 0;
|
||||||
|
for (int j = 0; j < 4; j++) color_seen[j] = 0;
|
||||||
|
repeat (40) begin
|
||||||
|
`checkd(ac.randomize(), 1);
|
||||||
|
`checkd(ac.color <= WHITE, 1);
|
||||||
|
color_seen[ac.color] = 1;
|
||||||
|
end
|
||||||
|
// Record first 4 values for sequence comparison
|
||||||
|
repeat (4) begin
|
||||||
|
`checkd(ac.randomize(), 1);
|
||||||
|
this_seq = this_seq * 8 + int'(ac.color);
|
||||||
|
end
|
||||||
|
`checkd(color_seen[0], 1);
|
||||||
|
`checkd(color_seen[1], 1);
|
||||||
|
`checkd(color_seen[2], 1);
|
||||||
|
`checkd(color_seen[3], 1);
|
||||||
|
if (trial == 0) first_seq = this_seq;
|
||||||
|
else if (this_seq != first_seq) all_same = 0;
|
||||||
|
end
|
||||||
|
`checkd(all_same, 0);
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue