mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support rand_mode
(#5273)
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
parent
403a197e23
commit
2f5c58b345
@ -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;
|
||||
|
@ -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
|
||||
|
@ -2834,6 +2834,7 @@ void AstCMethodHard::setPurity() {
|
||||
{"reverse", false},
|
||||
{"rsort", false},
|
||||
{"set", false},
|
||||
{"set_randmode", false},
|
||||
{"shuffle", false},
|
||||
{"size", true},
|
||||
{"slice", true},
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
|
9
test_regress/t/t_randomize_inline_var_ctl_unsup.out
Normal file
9
test_regress/t/t_randomize_inline_var_ctl_unsup.out
Normal 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
|
19
test_regress/t/t_randomize_inline_var_ctl_unsup.pl
Executable file
19
test_regress/t/t_randomize_inline_var_ctl_unsup.pl
Executable 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;
|
16
test_regress/t/t_randomize_inline_var_ctl_unsup.v
Normal file
16
test_regress/t/t_randomize_inline_var_ctl_unsup.v
Normal 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
|
@ -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(
|
||||
|
@ -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);
|
||||
|
27
test_regress/t/t_randomize_rand_mode_bad.out
Normal file
27
test_regress/t/t_randomize_rand_mode_bad.out
Normal 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
|
@ -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},
|
28
test_regress/t/t_randomize_rand_mode_bad.v
Normal file
28
test_regress/t/t_randomize_rand_mode_bad.v
Normal 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
|
25
test_regress/t/t_randomize_rand_mode_constr.pl
Executable file
25
test_regress/t/t_randomize_rand_mode_constr.pl
Executable 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;
|
143
test_regress/t/t_randomize_rand_mode_constr.v
Normal file
143
test_regress/t/t_randomize_rand_mode_constr.v
Normal 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
|
10
test_regress/t/t_randomize_rand_mode_unsup.out
Normal file
10
test_regress/t/t_randomize_rand_mode_unsup.out
Normal 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
|
19
test_regress/t/t_randomize_rand_mode_unsup.pl
Executable file
19
test_regress/t/t_randomize_rand_mode_unsup.pl
Executable 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;
|
18
test_regress/t/t_randomize_rand_mode_unsup.v
Normal file
18
test_regress/t/t_randomize_rand_mode_unsup.v
Normal 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
|
@ -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
|
Loading…
Reference in New Issue
Block a user