This commit is contained in:
parent
e0f1f316aa
commit
7cd49a8028
|
|
@ -722,8 +722,8 @@ void VlRandomizer::clearAll() {
|
||||||
|
|
||||||
void VlRandomizer::markRandc(const char* name) { m_randcVarNames.insert(name); }
|
void VlRandomizer::markRandc(const char* name) { m_randcVarNames.insert(name); }
|
||||||
|
|
||||||
void VlRandomizer::solveBefore(const char* beforeName, const char* afterName) {
|
void VlRandomizer::solveBefore(const std::string& beforeName, const std::string& afterName) {
|
||||||
m_solveBefore.emplace_back(std::string(beforeName), std::string(afterName));
|
m_solveBefore.emplace_back(beforeName, afterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VlRandomizer::nextPhased(VlRNG& rngr) {
|
bool VlRandomizer::nextPhased(VlRNG& rngr) {
|
||||||
|
|
|
||||||
|
|
@ -631,8 +631,8 @@ public:
|
||||||
void clearConstraints();
|
void clearConstraints();
|
||||||
void clearAll(); // Clear both constraints and variables
|
void clearAll(); // Clear both constraints and variables
|
||||||
void markRandc(const char* name); // Mark variable as randc for cyclic tracking
|
void markRandc(const char* name); // Mark variable as randc for cyclic tracking
|
||||||
void solveBefore(const char* beforeName,
|
void solveBefore(const std::string& beforeName,
|
||||||
const char* afterName); // Register solve-before ordering
|
const std::string& afterName); // Register solve-before ordering
|
||||||
void set_randmode(const VlQueue<CData>& randmode) { m_randmodep = &randmode; }
|
void set_randmode(const VlQueue<CData>& randmode) { m_randmodep = &randmode; }
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
void dump() const;
|
void dump() const;
|
||||||
|
|
|
||||||
|
|
@ -767,6 +767,88 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a C++ expression (as AstNodeExpr) that evaluates to a const char*
|
||||||
|
// containing the SMT variable name for a solve-before variable reference.
|
||||||
|
// Handles simple vars, member selects, and array element selects (for foreach).
|
||||||
|
// Returns nullptr for unsupported expression types.
|
||||||
|
// Helper: build a dynamic AstCExpr for "baseName[idx]" pattern
|
||||||
|
AstCExpr* buildArraySelNameExpr(FileLine* fl, const std::string& baseName,
|
||||||
|
const AstArraySel* selp) {
|
||||||
|
AstCExpr* const p = new AstCExpr{fl, ""};
|
||||||
|
p->add("(\""s + baseName + "[\" + std::to_string(");
|
||||||
|
p->add(selp->bitp()->cloneTreePure(false));
|
||||||
|
p->add(") + \"]\")");
|
||||||
|
p->dtypeSetString();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: get fromp from MemberSel or StructSel
|
||||||
|
static AstNodeExpr* getSelFromp(AstNodeExpr* exprp) {
|
||||||
|
if (AstMemberSel* const mp = VN_CAST(exprp, MemberSel)) return mp->fromp();
|
||||||
|
if (AstStructSel* const sp = VN_CAST(exprp, StructSel)) return sp->fromp();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNodeExpr* buildSolveBeforeNameExpr(FileLine* fl, AstNodeExpr* exprp) {
|
||||||
|
if (const AstVarRef* const varrefp = VN_CAST(exprp, VarRef)) {
|
||||||
|
AstCExpr* const p = new AstCExpr{fl, AstCExpr::Pure{}, "\"" + varrefp->name() + "\"s"};
|
||||||
|
p->dtypeSetString();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
// Handle MemberSel or StructSel (V3Width converts MemberSel -> StructSel for structs)
|
||||||
|
if (AstNodeExpr* const selFromp = getSelFromp(exprp)) {
|
||||||
|
const std::string selName = exprp->name();
|
||||||
|
// Check if fromp chain contains ArraySel (e.g., cfg[i].w)
|
||||||
|
if (const AstArraySel* const arrSelp = VN_CAST(selFromp, ArraySel)) {
|
||||||
|
std::string baseName;
|
||||||
|
if (const AstVarRef* const vp = VN_CAST(arrSelp->fromp(), VarRef)) {
|
||||||
|
baseName = vp->name();
|
||||||
|
} else if (const AstMemberSel* const mp = VN_CAST(arrSelp->fromp(), MemberSel)) {
|
||||||
|
baseName = buildMemberPath(mp);
|
||||||
|
}
|
||||||
|
if (baseName.empty()) return nullptr;
|
||||||
|
AstCExpr* const p = new AstCExpr{fl, ""};
|
||||||
|
p->add("(\""s + baseName + "[\" + std::to_string(");
|
||||||
|
p->add(arrSelp->bitp()->cloneTreePure(false));
|
||||||
|
p->add(") + \"]." + selName + "\")");
|
||||||
|
p->dtypeSetString();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
// Static member path (obj.field)
|
||||||
|
if (const AstVarRef* const vp = VN_CAST(selFromp, VarRef)) {
|
||||||
|
const std::string path = vp->name() + "." + selName;
|
||||||
|
AstCExpr* const p = new AstCExpr{fl, AstCExpr::Pure{}, "\"" + path + "\"s"};
|
||||||
|
p->dtypeSetString();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (VN_IS(selFromp, MemberSel)) {
|
||||||
|
const std::string path
|
||||||
|
= buildMemberPath(VN_AS(selFromp, MemberSel)) + "." + selName;
|
||||||
|
AstCExpr* const p = new AstCExpr{fl, AstCExpr::Pure{}, "\"" + path + "\"s"};
|
||||||
|
p->dtypeSetString();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (const AstArraySel* const selp = VN_CAST(exprp, ArraySel)) {
|
||||||
|
// arr[i] -> dynamic name
|
||||||
|
std::string baseName;
|
||||||
|
if (const AstVarRef* const vp = VN_CAST(selp->fromp(), VarRef)) {
|
||||||
|
baseName = vp->name();
|
||||||
|
} else if (const AstMemberSel* const mp = VN_CAST(selp->fromp(), MemberSel)) {
|
||||||
|
baseName = buildMemberPath(mp);
|
||||||
|
}
|
||||||
|
if (baseName.empty()) return nullptr;
|
||||||
|
return buildArraySelNameExpr(fl, baseName, selp);
|
||||||
|
}
|
||||||
|
// Packed struct member: SEL(ARRAYSEL(...)) -- bit select on array element.
|
||||||
|
// Solver registers the whole element, so promote to array element level.
|
||||||
|
if (const AstSel* const bitSelp = VN_CAST(exprp, Sel)) {
|
||||||
|
return buildSolveBeforeNameExpr(fl, bitSelp->fromp());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
AstSFormatF* getConstFormat(AstNodeExpr* nodep) {
|
AstSFormatF* getConstFormat(AstNodeExpr* nodep) {
|
||||||
return new AstSFormatF{nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false,
|
return new AstSFormatF{nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false,
|
||||||
nodep};
|
nodep};
|
||||||
|
|
@ -1876,32 +1958,25 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
AstNodeModule* const genModp = VN_AS(m_genp->user2p(), NodeModule);
|
AstNodeModule* const genModp = VN_AS(m_genp->user2p(), NodeModule);
|
||||||
|
|
||||||
for (AstNodeExpr* lhsp = nodep->lhssp(); lhsp; lhsp = VN_CAST(lhsp->nextp(), NodeExpr)) {
|
for (AstNodeExpr* lhsp = nodep->lhssp(); lhsp; lhsp = VN_CAST(lhsp->nextp(), NodeExpr)) {
|
||||||
const std::string lhsName = extractSolveBeforeVarName(lhsp);
|
AstNodeExpr* const lhsTestp = buildSolveBeforeNameExpr(fl, lhsp);
|
||||||
if (lhsName.empty()) {
|
if (!lhsTestp) {
|
||||||
lhsp->v3warn(CONSTRAINTIGN,
|
lhsp->v3fatalSrc("Unexpected expression type in solve...before lhs");
|
||||||
"Unsupported: non-variable expression in solve...before");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
VL_DO_DANGLING(lhsTestp->deleteTree(), lhsTestp);
|
||||||
for (AstNodeExpr* rhsp = nodep->rhssp(); rhsp;
|
for (AstNodeExpr* rhsp = nodep->rhssp(); rhsp;
|
||||||
rhsp = VN_CAST(rhsp->nextp(), NodeExpr)) {
|
rhsp = VN_CAST(rhsp->nextp(), NodeExpr)) {
|
||||||
const std::string rhsName = extractSolveBeforeVarName(rhsp);
|
AstNodeExpr* const rhsNamep = buildSolveBeforeNameExpr(fl, rhsp);
|
||||||
if (rhsName.empty()) {
|
if (!rhsNamep) {
|
||||||
rhsp->v3warn(CONSTRAINTIGN,
|
rhsp->v3fatalSrc("Unexpected expression type in solve...before rhs");
|
||||||
"Unsupported: non-variable expression in solve...before");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AstCMethodHard* const callp = new AstCMethodHard{
|
AstCMethodHard* const callp = new AstCMethodHard{
|
||||||
fl, new AstVarRef{fl, genModp, m_genp, VAccess::READWRITE},
|
fl, new AstVarRef{fl, genModp, m_genp, VAccess::READWRITE},
|
||||||
VCMethod::RANDOMIZER_SOLVE_BEFORE};
|
VCMethod::RANDOMIZER_SOLVE_BEFORE};
|
||||||
callp->dtypeSetVoid();
|
callp->dtypeSetVoid();
|
||||||
AstNodeExpr* const beforeNamep
|
callp->addPinsp(buildSolveBeforeNameExpr(fl, lhsp));
|
||||||
= new AstCExpr{fl, AstCExpr::Pure{}, "\"" + lhsName + "\""};
|
callp->addPinsp(rhsNamep);
|
||||||
beforeNamep->dtypeSetUInt32();
|
|
||||||
AstNodeExpr* const afterNamep
|
|
||||||
= new AstCExpr{fl, AstCExpr::Pure{}, "\"" + rhsName + "\""};
|
|
||||||
afterNamep->dtypeSetUInt32();
|
|
||||||
callp->addPinsp(beforeNamep);
|
|
||||||
callp->addPinsp(afterNamep);
|
|
||||||
nodep->addHereThisAsNext(callp->makeStmt());
|
nodep->addHereThisAsNext(callp->makeStmt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3784,6 +3859,12 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursively handle ConstraintForeach nodes (dist can be inside foreach)
|
||||||
|
if (AstConstraintForeach* const cfep = VN_CAST(itemp, ConstraintForeach)) {
|
||||||
|
if (cfep->bodyp()) lowerDistConstraints(taskp, cfep->bodyp());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
AstConstraintExpr* const constrExprp = VN_CAST(itemp, ConstraintExpr);
|
AstConstraintExpr* const constrExprp = VN_CAST(itemp, ConstraintExpr);
|
||||||
if (!constrExprp) continue;
|
if (!constrExprp) continue;
|
||||||
AstDist* const distp = VN_CAST(constrExprp->exprp(), Dist);
|
AstDist* const distp = VN_CAST(constrExprp->exprp(), Dist);
|
||||||
|
|
|
||||||
|
|
@ -7843,12 +7843,10 @@ constraint_primary<nodeExprp>: // ==IEEE: constraint_primary
|
||||||
constraint_expressionList<nodep>: // ==IEEE: { constraint_expression }
|
constraint_expressionList<nodep>: // ==IEEE: { constraint_expression }
|
||||||
constraint_expression { $$ = $1; }
|
constraint_expression { $$ = $1; }
|
||||||
| ySOLVE solve_before_list yBEFORE solve_before_list ';'
|
| ySOLVE solve_before_list yBEFORE solve_before_list ';'
|
||||||
{ ($<fl>1)->v3warn(CONSTRAINTIGN, "Ignoring unsupported: solve-before only supported as top-level constraint statement");
|
{ $$ = new AstConstraintBefore{$1, $2, $4}; }
|
||||||
$$ = nullptr; DEL($2, $4); }
|
|
||||||
| constraint_expressionList constraint_expression { $$ = addNextNull($1, $2); }
|
| constraint_expressionList constraint_expression { $$ = addNextNull($1, $2); }
|
||||||
| constraint_expressionList ySOLVE solve_before_list yBEFORE solve_before_list ';'
|
| constraint_expressionList ySOLVE solve_before_list yBEFORE solve_before_list ';'
|
||||||
{ ($<fl>2)->v3warn(CONSTRAINTIGN, "Ignoring unsupported: solve-before only supported as top-level constraint statement");
|
{ $$ = addNextNull($1, new AstConstraintBefore{$<fl>2, $3, $5}); }
|
||||||
$$ = $1; DEL($3, $5); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
constraint_expression<nodep>: // ==IEEE: constraint_expression
|
constraint_expression<nodep>: // ==IEEE: constraint_expression
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_expr_unsup.v:12:27: Unsupported: non-variable expression in solve...before
|
|
||||||
: ... note: In instance 't'
|
|
||||||
12 | constraint c { solve arr[0] before y; }
|
|
||||||
| ^
|
|
||||||
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
|
|
||||||
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
class Cls;
|
|
||||||
rand int x;
|
|
||||||
rand int y;
|
|
||||||
rand int arr[4];
|
|
||||||
|
|
||||||
constraint c { solve arr[0] before y; } // BAD: non-variable expression
|
|
||||||
endclass
|
|
||||||
|
|
||||||
module t;
|
|
||||||
// verilator lint_off IMPLICITSTATIC
|
|
||||||
initial begin
|
|
||||||
Cls c = new;
|
|
||||||
void'(c.randomize());
|
|
||||||
end
|
|
||||||
endmodule
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:20:7: Ignoring unsupported: solve-before only supported as top-level constraint statement
|
|
||||||
20 | solve x before data[i];
|
|
||||||
| ^~~~~
|
|
||||||
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
|
|
||||||
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
|
|
||||||
%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:29:7: Ignoring unsupported: solve-before only supported as top-level constraint statement
|
|
||||||
29 | solve x before cfg[i].w, cfg[i].r;
|
|
||||||
| ^~~~~
|
|
||||||
%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:30:7: Ignoring unsupported: solve-before only supported as top-level constraint statement
|
|
||||||
30 | solve cfg[i].l before cfg[i].x;
|
|
||||||
| ^~~~~
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// DESCRIPTION: Verilator: Verilog Test module
|
|
||||||
//
|
|
||||||
// This file ONLY is placed under the Creative Commons Public Domain
|
|
||||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
rand bit l;
|
|
||||||
rand bit x;
|
|
||||||
rand bit w;
|
|
||||||
rand bit r;
|
|
||||||
} reg_t;
|
|
||||||
|
|
||||||
class Packet;
|
|
||||||
rand bit [7:0] data[5];
|
|
||||||
rand bit x;
|
|
||||||
|
|
||||||
constraint c_data {
|
|
||||||
foreach (data[i]) {
|
|
||||||
solve x before data[i];
|
|
||||||
data[i] inside {8'h10, 8'h20, 8'h30, 8'h40, 8'h50};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rand reg_t cfg[];
|
|
||||||
|
|
||||||
constraint solves_only_c {
|
|
||||||
foreach (cfg[i]) {
|
|
||||||
solve x before cfg[i].w, cfg[i].r;
|
|
||||||
solve cfg[i].l before cfg[i].x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endclass
|
|
||||||
|
|
||||||
module t;
|
|
||||||
Packet p;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
p = new;
|
|
||||||
void'(p.randomize());
|
|
||||||
end
|
|
||||||
endmodule
|
|
||||||
|
|
@ -9,8 +9,13 @@
|
||||||
|
|
||||||
import vltest_bootstrap
|
import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('linter')
|
test.scenarios('simulator')
|
||||||
|
|
||||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
if not test.have_solver:
|
||||||
|
test.skip("No constraint solver installed")
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
module t;
|
||||||
|
class item;
|
||||||
|
rand int unsigned arr[4];
|
||||||
|
rand int unsigned wgt_zero;
|
||||||
|
rand int unsigned wgt_nonzero;
|
||||||
|
|
||||||
|
constraint wgt_c {
|
||||||
|
wgt_zero inside {[1:10]};
|
||||||
|
wgt_nonzero inside {[1:10]};
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint dist_foreach_c {
|
||||||
|
foreach (arr[i]) {
|
||||||
|
arr[i] dist {0 :/ wgt_zero, [1:15] :/ wgt_nonzero};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endclass
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
static item it = new;
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(it.randomize(), 1);
|
||||||
|
foreach (it.arr[i]) begin
|
||||||
|
`checkd(it.arr[i] <= 32'd15, 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -4,13 +4,18 @@
|
||||||
# This program is free software; you can redistribute it and/or modify it
|
# 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
|
# under the terms of either the GNU Lesser General Public License Version 3
|
||||||
# or the Perl Artistic License Version 2.0.
|
# or the Perl Artistic License Version 2.0.
|
||||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
import vltest_bootstrap
|
import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('vlt')
|
test.scenarios('simulator')
|
||||||
|
|
||||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
if not test.have_solver:
|
||||||
|
test.skip("No constraint solver installed")
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
// 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 checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rand bit l;
|
||||||
|
rand bit x;
|
||||||
|
rand bit w;
|
||||||
|
rand bit r;
|
||||||
|
} reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
bit l;
|
||||||
|
bit x;
|
||||||
|
bit w;
|
||||||
|
bit r;
|
||||||
|
} preg_t;
|
||||||
|
|
||||||
|
module t;
|
||||||
|
class item;
|
||||||
|
rand bit [3:0] mode;
|
||||||
|
rand bit [7:0] data[4];
|
||||||
|
rand int x;
|
||||||
|
rand int y;
|
||||||
|
rand int arr[4];
|
||||||
|
|
||||||
|
constraint mode_c {
|
||||||
|
mode inside {[0:3]};
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint data_c {
|
||||||
|
foreach (data[i]) {
|
||||||
|
solve mode before data[i];
|
||||||
|
if (mode == 0)
|
||||||
|
data[i] == 8'h00;
|
||||||
|
else
|
||||||
|
data[i] inside {[8'd1:8'd255]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static array index in solve...before (non-foreach)
|
||||||
|
constraint arr_c {
|
||||||
|
solve arr[0] before y;
|
||||||
|
}
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Packet;
|
||||||
|
rand bit [7:0] pdata[5];
|
||||||
|
rand bit px;
|
||||||
|
rand reg_t cfg[3];
|
||||||
|
rand preg_t pcfg[3];
|
||||||
|
|
||||||
|
constraint c_pdata {
|
||||||
|
foreach (pdata[i]) {
|
||||||
|
solve px before pdata[i];
|
||||||
|
pdata[i] inside {8'h10, 8'h20, 8'h30, 8'h40, 8'h50};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint c_cfg {
|
||||||
|
foreach (cfg[i]) {
|
||||||
|
solve px before cfg[i].w, cfg[i].r;
|
||||||
|
solve cfg[i].l before cfg[i].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint c_pcfg {
|
||||||
|
foreach (pcfg[i]) {
|
||||||
|
solve px before pcfg[i].w, pcfg[i].r;
|
||||||
|
solve pcfg[i].l before pcfg[i].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endclass
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
static item it = new;
|
||||||
|
static Packet pkt = new;
|
||||||
|
|
||||||
|
// Test 1: solve...before with conditional constraints
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(it.randomize(), 1);
|
||||||
|
if (it.mode == 0) begin
|
||||||
|
foreach (it.data[i]) begin
|
||||||
|
`checkh(it.data[i], 8'h00);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test 2: solve...before with unpacked/packed struct array members
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(pkt.randomize(), 1);
|
||||||
|
foreach (pkt.pdata[i]) begin
|
||||||
|
`checkd(pkt.pdata[i] inside {8'h10, 8'h20, 8'h30, 8'h40, 8'h50}, 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test 3: solve...before with static array index (non-foreach)
|
||||||
|
repeat (20) begin
|
||||||
|
`checkd(it.randomize(), 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue