Support rand_mode (#5273)

Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
Krzysztof Bieganski 2024-07-31 23:30:48 +02:00 committed by GitHub
parent 403a197e23
commit 2f5c58b345
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 762 additions and 189 deletions

View File

@ -403,8 +403,12 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
auto it = m_vars.find(name);
if (it == m_vars.end()) continue;
const VlRandomVar& varr = *it->second;
if (m_randmode && !varr.randModeIdxNone()) {
if (!(m_randmode->at(varr.randModeIdx()))) continue;
}
it->second->set(std::move(value));
varr.set(std::move(value));
}
return true;

View File

@ -38,15 +38,19 @@ class VlRandomVar final : public VlRandomExpr {
const char* const m_name; // Variable name
void* const m_datap; // Reference to variable data
const int m_width; // Variable width in bits
const std::uint32_t m_randModeIdx; // rand_mode index
public:
VlRandomVar(const char* name, int width, void* datap)
VlRandomVar(const char* name, int width, void* datap, std::uint32_t randModeIdx)
: m_name{name}
, m_datap{datap}
, m_width{width} {}
, m_width{width}
, m_randModeIdx{randModeIdx} {}
const char* name() const { return m_name; }
int width() const { return m_width; }
void* datap() const { return m_datap; }
std::uint32_t randModeIdx() const { return m_randModeIdx; }
bool randModeIdxNone() const { return randModeIdx() == std::numeric_limits<unsigned>::max(); }
bool set(std::string&&) const;
void emit(std::ostream& s) const override;
};
@ -94,8 +98,9 @@ public:
class VlRandomizer final {
// MEMBERS
std::vector<std::string> m_constraints; // Solver-dependent constraints
std::map<std::string, std::shared_ptr<const VlRandomVar>>
m_vars; // Solver-dependent variables
std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
// variables
const VlQueue<CData>* m_randmode; // rand_mode state;
// PRIVATE METHODS
std::shared_ptr<const VlRandomExpr> randomConstraint(VlRNG& rngr, int bits);
@ -106,13 +111,15 @@ public:
// Finds the next solution satisfying the constraints
bool next(VlRNG& rngr);
template <typename T>
void write_var(T& var, int width, const char* name) {
void write_var(T& var, int width, const char* name,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
auto it = m_vars.find(name);
if (it != m_vars.end()) return;
m_vars[name] = std::make_shared<const VlRandomVar>(name, width, &var);
m_vars[name] = std::make_shared<const VlRandomVar>(name, width, &var, randmodeIdx);
}
void hard(std::string&& constraint);
void clear();
void set_randmode(const VlQueue<CData>& randmode) { m_randmode = &randmode; }
#ifdef VL_DEBUG
void dump() const;
#endif

View File

@ -2834,6 +2834,7 @@ void AstCMethodHard::setPurity() {
{"reverse", false},
{"rsort", false},
{"set", false},
{"set_randmode", false},
{"shuffle", false},
{"size", true},
{"slice", true},

View File

@ -3322,8 +3322,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
// Resolved in V3Width
} else if (nodep->name() == "randomize" || nodep->name() == "srandom"
|| nodep->name() == "get_randstate"
|| nodep->name() == "set_randstate") {
|| nodep->name() == "get_randstate" || nodep->name() == "set_randstate"
|| nodep->name() == "rand_mode") {
if (AstClass* const classp = VN_CAST(m_modp, Class)) {
nodep->classOrPackagep(classp);
} else {

View File

@ -41,15 +41,64 @@
VL_DEFINE_DEBUG_FUNCTIONS;
// ######################################################################
// Establishes the target of a rand_mode() call
struct RandModeTarget final {
// MEMBERS
AstVar* const receiverp; // Variable that is the target of the rand_mode() call
AstNodeExpr* const fromp; // Expression from which the rand_mode() call originates
AstClass* const classp; // Class in which rand_mode should be set
// METHODS
static RandModeTarget get(AstNodeExpr* fromp, AstNodeModule* modp) {
if (!fromp) return {nullptr, nullptr, VN_AS(modp, Class)};
if (AstCMethodHard* const methodHardp = VN_CAST(fromp, CMethodHard)) {
return RandModeTarget::get(methodHardp->fromp(), modp);
}
AstVar* receiverp = nullptr;
if (AstVarRef* const varrefp = VN_CAST(fromp, VarRef)) {
receiverp = varrefp->varp();
} else if (AstMemberSel* const memberSelp = VN_CAST(fromp, MemberSel)) {
receiverp = memberSelp->varp();
}
UASSERT_OBJ(receiverp, fromp, "Unknown rand_mode() receiver");
if (receiverp->isRand()) {
if (AstMemberSel* const memberselp = VN_CAST(fromp, MemberSel)) {
return {receiverp, memberselp->fromp(),
VN_AS(memberselp->fromp()->dtypep()->skipRefp(), ClassRefDType)->classp()};
}
} else {
AstClassRefDType* const classRefDtp
= VN_CAST(receiverp->dtypep()->skipRefp(), ClassRefDType);
if (classRefDtp) return {receiverp, fromp, classRefDtp->classp()};
}
return {receiverp, nullptr, VN_AS(modp, Class)};
}
};
// ######################################################################
// Stores info about a variable's rand_mode state
union VarRandMode final {
// MEMBERS
struct {
bool usesRandMode : 1; // True if variable uses rand_mode
uint32_t index : 31; // Index of var in rand_mode vector
};
int asInt; // Representation as int to be stored in nodep->user*
};
//######################################################################
// Visitor that marks classes needing a randomize() method
class RandomizeMarkVisitor final : public VNVisitorConst {
class RandomizeMarkVisitor final : public VNVisitor {
// NODE STATE
// Cleared on Netlist
// AstClass::user1() -> bool. Set true to indicate needs randomize processing
// AstNodeExpr::user1() -> bool. Set true to indicate constraint expression depending on a
// randomized variable
// AstVar::user1() -> bool. Set true to indicate needs rand_mode
// AstVar::user2p() -> AstNodeModule*. Pointer to containing module
const VNUser1InUse m_inuser1;
const VNUser2InUse m_inuser2;
@ -61,6 +110,7 @@ class RandomizeMarkVisitor final : public VNVisitorConst {
AstClass* m_classp = nullptr; // Current class
AstNode* m_constraintExprp = nullptr; // Current constraint expression
AstNodeModule* m_modp; // Current module
AstNodeStmt* m_stmtp = nullptr; // Current statement
std::set<AstNodeVarRef*> m_staticRefs; // References to static variables under `with` clauses
// METHODS
@ -119,8 +169,78 @@ class RandomizeMarkVisitor final : public VNVisitorConst {
m_baseToDerivedMap[basep].insert(nodep);
}
}
void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_stmtp);
m_stmtp = nodep;
iterateChildren(nodep);
if (!nodep->backp()) VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
iterateChildrenConst(nodep);
if (nodep->name() == "rand_mode") {
AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall);
AstNodeExpr* const fromp = methodCallp ? methodCallp->fromp() : nullptr;
bool valid = true;
if (VN_IS(fromp, ArraySel)) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: 'rand_mode()' on unpacked array element");
valid = false;
} else if (VN_IS(fromp, Sel)) {
nodep->v3error("Cannot call 'rand_mode()' on packed array element");
valid = false;
} else if (AstCMethodHard* const methodHardp = VN_CAST(fromp, CMethodHard)) {
if (methodHardp->name() == "at" && VN_IS(fromp, CMethodHard)) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: 'rand_mode()' on dynamic array element");
valid = false;
} else {
methodHardp->v3fatal("Unknown rand_mode() receiver");
}
}
if (!nodep->pinsp() && VN_IS(nodep->backp(), StmtExpr)) {
nodep->v3warn(
IGNOREDRETURN,
"Ignoring return value of non-void function (IEEE 1800-2023 13.4.1)");
valid = false;
}
if (valid) {
const RandModeTarget randModeTarget = RandModeTarget::get(fromp, m_classp);
if ((!randModeTarget.receiverp || !randModeTarget.receiverp->isRand())
&& !nodep->pinsp()) {
nodep->v3error(
"Cannot call 'rand_mode()' as a function on non-random variable");
valid = false;
} else if (!randModeTarget.classp) {
nodep->v3error("Cannot call 'rand_mode()' on non-random, non-class variable");
valid = false;
} else if (nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
nodep->v3error("'rand_mode()' with arguments cannot be called as a function");
valid = false;
} else if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
// Called on a rand member variable
VarRandMode randMode = {};
randMode.usesRandMode = true;
randModeTarget.receiverp->user1(randMode.asInt);
} else {
// Called on 'this' or a non-rand class instance
randModeTarget.classp->foreachMember([&](AstClass*, AstVar* varp) {
if (!varp->isRand()) return;
VarRandMode randMode = {};
randMode.usesRandMode = true;
varp->user1(randMode.asInt);
});
}
}
if (!valid) {
if (!nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
m_stmtp->unlinkFrBack();
}
}
return;
}
if (nodep->name() != "randomize") return;
AstClass* classp = m_classp;
if (const AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall)) {
@ -192,17 +312,20 @@ class ConstraintExprVisitor final : public VNVisitor {
AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to
// (may be null, then new() is used)
AstVar* const m_genp; // VlRandomizer variable of the class
AstVar* m_randModeVarp; // Relevant randmode state variable
bool m_wantSingle = false; // Whether to merge constraint expressions with LOGAND
VMemberMap& m_memberMap; // Member names cached for fast lookup
AstSFormatF* getConstFormat(AstNodeExpr* nodep) {
return new AstSFormatF{nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false,
nodep};
}
bool editFormat(AstNodeExpr* nodep) {
if (nodep->user1()) return false;
// Replace computable expression with SMT constant
VNRelinker handle;
nodep->unlinkFrBack(&handle);
AstSFormatF* const newp = new AstSFormatF{
nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false, nodep};
handle.relink(newp);
handle.relink(getConstFormat(nodep));
return true;
}
void editSMT(AstNodeExpr* nodep, AstNodeExpr* lhsp = nullptr, AstNodeExpr* rhsp = nullptr,
@ -282,14 +405,28 @@ class ConstraintExprVisitor final : public VNVisitor {
// VISITORS
void visit(AstNodeVarRef* nodep) override {
if (editFormat(nodep)) return;
AstVar* const varp = nodep->varp();
const VarRandMode randMode = {.asInt = varp->user1()};
if (!randMode.usesRandMode && editFormat(nodep)) return;
// In SMT just variable name, but we also ensure write_var for the variable
const std::string smtName = nodep->name(); // Can be anything unique
nodep->replaceWith(new AstSFormatF{nodep->fileline(), smtName, false, nullptr});
AstVar* const varp = nodep->varp();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
VNRelinker relinker;
nodep->unlinkFrBack(&relinker);
AstNodeExpr* exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
if (randMode.usesRandMode) {
AstNodeExpr* constFormatp = getConstFormat(nodep);
AstCMethodHard* const atp = new AstCMethodHard{
nodep->fileline(),
new AstVarRef{varp->fileline(), VN_AS(m_randModeVarp->user2p(), NodeModule),
m_randModeVarp, VAccess::READ},
"at", new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
exprp = new AstCond{varp->fileline(), atp, exprp, constFormatp};
} else {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
relinker.relink(exprp);
if (!varp->user3()) {
AstCMethodHard* const methodp = new AstCMethodHard{
@ -308,6 +445,10 @@ class ConstraintExprVisitor final : public VNVisitor {
= new AstCExpr{varp->fileline(), "\"" + smtName + "\"", varp->width()};
varnamep->dtypep(varp->dtypep());
methodp->addPinsp(varnamep);
if (randMode.usesRandMode) {
methodp->addPinsp(
new AstConst{varp->fileline(), AstConst::Unsized64{}, randMode.index});
}
AstNodeFTask* initTaskp = m_inlineInitTaskp;
if (!initTaskp) {
varp->user3(true); // Mark as set up in new()
@ -430,9 +571,11 @@ class ConstraintExprVisitor final : public VNVisitor {
public:
// CONSTRUCTORS
explicit ConstraintExprVisitor(VMemberMap& memberMap, AstNode* nodep,
AstNodeFTask* inlineInitTaskp, AstVar* genp)
AstNodeFTask* inlineInitTaskp, AstVar* genp,
AstVar* randModeVarp)
: m_inlineInitTaskp{inlineInitTaskp}
, m_genp{genp}
, m_randModeVarp{randModeVarp}
, m_memberMap{memberMap} {
iterateAndNextNull(nodep);
}
@ -538,15 +681,19 @@ class RandomizeVisitor final : public VNVisitor {
// AstClass::user2p() -> AstTask*. Pointer to full constraint setup procedure
// AstVar::user3() -> bool. Handled in constraints
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
// AstClass::user4p() -> AstVar*. Rand mode state variable
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
const VNUser3InUse m_inuser3;
const VNUser4InUse m_inuser4;
// STATE
V3UniqueNames m_inlineUniqueNames; // For generating unique function names
VMemberMap m_memberMap; // Member names cached for fast lookup
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeStmt* m_stmtp = nullptr; // Current statement
AstDynArrayDType* m_dynarrayDtp = nullptr; // Dynamic array type (for rand mode)
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
int m_randCaseNum = 0; // Randcase number within a module for var naming
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
@ -579,14 +726,119 @@ class RandomizeVisitor final : public VNVisitor {
classp->user2p(setupAllTaskp);
return setupAllTaskp;
}
AstVar* getCreateRandModeVar(AstClass* const classp) {
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
if (AstClassExtends* const extendsp = classp->extendsp()) {
return getCreateRandModeVar(extendsp->classp());
}
FileLine* const fl = classp->fileline();
if (!m_dynarrayDtp) {
m_dynarrayDtp = new AstDynArrayDType{
fl, v3Global.rootp()->typeTablep()->findBitDType()->dtypep()};
m_dynarrayDtp->dtypep(m_dynarrayDtp);
v3Global.rootp()->typeTablep()->addTypesp(m_dynarrayDtp);
}
AstVar* const randModeVarp
= new AstVar{fl, VVarType::MODULETEMP, "__Vrandmode", m_dynarrayDtp};
randModeVarp->user2p(classp);
classp->addStmtsp(randModeVarp);
classp->user4p(randModeVarp);
return randModeVarp;
}
AstVar* getRandModeVar(AstClass* const classp) {
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
if (AstClassExtends* const extendsp = classp->extendsp()) {
return getRandModeVar(extendsp->classp());
}
return nullptr;
}
void addSetRandMode(AstNodeFTask* const ftaskp, AstVar* const genp,
AstVar* const randModeVarp) {
FileLine* const fl = ftaskp->fileline();
AstCMethodHard* const setRandModep = new AstCMethodHard{
fl, new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::WRITE},
"set_randmode",
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), NodeModule), randModeVarp,
VAccess::READ}};
setRandModep->dtypeSetVoid();
ftaskp->addStmtsp(setRandModep->makeStmt());
}
void createRandomizeClassVars(AstNetlist* const netlistp) {
netlistp->foreach([&](AstClass* const classp) {
if (classp->existsMember(
[&](const AstClass*, const AstConstraint*) { return true; })) {
createRandomGenerator(classp);
}
uint32_t randModeCount = 0;
classp->foreachMember([&](AstClass*, AstVar* memberVarp) {
VarRandMode randMode = {.asInt = memberVarp->user1()};
if (!randMode.usesRandMode) return;
// SystemVerilog only allows single inheritance, so we don't need to worry about
// index overlap. If the index > 0, it's already been set.
if (randMode.index == 0) {
randMode.index = randModeCount++;
memberVarp->user1(randMode.asInt);
} else {
randModeCount = randMode.index + 1;
}
});
if (randModeCount > 0) {
AstVar* const randModeVarp = getCreateRandModeVar(classp);
AstNodeModule* const randModeModp = VN_AS(randModeVarp->user2p(), NodeModule);
FileLine* fl = randModeVarp->fileline();
AstCMethodHard* const dynarrayNewp = new AstCMethodHard{
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
"renew_copy", new AstConst{fl, randModeCount}};
dynarrayNewp->addPinsp(
new AstVarRef{fl, randModeModp, randModeVarp, VAccess::READ});
dynarrayNewp->dtypeSetVoid();
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
fl = classp->fileline();
UASSERT_OBJ(newp, classp, "No new() in class");
newp->addStmtsp(dynarrayNewp->makeStmt());
newp->addStmtsp(makeRandModeInitLoop(
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
new AstConst{fl, 1}, true));
}
});
}
static AstNode* makeRandModeInitLoop(FileLine* const fl, AstNodeExpr* const lhsp,
AstNodeExpr* const rhsp, bool inTask) {
AstVar* const iterVarp = new AstVar{fl, VVarType::BLOCKTEMP, "i", lhsp->findUInt32DType()};
iterVarp->funcLocal(inTask);
iterVarp->lifetime(VLifetime::AUTOMATIC);
AstCMethodHard* const sizep = new AstCMethodHard{fl, lhsp, "size", nullptr};
sizep->dtypeSetUInt32();
AstCMethodHard* const atp = new AstCMethodHard{fl, lhsp->cloneTree(false), "at",
new AstVarRef{fl, iterVarp, VAccess::READ}};
atp->dtypeSetUInt32();
AstNode* const stmtsp = iterVarp;
stmtsp->addNext(
new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE}, new AstConst{fl, 0}});
stmtsp->addNext(
new AstWhile{fl, new AstLt{fl, new AstVarRef{fl, iterVarp, VAccess::READ}, sizep},
new AstAssign{fl, atp, rhsp},
new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE},
new AstAdd{fl, new AstConst{fl, 1},
new AstVarRef{fl, iterVarp, VAccess::READ}}}});
return new AstBegin{fl, "", stmtsp, false, true};
}
AstNodeStmt* wrapIfRandMode(AstVar* const varp, AstNodeStmt* stmtp) {
FileLine* const fl = stmtp->fileline();
const VarRandMode randMode = {.asInt = varp->user1()};
if (randMode.usesRandMode) {
AstVar* randModeVarp = getRandModeVar(VN_AS(m_modp, Class));
AstCMethodHard* const atp
= new AstCMethodHard{fl,
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), Class),
randModeVarp, VAccess::READ},
"at", new AstConst{fl, randMode.index}};
atp->dtypeSetUInt32();
return new AstIf{fl, atp, stmtp};
}
return stmtp;
}
AstVar* enumValueTabp(AstEnumDType* const nodep) {
if (nodep->user2p()) return VN_AS(nodep->user2p(), Var);
UINFO(9, "Construct Venumvaltab " << nodep << endl);
@ -702,10 +954,17 @@ class RandomizeVisitor final : public VNVisitor {
valp
= newRandValue(fl, randcVarp, (memberp ? memberp->dtypep() : exprp->dtypep()));
}
return new AstAssign{fl,
new AstSel{fl, exprp, offset + (memberp ? memberp->lsb() : 0),
memberp ? memberp->width() : exprp->width()},
valp};
AstAssign* assignp
= new AstAssign{fl,
new AstSel{fl, exprp, offset + (memberp ? memberp->lsb() : 0),
memberp ? memberp->width() : exprp->width()},
valp};
AstVar* varp = nullptr;
exprp->exists([&](const AstVarRef* varrefp) {
if (varrefp->access().isWriteOrRW()) varp = varrefp->varp();
return varp != nullptr;
});
return wrapIfRandMode(varp, assignp);
}
}
AstNodeExpr* newRandValue(FileLine* const fl, AstVar* const randcVarp,
@ -780,7 +1039,7 @@ class RandomizeVisitor final : public VNVisitor {
new AstConst{fl, AstConst::Null{}}},
new AstAssign{fl, basicFvarRefp->cloneTree(false),
new AstAnd{fl, basicFvarRefReadp, callp}}};
basicRandomizep->addStmtsp(assignIfNotNullp);
basicRandomizep->addStmtsp(wrapIfRandMode(memberVarp, assignIfNotNullp));
} else {
memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type "
<< memberVarp->dtypep()->prettyDTypeNameQ());
@ -815,6 +1074,7 @@ class RandomizeVisitor final : public VNVisitor {
addPrePostCall(nodep, randomizep, "pre_randomize");
FileLine* fl = nodep->fileline();
AstVar* const randModeVarp = getRandModeVar(nodep);
AstNodeExpr* beginValp = nullptr;
AstVar* genp = getRandomGenerator(nodep);
if (genp) {
@ -833,7 +1093,7 @@ class RandomizeVisitor final : public VNVisitor {
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
});
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
@ -843,13 +1103,22 @@ class RandomizeVisitor final : public VNVisitor {
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
randomizep->addStmtsp(setupTaskRefp->makeStmt());
AstVarRef* genRefp
= new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::READWRITE};
AstNodeModule* const genModp = VN_AS(genp->user2p(), NodeModule);
AstVarRef* const genRefp = new AstVarRef{fl, genModp, genp, VAccess::READWRITE};
AstNode* const argsp = genRefp;
argsp->addNext(new AstText{fl, ".next(__Vm_rng)"});
AstNodeExpr* const solverCallp = new AstCExpr{fl, argsp};
solverCallp->dtypeSetBit();
beginValp = solverCallp;
if (randModeVarp) {
AstNodeModule* const randModeClassp = VN_AS(randModeVarp->user2p(), Class);
AstNodeFTask* const newp
= VN_AS(m_memberMap.findMember(randModeClassp, "new"), NodeFTask);
UASSERT_OBJ(newp, randModeClassp, "No new() in class");
addSetRandMode(newp, genp, randModeVarp);
}
} else {
beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1};
}
@ -933,6 +1202,58 @@ class RandomizeVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
if (nodep->name() == "rand_mode") {
AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall);
AstNodeExpr* const fromp = methodCallp ? methodCallp->fromp() : nullptr;
const RandModeTarget randModeTarget = RandModeTarget::get(fromp, m_modp);
UASSERT_OBJ(randModeTarget.classp, nodep,
"Should have checked in RandomizeMarkVisitor");
AstVar* const randModeVarp = getRandModeVar(randModeTarget.classp);
AstNodeExpr* lhsp = nullptr;
if (randModeTarget.classp == m_modp) {
// Called on 'this' or a member of 'this'
lhsp = new AstVarRef{nodep->fileline(), VN_AS(randModeVarp->user2p(), NodeModule),
randModeVarp, VAccess::WRITE};
} else {
AstMemberSel* const memberselp = new AstMemberSel{
nodep->fileline(), randModeTarget.fromp->unlinkFrBack(), randModeVarp};
memberselp->foreach([](AstVarRef* varrefp) { varrefp->access(VAccess::WRITE); });
lhsp = memberselp;
}
if (nodep->pinsp()) { // Set rand mode
UASSERT_OBJ(VN_IS(nodep->backp(), StmtExpr), nodep, "Should be a statement");
AstNodeExpr* const rhsp = VN_AS(nodep->pinsp(), Arg)->exprp()->unlinkFrBack();
if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
// Called on a rand member variable. Set the variable's rand mode
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
AstCMethodHard* const atp
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
m_stmtp->replaceWith(new AstAssign{nodep->fileline(), atp, rhsp});
} else {
// Called on 'this' or a non-rand class instance. Set the rand mode of all
// members
m_stmtp->replaceWith(
makeRandModeInitLoop(nodep->fileline(), lhsp, rhsp, m_ftaskp));
}
pushDeletep(m_stmtp);
} else { // Retrieve rand mode
UASSERT_OBJ(randModeTarget.receiverp, nodep, "Should have receiver");
UASSERT_OBJ(randModeTarget.receiverp->isRand(), nodep, "Should be rand");
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
AstCMethodHard* const atp
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
nodep->replaceWith(atp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
return;
}
AstWith* const withp = VN_CAST(nodep->pinsp(), With);
if (!(nodep->name() == "randomize") || !withp) {
@ -1018,9 +1339,14 @@ class RandomizeVisitor final : public VNVisitor {
VAccess::READ}});
}
// Set rand mode if present (not needed if classGenp exists and was copied)
AstVar* const randModeVarp = getRandModeVar(classp);
if (!classGenp && randModeVarp) addSetRandMode(randomizeFuncp, localGenp, randModeVarp);
// Generate constraint setup code and a hardcoded call to the solver
randomizeFuncp->addStmtsp(captured.getTree());
ConstraintExprVisitor{m_memberMap, captured.getTree(), randomizeFuncp, localGenp};
ConstraintExprVisitor{m_memberMap, captured.getTree(), randomizeFuncp, localGenp,
randModeVarp};
// Call the solver and set return value
AstVarRef* const randNextp
@ -1042,6 +1368,11 @@ class RandomizeVisitor final : public VNVisitor {
UINFO(9, "Added `%s` randomization procedure");
VL_DO_DANGLING(withp->deleteTree(), withp);
}
void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_stmtp);
m_stmtp = nodep;
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

@ -2965,6 +2965,12 @@ class WidthVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
bool memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) {
if (nodep->name() == "rand_mode") {
nodep->replaceWith(new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"rand_mode", nullptr});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return true;
}
// Returns true if ok
// No need to width-resolve the class, as it was done when we did the child
AstClass* const first_classp = adtypep->classp();
@ -3885,12 +3891,14 @@ class WidthVisitor final : public VNVisitor {
}
}
void methodCallRandMode(AstMethodCall* nodep) {
// Method call on constraint (currently hacked as just a var)
methodOkArguments(nodep, 0, 1);
nodep->v3warn(CONSTRAINTIGN, "rand_mode ignored (unsupported)");
// Disables ignored, so we just return "ON"
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
// IEEE 1800-2023 18.8
if (nodep->pinsp()) {
nodep->dtypep(nodep->findBasicDType(VBasicDTypeKwd::INT));
} else {
nodep->dtypeSetVoid();
}
v3Global.useRandomizeMethods(true);
}
void methodCallUnpack(AstMethodCall* nodep, AstUnpackArrayDType* adtypep) {
enum : uint8_t {
@ -6021,9 +6029,13 @@ class WidthVisitor final : public VNVisitor {
// Function hasn't been widthed, so make it so.
UINFO(5, " FTASKREF " << nodep << endl);
AstWith* withp = nullptr;
if (nodep->name() == "randomize" || nodep->name() == "srandom"
|| (!nodep->taskp()
&& (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) {
if (nodep->name() == "rand_mode") {
v3Global.useRandomizeMethods(true);
nodep->dtypep(nodep->findBasicDType(VBasicDTypeKwd::INT));
} else if (nodep->name() == "randomize" || nodep->name() == "srandom"
|| (!nodep->taskp()
&& (nodep->name() == "get_randstate"
|| nodep->name() == "set_randstate"))) {
// TODO perhaps this should move to V3LinkDot
AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class);
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
@ -6035,7 +6047,8 @@ class WidthVisitor final : public VNVisitor {
withp = methodWithArgument(nodep, false, false, adtypep->findVoidDType(),
adtypep->findBitDType(), adtypep);
if (nodep->pinsp()) {
nodep->pinsp()->v3warn(CONSTRAINTIGN, "rand_mode ignored (unsupported)");
nodep->pinsp()->v3warn(CONSTRAINTIGN,
"Inline random variable control (unsupported)");
nodep->pinsp()->unlinkFrBackWithNext()->deleteTree();
}
} else if (nodep->name() == "srandom") {
@ -6070,6 +6083,7 @@ class WidthVisitor final : public VNVisitor {
UASSERT_OBJ(false, nodep, "Bad case");
}
}
if (nodep->name() == "rand_mode") return; // Handled in V3Randomize
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
if (nodep->didWidth()) return;
if ((nodep->taskp()->classMethod() && !nodep->taskp()->isStatic())

View File

@ -79,6 +79,11 @@ private:
// Check local/protected status and complain
bool local = false;
bool prot = false;
if (!defp) {
// rand_mode() handled in V3Randomize
UASSERT_OBJ(nodep->name() == "rand_mode", nodep, "Only rand_mode() can have no def");
return;
}
if (const auto varp = VN_CAST(defp, Var)) {
local = varp->isHideLocal();
prot = varp->isHideProtected();

View File

@ -0,0 +1,9 @@
%Warning-CONSTRAINTIGN: t/t_randomize_inline_var_ctl_unsup.v:13:23: Inline random variable control (unsupported)
13 | void'(randomize(one));
| ^~~
... 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_inline_var_ctl_unsup.v:14:23: Inline random variable control (unsupported)
14 | void'(randomize(two, three));
| ^~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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
scenarios(linter => 1);
lint(
expect_filename => $Self->{golden_filename},
fails => 1,
);
ok(1);
1;

View File

@ -0,0 +1,16 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int one;
int two;
static int three;
function void test;
void'(randomize(one));
void'(randomize(two, three));
endfunction
endclass

View File

@ -11,7 +11,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1);
compile(
verilator_flags2 => ['-Wno-CONSTRAINTIGN'],
);
execute(

View File

@ -7,28 +7,50 @@
`define stop $stop
`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);
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
`ifdef VERILATOR
`define checkh_vlt1(gotv,expv) `checkh(gotv,1)
`else
`define checkh_vlt1(gotv,expv) `checkh(gotv,expv)
`endif
class Packet;
class Base;
rand int m_one;
rand int m_two;
task test1;
m_one.rand_mode(0);
`checkh_vlt1(m_one.rand_mode(), 0);
m_two.rand_mode(0);
`checkh_vlt1(m_two.rand_mode(), 0);
`checkh(m_one.rand_mode(), 0);
verify(0);
m_one.rand_mode(1);
`checkh(m_one.rand_mode(), 1);
verify(1);
endtask
task verify(int mode_one);
bit one_ne10 = '0;
int v;
if (m_one.rand_mode() != mode_one) $stop;
for (int i = 0; i < 20; ++i) begin
m_one = 10;
v = randomize();
if (m_one != 10) one_ne10 = 1'b1;
`ifdef TEST_VERBOSE
$display("one=%0d(rand_mode=%0d)", m_one, mode_one);
`endif
end
if (mode_one != 0 && !one_ne10) $stop;
if (mode_one == 0 && one_ne10) $stop;
endtask
endclass
class Packet extends Base;
rand int m_two;
task test2;
rand_mode(0);
`checkh(m_one.rand_mode(), 0);
`checkh(m_two.rand_mode(), 0);
verify(0, 0);
m_one.rand_mode(0);
`checkh_vlt1(m_one.rand_mode(), 0);
`checkh(m_one.rand_mode(), 0);
m_two.rand_mode(1);
`checkh_vlt1(m_two.rand_mode(), 1);
`checkh(m_two.rand_mode(), 1);
verify(0, 1);
endtask
@ -36,31 +58,23 @@ class Packet;
bit one_ne10 = '0;
bit two_ne10 = '0;
int v;
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
`ifndef VERILATOR
if (m_one.rand_mode() != mode_one) $stop;
if (m_two.rand_mode() != mode_two) $stop;
`else
if (m_one.rand_mode() != 1) $stop;
if (m_two.rand_mode() != 1) $stop;
`endif
for (int i = 0; i < 20; ++i) begin
m_one = 10;
m_two = 10;
v = randomize();
if (m_one != 10) one_ne10 = 1'b1;
if (m_two != 10) two_ne10 = 1'b1;
m_one = 10;
m_two = 10;
v = randomize();
if (m_one != 10) one_ne10 = 1'b1;
if (m_two != 10) two_ne10 = 1'b1;
`ifdef TEST_VERBOSE
$display("one=%0d(rand_mode=%0d) two=%0d(rand_mode=%0d)",
m_one, mode_one, m_two, mode_two);
$display("one=%0d(rand_mode=%0d) two=%0d(rand_mode=%0d)",
m_one, mode_one, m_two, mode_two);
`endif
end
if (mode_one != 0 && !one_ne10) $stop;
if (mode_two != 0 && !two_ne10) $stop;
`ifndef VERILATOR
if (mode_one == 0 && one_ne10) $stop;
if (mode_two == 0 && two_ne10) $stop;
`endif
endtask
endclass
@ -75,6 +89,7 @@ module t (/*AUTOARG*/);
p = new;
p.test1();
p.test2();
// IEEE: function void object[.random_variable].rand_mode(bit on_off);
// IEEE: function int object.random_variable.rand_mode();
@ -83,15 +98,15 @@ module t (/*AUTOARG*/);
// We call rand_mode here too becuase the parsing is different from that
// called from the class itself
p.m_one.rand_mode(0);
`checkh_vlt1(p.m_one.rand_mode(), 0);
`checkh(p.m_one.rand_mode(), 0);
p.m_two.rand_mode(0);
`checkh_vlt1(p.m_two.rand_mode(), 0);
`checkh(p.m_two.rand_mode(), 0);
p.verify(0, 0);
p.m_one.rand_mode(0);
`checkh_vlt1(p.m_one.rand_mode(), 0);
`checkh(p.m_one.rand_mode(), 0);
p.m_two.rand_mode(1);
`checkh_vlt1(p.m_two.rand_mode(), 1);
`checkh(p.m_two.rand_mode(), 1);
p.verify(0, 1);
p.rand_mode(1);

View File

@ -0,0 +1,27 @@
%Error: t/t_randomize_rand_mode_bad.v:22:15: Cannot call 'rand_mode()' on non-random, non-class variable
: ... note: In instance 't'
22 | p.m_val.rand_mode(0);
| ^~~~~~~~~
%Error: t/t_randomize_rand_mode_bad.v:23:19: Cannot call 'rand_mode()' on packed array element
: ... note: In instance 't'
23 | p.m_pack[0].rand_mode(0);
| ^~~~~~~~~
%Error: t/t_randomize_rand_mode_bad.v:24:39: Cannot call 'rand_mode()' as a function on non-random variable
: ... note: In instance 't'
24 | $display("p.rand_mode()=%0d", p.rand_mode());
| ^~~~~~~~~
%Error: t/t_randomize_rand_mode_bad.v:25:18: 'rand_mode()' with arguments cannot be called as a function
: ... note: In instance 't'
25 | $display(p.rand_mode(0));
| ^~~~~~~~~
%Warning-IGNOREDRETURN: t/t_randomize_rand_mode_bad.v:26:21: Ignoring return value of non-void function (IEEE 1800-2023 13.4.1)
: ... note: In instance 't'
26 | p.m_other_val.rand_mode();
| ^~~~~~~~~
... For warning description see https://verilator.org/warn/IGNOREDRETURN?v=latest
... Use "/* verilator lint_off IGNOREDRETURN */" and lint_on around source to disable this message.
%Error: t/t_randomize_rand_mode_bad.v:13:14: Cannot call 'rand_mode()' as a function on non-random variable
: ... note: In instance 't'
13 | return rand_mode();
| ^~~~~~~~~
%Error: Exiting due to

View File

@ -10,8 +10,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(vlt => 1);
top_filename("t/t_randomize_rand_mode.v");
lint(
fails => 1,
expect_filename => $Self->{golden_filename},

View File

@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class Packet;
int m_val;
rand int m_other_val;
rand logic [7:0] m_pack;
function int get_rand_mode;
return rand_mode();
endfunction
endclass
module t;
Packet p;
initial begin
p = new;
p.m_val.rand_mode(0);
p.m_pack[0].rand_mode(0);
$display("p.rand_mode()=%0d", p.rand_mode());
$display(p.rand_mode(0));
p.m_other_val.rand_mode();
end
endmodule

View File

@ -0,0 +1,25 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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
scenarios(simulator => 1);
if (!$Self->have_solver) {
skip("No constraint solver installed");
} else {
compile(
);
execute(
check_finished => 1,
);
}
ok(1);
1;

View File

@ -0,0 +1,143 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class Foo;
rand int a;
rand int b;
endclass
class Bar;
rand int x;
rand Foo foo;
constraint x_gt_0 {x > 0;};
function new;
foo = new;
endfunction
endclass
class Qux extends Bar;
rand int y;
constraint y_gt_x {y > x;};
constraint y_lt_10 {y < 10;};
function void test;
logic ok = 0;
x.rand_mode(1);
if (x.rand_mode == 0) $stop;
y.rand_mode(0);
if (y.rand_mode == 1) $stop;
foo.a.rand_mode(0);
if (foo.a.rand_mode == 1) $stop;
foo.b.rand_mode(1);
if (foo.b.rand_mode == 0) $stop;
for (int i = 0; i < 20; ++i) begin
x = 4;
y = 8;
foo.a = 15;
foo.b = 16;
void'(randomize());
if (x >= y) $stop;
if (x != 4) ok = 1;
if (y != 8) $stop;
if (foo.a != 15) $stop;
if (foo.b != 16) ok = 1;
end
if (!ok) $stop;
foo.b = 16;
foo.rand_mode(0);
if (foo.rand_mode == 1) $stop;
if (foo.a.rand_mode == 1) $stop;
if (foo.b.rand_mode == 0) $stop;
void'(randomize());
if (foo.a != 15) $stop;
if (foo.b != 16) $stop;
ok = 0;
foo.rand_mode(1);
if (foo.rand_mode == 0) $stop;
for (int i = 0; i < 20; ++i) begin
foo.a = 23;
foo.b = 42;
void'(randomize());
if (foo.a != 23) $stop;
if (foo.b != 42) ok = 1;
end
if (!ok) $stop;
endfunction
endclass
class Baz;
Qux qux;
function new();
qux = new;
endfunction
function void test;
qux.x = 42;
qux.rand_mode(0);
if (qux.x.rand_mode == 1) $stop;
void'(qux.randomize());
if (qux.x != 42) $stop;
endfunction
endclass
class Quux;
rand int x;
endclass
module t;
initial begin
logic ok = 0;
int res;
Baz baz = new;
Qux qux = new;
Quux quux = new;
baz.test;
qux.test;
qux.x.rand_mode(0);
if (qux.x.rand_mode == 1) $stop;
qux.y.rand_mode(1);
if (qux.y.rand_mode == 0) $stop;
qux.foo.a.rand_mode(1);
if (qux.foo.a.rand_mode == 0) $stop;
qux.foo.b.rand_mode(0);
if (qux.foo.b.rand_mode == 1) $stop;
for (int i = 0; i < 20; ++i) begin
qux.x = 5;
qux.y = 8;
qux.foo.a = 13;
qux.foo.b = 21;
res = qux.randomize() with {y > 5;};
if (qux.x >= qux.y) $stop;
if (qux.y <= 5) $stop;
if (qux.x != 5) $stop;
if (qux.y != 8) ok = 1;
if (qux.foo.a != 13) ok = 1;
if (qux.foo.b != 21) $stop;
end
if (!ok) $stop;
quux.x.rand_mode(0);
quux.x = 1000;
res = quux.randomize() with {x != 1000;};
if (quux.x != 1000) $stop;
quux.rand_mode(1);
res = quux.randomize() with {x != 1000;};
if (quux.x == 1000) $stop;
qux.x = 1024;
qux.y = 512;
qux.rand_mode(0);
if (qux.randomize() == 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,10 @@
%Error-UNSUPPORTED: t/t_randomize_rand_mode_unsup.v:15:22: Unsupported: 'rand_mode()' on dynamic array element
: ... note: In instance 't'
15 | p.m_dyn_arr[0].rand_mode(0);
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_randomize_rand_mode_unsup.v:16:22: Unsupported: 'rand_mode()' on unpacked array element
: ... note: In instance 't'
16 | p.m_unp_arr[0].rand_mode(0);
| ^~~~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2019 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
scenarios(vlt => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,18 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int m_dyn_arr[];
rand int m_unp_arr[10];
endclass
module t;
initial begin
Packet p = new;
p.m_dyn_arr[0].rand_mode(0);
p.m_unp_arr[0].rand_mode(0);
end
endmodule

View File

@ -1,115 +0,0 @@
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:22:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
22 | m_one.rand_mode(0);
| ^~~~~~~~~
... 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_rand_mode.v:23:136: rand_mode ignored (unsupported)
: ... note: In instance 't'
23 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",23, (m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:23:21: rand_mode ignored (unsupported)
: ... note: In instance 't'
23 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",23, (m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:24:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
24 | m_two.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:25:136: rand_mode ignored (unsupported)
: ... note: In instance 't'
25 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",25, (m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:25:21: rand_mode ignored (unsupported)
: ... note: In instance 't'
25 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",25, (m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:44:17: rand_mode ignored (unsupported)
: ... note: In instance 't'
44 | if (m_one.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:45:17: rand_mode ignored (unsupported)
: ... note: In instance 't'
45 | if (m_two.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:28:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
28 | m_one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:29:136: rand_mode ignored (unsupported)
: ... note: In instance 't'
29 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",29, (m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:29:21: rand_mode ignored (unsupported)
: ... note: In instance 't'
29 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",29, (m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:30:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
30 | m_two.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:31:136: rand_mode ignored (unsupported)
: ... note: In instance 't'
31 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",31, (m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:31:21: rand_mode ignored (unsupported)
: ... note: In instance 't'
31 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",31, (m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:85:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
85 | p.m_one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:86:140: rand_mode ignored (unsupported)
: ... note: In instance 't'
86 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",86, (p.m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:86:23: rand_mode ignored (unsupported)
: ... note: In instance 't'
86 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",86, (p.m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:87:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
87 | p.m_two.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:88:140: rand_mode ignored (unsupported)
: ... note: In instance 't'
88 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",88, (p.m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:88:23: rand_mode ignored (unsupported)
: ... note: In instance 't'
88 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",88, (p.m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:91:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
91 | p.m_one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:92:140: rand_mode ignored (unsupported)
: ... note: In instance 't'
92 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",92, (p.m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:92:23: rand_mode ignored (unsupported)
: ... note: In instance 't'
92 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",92, (p.m_one.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:93:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
93 | p.m_two.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:94:140: rand_mode ignored (unsupported)
: ... note: In instance 't'
94 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",94, (p.m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:94:23: rand_mode ignored (unsupported)
: ... note: In instance 't'
94 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",94, (p.m_two.rand_mode()), (1)); $stop; end while(0);;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:97:9: rand_mode ignored (unsupported)
: ... note: In instance 't'
97 | p.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:100:9: rand_mode ignored (unsupported)
: ... note: In instance 't'
100 | p.rand_mode(0);
| ^~~~~~~~~
%Error: Exiting due to