Support passing constraints to --xml-only output (still otherwise unsupported) (#4683)
This commit is contained in:
parent
673f086e87
commit
99dbd23f1b
1
Changes
1
Changes
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, '{}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
280
src/V3Width.cpp
280
src/V3Width.cpp
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,202 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!-- DESCRIPTION: Verilator output: XML representation of netlist -->
|
||||
<verilator_xml>
|
||||
<files>
|
||||
<file id="a" filename="<built-in>" language="1800-2017"/>
|
||||
<file id="b" filename="<command-line>" 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 *-* " 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'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'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'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'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'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'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'h0" dtype_id="10"/>
|
||||
<const loc="d,38,16,38,17" name="32'h1" dtype_id="10"/>
|
||||
</sel>
|
||||
</arraysel>
|
||||
<const loc="d,38,27,38,28" name="32'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'h0" dtype_id="10"/>
|
||||
<const loc="d,38,16,38,17" name="32'h1" dtype_id="10"/>
|
||||
</sel>
|
||||
</arraysel>
|
||||
<const loc="d,38,30,38,31" name="32'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'h0" dtype_id="10"/>
|
||||
<const loc="d,38,16,38,17" name="32'h1" dtype_id="10"/>
|
||||
</sel>
|
||||
</arraysel>
|
||||
<const loc="d,38,33,38,34" name="32'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'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'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'h0" dtype_id="10"/>
|
||||
<const loc="d,14,19,14,20" name="32'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>
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
Loading…
Reference in New Issue