mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support randc (#4349).
This commit is contained in:
parent
47b3f464a9
commit
24ff3155ae
1
Changes
1
Changes
@ -13,6 +13,7 @@ Verilator 5.017 devel
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Support randc (#4349).
|
||||
* Support resizing function call inout arguments (#4467).
|
||||
|
||||
|
||||
|
@ -1360,7 +1360,10 @@ List Of Warnings
|
||||
|
||||
.. option:: RANDC
|
||||
|
||||
Warns that the :code:`randc` keyword is unsupported and being converted
|
||||
Historical, never issued since version 5.018, when :code:`randc` became
|
||||
fully supported.
|
||||
|
||||
Warned that the :code:`randc` keyword was unsupported and was converted
|
||||
to :code:`rand`.
|
||||
|
||||
|
||||
|
@ -74,8 +74,18 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
#define VL_OUTW(name, msb, lsb, words) VlWide<words> name ///< Declare output signal, 65+ bits
|
||||
|
||||
//===================================================================
|
||||
// VlProcess stores metadata of running processes
|
||||
// Functions needed here
|
||||
|
||||
constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE {
|
||||
if (VL_UNLIKELY(!lhs)) return 0;
|
||||
--lhs;
|
||||
int shifts = 0;
|
||||
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
|
||||
return shifts;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// VlProcess stores metadata of running processes
|
||||
class VlProcess final {
|
||||
// MEMBERS
|
||||
int m_state; // Current state of the process
|
||||
@ -210,6 +220,58 @@ public:
|
||||
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
|
||||
};
|
||||
|
||||
template <class T_Value, std::size_t T_numValues>
|
||||
class VlRandC final {
|
||||
T_Value m_remaining = 0; // Number of values to pull before re-randomize
|
||||
T_Value m_lfsr = 1; // LFSR state
|
||||
// Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/
|
||||
static constexpr uint64_t s_polynomials[] = {
|
||||
0x0ULL, // 0 never used (constant, no randomization)
|
||||
0x0ULL, // 1
|
||||
0x3ULL, 0x5ULL, 0x9ULL, 0x12ULL, 0x21ULL,
|
||||
0x41ULL, 0x8eULL, 0x108ULL, 0x204ULL, 0x402ULL,
|
||||
0x829ULL, 0x100dULL, 0x2015ULL, 0x4001ULL,
|
||||
0x8016ULL, // 16
|
||||
0x10004ULL, 0x20040ULL, 0x40013ULL, 0x80004ULL, 0x100002ULL,
|
||||
0x200001ULL, 0x400010ULL, 0x80000dULL, 0x1000004ULL, 0x2000023ULL,
|
||||
0x4000013ULL, 0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL,
|
||||
0x80000057ULL, // 32
|
||||
0x100000029ULL // 33
|
||||
};
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlRandC() {
|
||||
static_assert(T_numValues >= 1, "");
|
||||
static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), "");
|
||||
}
|
||||
// METHODS
|
||||
T_Value randomize(VlRNG& rngr) {
|
||||
if (VL_UNLIKELY(!m_remaining)) reseed(rngr);
|
||||
constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
|
||||
constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth;
|
||||
constexpr T_Value polynomial = static_cast<T_Value>(s_polynomials[lfsrWidth]);
|
||||
// printf(" numV=%ld w=%d poly=%x\n", T_numValues, lfsrWidth, polynomial);
|
||||
// Loop until get reasonable value. Because we picked a LFSR of at most one
|
||||
// extra bit in width, this will only require at most on average 1.5 loops
|
||||
do {
|
||||
m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL);
|
||||
} while (m_lfsr > T_numValues); // Note if == then output value 0
|
||||
--m_remaining;
|
||||
T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr;
|
||||
// printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining);
|
||||
return result;
|
||||
}
|
||||
void reseed(VlRNG& rngr) {
|
||||
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
|
||||
m_remaining = T_numValues;
|
||||
do {
|
||||
m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth);
|
||||
// printf(" lfsr.reseed=%x\n", m_lfsr);
|
||||
} while (!m_lfsr); // 0 not a legal seed
|
||||
}
|
||||
};
|
||||
|
||||
// These require the class object to have the thread safety lock
|
||||
inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
|
@ -494,6 +494,41 @@ public:
|
||||
int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
bool isCompound() const override { return true; }
|
||||
};
|
||||
class AstCDType final : public AstNodeDType {
|
||||
// Raw "C" data type passed directly to output
|
||||
string m_name; // Name of data type, printed when do V3EmitC
|
||||
public:
|
||||
AstCDType(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_CDType(fl)
|
||||
, m_name{name} {
|
||||
this->dtypep(this);
|
||||
}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstCDType;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCDType* const asamep = static_cast<const AstCDType*>(samep);
|
||||
return m_name == asamep->m_name;
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return same(samep); }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string prettyDTypeName() const override { return m_name; }
|
||||
const char* broken() const override { return nullptr; }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return 8; } // Assume
|
||||
int widthTotalBytes() const override { return 8; } // Assume
|
||||
bool isCompound() const override { return true; }
|
||||
static string typeToHold(uint64_t maxItem) {
|
||||
return (maxItem < (1ULL << 8)) ? "CData"
|
||||
: (maxItem < (1ULL << 16)) ? "SData"
|
||||
: (maxItem < (1ULL << 32)) ? "IData"
|
||||
: "QData";
|
||||
}
|
||||
};
|
||||
class AstClassRefDType final : public AstNodeDType {
|
||||
// Reference to a class
|
||||
// @astgen op1 := paramsp: List[AstPin]
|
||||
|
@ -1684,6 +1684,7 @@ class AstVar final : public AstNode {
|
||||
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
||||
bool m_fileDescr : 1; // File descriptor
|
||||
bool m_isRand : 1; // Random variable
|
||||
bool m_isRandC : 1; // Random cyclic variable (isRand also set)
|
||||
bool m_isConst : 1; // Table contains constant data
|
||||
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
|
||||
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
|
||||
@ -1691,6 +1692,7 @@ class AstVar final : public AstNode {
|
||||
bool m_isPulldown : 1; // Tri0
|
||||
bool m_isPullup : 1; // Tri1
|
||||
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
|
||||
bool m_isInternal : 1; // Internal state, don't add to method pinter
|
||||
bool m_isDpiOpenArray : 1; // DPI import open array
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
@ -1728,6 +1730,7 @@ class AstVar final : public AstNode {
|
||||
m_attrSplitVar = false;
|
||||
m_fileDescr = false;
|
||||
m_isRand = false;
|
||||
m_isRandC = false;
|
||||
m_isConst = false;
|
||||
m_isContinuously = false;
|
||||
m_hasStrengthAssignment = false;
|
||||
@ -1735,6 +1738,7 @@ class AstVar final : public AstNode {
|
||||
m_isPulldown = false;
|
||||
m_isPullup = false;
|
||||
m_isIfaceParent = false;
|
||||
m_isInternal = false;
|
||||
m_isDpiOpenArray = false;
|
||||
m_isHideLocal = false;
|
||||
m_isHideProtected = false;
|
||||
@ -1880,10 +1884,15 @@ public:
|
||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||
void isRand(bool flag) { m_isRand = flag; }
|
||||
void isRandC(bool flag) {
|
||||
m_isRandC = flag;
|
||||
if (flag) isRand(true);
|
||||
}
|
||||
void isConst(bool flag) { m_isConst = flag; }
|
||||
void isContinuously(bool flag) { m_isContinuously = flag; }
|
||||
void isStatic(bool flag) { m_isStatic = flag; }
|
||||
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
|
||||
void isInternal(bool flag) { m_isInternal = flag; }
|
||||
void funcLocal(bool flag) {
|
||||
m_funcLocal = flag;
|
||||
if (flag) m_funcLocalSticky = true;
|
||||
@ -1929,6 +1938,7 @@ public:
|
||||
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
|
||||
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
|
||||
bool isIfaceParent() const { return m_isIfaceParent; }
|
||||
bool isInternal() const { return m_isInternal; }
|
||||
bool isSignal() const { return varType().isSignal(); }
|
||||
bool isNet() const { return varType().isNet(); }
|
||||
bool isTemp() const { return varType().isTemp(); }
|
||||
@ -1964,6 +1974,7 @@ public:
|
||||
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
bool isRand() const { return m_isRand; }
|
||||
bool isRandC() const { return m_isRandC; }
|
||||
bool isConst() const VL_MT_SAFE { return m_isConst; }
|
||||
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
|
||||
bool isLatched() const { return m_isLatched; }
|
||||
|
@ -799,6 +799,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
||||
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, CDType)) {
|
||||
info.m_type = adtypep->name();
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
|
||||
@ -2187,8 +2189,14 @@ void AstVar::dump(std::ostream& str) const {
|
||||
if (isPulldown()) str << " [PULLDOWN]";
|
||||
if (isUsedClock()) str << " [CLK]";
|
||||
if (isSigPublic()) str << " [P]";
|
||||
if (isInternal()) str << " [INTERNAL]";
|
||||
if (isLatched()) str << " [LATCHED]";
|
||||
if (isUsedLoopIdx()) str << " [LOOP]";
|
||||
if (isRandC()) {
|
||||
str << " [RANDC]";
|
||||
} else if (isRand()) {
|
||||
str << " [RAND]";
|
||||
}
|
||||
if (noReset()) str << " [!RST]";
|
||||
if (attrIsolateAssign()) str << " [aISO]";
|
||||
if (attrFileDescr()) str << " [aFD]";
|
||||
|
@ -116,7 +116,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
||||
std::string comma;
|
||||
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
|
||||
if (const auto* const varp = VN_CAST(itemp, Var)) {
|
||||
if (!varp->isParam()) {
|
||||
if (!varp->isParam() && !varp->isInternal()) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
|
@ -667,6 +667,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (VN_IS(dtypep, CDType)) {
|
||||
return ""; // Constructor does it
|
||||
} else if (VN_IS(dtypep, ClassRefDType)) {
|
||||
return ""; // Constructor does it
|
||||
} else if (VN_IS(dtypep, IfaceRefDType)) {
|
||||
|
@ -147,6 +147,11 @@ private:
|
||||
m_hash += nodep->nrange().right();
|
||||
});
|
||||
}
|
||||
void visit(AstCDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
m_hash += nodep->name();
|
||||
});
|
||||
}
|
||||
void visit(AstConstDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateConstNull(nodep->virtRefDTypep());
|
||||
|
@ -83,11 +83,8 @@ struct VMemberQualifiers {
|
||||
}
|
||||
void applyToNodes(AstVar* nodesp) const {
|
||||
for (AstVar* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), Var)) {
|
||||
if (m_randc) {
|
||||
nodep->v3warn(RANDC, "Unsupported: Converting 'randc' to 'rand'");
|
||||
nodep->isRand(true);
|
||||
}
|
||||
if (m_rand) nodep->isRand(true);
|
||||
if (m_randc) nodep->isRandC(true);
|
||||
if (m_local) nodep->isHideLocal(true);
|
||||
if (m_protected) nodep->isHideProtected(true);
|
||||
if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
|
@ -144,6 +144,7 @@ private:
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
||||
int m_randCaseNum = 0; // Randcase number within a module for var naming
|
||||
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
|
||||
|
||||
// METHODS
|
||||
AstVar* enumValueTabp(AstEnumDType* nodep) {
|
||||
@ -172,8 +173,49 @@ private:
|
||||
nodep->user2p(varp);
|
||||
return varp;
|
||||
}
|
||||
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, int offset = 0,
|
||||
AstMemberDType* memberp = nullptr) {
|
||||
|
||||
AstCDType* findVlRandCDType(FileLine* fl, uint64_t items) {
|
||||
// For 8 items we need to have a 9 item LFSR so items is max count
|
||||
const std::string type = AstCDType::typeToHold(items);
|
||||
const std::string name = "VlRandC<" + type + ", " + cvtToStr(items) + "ULL>";
|
||||
// Create or reuse (to avoid duplicates) randomization object dtype
|
||||
auto it = m_randcDtypes.find(name);
|
||||
if (it != m_randcDtypes.end()) return it->second;
|
||||
AstCDType* newp = new AstCDType{fl, name};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
m_randcDtypes.emplace(std::make_pair(name, newp));
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstVar* newRandcVarsp(AstVar* varp) {
|
||||
// If a randc, make a VlRandC object to hold the state
|
||||
if (!varp->isRandC()) return nullptr;
|
||||
uint64_t items = 0;
|
||||
|
||||
if (AstEnumDType* const enumDtp = VN_CAST(varp->dtypep()->skipRefToEnump(), EnumDType)) {
|
||||
items = static_cast<uint64_t>(enumDtp->itemCount());
|
||||
} else {
|
||||
AstBasicDType* const basicp = varp->dtypep()->skipRefp()->basicp();
|
||||
UASSERT_OBJ(basicp, varp, "Unexpected randc variable dtype");
|
||||
if (basicp->width() > 32) {
|
||||
varp->v3error("Maxiumum implemented width for randc is 32 bits, "
|
||||
<< varp->prettyNameQ() << " is " << basicp->width() << " bits");
|
||||
varp->isRandC(false);
|
||||
varp->isRand(true);
|
||||
return nullptr;
|
||||
}
|
||||
items = 1ULL << basicp->width();
|
||||
}
|
||||
AstCDType* newdtp = findVlRandCDType(varp->fileline(), items);
|
||||
AstVar* newp
|
||||
= new AstVar{varp->fileline(), VVarType::MEMBER, varp->name() + "__Vrandc", newdtp};
|
||||
newp->isInternal(true);
|
||||
varp->addNextHere(newp);
|
||||
UINFO(9, "created " << varp << endl);
|
||||
return newp;
|
||||
}
|
||||
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, AstVar* randcVarp,
|
||||
int offset = 0, AstMemberDType* memberp = nullptr) {
|
||||
if (const auto* const structDtp
|
||||
= VN_CAST(memberp ? memberp->subDTypep()->skipRefp() : varrefp->dtypep()->skipRefp(),
|
||||
StructDType)) {
|
||||
@ -182,7 +224,7 @@ private:
|
||||
for (AstMemberDType* smemberp = structDtp->membersp(); smemberp;
|
||||
smemberp = VN_AS(smemberp->nextp(), MemberDType)) {
|
||||
AstNodeStmt* const randp = newRandStmtsp(
|
||||
fl, stmtsp ? varrefp->cloneTree(false) : varrefp, offset, smemberp);
|
||||
fl, stmtsp ? varrefp->cloneTree(false) : varrefp, nullptr, offset, smemberp);
|
||||
if (stmtsp) {
|
||||
stmtsp->addNext(randp);
|
||||
} else {
|
||||
@ -198,15 +240,15 @@ private:
|
||||
AstVarRef* const tabRefp
|
||||
= new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ};
|
||||
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstRandRNG* const randp
|
||||
= new AstRandRNG{fl, varrefp->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
AstNodeExpr* const randp
|
||||
= newRandValue(fl, randcVarp, varrefp->findBasicDType(VBasicDTypeKwd::UINT32));
|
||||
AstNodeExpr* const moddivp = new AstModDiv{
|
||||
fl, randp, new AstConst{fl, static_cast<uint32_t>(enumDtp->itemCount())}};
|
||||
moddivp->dtypep(enumDtp);
|
||||
valp = new AstArraySel{fl, tabRefp, moddivp};
|
||||
} else {
|
||||
valp = new AstRandRNG{fl,
|
||||
(memberp ? memberp->dtypep() : varrefp->varp()->dtypep())};
|
||||
valp = newRandValue(fl, randcVarp,
|
||||
(memberp ? memberp->dtypep() : varrefp->varp()->dtypep()));
|
||||
}
|
||||
return new AstAssign{fl,
|
||||
new AstSel{fl, varrefp, offset + (memberp ? memberp->lsb() : 0),
|
||||
@ -214,6 +256,17 @@ private:
|
||||
valp};
|
||||
}
|
||||
}
|
||||
AstNodeExpr* newRandValue(FileLine* fl, AstVar* randcVarp, AstNodeDType* dtypep) {
|
||||
if (randcVarp) {
|
||||
AstNode* argsp = new AstVarRef{fl, randcVarp, VAccess::READWRITE};
|
||||
argsp->addNext(new AstText{fl, ".randomize(__Vm_rng)"});
|
||||
AstCExpr* newp = new AstCExpr{fl, argsp};
|
||||
newp->dtypep(dtypep);
|
||||
return newp;
|
||||
} else {
|
||||
return new AstRandRNG{fl, dtypep};
|
||||
}
|
||||
}
|
||||
void addPrePostCall(AstClass* classp, AstFunc* funcp, const string& name) {
|
||||
if (AstTask* userFuncp = VN_CAST(m_memberMap.findMember(classp, name), Task)) {
|
||||
AstTaskRef* const callp
|
||||
@ -271,8 +324,9 @@ private:
|
||||
if (!memberVarp || !memberVarp->isRand()) continue;
|
||||
const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp();
|
||||
if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) {
|
||||
AstVar* const randcVarp = newRandcVarsp(memberVarp);
|
||||
AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE};
|
||||
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp);
|
||||
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp);
|
||||
funcp->addStmtsp(stmtp);
|
||||
} else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) {
|
||||
if (classRefp->classp() == nodep) {
|
||||
|
@ -452,6 +452,18 @@ private:
|
||||
}
|
||||
if (debug() >= 9) nodep->dumpTree("- arraysel_old: ");
|
||||
|
||||
// If value MODDIV constant, where constant <= declElements, known ok
|
||||
// V3Random makes these to intentionally prevent exceeding enum array bounds.
|
||||
if (const AstModDiv* const moddivp = VN_CAST(nodep->bitp(), ModDiv)) {
|
||||
if (const AstConst* const modconstp = VN_CAST(moddivp->rhsp(), Const)) {
|
||||
if (modconstp->width() <= 32
|
||||
&& modconstp->toUInt() <= static_cast<uint32_t>(declElements)) {
|
||||
UINFO(9, "arraysel mod const " << declElements
|
||||
<< " >= " << modconstp->toUInt() << endl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if the condition is constant true
|
||||
AstNodeExpr* condp
|
||||
= new AstGte{nodep->fileline(),
|
||||
|
@ -1,12 +0,0 @@
|
||||
%Warning-RANDC: t/t_randc.v:8:26: Unsupported: Converting 'randc' to 'rand'
|
||||
8 | randc bit [WIDTH-1:0] m_var;
|
||||
| ^~~~~
|
||||
... For warning description see https://verilator.org/warn/RANDC?v=latest
|
||||
... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message.
|
||||
%Warning-RANDC: t/t_randc.v:46:26: Unsupported: Converting 'randc' to 'rand'
|
||||
46 | randc bit [WIDTH-1:0] m_var;
|
||||
| ^~~~~
|
||||
%Warning-RANDC: t/t_randc.v:76:17: Unsupported: Converting 'randc' to 'rand'
|
||||
76 | randc enum_t m_var;
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
@ -8,11 +8,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(linter => 1);
|
||||
scenarios(simulator => 1);
|
||||
|
||||
lint(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
@ -1,24 +0,0 @@
|
||||
#!/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(vlt => 1);
|
||||
|
||||
top_filename("t/t_randc.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['-Wno-RANDC -DTEST_IGNORE_RANDC'],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
@ -1,6 +1,5 @@
|
||||
%Warning-RANDC: t/t_randc_oversize_bad.v:8:21: Unsupported: Converting 'randc' to 'rand'
|
||||
8 | randc bit [33:0] i;
|
||||
%Error: t/t_randc_oversize_bad.v:8:21: Maxiumum implemented width for randc is 32 bits, 'i' is 38 bits
|
||||
: ... In instance t
|
||||
8 | randc bit [37:0] i;
|
||||
| ^
|
||||
... For warning description see https://verilator.org/warn/RANDC?v=latest
|
||||
... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message.
|
||||
%Error: Exiting due to
|
||||
|
@ -5,8 +5,13 @@
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Cls;
|
||||
randc bit [33:0] i;
|
||||
randc bit [37:0] i;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
Cls c;
|
||||
initial begin
|
||||
c = new;
|
||||
c.randomize;
|
||||
end
|
||||
endmodule
|
||||
|
@ -15,7 +15,6 @@ compile(
|
||||
"-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT",
|
||||
"-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC",
|
||||
"-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream
|
||||
"-Wno-RANDC", # TODO issue #4349, add support
|
||||
"-Wno-ZERODLY", # TODO issue #4494, add support
|
||||
],
|
||||
verilator_make_gmake => 0,
|
||||
|
Loading…
Reference in New Issue
Block a user