parent
4e6eafd994
commit
cd8818ca23
|
|
@ -88,6 +88,7 @@ public:
|
|||
m_arrVarsRefp = arrVarsRefp;
|
||||
}
|
||||
mutable std::map<std::string, int> count_cache;
|
||||
void clearCountCache() const { count_cache.clear(); }
|
||||
int countMatchingElements(const ArrayInfoMap& arr_vars, const std::string& base_name) const {
|
||||
if (VL_LIKELY(count_cache.find(base_name) != count_cache.end()))
|
||||
return count_cache[base_name];
|
||||
|
|
@ -172,7 +173,14 @@ public:
|
|||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
}
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
s << "(_ BitVec " << width() << ")";
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"indexed_name not found in m_arr_vars");
|
||||
}
|
||||
}
|
||||
}
|
||||
int totalWidth() const override {
|
||||
|
|
@ -355,12 +363,15 @@ public:
|
|||
typename std::enable_if<!VlContainsCustomStruct<T>::value, void>::type
|
||||
write_var(VlQueue<T>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (m_vars.find(name) == m_vars.end()) {
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
if (dimension > 0) {
|
||||
m_index = 0;
|
||||
clear_arr_table(name);
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
m_vars[name]->clearCountCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,15 +388,17 @@ public:
|
|||
write_var(VlUnpacked<T, N_Depth>& var, uint32_t width, const std::string& name,
|
||||
uint32_t dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (m_vars.find(name) == m_vars.end()) {
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
|
||||
if (dimension > 0) {
|
||||
m_index = 0;
|
||||
clear_arr_table(name);
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
m_vars[name]->clearCountCache();
|
||||
}
|
||||
}
|
||||
// Register unpacked array of structs
|
||||
|
|
@ -401,13 +414,16 @@ public:
|
|||
typename std::enable_if<!VlContainsCustomStruct<T_Value>::value, void>::type
|
||||
write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (m_vars.find(name) == m_vars.end()) {
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
if (dimension > 0) {
|
||||
m_index = 0;
|
||||
clear_arr_table(name);
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
m_vars[name]->clearCountCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -592,10 +608,25 @@ public:
|
|||
+ std::to_string(idx);
|
||||
}
|
||||
|
||||
// Helper: Clear existing array element entries for a base name
|
||||
void clear_arr_table(const std::string& name) {
|
||||
for (int index = 0;; ++index) {
|
||||
const std::string key = generateKey(name, index);
|
||||
const auto it = m_arr_vars.find(key);
|
||||
if (it == m_arr_vars.end()) break;
|
||||
m_arr_vars.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void hard(std::string&& constraint, const char* filename = "", uint32_t linenum = 0,
|
||||
const char* source = "");
|
||||
void soft(std::string&& constraint, const char* filename = "", uint32_t linenum = 0,
|
||||
const char* source = "");
|
||||
void pin_var(const char* name, int width, uint64_t value) {
|
||||
std::string constraint = "(__Vbv (= "s + name + " (_ bv" + std::to_string(value) + " "
|
||||
+ std::to_string(width) + ")))";
|
||||
hard(std::move(constraint));
|
||||
}
|
||||
void disable_soft(const std::string& varName);
|
||||
void clearConstraints();
|
||||
void clearAll(); // Clear both constraints and variables
|
||||
|
|
|
|||
|
|
@ -821,6 +821,7 @@ public:
|
|||
RANDOMIZER_UNIQUE,
|
||||
RANDOMIZER_MARK_RANDC,
|
||||
RANDOMIZER_SOLVE_BEFORE,
|
||||
RANDOMIZER_PIN_VAR,
|
||||
RANDOMIZER_WRITE_VAR,
|
||||
RNG_GET_RANDSTATE,
|
||||
RNG_SET_RANDSTATE,
|
||||
|
|
@ -959,6 +960,7 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|||
{RANDOMIZER_UNIQUE, "rand_unique", false}, \
|
||||
{RANDOMIZER_MARK_RANDC, "markRandc", false}, \
|
||||
{RANDOMIZER_SOLVE_BEFORE, "solveBefore", false}, \
|
||||
{RANDOMIZER_PIN_VAR, "pin_var", false}, \
|
||||
{RANDOMIZER_WRITE_VAR, "write_var", false}, \
|
||||
{RNG_GET_RANDSTATE, "__Vm_rng.get_randstate", true}, \
|
||||
{RNG_SET_RANDSTATE, "__Vm_rng.set_randstate", false}, \
|
||||
|
|
|
|||
|
|
@ -740,6 +740,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// (used to format "%@.%@" for struct arrays)
|
||||
std::set<std::string>& m_writtenVars; // Track which variable paths have write_var generated
|
||||
// (shared across all constraints)
|
||||
std::set<AstVar*>* m_sizeConstrainedArraysp = nullptr; // Arrays with size+element constraints
|
||||
|
||||
// Build full path for a MemberSel chain (e.g., "obj.l2.l3.l4")
|
||||
std::string buildMemberPath(const AstMemberSel* const memberSelp) {
|
||||
|
|
@ -953,9 +954,14 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstVar* varp = nodep->varp();
|
||||
if (varp->user4p()) {
|
||||
varp->user4p()->v3warn(
|
||||
CONSTRAINTIGN,
|
||||
"Size constraint combined with element constraint may not work correctly");
|
||||
bool isSizeRef = false;
|
||||
if (AstCMethodHard* const methodp = VN_CAST(nodep->backp(), CMethodHard)) {
|
||||
if (methodp->method() == VCMethod::ASSOC_SIZE
|
||||
|| methodp->method() == VCMethod::DYN_SIZE) {
|
||||
isSizeRef = true;
|
||||
}
|
||||
}
|
||||
if (!isSizeRef && m_sizeConstrainedArraysp) { m_sizeConstrainedArraysp->insert(varp); }
|
||||
}
|
||||
|
||||
// Check if this variable is marked as globally constrained
|
||||
|
|
@ -2394,14 +2400,16 @@ public:
|
|||
explicit ConstraintExprVisitor(AstClass* classp, VMemberMap& memberMap, AstNode* nodep,
|
||||
AstNodeFTask* inlineInitTaskp, AstVar* genp,
|
||||
AstVar* randModeVarp, std::set<std::string>& writtenVars,
|
||||
AstNodeFTask* memberselInitTaskp = nullptr)
|
||||
AstNodeFTask* memberselInitTaskp = nullptr,
|
||||
std::set<AstVar*>* sizeConstrainedArraysp = nullptr)
|
||||
: m_classp{classp}
|
||||
, m_inlineInitTaskp{inlineInitTaskp}
|
||||
, m_memberselInitTaskp{memberselInitTaskp}
|
||||
, m_genp{genp}
|
||||
, m_randModeVarp{randModeVarp}
|
||||
, m_memberMap{memberMap}
|
||||
, m_writtenVars{writtenVars} {
|
||||
, m_writtenVars{writtenVars}
|
||||
, m_sizeConstrainedArraysp{sizeConstrainedArraysp} {
|
||||
iterateAndNextNull(nodep);
|
||||
}
|
||||
};
|
||||
|
|
@ -2699,6 +2707,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
|
||||
AstConstraint* m_constraintp = nullptr; // Current constraint
|
||||
std::set<std::string> m_writtenVars; // Track write_var calls per class to avoid duplicates
|
||||
std::map<AstClass*, std::set<AstVar*>> m_sizeConstrainedArrays; // Per-class arrays
|
||||
std::map<AstClass*, AstVar*>
|
||||
m_staticConstraintModeVars; // Static constraint mode vars per class
|
||||
|
||||
|
|
@ -3985,8 +3994,10 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
if (constrp->itemsp()) expandUniqueElementList(constrp->itemsp());
|
||||
if (constrp->itemsp()) lowerDistConstraints(taskp, constrp->itemsp());
|
||||
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
|
||||
genp, randModeVarp, m_writtenVars, randomizep};
|
||||
std::set<AstVar*>& sizeArrays = m_sizeConstrainedArrays[classp];
|
||||
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(),
|
||||
nullptr, genp, randModeVarp,
|
||||
m_writtenVars, randomizep, &sizeArrays};
|
||||
if (constrp->itemsp()) {
|
||||
taskp->addStmtsp(wrapIfConstraintMode(
|
||||
nodep, constrp, constrp->itemsp()->unlinkFrBackWithNext()));
|
||||
|
|
@ -4090,7 +4101,106 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
solverCallp->dtypeSetBit();
|
||||
solverCallp->add(new AstVarRef{fl, genModp, genp, VAccess::READWRITE});
|
||||
solverCallp->add(".next(__Vm_rng)");
|
||||
beginValp = solverCallp;
|
||||
const auto sizeArraysIt = m_sizeConstrainedArrays.find(nodep);
|
||||
const bool needsSizePhase
|
||||
= sizeArraysIt != m_sizeConstrainedArrays.end() && !sizeArraysIt->second.empty();
|
||||
if (needsSizePhase) {
|
||||
AstVar* const sizeOkVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__Vsize_ok",
|
||||
nodep->findBasicDType(VBasicDTypeKwd::BIT)};
|
||||
sizeOkVarp->funcLocal(true);
|
||||
randomizep->addStmtsp(sizeOkVarp);
|
||||
|
||||
AstVar* const finalOkVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__Vfinal_ok",
|
||||
nodep->findBasicDType(VBasicDTypeKwd::BIT)};
|
||||
finalOkVarp->funcLocal(true);
|
||||
randomizep->addStmtsp(finalOkVarp);
|
||||
|
||||
// First pass: solve size variables (and other constraints) to determine sizes
|
||||
randomizep->addStmtsp(
|
||||
new AstAssign{fl, new AstVarRef{fl, sizeOkVarp, VAccess::WRITE}, solverCallp});
|
||||
|
||||
// Resize constrained arrays before rebuilding constraints
|
||||
if (AstTask* const resizeAllTaskp
|
||||
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
|
||||
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp};
|
||||
AstIf* const ifp = new AstIf{fl, new AstVarRef{fl, sizeOkVarp, VAccess::READ},
|
||||
resizeTaskRefp->makeStmt(), nullptr};
|
||||
randomizep->addStmtsp(ifp);
|
||||
}
|
||||
|
||||
// Refresh array element tables after resize
|
||||
for (AstVar* const arrVarp : sizeArraysIt->second) {
|
||||
AstCMethodHard* const methodp = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, genModp, genp, VAccess::READWRITE},
|
||||
VCMethod::RANDOMIZER_WRITE_VAR};
|
||||
methodp->dtypeSetVoid();
|
||||
|
||||
AstNodeModule* const classp = VN_AS(arrVarp->user2p(), NodeModule);
|
||||
AstVarRef* const varRefp = new AstVarRef{fl, classp, arrVarp, VAccess::WRITE};
|
||||
varRefp->classOrPackagep(classp);
|
||||
methodp->addPinsp(varRefp);
|
||||
|
||||
uint32_t dimension = 0;
|
||||
if (VN_IS(arrVarp->dtypep(), UnpackArrayDType)
|
||||
|| VN_IS(arrVarp->dtypep(), DynArrayDType)
|
||||
|| VN_IS(arrVarp->dtypep(), QueueDType)
|
||||
|| VN_IS(arrVarp->dtypep(), AssocArrayDType)) {
|
||||
const std::pair<uint32_t, uint32_t> dims
|
||||
= arrVarp->dtypep()->dimensions(/*includeBasic=*/true);
|
||||
dimension = dims.second;
|
||||
}
|
||||
|
||||
AstNodeDType* tmpDtypep = arrVarp->dtypep();
|
||||
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
||||
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
|
||||
tmpDtypep = tmpDtypep->subDTypep();
|
||||
const size_t width = tmpDtypep->width();
|
||||
|
||||
methodp->addPinsp(new AstConst{fl, AstConst::Unsized64{}, width});
|
||||
AstNodeExpr* const varnamep = new AstCExpr{
|
||||
fl, AstCExpr::Pure{}, "\"" + arrVarp->name() + "\"", arrVarp->width()};
|
||||
varnamep->dtypep(arrVarp->dtypep());
|
||||
methodp->addPinsp(varnamep);
|
||||
methodp->addPinsp(new AstConst{fl, AstConst::Unsized64{}, dimension});
|
||||
|
||||
randomizep->addStmtsp(methodp->makeStmt());
|
||||
}
|
||||
|
||||
// Rebuild constraints after resize and pin size variables
|
||||
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
|
||||
AstTaskRef* const setupTaskRefp2 = new AstTaskRef{fl, setupAllTaskp};
|
||||
randomizep->addStmtsp(setupTaskRefp2->makeStmt());
|
||||
|
||||
for (AstVar* const arrVarp : sizeArraysIt->second) {
|
||||
AstVar* const sizeVarp = VN_CAST(arrVarp->user4p(), Var);
|
||||
if (!sizeVarp) continue;
|
||||
AstCMethodHard* const pinp = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, genModp, genp, VAccess::READWRITE},
|
||||
VCMethod::RANDOMIZER_PIN_VAR};
|
||||
pinp->dtypeSetVoid();
|
||||
AstCExpr* const namep
|
||||
= new AstCExpr{fl, AstCExpr::Pure{}, "\"" + sizeVarp->name() + "\""};
|
||||
namep->dtypeSetUInt32();
|
||||
pinp->addPinsp(namep);
|
||||
pinp->addPinsp(new AstConst{fl, AstConst::Unsized64{},
|
||||
static_cast<uint64_t>(sizeVarp->width())});
|
||||
pinp->addPinsp(new AstVarRef{fl, sizeVarp, VAccess::READ});
|
||||
randomizep->addStmtsp(pinp->makeStmt());
|
||||
}
|
||||
|
||||
// Final pass: solve full constraints with sizes pinned
|
||||
AstCExpr* const solverCallp2 = new AstCExpr{fl};
|
||||
solverCallp2->dtypeSetBit();
|
||||
solverCallp2->add(new AstVarRef{fl, genModp, genp, VAccess::READWRITE});
|
||||
solverCallp2->add(".next(__Vm_rng)");
|
||||
randomizep->addStmtsp(new AstAssign{
|
||||
fl, new AstVarRef{fl, finalOkVarp, VAccess::WRITE}, solverCallp2});
|
||||
|
||||
beginValp = new AstAnd{fl, new AstVarRef{fl, sizeOkVarp, VAccess::READ},
|
||||
new AstVarRef{fl, finalOkVarp, VAccess::READ}};
|
||||
} else {
|
||||
beginValp = solverCallp;
|
||||
}
|
||||
if (randModeVarp) {
|
||||
AstNodeModule* const randModeClassp = VN_AS(randModeVarp->user2p(), Class);
|
||||
AstNodeFTask* const newp
|
||||
|
|
@ -4105,10 +4215,15 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE};
|
||||
randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp});
|
||||
|
||||
if (AstTask* const resizeAllTaskp
|
||||
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
|
||||
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp};
|
||||
randomizep->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
const auto sizeArraysIt = m_sizeConstrainedArrays.find(nodep);
|
||||
const bool needsSizePhase
|
||||
= sizeArraysIt != m_sizeConstrainedArrays.end() && !sizeArraysIt->second.empty();
|
||||
if (!needsSizePhase) {
|
||||
if (AstTask* const resizeAllTaskp
|
||||
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
|
||||
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp};
|
||||
randomizep->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
}
|
||||
}
|
||||
|
||||
AstVarRef* const fvarRefReadp = fvarRefp->cloneTree(false);
|
||||
|
|
@ -4321,7 +4436,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
{
|
||||
expandUniqueElementList(capturedTreep);
|
||||
ConstraintExprVisitor{nullptr, m_memberMap, capturedTreep, randomizeFuncp,
|
||||
stdrand, nullptr, m_writtenVars};
|
||||
stdrand, nullptr, m_writtenVars, nullptr};
|
||||
}
|
||||
AstCExpr* const solverCallp = new AstCExpr{fl};
|
||||
solverCallp->dtypeSetBit();
|
||||
|
|
@ -4455,7 +4570,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
{
|
||||
expandUniqueElementList(capturedTreep);
|
||||
ConstraintExprVisitor{classp, m_memberMap, capturedTreep, randomizeFuncp,
|
||||
localGenp, randModeVarp, m_writtenVars};
|
||||
localGenp, randModeVarp, m_writtenVars, nullptr};
|
||||
}
|
||||
|
||||
// Call the solver and set return value
|
||||
|
|
|
|||
|
|
@ -3,16 +3,12 @@
|
|||
| ^~~~
|
||||
... 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_randomize_method_types_unsup.v:27:7: Size constraint combined with element constraint may not work correctly
|
||||
: ... note: In instance 't'
|
||||
27 | q.size < 5;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:12: Unsupported: random member variable with the type of the containing class
|
||||
: ... note: In instance 't'
|
||||
15 | rand Cls cls;
|
||||
| ^~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:43:41: Unsupported: randomizing this expression, treating as state
|
||||
43 | res = obj.randomize() with { dynarr.size > 2; };
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:39:41: Unsupported: randomizing this expression, treating as state
|
||||
39 | res = obj.randomize() with { dynarr.size > 2; };
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ class Cls;
|
|||
dynarr[1].size < 10;
|
||||
}
|
||||
constraint statedep { i < st + 2; }
|
||||
constraint q_size_elem {
|
||||
q.size < 5;
|
||||
q[i] < 10;
|
||||
}
|
||||
constraint global_constraint {
|
||||
foo.x < y;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: 2024 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
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define check_rand(cl, field, cond) \
|
||||
begin \
|
||||
automatic longint prev_result; \
|
||||
automatic int ok; \
|
||||
if (!bit'(cl.randomize())) $stop; \
|
||||
prev_result = longint'(field); \
|
||||
if (!(cond)) $stop; \
|
||||
repeat(20) begin \
|
||||
longint result; \
|
||||
if (!bit'(cl.randomize())) $stop; \
|
||||
result = longint'(field); \
|
||||
if (!(cond)) $stop; \
|
||||
if (result != prev_result) ok = 1; \
|
||||
prev_result = result; \
|
||||
end \
|
||||
if (ok != 1) $stop; \
|
||||
end
|
||||
|
||||
class SizeElemQ;
|
||||
rand int q[$];
|
||||
constraint c {
|
||||
q.size() > 1;
|
||||
q.size() < 6;
|
||||
q[0] > 100;
|
||||
q[1] == q[0] + 1;
|
||||
}
|
||||
endclass
|
||||
|
||||
class SizeElemQ2;
|
||||
rand int q[$];
|
||||
rand int min_sz;
|
||||
constraint c {
|
||||
min_sz inside {[2:4]};
|
||||
q.size() == min_sz;
|
||||
foreach (q[i]) q[i] inside {[10:20]};
|
||||
q[0] != q[q.size() - 1];
|
||||
}
|
||||
endclass
|
||||
|
||||
class SizeElemDynArr;
|
||||
rand int da[];
|
||||
constraint c {
|
||||
da.size() inside {[3:5]};
|
||||
da[0] < 50;
|
||||
da[da.size() - 1] > 50;
|
||||
foreach (da[i]) da[i] inside {[1:100]};
|
||||
}
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
automatic SizeElemQ obj = new;
|
||||
automatic SizeElemQ2 obj2 = new;
|
||||
automatic SizeElemDynArr obj3 = new;
|
||||
|
||||
`check_rand(obj, obj.q[0],
|
||||
obj.q.size() > 1 && obj.q.size() < 6
|
||||
&& obj.q[0] > 100
|
||||
&& obj.q[1] == obj.q[0] + 1);
|
||||
|
||||
`check_rand(obj2, obj2.q[0],
|
||||
obj2.min_sz inside {[2:4]}
|
||||
&& obj2.q.size() == obj2.min_sz
|
||||
&& obj2.q[0] inside {[10:20]}
|
||||
&& obj2.q[obj2.q.size() - 1] inside {[10:20]}
|
||||
&& obj2.q[0] != obj2.q[obj2.q.size() - 1]);
|
||||
|
||||
`check_rand(obj3, obj3.da[0],
|
||||
obj3.da.size() inside {[3:5]}
|
||||
&& obj3.da[0] < 50
|
||||
&& obj3.da[obj3.da.size() - 1] > 50);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue