Support passing constraints to --xml-only output (still otherwise unsupported) (#4683)

This commit is contained in:
Wilson Snyder 2023-11-11 20:20:37 -05:00 committed by GitHub
parent 673f086e87
commit 99dbd23f1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1114 additions and 299 deletions

View File

@ -20,6 +20,7 @@ Verilator 5.019 devel
**Minor:**
* Support ccache when compiling Verilator with CMake (#4678). [Anthony Donlon]
* Support passing constraints to --xml-only output (still otherwise unsupported) (#4683). [Shahid Ikram]
* Remove deprecated options (#4663). [Geza Lore]
* Optimize timing-delayed queue (#4584). [qrqiuren]
* Fix VPI TOP level variable iteration (#3919) (#4618). [Marlon James]

View File

@ -1447,18 +1447,21 @@ AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin,
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);
}
AstNodeDType* AstNode::findConstraintRefDType() const {
return v3Global.rootp()->typeTablep()->findConstraintRefDType(fileline());
}
AstNodeDType* AstNode::findEmptyQueueDType() const {
return v3Global.rootp()->typeTablep()->findEmptyQueueDType(fileline());
}
AstNodeDType* AstNode::findQueueIndexDType() const {
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
}
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
AstNodeDType* AstNode::findStreamDType() const {
return v3Global.rootp()->typeTablep()->findStreamDType(fileline());
}
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
while (true) {

View File

@ -2121,8 +2121,8 @@ public:
void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
void dtypeSetVoid() { dtypep(findVoidDType()); }
void dtypeSetStream() { dtypep(findStreamDType()); }
void dtypeSetVoid() { dtypep(findVoidDType()); }
// Data type locators
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
@ -2132,10 +2132,11 @@ public:
AstNodeDType* findUInt32DType() const { return findBasicDType(VBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() const { return findBasicDType(VBasicDTypeKwd::UINT64); }
AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); }
AstNodeDType* findConstraintRefDType() const;
AstNodeDType* findEmptyQueueDType() const;
AstNodeDType* findVoidDType() const;
AstNodeDType* findStreamDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findStreamDType() const;
AstNodeDType* findVoidDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,

View File

@ -622,6 +622,32 @@ public:
return false;
}
};
class AstConstraintRefDType final : public AstNodeDType {
// For e.g. a reference to constraint for constraint_mode
public:
explicit AstConstraintRefDType(FileLine* fl)
: ASTGEN_SUPER_ConstraintRefDType(fl) {
dtypep(this);
}
ASTGEN_MEMBERS_AstConstraintRefDType;
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }
bool undead() const override { return true; }
AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* virtRefDTypep() const override { return nullptr; }
void virtRefDTypep(AstNodeDType* nodep) override {}
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
int widthAlignBytes() const override { return 1; }
int widthTotalBytes() const override { return 1; }
bool isCompound() const override { return false; }
};
class AstDefImplicitDType final : public AstNodeDType {
// For parsing enum/struct/unions that are declared with a variable rather than typedef
// This allows "var enum {...} a,b" to share the enum definition for both variables

View File

@ -1062,6 +1062,29 @@ public:
// May return nullptr on parse failure.
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
};
class AstConstraintRef final : public AstNodeExpr {
// A reference to a constraint identifier
// Not saving pointer to constraint yet, as constraint_mode is an unsupported construct
// @astgen op4 := scopeNamep : Optional[AstScopeName]
AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the constraint
string m_name; // Name of constraint
public:
AstConstraintRef(FileLine* fl, const string& name)
: ASTGEN_SUPER_ConstraintRef(fl)
, m_name{name} {
dtypep(findConstraintRefDType());
}
ASTGEN_MEMBERS_AstConstraintRef;
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
void name(const string& name) override { m_name = name; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
};
class AstCvtDynArrayToPacked final : public AstNodeExpr {
// Cast from dynamic queue data type to packed array
// @astgen op1 := fromp : AstNodeExpr
@ -1905,6 +1928,7 @@ public:
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
bool hasDType() const override { return false; }
};
class AstSetAssoc final : public AstNodeExpr {
// Set an assoc array element and return object, '{}

View File

@ -434,6 +434,21 @@ public:
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := arrayp : AstNode
// @astgen op2 := stmtsp : List[AstNode]
public:
AstNodeForeach(VNType t, FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: AstNodeStmt(t, fl) {
this->arrayp(arrayp);
this->addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstNodeForeach;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* /*samep*/) const override { return true; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := thensp : List[AstNode]
@ -965,6 +980,40 @@ public:
// false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true.
AstVarScope* findConst(AstConst* initp, bool mergeDType);
};
class AstConstraint final : public AstNode {
// Constraint
// @astgen op1 := itemsp : List[AstNode]
string m_name; // Name of constraint
bool m_isStatic = false; // static constraint
public:
AstConstraint(FileLine* fl, const string& name, AstNode* itemsp)
: ASTGEN_SUPER_Constraint(fl)
, m_name(name) {
this->addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstConstraint;
string name() const override VL_MT_STABLE { return m_name; } // * = Scope name
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
void isStatic(bool flag) { m_isStatic = flag; }
bool isStatic() const { return m_isStatic; }
};
class AstConstraintBefore final : public AstNode {
// Constraint solve before item
// @astgen op1 := lhssp : List[AstNodeExpr]
// @astgen op2 := rhssp : List[AstNodeExpr]
public:
AstConstraintBefore(FileLine* fl, AstNodeExpr* lhssp, AstNodeExpr* rhssp)
: ASTGEN_SUPER_ConstraintBefore(fl) {
this->addLhssp(lhssp);
this->addRhssp(rhssp);
}
ASTGEN_MEMBERS_AstConstraintBefore;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstDefParam final : public AstNode {
// A defparam assignment
// Parents: MODULE
@ -983,6 +1032,24 @@ public:
bool same(const AstNode*) const override { return true; }
string path() const { return m_path; }
};
class AstDistItem final : public AstNode {
// Constraint distribution item
// @astgen op1 := rangep : AstNodeExpr
// @astgen op2 := weightp : AstNodeExpr
bool m_isWhole = false; // True for weight ':/', false for ':='
public:
AstDistItem(FileLine* fl, AstNodeExpr* rangep, AstNodeExpr* weightp)
: ASTGEN_SUPER_DistItem(fl) {
this->rangep(rangep);
this->weightp(weightp);
}
ASTGEN_MEMBERS_AstDistItem;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
void isWhole(bool flag) { m_isWhole = flag; }
bool isWhole() const { return m_isWhole; }
};
class AstDpiExport final : public AstNode {
// We could put an AstNodeFTaskRef instead of the verilog function name,
// however we're not *calling* it, so that seems somehow wrong.
@ -1560,10 +1627,11 @@ public:
class AstTypeTable final : public AstNode {
// Container for hash of standard data types
// @astgen op1 := typesp : List[AstNodeDType]
AstConstraintRefDType* m_constraintRefp = nullptr;
AstEmptyQueueDType* m_emptyQueuep = nullptr;
AstQueueDType* m_queueIndexp = nullptr;
AstVoidDType* m_voidp = nullptr;
AstStreamDType* m_streamp = nullptr;
AstVoidDType* m_voidp = nullptr;
AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{};
//
using DetailedMap = std::map<VBasicTypeKey, AstBasicDType*>;
@ -1586,10 +1654,11 @@ public:
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range,
int widthMin, VSigning numeric);
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
AstConstraintRefDType* findConstraintRefDType(FileLine* fl);
AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl);
AstQueueDType* findQueueIndexDType(FileLine* fl);
AstVoidDType* findVoidDType(FileLine* fl);
AstStreamDType* findStreamDType(FileLine* fl);
AstVoidDType* findVoidDType(FileLine* fl);
void clearCache();
void repairCache();
void dump(std::ostream& str = std::cout) const override;
@ -2562,6 +2631,38 @@ public:
bool same(const AstNode* samep) const override { return true; } // Ignore name in comments
virtual bool showAt() const { return m_showAt; }
};
class AstConstraintExpr final : public AstNodeStmt {
// Constraint expression
// @astgen op1 := exprp : AstNodeExpr
bool m_isSoft = false; // Soft constraint expression
bool m_isDisableSoft = false; // Disable soft constraint expression
public:
AstConstraintExpr(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_ConstraintExpr(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstConstraintExpr;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
void isDisableSoft(bool flag) { m_isDisableSoft = flag; }
bool isDisableSoft() const { return m_isDisableSoft; }
void isSoft(bool flag) { m_isSoft = flag; }
bool isSoft() const { return m_isSoft; }
};
class AstConstraintUnique final : public AstNodeStmt {
// Constraint unique statement
// @astgen op1 := rangesp : List[AstNode]
public:
AstConstraintUnique(FileLine* fl, AstNode* rangesp)
: ASTGEN_SUPER_ConstraintUnique(fl) {
this->addRangesp(rangesp);
}
ASTGEN_MEMBERS_AstConstraintUnique;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstContinue final : public AstNodeStmt {
public:
explicit AstContinue(FileLine* fl)
@ -2869,21 +2970,6 @@ public:
ASTGEN_MEMBERS_AstFireEvent;
bool isDelayed() const { return m_delayed; }
};
class AstForeach final : public AstNodeStmt {
// @astgen op1 := arrayp : AstNode
// @astgen op2 := stmtsp : List[AstNode]
public:
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: ASTGEN_SUPER_Foreach(fl) {
this->arrayp(arrayp);
this->addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstForeach;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool same(const AstNode* /*samep*/) const override { return true; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstJumpBlock final : public AstNodeStmt {
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
// Parents: {statement list}
@ -3539,7 +3625,28 @@ public:
ASTGEN_MEMBERS_AstGenFor;
};
// === AstNodeForeach ===
class AstConstraintForeach final : public AstNodeForeach {
// Constraint foreach statement
public:
AstConstraintForeach(FileLine* fl, AstNodeExpr* exprp, AstNode* bodysp)
: ASTGEN_SUPER_ConstraintForeach(fl, exprp, bodysp) {}
ASTGEN_MEMBERS_AstConstraintForeach;
};
class AstForeach final : public AstNodeForeach {
public:
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp)
: ASTGEN_SUPER_Foreach(fl, arrayp, stmtsp) {}
ASTGEN_MEMBERS_AstForeach;
};
// === AstNodeIf ===
class AstConstraintIf final : public AstNodeIf {
public:
AstConstraintIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstConstraintIf;
};
class AstGenIf final : public AstNodeIf {
public:
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)

View File

@ -1096,6 +1096,14 @@ void AstTypeTable::repairCache() {
}
}
AstConstraintRefDType* AstTypeTable::findConstraintRefDType(FileLine* fl) {
if (VL_UNLIKELY(!m_constraintRefp)) {
AstConstraintRefDType* const newp = new AstConstraintRefDType{fl};
addTypesp(newp);
m_constraintRefp = newp;
}
return m_constraintRefp;
}
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
if (VL_UNLIKELY(!m_emptyQueuep)) {
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
@ -1104,16 +1112,6 @@ AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
}
return m_emptyQueuep;
}
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
if (VL_UNLIKELY(!m_voidp)) {
AstVoidDType* const newp = new AstVoidDType{fl};
addTypesp(newp);
m_voidp = newp;
}
return m_voidp;
}
AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) {
if (VL_UNLIKELY(!m_streamp)) {
AstStreamDType* const newp = new AstStreamDType{fl};
@ -1122,7 +1120,6 @@ AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) {
}
return m_streamp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr};
@ -1131,6 +1128,14 @@ AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
}
return m_queueIndexp;
}
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
if (VL_UNLIKELY(!m_voidp)) {
AstVoidDType* const newp = new AstVoidDType{fl};
addTypesp(newp);
m_voidp = newp;
}
return m_voidp;
}
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
@ -1467,7 +1472,7 @@ void AstClassPackage::cloneRelink() {
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
}
bool AstClass::isCacheableChild(const AstNode* nodep) {
return (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
return (VN_IS(nodep, Var) || VN_IS(nodep, Constraint) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|| VN_IS(nodep, CFunc));
}

View File

@ -235,6 +235,8 @@ public:
}
} else if (VN_IS(nodep, Cell)) {
return "instance";
} else if (VN_IS(nodep, Constraint)) {
return "constraint";
} else if (VN_IS(nodep, Task)) {
return "task";
} else if (VN_IS(nodep, Func)) {
@ -1188,6 +1190,11 @@ class LinkDotFindVisitor final : public VNVisitor {
nodep->varp(newvarp);
iterate(nodep->exprp());
}
void visit(AstConstraint* nodep) override {
VL_RESTORER(m_curSymp);
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
iterateChildren(nodep);
}
void visit(AstVar* nodep) override {
// Var: Remember its name for later resolution
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
@ -1429,7 +1436,7 @@ class LinkDotFindVisitor final : public VNVisitor {
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
// Symbol table needs nodep->name() as the index variable's name
VL_RESTORER(m_curSymp);
{
@ -1810,7 +1817,7 @@ class LinkDotScopeVisitor final : public VNVisitor {
symp->fallbackp(m_modSymp);
iterateChildren(nodep);
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
@ -2803,6 +2810,13 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else if (AstConstraint* const consp = VN_CAST(foundp->nodep(), Constraint)) {
AstNode* const newp = new AstConstraintRef{nodep->fileline(), consp->name()};
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
ok = true;
m_ds.m_dotPos = DP_MEMBER;
m_ds.m_dotText = "";
} else if (AstEnumItem* const valuep = VN_CAST(foundp->nodep(), EnumItem)) {
if (allowVar) {
AstNode* const newp
@ -2936,6 +2950,12 @@ private:
<< nodep->classOrPackageNodep()->prettyName() << "#()'");
}
}
void visit(AstConstraintRef* nodep) override {
if (nodep->user3SetOnce()) return;
UINFO(8, " " << nodep << endl);
UINFO(8, " " << m_ds.ascii() << endl);
// No children defined
}
void visit(AstVarRef* nodep) override {
// VarRef: Resolve its reference
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
@ -3388,7 +3408,7 @@ private:
m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp);
m_ftaskp = nullptr;
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
VL_RESTORER(m_curSymp);

View File

@ -129,7 +129,7 @@ private:
// Done the loop
m_insStmtp = nullptr; // Next thing should be new statement
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
// Special, as statements need to be put in different places
// Body insert just before themselves
m_insStmtp = nullptr; // First thing should be new statement

View File

@ -245,7 +245,7 @@ private:
whilep->addHereThisAsNext(copiedBodyp);
}
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
VL_RESTORER(m_loopp);
{
m_loopp = nodep;

View File

@ -242,6 +242,10 @@ private:
}
}
void visit(AstNodeDType* nodep) override { visitIterateNodeDType(nodep); }
void visit(AstConstraint* nodep) override {
v3Global.useRandomizeMethods(true);
iterateChildren(nodep);
}
void visit(AstEnumDType* nodep) override {
if (nodep->name() == "") {
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
@ -533,7 +537,7 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
// FOREACH(array, loopvars, body)
UINFO(9, "FOREACH " << nodep << endl);
cleanFileline(nodep);

View File

@ -358,6 +358,10 @@ private:
addPrePostCall(nodep, funcp, "post_randomize");
nodep->user1(false);
}
void visit(AstConstraint* nodep) override {
nodep->v3warn(CONSTRAINTIGN, "Constraint ignored (unsupported)");
if (!v3Global.opt.xmlOnly()) VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
void visit(AstRandCase* nodep) override {
// RANDCASE
// CASEITEM expr1 : stmt1

View File

@ -1693,6 +1693,10 @@ private:
// visit
VL_DO_DANGLING(userIterate(newp, nullptr), newp);
}
void visit(AstConstraintRefDType* nodep) override {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
nodep->dtypep(nodep);
}
void visit(AstDynArrayDType* nodep) override {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
// Iterate into subDTypep() to resolve that type and update pointer.
@ -2090,6 +2094,20 @@ private:
VL_DANGLING(underp);
}
}
void visit(AstConstraintBefore* nodep) override {
userIterateAndNext(nodep->lhssp(), WidthVP{SELF, BOTH}.p());
userIterateAndNext(nodep->rhssp(), WidthVP{SELF, BOTH}.p());
}
void visit(AstConstraintExpr* nodep) override {
userIterateAndNext(nodep->exprp(), WidthVP{SELF, BOTH}.p());
}
void visit(AstConstraintUnique* nodep) override {
userIterateAndNext(nodep->rangesp(), WidthVP{SELF, BOTH}.p());
}
void visit(AstDistItem* nodep) override {
userIterate(nodep->rangep(), WidthVP{SELF, BOTH}.p());
userIterate(nodep->weightp(), WidthVP{SELF, BOTH}.p());
}
void visit(AstVar* nodep) override {
// if (debug()) nodep->dumpTree("- InitPre: ");
// Must have deterministic constant width
@ -2791,6 +2809,13 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return true;
}
if (VN_IS(foundp, Constraint)) {
// We don't support constraints yet, so just keep as unlinked for now
// Presumably we'll next see a constraint_mode AstMethodCall
nodep->dtypep(nodep->findConstraintRefDType());
UINFO(9, "Unsupported constraint select " << nodep << endl);
return true;
}
UINFO(1, "found object " << foundp << endl);
nodep->v3fatalSrc("MemberSel of non-variable\n"
<< nodep->warnContextPrimary() << '\n'
@ -2803,7 +2828,7 @@ private:
VSpellCheck speller;
for (AstClass* classp = first_classp; classp;) {
for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var) || VN_IS(itemp, EnumItemRef)) {
if (VN_IS(itemp, Constraint) || VN_IS(itemp, EnumItemRef) || VN_IS(itemp, Var)) {
speller.pushCandidate(itemp->prettyName());
}
}
@ -2915,8 +2940,8 @@ private:
methodCallClass(nodep, adtypep);
} else if (AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
methodCallUnpack(nodep, adtypep);
} else if (basicp && nodep->name() == "constraint_mode") {
methodCallConstraint(nodep, basicp);
} else if (AstConstraintRefDType* const adtypep = VN_CAST(fromDtp, ConstraintRefDType)) {
methodCallConstraint(nodep, adtypep);
} else if (basicp && basicp->isEvent()) {
methodCallEvent(nodep, basicp);
} else if (basicp && basicp->isString()) {
@ -3557,6 +3582,11 @@ private:
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
} else if (nodep->name() == "constraint_mode") {
nodep->v3warn(CONSTRAINTIGN, "Unsupported: 'constraint_mode' called on object");
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
}
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
}
@ -3576,8 +3606,8 @@ private:
}
nodep->dtypeSetSigned32(); // Guess on error
}
void methodCallConstraint(AstMethodCall* nodep, AstBasicDType*) {
// Method call on constraint (currently hacked as just a var)
void methodCallConstraint(AstMethodCall* nodep, AstConstraintRefDType*) {
// Method call on constraint
if (nodep->name() == "constraint_mode") {
methodOkArguments(nodep, 0, 1);
nodep->v3warn(CONSTRAINTIGN, "constraint_mode ignored (unsupported)");
@ -3585,7 +3615,9 @@ private:
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else {
nodep->v3fatalSrc("Unknown built-in constraint method " << nodep->prettyNameQ());
nodep->v3error("No such constraint method " << nodep->prettyNameQ());
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
void methodCallRandMode(AstMethodCall* nodep) {
@ -4549,7 +4581,9 @@ private:
userIterateAndNext(nodep->resultp(), m_vup);
nodep->dtypeFrom(nodep->resultp());
}
void visit(AstForeach* nodep) override {
void visit(AstNodeForeach* nodep) override {
if (nodep->didWidth()) return;
nodep->didWidth(true);
const AstSelLoopVars* const loopsp = VN_CAST(nodep->arrayp(), SelLoopVars);
UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach");
// if (debug()) nodep->dumpTree("- foreach-old: ");
@ -4558,20 +4592,16 @@ private:
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
// Split into for loop
AstNode* bodyp = nodep->stmtsp(); // Might be null
if (bodyp) bodyp->unlinkFrBackWithNext();
// We record where the body needs to eventually go with bodyPointp
// (Can't use bodyp as might be null)
AstNode* lastBodyPointp = nullptr;
AstNode* newp = nullptr;
// Major dimension first
while (AstNode* argsp
= loopsp->elementsp()) { // Loop advances due to below varp->unlinkFrBack()
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
next_argsp = argsp->nextp();
const bool empty = VN_IS(argsp, Empty);
AstVar* const varp = VN_CAST(argsp, Var);
UASSERT_OBJ(varp || empty, argsp, "Missing foreach loop variable");
if (varp) varp->usedLoopIdx(true);
argsp->unlinkFrBack();
if (!fromDtp) {
argsp->v3error("foreach loop variables exceed number of indices of array");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
@ -4582,121 +4612,138 @@ private:
UINFO(9, "- from on " << fromp << endl);
UINFO(9, "- from dtp " << fromDtp << endl);
FileLine* const fl = argsp->fileline();
AstNode* bodyPointp = new AstBegin{fl, "[EditWrapper]", nullptr};
AstNode* loopp = nullptr;
if (const AstNodeArrayDType* const adtypep = VN_CAST(fromDtp, NodeArrayDType)) {
if (varp) {
loopp = createForeachLoopRanged(nodep, bodyPointp, varp, adtypep->declRange());
}
if (VN_IS(nodep, ConstraintForeach)) {
// For now unsupported
userIterate(varp, nullptr);
// Prep for next
fromDtp = fromDtp->subDTypep();
} else if (AstBasicDType* const adtypep = VN_CAST(fromDtp, BasicDType)) {
if (adtypep->isString()) {
if (varp) {
AstConst* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
AstLt* const condp
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ},
new AstLenN{fl, fromp->cloneTreePure(false)}};
AstAdd* const incp
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
new AstVarRef{fl, varp, VAccess::READ}};
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
}
} else if (!adtypep->isRanged()) {
argsp->v3error("Illegal to foreach loop on basic '" + fromDtp->prettyTypeName()
+ "'");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
VL_DO_DANGLING(bodyPointp->deleteTree(), bodyPointp);
return;
} else {
fromDtp = nullptr;
} else {
argsp->unlinkFrBack();
FileLine* const fl = argsp->fileline();
AstNode* bodyPointp = new AstBegin{fl, "[EditWrapper]", nullptr};
AstNode* loopp = nullptr;
if (const AstNodeArrayDType* const adtypep = VN_CAST(fromDtp, NodeArrayDType)) {
if (varp) {
loopp = createForeachLoopRanged(nodep, bodyPointp, varp,
adtypep->declRange());
}
}
// Prep for next
fromDtp = nullptr;
} else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) {
if (varp) {
auto* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
auto* const sizep
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"};
sizep->dtypeSetSigned32();
sizep->didWidth(true);
sizep->protect(false);
AstNodeExpr* const condp
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, sizep};
AstNodeExpr* const incp
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
new AstVarRef{fl, varp, VAccess::READ}};
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
}
// Prep for next
fromDtp = fromDtp->subDTypep();
} else if (const AstAssocArrayDType* const adtypep
= VN_CAST(fromDtp, AssocArrayDType)) {
// Make this: var KEY_TYPE index;
// bit index__Vfirst;
// index__Vfirst = 0;
// if (0 != array.first(index))
// do body while (index__Vfirst || 0 != array.next(index))
varp->dtypeFrom(adtypep->keyDTypep());
AstVar* const first_varp = new AstVar{
fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1};
first_varp->usedLoopIdx(true);
AstNodeExpr* const firstp = new AstMethodCall{
fl, fromp->cloneTreePure(false), "first",
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
AstNodeExpr* const nextp = new AstMethodCall{
fl, fromp->cloneTreePure(false), "next",
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
AstNode* const first_clearp
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}};
auto* const orp = new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
AstNode* const whilep = new AstWhile{fl, orp, first_clearp};
first_clearp->addNext(bodyPointp);
AstNode* const ifbodyp
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}};
ifbodyp->addNext(whilep);
AstNode* const stmtsp = varp; // New statements for under new Begin
stmtsp->addNext(first_varp);
stmtsp->addNext(
new AstIf{fl, new AstNeq{fl, new AstConst{fl, 0}, firstp}, ifbodyp});
loopp = new AstBegin{nodep->fileline(), "", stmtsp, false, true};
// Prep for next
fromDtp = fromDtp->subDTypep();
} else {
argsp->v3error("Illegal to foreach loop on '" + fromDtp->prettyTypeName() + "'");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
// New loop goes UNDER previous loop
if (varp) {
if (!newp) {
newp = loopp;
// Prep for next
fromDtp = fromDtp->subDTypep();
} else if (AstBasicDType* const adtypep = VN_CAST(fromDtp, BasicDType)) {
if (adtypep->isString()) {
if (varp) {
AstConst* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
AstLt* const condp
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ},
new AstLenN{fl, fromp->cloneTreePure(false)}};
AstAdd* const incp
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
new AstVarRef{fl, varp, VAccess::READ}};
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
}
} else if (!adtypep->isRanged()) {
argsp->v3error("Illegal to foreach loop on basic '"
+ fromDtp->prettyTypeName() + "'");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
VL_DO_DANGLING(bodyPointp->deleteTree(), bodyPointp);
return;
} else {
if (varp) {
loopp = createForeachLoopRanged(nodep, bodyPointp, varp,
adtypep->declRange());
}
}
// Prep for next
fromDtp = nullptr;
} else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) {
if (varp) {
auto* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
auto* const sizep
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"};
sizep->dtypeSetSigned32();
sizep->didWidth(true);
sizep->protect(false);
AstNodeExpr* const condp
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, sizep};
AstNodeExpr* const incp
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
new AstVarRef{fl, varp, VAccess::READ}};
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
}
// Prep for next
fromDtp = fromDtp->subDTypep();
} else if (const AstAssocArrayDType* const adtypep
= VN_CAST(fromDtp, AssocArrayDType)) {
// Make this: var KEY_TYPE index;
// bit index__Vfirst;
// index__Vfirst = 0;
// if (0 != array.first(index))
// do body while (index__Vfirst || 0 != array.next(index))
varp->dtypeFrom(adtypep->keyDTypep());
AstVar* const first_varp = new AstVar{
fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1};
first_varp->usedLoopIdx(true);
AstNodeExpr* const firstp = new AstMethodCall{
fl, fromp->cloneTreePure(false), "first",
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
AstNodeExpr* const nextp = new AstMethodCall{
fl, fromp->cloneTreePure(false), "next",
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
AstNode* const first_clearp
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitFalse{}}};
auto* const orp
= new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
AstNode* const whilep = new AstWhile{fl, orp, first_clearp};
first_clearp->addNext(bodyPointp);
AstNode* const ifbodyp
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
new AstConst{fl, AstConst::BitTrue{}}};
ifbodyp->addNext(whilep);
AstNode* const stmtsp = varp; // New statements for under new Begin
stmtsp->addNext(first_varp);
stmtsp->addNext(
new AstIf{fl, new AstNeq{fl, new AstConst{fl, 0}, firstp}, ifbodyp});
loopp = new AstBegin{nodep->fileline(), "", stmtsp, false, true};
// Prep for next
fromDtp = fromDtp->subDTypep();
} else {
lastBodyPointp->replaceWith(loopp);
argsp->v3error("Illegal to foreach loop on '" + fromDtp->prettyTypeName()
+ "'");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
// New loop goes UNDER previous loop
if (varp) {
if (!newp) {
newp = loopp;
} else {
lastBodyPointp->replaceWith(loopp);
}
lastBodyPointp = bodyPointp;
}
lastBodyPointp = bodyPointp;
}
}
// The parser validates we don't have "foreach (array[,,,])"
UASSERT_OBJ(newp, nodep, "foreach has no non-empty loop variable");
if (bodyp) {
lastBodyPointp->replaceWith(bodyp);
AstNode* const bodyp = nodep->stmtsp();
if (VN_IS(nodep, ConstraintForeach)) {
userIterateAndNext(bodyp, nullptr);
} else {
lastBodyPointp->unlinkFrBack();
UASSERT_OBJ(newp, nodep, "foreach has no non-empty loop variable");
if (bodyp) {
lastBodyPointp->replaceWith(bodyp->unlinkFrBackWithNext());
} else {
lastBodyPointp->unlinkFrBack();
}
// if (debug()) newp->dumpTreeAndNext(cout, "- foreach-new: ");
nodep->replaceWith(newp);
if (lastBodyPointp) VL_DO_DANGLING(lastBodyPointp->deleteTree(), lastBodyPointp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
// if (debug()) newp->dumpTreeAndNext(cout, "- foreach-new: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(lastBodyPointp->deleteTree(), lastBodyPointp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
AstNode* createForeachLoopRanged(AstForeach* nodep, AstNode* bodysp, AstVar* varp,
AstNode* createForeachLoopRanged(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
const VNumRange& declRange) {
FileLine* const fl = varp->fileline();
AstNodeExpr* const leftp = new AstConst{fl, AstConst::Signed32{}, declRange.left()};
@ -4714,7 +4761,7 @@ private:
}
return createForeachLoop(nodep, bodysp, varp, leftp, condp, incp);
}
AstNode* createForeachLoop(AstForeach* nodep, AstNode* bodysp, AstVar* varp,
AstNode* createForeachLoop(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
AstNodeExpr* leftp, AstNodeExpr* condp, AstNodeExpr* incp) {
FileLine* const fl = varp->fileline();
auto* const whilep = new AstWhile{
@ -4973,6 +5020,7 @@ private:
nodep->text(newFormat);
UINFO(9, " Display out " << nodep->text() << endl);
}
void visit(AstConstraintRef* nodep) override { userIterateChildren(nodep, nullptr); }
void visit(AstDisplay* nodep) override {
assertAtStatement(nodep);
if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH);

View File

@ -4907,7 +4907,7 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
//
// // IEEE: expression_or_dist - here to avoid reduce problems
// // "expr yDIST '{' dist_list '}'"
| ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); }
| ~l~expr yDIST '{' dist_list '}' { $$ = $1; }
;
fexpr<nodeExprp>: // For use as first part of statement (disambiguates <=)
@ -7107,21 +7107,29 @@ memberQualOne<qualifiers>: // IEEE: property_qualifier + me
//**********************************************************************
// Constraints
class_constraint<nodep>: // ==IEEE: class_constraint
class_constraint<constraintp>: // ==IEEE: class_constraint
// // IEEE: constraint_declaration
// // UNSUP: We have the unsupported warning on the randomize() call, so don't bother on
// // constraint blocks. When we support randomize we need to make AST nodes for below rules
constraintStaticE yCONSTRAINT idAny constraint_block
{ // Variable so we can link and later ignore constraint_mode() methods
$$ = new AstVar{$<fl>3, VVarType::MEMBER, *$3, VFlagBitPacked{}, 1};
$2->v3warn(CONSTRAINTIGN, "Constraint ignored (unsupported)"); }
constraintStaticE yCONSTRAINT constraintIdNew constraint_block
{ $$ = $3; $$->isStatic($1); $$->addItemsp($4); SYMP->popScope($$); }
| constraintStaticE yCONSTRAINT constraintIdNew '{' '}'
{ $$ = $3; $$->isStatic($1); SYMP->popScope($$); }
// // IEEE: constraint_prototype + constraint_prototype_qualifier
| constraintStaticE yCONSTRAINT idAny ';'
{ $$ = nullptr; }
| yEXTERN constraintStaticE yCONSTRAINT idAny ';'
{ $$ = nullptr; BBUNSUP($1, "Unsupported: extern constraint"); }
| yPURE constraintStaticE yCONSTRAINT idAny ';'
{ $$ = nullptr; BBUNSUP($1, "Unsupported: pure constraint"); }
| constraintStaticE yCONSTRAINT constraintIdNew ';'
{ $$ = $3; $$->isStatic($1); SYMP->popScope($$); }
| yEXTERN constraintStaticE yCONSTRAINT constraintIdNew ';'
{ $$ = $4; $$->isStatic($1); SYMP->popScope($4);
BBUNSUP($1, "Unsupported: extern constraint"); }
| yPURE constraintStaticE yCONSTRAINT constraintIdNew ';'
{ $$ = $4; $$->isStatic($1); SYMP->popScope($4);
BBUNSUP($1, "Unsupported: pure constraint"); }
;
constraintIdNew<constraintp>: // IEEE: id part of class_constraint
idAny/*constraint_identifier*/
{ $$ = new AstConstraint{$<fl>1, *$1, nullptr};
SYMP->pushNewUnderNodeOrCurrent($$, nullptr); }
;
constraint_block<nodep>: // ==IEEE: constraint_block
@ -7136,15 +7144,15 @@ constraint_block_itemList<nodep>: // IEEE: { constraint_block_item }
constraint_block_item<nodep>: // ==IEEE: constraint_block_item
constraint_expression { $$ = $1; }
| ySOLVE solve_before_list yBEFORE solve_before_list ';'
{ $$ = nullptr; BBUNSUP($2, "Unsupported: solve before"); }
{ $$ = new AstConstraintBefore{$1, $2, $4}; }
;
solve_before_list<nodep>: // ==IEEE: solve_before_list
solve_before_list<nodeExprp>: // ==IEEE: solve_before_list
constraint_primary { $$ = $1; }
| solve_before_list ',' constraint_primary { $$ = addNextNull($1, $3); }
;
constraint_primary<nodep>: // ==IEEE: constraint_primary
constraint_primary<nodeExprp>: // ==IEEE: constraint_primary
// // exprScope more general than:
// // [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select
exprScope { $$ = $1; }
@ -7156,21 +7164,32 @@ constraint_expressionList<nodep>: // ==IEEE: { constraint_expression }
;
constraint_expression<nodep>: // ==IEEE: constraint_expression
expr/*expression_or_dist*/ ';' { $$ = $1; }
expr/*expression_or_dist*/ ';'
{ $$ = new AstConstraintExpr{$1->fileline(), $1}; }
// // 1800-2012:
| ySOFT expr/*expression_or_dist*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ }
| ySOFT expr/*expression_or_dist*/ ';'
{ AstConstraintExpr* const newp = new AstConstraintExpr{$1, $2};
newp->isSoft(true);
$$ = newp; }
// // 1800-2012:
// // IEEE: uniqueness_constraint ';'
| yUNIQUE '{' range_list '}' { $$ = nullptr; /*UNSUP-no-UVM*/ }
| yUNIQUE '{' range_list '}'
{ $$ = new AstConstraintUnique{$1, $3}; }
// // IEEE: expr yP_MINUSGT constraint_set
// // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there
//
| yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$ = nullptr; /*UNSUP-UVM*/ }
| yIF '(' expr ')' constraint_set yELSE constraint_set { $$ = nullptr; /*UNSUP-UVM*/ }
| yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE
{ $$ = new AstConstraintIf{$1, $3, $5, nullptr}; }
| yIF '(' expr ')' constraint_set yELSE constraint_set
{ $$ = new AstConstraintIf{$1, $3, $5, $7}; }
// // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009
| yFOREACH '(' idClassSelForeach ')' constraint_set { $$ = nullptr; /*UNSUP-UVM*/ }
| yFOREACH '(' idClassSelForeach ')' constraint_set
{ $$ = new AstConstraintForeach{$1, $3, $5}; }
// // soft is 1800-2012
| yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ }
| yDISABLE ySOFT expr/*constraint_primary*/ ';'
{ AstConstraintExpr* const newp = new AstConstraintExpr{$1, $3};
newp->isDisableSoft(true);
$$ = newp; }
;
constraint_set<nodep>: // ==IEEE: constraint_set
@ -7183,14 +7202,17 @@ dist_list<nodep>: // ==IEEE: dist_list
| dist_list ',' dist_item { $$ = addNextNull($1, $3); }
;
dist_item<nodep>: // ==IEEE: dist_item + dist_weight
value_range { $$ = $1; /* Same as := 1 */ }
| value_range yP_COLONEQ expr { $$ = $1; /*UNSUP-no-UVM*/ }
| value_range yP_COLONDIV expr { $$ = $1; /*UNSUP-no-UVM*/ }
dist_item<distItemp>: // ==IEEE: dist_item + dist_weight
value_range
{ $$ = new AstDistItem{$1->fileline(), $1, new AstConst{$1->fileline(), 1}}; }
| value_range yP_COLONEQ expr
{ $$ = new AstDistItem{$2, $1, $3}; }
| value_range yP_COLONDIV expr
{ $$ = new AstDistItem{$2, $1, $3}; $$->isWhole(true); }
;
extern_constraint_declaration<nodep>: // ==IEEE: extern_constraint_declaration
constraintStaticE yCONSTRAINT packageClassScopeE idAny
constraintStaticE yCONSTRAINT packageClassScopeE idAny constraint_block
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: extern constraint"); }
;

View File

@ -0,0 +1,5 @@
%Error: t/t_constraint_method_bad.v:13:12: No such constraint method 'bad_method'
: ... note: In instance 't'
13 | cons.bad_method(1);
| ^~~~~~~~~~
%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 2020 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(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,19 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int m_one;
constraint cons { m_one > 0 && m_one < 2; }
task test1;
cons.bad_method(1); // BAD
endtask
endclass
module t (/*AUTOARG*/);
endmodule

View File

@ -5,20 +5,17 @@
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int one;
rand int m_one;
constraint a { one > 0 && one < 2; }
constraint cons { m_one > 0 && m_one < 2; }
Packet other;
task test1;
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
one.rand_mode(0);
one.rand_mode(1);
if (one.rand_mode() != 1) $stop;
// TODO Verilator ignores this setting currently, always returning 0 (constraint off)
a.constraint_mode(1);
a.constraint_mode(0);
if (a.constraint_mode() != 0) $stop;
cons.constraint_mode(1);
cons.constraint_mode(0);
if (cons.constraint_mode() != 0) $stop;
endtask
endclass
@ -34,23 +31,34 @@ module t (/*AUTOARG*/);
v = p.randomize();
if (v != 1) $stop;
`ifndef VERILATOR
if (p.one != 1) $stop;
if (p.m_one != 1) $stop;
`endif
// IEEE: function void object[.constraint_identifier].constraint_mode(bit on_off);
// IEEE: function int object.constraint_identifier.constraint_mode();
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
p.one.rand_mode(0);
p.one.rand_mode(1);
if (p.one.rand_mode() != 1) $stop;
// TODO test that these control constraints as specified
p.constraint_mode(0);
p.constraint_mode(1);
// Not legal to get current constraint_mode() value on a class-only call
// TODO Verilator ignores this setting currently, always returning 0 (constraint off)
p.a.constraint_mode(1);
p.a.constraint_mode(0);
if (p.a.constraint_mode() != 0) $stop;
// TODO test that these control constraints as specified
p.cons.constraint_mode(1);
p.cons.constraint_mode(0);
if (p.cons.constraint_mode() != 0) $stop;
// TODO Verilator ignores this setting currently, always returning 0 (constraint off)
// TODO test that these control constraints as specified
p.other = new;
p.other.cons.constraint_mode(1);
p.other.cons.constraint_mode(0);
if (p.other.cons.constraint_mode() != 0) $stop;
p.test1();
// TODO test can't redefine constraint_mode
// TODO test can't redefine rand_mode
// TODO test can't call constraint_mode on non-constraint
$write("*-* All Finished *-*\n");

View File

@ -1,54 +1,51 @@
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:10:4: Constraint ignored (unsupported)
10 | constraint a { one > 0 && one < 2; }
| ^~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:16:12: constraint_mode ignored (unsupported)
: ... note: In instance 't'
16 | cons.constraint_mode(1);
| ^~~~~~~~~~~~~~~
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:14:11: rand_mode ignored (unsupported)
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:17:12: constraint_mode ignored (unsupported)
: ... note: In instance 't'
14 | one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:15:11: rand_mode ignored (unsupported)
17 | cons.constraint_mode(0);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:18:16: constraint_mode ignored (unsupported)
: ... note: In instance 't'
15 | one.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:16:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
16 | if (one.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:19:9: constraint_mode ignored (unsupported)
18 | if (cons.constraint_mode() != 0) $stop;
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:42:9: Unsupported: 'constraint_mode' called on object
: ... note: In instance 't'
19 | a.constraint_mode(1);
42 | p.constraint_mode(0);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:20:9: constraint_mode ignored (unsupported)
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:43:9: Unsupported: 'constraint_mode' called on object
: ... note: In instance 't'
20 | a.constraint_mode(0);
43 | p.constraint_mode(1);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:21:13: constraint_mode ignored (unsupported)
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:48:14: constraint_mode ignored (unsupported)
: ... note: In instance 't'
21 | if (a.constraint_mode() != 0) $stop;
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:41:13: rand_mode ignored (unsupported)
48 | p.cons.constraint_mode(1);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:49:14: constraint_mode ignored (unsupported)
: ... note: In instance 't'
41 | p.one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:42:13: rand_mode ignored (unsupported)
49 | p.cons.constraint_mode(0);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:50:18: constraint_mode ignored (unsupported)
: ... note: In instance 't'
42 | p.one.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:43:17: rand_mode ignored (unsupported)
50 | if (p.cons.constraint_mode() != 0) $stop;
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:55:20: constraint_mode ignored (unsupported)
: ... note: In instance 't'
43 | if (p.one.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:46:11: constraint_mode ignored (unsupported)
55 | p.other.cons.constraint_mode(1);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:56:20: constraint_mode ignored (unsupported)
: ... note: In instance 't'
46 | p.a.constraint_mode(1);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:47:11: constraint_mode ignored (unsupported)
56 | p.other.cons.constraint_mode(0);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:57:24: constraint_mode ignored (unsupported)
: ... note: In instance 't'
47 | p.a.constraint_mode(0);
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:48:15: constraint_mode ignored (unsupported)
57 | if (p.other.cons.constraint_mode() != 0) $stop;
| ^~~~~~~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:10:15: Constraint ignored (unsupported)
: ... note: In instance 't'
48 | if (p.a.constraint_mode() != 0) $stop;
| ^~~~~~~~~~~~~~~
10 | constraint cons { m_one > 0 && m_one < 2; }
| ^~~~
%Error: Exiting due to

View File

@ -0,0 +1,202 @@
<?xml version="1.0" ?>
<!-- DESCRIPTION: Verilator output: XML representation of netlist -->
<verilator_xml>
<files>
<file id="a" filename="&lt;built-in&gt;" language="1800-2017"/>
<file id="b" filename="&lt;command-line&gt;" language="1800-2017"/>
<file id="c" filename="input.vc" language="1800-2017"/>
<file id="d" filename="t/t_constraint_xml.v" language="1800-2017"/>
</files>
<module_files>
<file id="d" filename="t/t_constraint_xml.v" language="1800-2017"/>
</module_files>
<cells>
<cell loc="d,53,8,53,9" name="t" submodname="t" hier="t"/>
</cells>
<netlist>
<module loc="d,53,8,53,9" name="t" origName="t">
<var loc="d,55,11,55,12" name="p" dtype_id="1" vartype="Packet" origName="p"/>
<initial loc="d,57,4,57,11">
<begin loc="d,57,12,57,17">
<display loc="d,59,7,59,13" displaytype="$write">
<sformatf loc="d,59,7,59,13" name="*-* All Finished *-*&#10;" dtype_id="2"/>
</display>
<finish loc="d,60,7,60,14"/>
</begin>
</initial>
</module>
<package loc="a,0,0,0,0" name="$unit" origName="__024unit">
<class loc="d,7,1,7,6" name="Packet" origName="Packet">
<var loc="d,8,13,8,19" name="header" dtype_id="3" vartype="int" origName="header"/>
<var loc="d,9,13,9,19" name="length" dtype_id="3" vartype="int" origName="length"/>
<var loc="d,10,13,10,22" name="sublength" dtype_id="3" vartype="int" origName="sublength"/>
<var loc="d,11,13,11,17" name="if_4" dtype_id="4" vartype="bit" origName="if_4"/>
<var loc="d,12,13,12,20" name="iff_5_6" dtype_id="4" vartype="bit" origName="iff_5_6"/>
<var loc="d,14,13,14,18" name="array" dtype_id="5" vartype="" origName="array"/>
<constraint loc="d,16,15,16,20" name="empty"/>
<constraint loc="d,18,15,18,19" name="size">
<constraintexpr loc="d,19,18,19,20">
<and loc="d,19,18,19,20" dtype_id="6">
<lts loc="d,19,14,19,15" dtype_id="6">
<const loc="d,19,16,19,17" name="32&apos;sh0" dtype_id="7"/>
<varref loc="d,19,7,19,13" name="header" dtype_id="3"/>
</lts>
<gtes loc="d,19,28,19,30" dtype_id="6">
<const loc="d,19,31,19,32" name="32&apos;sh7" dtype_id="7"/>
<varref loc="d,19,21,19,27" name="header" dtype_id="3"/>
</gtes>
</and>
</constraintexpr>
<constraintexpr loc="d,20,14,20,16">
<gtes loc="d,20,14,20,16" dtype_id="6">
<const loc="d,20,17,20,19" name="32&apos;shf" dtype_id="7"/>
<varref loc="d,20,7,20,13" name="length" dtype_id="3"/>
</gtes>
</constraintexpr>
<constraintexpr loc="d,21,14,21,16">
<gtes loc="d,21,14,21,16" dtype_id="6">
<varref loc="d,21,7,21,13" name="length" dtype_id="3"/>
<varref loc="d,21,17,21,23" name="header" dtype_id="3"/>
</gtes>
</constraintexpr>
<constraintexpr loc="d,22,7,22,13">
<varref loc="d,22,7,22,13" name="length" dtype_id="3"/>
</constraintexpr>
</constraint>
<constraint loc="d,25,15,25,18" name="ifs">
<if loc="d,26,7,26,9">
<lts loc="d,26,18,26,19" dtype_id="6">
<const loc="d,26,20,26,21" name="32&apos;sh4" dtype_id="7"/>
<varref loc="d,26,11,26,17" name="header" dtype_id="3"/>
</lts>
<begin>
<constraintexpr loc="d,27,15,27,17">
<varref loc="d,27,10,27,14" name="if_4" dtype_id="6"/>
</constraintexpr>
</begin>
</if>
<if loc="d,29,7,29,9">
<or loc="d,29,23,29,25" dtype_id="6">
<eq loc="d,29,18,29,20" dtype_id="6">
<const loc="d,29,21,29,22" name="32&apos;sh5" dtype_id="7"/>
<varref loc="d,29,11,29,17" name="header" dtype_id="3"/>
</eq>
<eq loc="d,29,33,29,35" dtype_id="6">
<const loc="d,29,36,29,37" name="32&apos;sh6" dtype_id="7"/>
<varref loc="d,29,26,29,32" name="header" dtype_id="3"/>
</eq>
</or>
<begin>
<constraintexpr loc="d,30,18,30,20">
<varref loc="d,30,10,30,17" name="iff_5_6" dtype_id="6"/>
</constraintexpr>
</begin>
<begin>
<constraintexpr loc="d,32,18,32,20">
<not loc="d,32,18,32,20" dtype_id="4">
<varref loc="d,32,10,32,17" name="iff_5_6" dtype_id="4"/>
</not>
</constraintexpr>
</begin>
</if>
</constraint>
<constraint loc="d,36,15,36,23" name="arr_uniq">
<constraintforeach loc="d,37,7,37,14">
<selloopvars loc="d,37,21,37,22">
<varref loc="d,37,16,37,21" name="array" dtype_id="5"/>
<var loc="d,37,22,37,23" name="i" dtype_id="8" vartype="integer" origName="i"/>
</selloopvars>
<constraintexpr loc="d,38,19,38,25">
<or loc="d,38,19,38,25" dtype_id="6">
<or loc="d,38,19,38,25" dtype_id="6">
<eqwild loc="d,38,27,38,28" dtype_id="6">
<arraysel loc="d,38,15,38,16" dtype_id="3">
<varref loc="d,38,10,38,15" name="array" dtype_id="5"/>
<sel loc="d,38,16,38,17" dtype_id="9">
<varref loc="d,38,16,38,17" name="i" dtype_id="8"/>
<const loc="d,38,16,38,17" name="32&apos;h0" dtype_id="10"/>
<const loc="d,38,16,38,17" name="32&apos;h1" dtype_id="10"/>
</sel>
</arraysel>
<const loc="d,38,27,38,28" name="32&apos;sh2" dtype_id="7"/>
</eqwild>
<eqwild loc="d,38,30,38,31" dtype_id="6">
<arraysel loc="d,38,15,38,16" dtype_id="3">
<varref loc="d,38,10,38,15" name="array" dtype_id="5"/>
<sel loc="d,38,16,38,17" dtype_id="9">
<varref loc="d,38,16,38,17" name="i" dtype_id="8"/>
<const loc="d,38,16,38,17" name="32&apos;h0" dtype_id="10"/>
<const loc="d,38,16,38,17" name="32&apos;h1" dtype_id="10"/>
</sel>
</arraysel>
<const loc="d,38,30,38,31" name="32&apos;sh4" dtype_id="7"/>
</eqwild>
</or>
<eqwild loc="d,38,33,38,34" dtype_id="6">
<arraysel loc="d,38,15,38,16" dtype_id="3">
<varref loc="d,38,10,38,15" name="array" dtype_id="5"/>
<sel loc="d,38,16,38,17" dtype_id="9">
<varref loc="d,38,16,38,17" name="i" dtype_id="8"/>
<const loc="d,38,16,38,17" name="32&apos;h0" dtype_id="10"/>
<const loc="d,38,16,38,17" name="32&apos;h1" dtype_id="10"/>
</sel>
</arraysel>
<const loc="d,38,33,38,34" name="32&apos;sh6" dtype_id="7"/>
</eqwild>
</or>
</constraintexpr>
</constraintforeach>
<constraintunique loc="d,40,7,40,13">
<arraysel loc="d,40,21,40,22" dtype_id="3">
<varref loc="d,40,16,40,21" name="array" dtype_id="5"/>
<const loc="d,40,22,40,23" name="1&apos;h0" dtype_id="9"/>
</arraysel>
<arraysel loc="d,40,31,40,32" dtype_id="3">
<varref loc="d,40,26,40,31" name="array" dtype_id="5"/>
<const loc="d,40,32,40,33" name="1&apos;h1" dtype_id="9"/>
</arraysel>
</constraintunique>
</constraint>
<constraint loc="d,43,15,43,20" name="order">
<constraintbefore loc="d,43,23,43,28">
<varref loc="d,43,29,43,35" name="length" dtype_id="3"/>
<varref loc="d,43,43,43,49" name="header" dtype_id="3"/>
</constraintbefore>
</constraint>
<constraint loc="d,45,15,45,18" name="dis">
<constraintexpr loc="d,46,7,46,11">
<varref loc="d,46,12,46,21" name="sublength" dtype_id="3"/>
</constraintexpr>
<constraintexpr loc="d,47,7,47,14">
<varref loc="d,47,20,47,29" name="sublength" dtype_id="3"/>
</constraintexpr>
<constraintexpr loc="d,48,17,48,19">
<ltes loc="d,48,17,48,19" dtype_id="6">
<varref loc="d,48,7,48,16" name="sublength" dtype_id="3"/>
<varref loc="d,48,20,48,26" name="length" dtype_id="3"/>
</ltes>
</constraintexpr>
</constraint>
<func loc="d,7,1,7,6" name="new" dtype_id="11"/>
</class>
</package>
<typetable loc="a,0,0,0,0">
<basicdtype loc="d,19,14,19,15" id="6" name="logic"/>
<basicdtype loc="d,22,21,22,22" id="10" name="logic" left="31" right="0"/>
<basicdtype loc="d,59,7,59,13" id="2" name="string"/>
<basicdtype loc="d,37,22,37,23" id="8" name="integer" left="31" right="0" signed="true"/>
<basicdtype loc="d,8,9,8,12" id="3" name="int" left="31" right="0" signed="true"/>
<basicdtype loc="d,11,9,11,12" id="4" name="bit"/>
<unpackarraydtype loc="d,14,18,14,19" id="5" sub_dtype_id="3">
<range loc="d,14,18,14,19">
<const loc="d,14,19,14,20" name="32&apos;h0" dtype_id="10"/>
<const loc="d,14,19,14,20" name="32&apos;h1" dtype_id="10"/>
</range>
</unpackarraydtype>
<basicdtype loc="d,29,18,29,20" id="9" name="logic" signed="true"/>
<voiddtype loc="d,7,1,7,6" id="11"/>
<classrefdtype loc="d,55,4,55,10" id="1" name="Packet"/>
<basicdtype loc="d,19,16,19,17" id="7" name="logic" left="31" right="0" signed="true"/>
</typetable>
</netlist>
</verilator_xml>

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 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);
my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml";
compile(
verilator_flags2 => ['--no-std', '--xml-only', '-Wno-CONSTRAINTIGN'],
verilator_make_gmake => 0,
make_top_shell => 0,
make_main => 0,
);
files_identical($out_filename, $Self->{golden_filename});
ok(1);
1;

View File

@ -0,0 +1,62 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int header; // 0..7
rand int length; // 0..15
rand int sublength; // 0..15
rand bit if_4;
rand bit iff_5_6;
rand int array[2]; // 2,4,6
constraint empty {}
constraint size {
header > 0 && header <= 7;
length <= 15;
length >= header;
length dist { [0:1], [2:5] :/ 2, 6 := 6, 7 := 10, 1};
}
constraint ifs {
if (header > 4) {
if_4 == '1;
}
if (header == 5 || header == 6) {
iff_5_6 == '1;
} else {
iff_5_6 == '0;
}
}
constraint arr_uniq {
foreach (array[i]) {
array[i] inside {2, 4, 6};
}
unique { array[0], array[1] }
}
constraint order { solve length before header; }
constraint dis {
soft sublength;
disable soft sublength;
sublength <= length;
}
endclass
module t (/*AUTOARG*/);
Packet p;
initial begin
// Not testing use of constraints
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -31,7 +31,6 @@ foreach my $s (
'Unsupported: Ranges ignored in port-lists', # Hard to hit
'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error
# Not yet analyzed
' is not an in/out/inout/param/interface: ',
' loading non-variable',
'--pipe-filter protocol error, unexpected: ',
'/*verilator sformat*/ can only be applied to last argument of ',

View File

@ -1,4 +1,5 @@
%Error: t/t_foreach_nindex_bad.v:12:34: foreach loop variables exceed number of indices of array
: ... note: In instance 't'
12 | foreach (array[i, j, badk, badl]);
| ^~~~
%Error: Exiting due to

View File

@ -1,36 +1,31 @@
%Error-UNSUPPORTED: t/t_randomize.v:11:4: Unsupported: extern constraint
11 | extern constraint ex;
| ^~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Warning-CONSTRAINTIGN: t/t_randomize.v:13:4: Constraint ignored (unsupported)
13 | constraint a { header > 0 && header < 1000; }
| ^~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:16:15: Constraint ignored (unsupported)
: ... note: In instance 't'
16 | constraint empty {}
| ^~~~~
... 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.v:14:4: Constraint ignored (unsupported)
14 | constraint b {
| ^~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:19:4: Constraint ignored (unsupported)
19 | constraint c {
| ^~~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:23:4: Constraint ignored (unsupported)
23 | constraint d {
| ^~~~~~~~~~
%Error-UNSUPPORTED: t/t_randomize.v:29:29: Unsupported: solve before
29 | constraint order { solve length before header; }
| ^~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:29:4: Constraint ignored (unsupported)
29 | constraint order { solve length before header; }
| ^~~~~~~~~~
%Error-UNSUPPORTED: t/t_randomize.v:32:9: Unsupported: dist
32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400};
| ^~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:30:4: Constraint ignored (unsupported)
30 | constraint dis {
| ^~~~~~~~~~
%Error-UNSUPPORTED: t/t_randomize.v:37:1: Unsupported: extern constraint
37 | constraint Packet::ex { header > 0 };
| ^~~~~~~~~~
%Error: t/t_randomize.v:37:23: syntax error, unexpected '{'
37 | constraint Packet::ex { header > 0 };
| ^
%Warning-CONSTRAINTIGN: t/t_randomize.v:18:15: Constraint ignored (unsupported)
: ... note: In instance 't'
18 | constraint size {
| ^~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:25:15: Constraint ignored (unsupported)
: ... note: In instance 't'
25 | constraint ifs {
| ^~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:36:15: Constraint ignored (unsupported)
: ... note: In instance 't'
36 | constraint arr_uniq {
| ^~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:43:15: Constraint ignored (unsupported)
: ... note: In instance 't'
43 | constraint order { solve length before header; }
| ^~~~~
%Warning-CONSTRAINTIGN: t/t_randomize.v:45:15: Constraint ignored (unsupported)
: ... note: In instance 't'
45 | constraint dis {
| ^~~
%Error-UNSUPPORTED: t/t_randomize.v:14:13: Unsupported: random member variable with type 'int$[0:1]'
: ... note: In instance 't'
14 | rand int array[2];
| ^~~~~
%Error: Exiting due to

View File

@ -5,37 +5,51 @@
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int header;
rand int length;
rand int header; // 0..7
rand int length; // 0..15
rand int sublength; // 0..15
rand bit if_4;
rand bit iff_5_6;
extern constraint ex;
rand int array[2]; // 2,4,6
constraint a { header > 0 && header < 1000; }
constraint b {
if (64 > header) {
header < (64'h1 << length);
constraint empty {}
constraint size {
header > 0 && header <= 7;
length <= 15;
length >= header;
length dist { [0:1], [2:5] :/ 2, 6 := 6, 7 := 10, 1};
}
constraint ifs {
if (header > 4) {
if_4 == '1;
}
if (header == 5 || header == 6) {
iff_5_6 == '1;
} else {
iff_5_6 == '0;
}
}
constraint c {
header >= length - 10;
header <= length;
}
constraint d {
foreach (in_use[i]) {
!(start_offset <= in_use[i].Xend_offsetX &&
start_offset + length - 1 >= in_use[i].Xstart_offsetX);
constraint arr_uniq {
foreach (array[i]) {
array[i] inside {2, 4, 6};
}
unique { array[0], array[1] }
}
constraint order { solve length before header; }
constraint dis {
disable soft x;
x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400};
soft sublength;
disable soft sublength;
sublength <= length;
}
endclass
constraint Packet::ex { header > 0 };
module t (/*AUTOARG*/);
Packet p;
@ -43,15 +57,12 @@ module t (/*AUTOARG*/);
initial begin
int v;
// TODO not testing constrained values
v = p.randomize();
if (v != 1) $stop;
v = p.randomize(1);
if (v != 1) $stop;
v = p.randomize(1, 2);
if (v != 1) $stop;
v = p.randomize() with {};
if (v != 1) $stop;
// Not testing other randomize forms as unused in UVM
// TODO not testing other randomize forms as unused in UVM
$write("*-* All Finished *-*\n");
$finish;

View File

@ -0,0 +1,11 @@
%Error-UNSUPPORTED: t/t_randomize_extern.v:8:4: Unsupported: pure constraint
8 | pure constraint pur;
| ^~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_randomize_extern.v:17:4: Unsupported: extern constraint
17 | extern constraint ex;
| ^~~~~~
%Error-UNSUPPORTED: t/t_randomize_extern.v:21:1: Unsupported: extern constraint
21 | constraint Packet::ex { header == 2; }
| ^~~~~~~~~~
%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,42 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Base;
pure constraint pur;
endclass
class Packet extends Base;
rand int header;
rand int length;
constraint pur { length == 3; }
extern constraint ex;
endclass
constraint Packet::ex { header == 2; }
module t (/*AUTOARG*/);
Packet p;
initial begin
int v;
v = p.randomize();
if (v != 1) $stop;
if (p.header != 2) $stop;
if (p.length != 3) $stop;
v = p.randomize(1);
if (v != 1) $stop;
if (p.header != 2) $stop;
if (p.length != 3) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,23 @@
#!/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(simulator => 1);
compile(
verilator_flags2 => ['-Wno-CONSTRAINTIGN'],
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,56 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int m_one;
Packet other;
task test1;
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
// TODO test that these control randomization as specified
m_one.rand_mode(0);
m_one.rand_mode(1);
if (m_one.rand_mode() != 1) $stop;
endtask
endclass
module t (/*AUTOARG*/);
Packet p;
int v;
initial begin
p = new;
v = p.randomize();
if (v != 1) $stop;
`ifndef VERILATOR
if (p.m_one != 1) $stop;
`endif
// IEEE: function void object[.random_variable].rand_mode(bit on_off);
// IEEE: function int object.random_variable.rand_mode();
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
// TODO test that these control randomization as specified
p.rand_mode(0);
p.rand_mode(1);
// Not legal to get current rand() value on a class-only call
// TODO Verilator ignores this setting currently, always returning 1 (rand on)
// TODO test that these control randomization as specified
p.m_one.rand_mode(0);
p.m_one.rand_mode(1);
if (p.m_one.rand_mode() != 1) $stop;
// TODO test can't redefine rand_mode
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,35 @@
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:15:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
15 | 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:16:13: rand_mode ignored (unsupported)
: ... note: In instance 't'
16 | m_one.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:17:17: rand_mode ignored (unsupported)
: ... note: In instance 't'
17 | if (m_one.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:41:9: rand_mode ignored (unsupported)
: ... note: In instance 't'
41 | p.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:42:9: rand_mode ignored (unsupported)
: ... note: In instance 't'
42 | p.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:47:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
47 | p.m_one.rand_mode(0);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:48:15: rand_mode ignored (unsupported)
: ... note: In instance 't'
48 | p.m_one.rand_mode(1);
| ^~~~~~~~~
%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:49:19: rand_mode ignored (unsupported)
: ... note: In instance 't'
49 | if (p.m_one.rand_mode() != 1) $stop;
| ^~~~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,21 @@
#!/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);
top_filename("t/t_randomize_rand_mode.v");
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;