parent
e0e164cea2
commit
6b4183632c
|
|
@ -175,6 +175,9 @@ enum class VerilatedAssertDirectiveType : uint8_t {
|
||||||
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
||||||
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
||||||
|
|
||||||
|
// Type trait for custom struct
|
||||||
|
template <typename>
|
||||||
|
struct VlIsCustomStruct : public std::false_type {};
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Utility functions
|
// Utility functions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -508,7 +508,7 @@ void VlRandomizer::clear() { m_constraints.clear(); }
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
void VlRandomizer::dump() const {
|
void VlRandomizer::dump() const {
|
||||||
for (const auto& var : m_vars) {
|
for (const auto& var : m_vars) {
|
||||||
VL_PRINTF("Variable (%d): %s\n", var.second->width(), var.second->name());
|
VL_PRINTF("Variable (%d): %s\n", var.second->width(), var.second->name().c_str());
|
||||||
}
|
}
|
||||||
for (const std::string& c : m_constraints) VL_PRINTF("Constraint: %s\n", c.c_str());
|
for (const std::string& c : m_constraints) VL_PRINTF("Constraint: %s\n", c.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,21 +54,22 @@ public:
|
||||||
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
||||||
|
|
||||||
class VlRandomVar VL_NOT_FINAL {
|
class VlRandomVar VL_NOT_FINAL {
|
||||||
const char* const m_name; // Variable name
|
std::string m_name; // Variable name
|
||||||
void* const m_datap; // Reference to variable data
|
void* const m_datap; // Reference to variable data
|
||||||
const int m_width; // Variable width in bits
|
const int m_width; // Variable width in bits
|
||||||
const int m_dimension; //Variable dimension, default is 0
|
const int m_dimension; //Variable dimension, default is 0
|
||||||
const std::uint32_t m_randModeIdx; // rand_mode index
|
const std::uint32_t m_randModeIdx; // rand_mode index
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VlRandomVar(const char* name, int width, void* datap, int dimension, std::uint32_t randModeIdx)
|
VlRandomVar(const std::string& name, int width, void* datap, int dimension,
|
||||||
|
std::uint32_t randModeIdx)
|
||||||
: m_name{name}
|
: m_name{name}
|
||||||
, m_datap{datap}
|
, m_datap{datap}
|
||||||
, m_width{width}
|
, m_width{width}
|
||||||
, m_dimension{dimension}
|
, m_dimension{dimension}
|
||||||
, m_randModeIdx{randModeIdx} {}
|
, m_randModeIdx{randModeIdx} {}
|
||||||
virtual ~VlRandomVar() = default;
|
virtual ~VlRandomVar() = default;
|
||||||
const char* name() const { return m_name; }
|
std::string name() const { return m_name; }
|
||||||
int width() const { return m_width; }
|
int width() const { return m_width; }
|
||||||
int dimension() const { return m_dimension; }
|
int dimension() const { return m_dimension; }
|
||||||
virtual void* datap(int idx) const { return m_datap; }
|
virtual void* datap(int idx) const { return m_datap; }
|
||||||
|
|
@ -99,7 +100,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
||||||
public:
|
public:
|
||||||
VlRandomArrayVarTemplate(const char* name, int width, void* datap, int dimension,
|
VlRandomArrayVarTemplate(const std::string& name, int width, void* datap, int dimension,
|
||||||
std::uint32_t randModeIdx)
|
std::uint32_t randModeIdx)
|
||||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||||
void* datap(int idx) const override {
|
void* datap(int idx) const override {
|
||||||
|
|
@ -300,8 +301,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void write_var(T& var, int width, const char* name, int dimension,
|
typename std::enable_if<!VlIsCustomStruct<T>::value, void>::type
|
||||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
write_var(T& var, int width, const char* name, int dimension,
|
||||||
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
if (m_vars.find(name) != m_vars.end()) return;
|
if (m_vars.find(name) != m_vars.end()) return;
|
||||||
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
||||||
m_vars[name]
|
m_vars[name]
|
||||||
|
|
@ -341,6 +343,22 @@ public:
|
||||||
record_arr_table(var, name, dimension, {}, {});
|
record_arr_table(var, name, dimension, {}, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <typename T, std::size_t... I>
|
||||||
|
void modifyMembers(T& obj, std::index_sequence<I...>, std::string baseName) {
|
||||||
|
// Use the indices to access each member via std::get
|
||||||
|
(void)std::initializer_list<int>{
|
||||||
|
(write_var(std::get<I>(obj.getMembers(obj)),
|
||||||
|
sizeof(std::get<I>(obj.getMembers(obj))) * 8,
|
||||||
|
(baseName + "." + obj.memberNames()[I]).c_str(), 0),
|
||||||
|
0)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<VlIsCustomStruct<T>::value, void>::type
|
||||||
|
write_var(T& var, int width, const char* name, int dimension,
|
||||||
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
|
modifyMembers(var, var.memberIndices(), name);
|
||||||
|
}
|
||||||
|
|
||||||
int idx;
|
int idx;
|
||||||
std::string generateKey(const std::string& name, int idx) {
|
std::string generateKey(const std::string& name, int idx) {
|
||||||
|
|
@ -355,8 +373,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void record_arr_table(T& var, const std::string name, int dimension,
|
typename std::enable_if<!std::is_class<T>::value, void>::type
|
||||||
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
record_arr_table(T& var, const std::string name, int dimension, std::vector<IData> indices,
|
||||||
|
std::vector<size_t> idxWidths) {
|
||||||
const std::string key = generateKey(name, idx);
|
const std::string key = generateKey(name, idx);
|
||||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
|
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
|
||||||
++idx;
|
++idx;
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
||||||
const int m_uniqueNum;
|
const int m_uniqueNum;
|
||||||
bool m_packed;
|
bool m_packed;
|
||||||
bool m_isFourstate = false; // V3Width computes
|
bool m_isFourstate = false; // V3Width computes
|
||||||
|
bool m_constrainedRand = false; // True if struct has constraint expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
|
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
|
||||||
|
|
@ -244,7 +245,8 @@ protected:
|
||||||
, m_name(other.m_name)
|
, m_name(other.m_name)
|
||||||
, m_uniqueNum(uniqueNumInc())
|
, m_uniqueNum(uniqueNumInc())
|
||||||
, m_packed(other.m_packed)
|
, m_packed(other.m_packed)
|
||||||
, m_isFourstate(other.m_isFourstate) {}
|
, m_isFourstate(other.m_isFourstate)
|
||||||
|
, m_constrainedRand(false) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
||||||
|
|
@ -284,6 +286,8 @@ public:
|
||||||
VNumRange declRange() const VL_MT_STABLE { return VNumRange{hi(), lo()}; }
|
VNumRange declRange() const VL_MT_STABLE { return VNumRange{hi(), lo()}; }
|
||||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||||
|
bool isConstrainedRand() { return m_constrainedRand; }
|
||||||
|
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Concrete node types =====================================================
|
// === Concrete node types =====================================================
|
||||||
|
|
@ -905,12 +909,14 @@ class AstMemberDType final : public AstNodeDType {
|
||||||
string m_name; // Name of variable
|
string m_name; // Name of variable
|
||||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||||
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
||||||
|
bool m_constrainedRand = false;
|
||||||
// UNSUP: int m_randType; // Randomization type (IEEE)
|
// UNSUP: int m_randType; // Randomization type (IEEE)
|
||||||
public:
|
public:
|
||||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
||||||
AstNode* valuep)
|
AstNode* valuep)
|
||||||
: ASTGEN_SUPER_MemberDType(fl)
|
: ASTGEN_SUPER_MemberDType(fl)
|
||||||
, m_name{name} {
|
, m_name{name}
|
||||||
|
, m_constrainedRand(false) {
|
||||||
childDTypep(dtp); // Only for parser
|
childDTypep(dtp); // Only for parser
|
||||||
this->valuep(valuep);
|
this->valuep(valuep);
|
||||||
dtypep(nullptr); // V3Width will resolve
|
dtypep(nullptr); // V3Width will resolve
|
||||||
|
|
@ -918,13 +924,16 @@ public:
|
||||||
}
|
}
|
||||||
AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp)
|
AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp)
|
||||||
: ASTGEN_SUPER_MemberDType(fl)
|
: ASTGEN_SUPER_MemberDType(fl)
|
||||||
, m_name{name} {
|
, m_name{name}
|
||||||
|
, m_constrainedRand(false) {
|
||||||
UASSERT(dtp, "AstMember created with no dtype");
|
UASSERT(dtp, "AstMember created with no dtype");
|
||||||
refDTypep(dtp);
|
refDTypep(dtp);
|
||||||
dtypep(this);
|
dtypep(this);
|
||||||
widthFromSub(subDTypep());
|
widthFromSub(subDTypep());
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstMemberDType;
|
ASTGEN_MEMBERS_AstMemberDType;
|
||||||
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
void dumpSmall(std::ostream& str) const override;
|
void dumpSmall(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||||
|
|
@ -958,6 +967,8 @@ public:
|
||||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool isConstrainedRand() const { return m_constrainedRand; }
|
||||||
|
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||||
};
|
};
|
||||||
class AstNBACommitQueueDType final : public AstNodeDType {
|
class AstNBACommitQueueDType final : public AstNodeDType {
|
||||||
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
||||||
|
|
|
||||||
|
|
@ -1950,6 +1950,20 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
||||||
}
|
}
|
||||||
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
|
||||||
|
void AstMemberDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (isConstrainedRand()) str << " [CONSTRAINEDRAND]";
|
||||||
|
if (name() != "") str << " name=" << name();
|
||||||
|
if (tag() != "") str << " tag=" << tag();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AstMemberDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFunc(str, isConstrainedRand);
|
||||||
|
dumpJsonStrFunc(str, name);
|
||||||
|
dumpJsonStrFunc(str, tag);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
|
||||||
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "member";
|
str << "member";
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,43 @@ class EmitCHeader final : public EmitCConstInit {
|
||||||
putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
||||||
puts(";\n");
|
puts(";\n");
|
||||||
}
|
}
|
||||||
|
// Three helper functions for struct constrained randomization:
|
||||||
|
// - memberNames: Get member names
|
||||||
|
// - getMembers: Access member references
|
||||||
|
// - memberIndices: Retrieve member indices
|
||||||
|
if (sdtypep->isConstrainedRand()) {
|
||||||
|
putns(sdtypep, "\nstd::vector<std::string> memberNames(void) const {\n");
|
||||||
|
puts("return {");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand()) putns(itemp, "\"" + itemp->shortName() + "\"");
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(",\n");
|
||||||
|
}
|
||||||
|
puts("};\n}\n");
|
||||||
|
|
||||||
|
putns(sdtypep, "\nauto memberIndices(void) const {\n");
|
||||||
|
puts("return std::index_sequence_for<");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand())
|
||||||
|
putns(itemp, itemp->dtypep()->cType("", false, false));
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(",\n");
|
||||||
|
}
|
||||||
|
puts(">{};\n}\n");
|
||||||
|
|
||||||
|
putns(sdtypep, "\ntemplate <typename T>");
|
||||||
|
putns(sdtypep, "\nauto getMembers(T& obj) {\n");
|
||||||
|
puts("return std::tie(");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand()) putns(itemp, "obj." + itemp->nameProtect());
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(", ");
|
||||||
|
}
|
||||||
|
puts(");\n}\n");
|
||||||
|
}
|
||||||
putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
|
putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
+ "& rhs) const {\n");
|
+ "& rhs) const {\n");
|
||||||
puts("return ");
|
puts("return ");
|
||||||
|
|
@ -280,6 +316,9 @@ class EmitCHeader final : public EmitCConstInit {
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
puts("};\n");
|
puts("};\n");
|
||||||
|
puts("template <>\n");
|
||||||
|
putns(sdtypep, "struct VlIsCustomStruct<" + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
|
+ "> : public std::true_type {};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// getfunc: VL_ASSIGNSEL_XX(rbits, obits, off, lhsdata, rhsdata);
|
// getfunc: VL_ASSIGNSEL_XX(rbits, obits, off, lhsdata, rhsdata);
|
||||||
|
|
|
||||||
|
|
@ -629,6 +629,11 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
const uint32_t unpackedDimensions = dims.second;
|
const uint32_t unpackedDimensions = dims.second;
|
||||||
dimension = unpackedDimensions;
|
dimension = unpackedDimensions;
|
||||||
}
|
}
|
||||||
|
if (VN_IS(varp->dtypeSkipRefp(), StructDType)
|
||||||
|
&& !VN_AS(varp->dtypeSkipRefp(), StructDType)->packed()) {
|
||||||
|
VN_AS(varp->dtypeSkipRefp(), StructDType)->markConstrainedRand(true);
|
||||||
|
dimension = 1;
|
||||||
|
}
|
||||||
methodp->dtypeSetVoid();
|
methodp->dtypeSetVoid();
|
||||||
AstClass* const classp = VN_AS(varp->user2p(), Class);
|
AstClass* const classp = VN_AS(varp->user2p(), Class);
|
||||||
AstVarRef* const varRefp
|
AstVarRef* const varRefp
|
||||||
|
|
@ -706,6 +711,26 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
|
|
||||||
editSMT(nodep, nodep->fromp(), lsbp, msbp);
|
editSMT(nodep, nodep->fromp(), lsbp, msbp);
|
||||||
}
|
}
|
||||||
|
void visit(AstStructSel* nodep) override {
|
||||||
|
if (VN_IS(nodep->fromp()->dtypep()->skipRefp(), StructDType)) {
|
||||||
|
AstMemberDType* memberp
|
||||||
|
= VN_AS(nodep->fromp()->dtypep()->skipRefp(), StructDType)->membersp();
|
||||||
|
while (memberp->nextp()) {
|
||||||
|
if (memberp->name() == nodep->name()) {
|
||||||
|
memberp->markConstrainedRand(true);
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
memberp = VN_CAST(memberp->nextp(), MemberDType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
if (editFormat(nodep)) return;
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
AstSFormatF* const newp
|
||||||
|
= new AstSFormatF{fl, nodep->fromp()->name() + "." + nodep->name(), false, nullptr};
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
}
|
||||||
void visit(AstAssocSel* nodep) override {
|
void visit(AstAssocSel* nodep) override {
|
||||||
if (editFormat(nodep)) return;
|
if (editFormat(nodep)) return;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
if not test.have_solver:
|
||||||
|
test.skip("No constraint solver installed")
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by PlanV GmbH.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
bit [7:0] byte_value;
|
||||||
|
int int_value;
|
||||||
|
} PackedStruct;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rand bit [7:0] byte_value;
|
||||||
|
rand int int_value;
|
||||||
|
int non_rand_value; // Non-randomized member
|
||||||
|
} UnpackedStruct;
|
||||||
|
|
||||||
|
class PackedStructTest;
|
||||||
|
rand PackedStruct packed_struct;
|
||||||
|
|
||||||
|
function new();
|
||||||
|
packed_struct.byte_value = 8'hA0;
|
||||||
|
packed_struct.int_value = 0;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Constraint block for packed struct
|
||||||
|
constraint packed_struct_constraint {
|
||||||
|
packed_struct.byte_value == 8'hA0;
|
||||||
|
packed_struct.int_value inside {[0:100]};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-check function for packed struct
|
||||||
|
function void check();
|
||||||
|
if (packed_struct.byte_value != 8'hA0) $stop;
|
||||||
|
if (!(packed_struct.int_value inside {[0:100]})) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class UnpackedStructTest;
|
||||||
|
rand UnpackedStruct unpacked_struct;
|
||||||
|
|
||||||
|
function new();
|
||||||
|
unpacked_struct.byte_value = 8'h00;
|
||||||
|
unpacked_struct.int_value = 0;
|
||||||
|
unpacked_struct.non_rand_value = 42;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Constraint block for unpacked struct
|
||||||
|
constraint unpacked_struct_constraint {
|
||||||
|
unpacked_struct.byte_value inside {8'hA0, 8'hB0, 8'hC0};
|
||||||
|
unpacked_struct.int_value inside {[50:150]};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-check function for unpacked struct
|
||||||
|
function void check();
|
||||||
|
if (!(unpacked_struct.byte_value inside {8'hA0, 8'hB0, 8'hC0})) $stop;
|
||||||
|
if (!(unpacked_struct.int_value inside {[50:150]})) $stop;
|
||||||
|
if (unpacked_struct.non_rand_value != 42) $stop; // Check non-randomized member
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t_constraint_struct;
|
||||||
|
PackedStructTest packed_struct_test;
|
||||||
|
UnpackedStructTest unpacked_struct_test;
|
||||||
|
int success;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// Test packed struct
|
||||||
|
packed_struct_test = new();
|
||||||
|
repeat(10) begin
|
||||||
|
success = packed_struct_test.randomize();
|
||||||
|
if (success == 0) $stop;
|
||||||
|
packed_struct_test.check(); // Self-check for packed struct
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test unpacked struct
|
||||||
|
unpacked_struct_test = new();
|
||||||
|
repeat(10) begin
|
||||||
|
success = unpacked_struct_test.randomize();
|
||||||
|
if (success == 0) $stop;
|
||||||
|
unpacked_struct_test.check(); // Self-check for unpacked struct
|
||||||
|
end
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -69,10 +69,10 @@
|
||||||
{"type":"BASICDTYPE","name":"logic","addr":"(RB)","loc":"d,24:7,24:12","dtypep":"(RB)","keyword":"logic","generic":false,"rangep": []},
|
{"type":"BASICDTYPE","name":"logic","addr":"(RB)","loc":"d,24:7,24:12","dtypep":"(RB)","keyword":"logic","generic":false,"rangep": []},
|
||||||
{"type":"STRUCTDTYPE","name":"m.my_struct","addr":"(K)","loc":"d,20:12,20:18","dtypep":"(K)","packed":true,"isFourstate":true,"generic":false,"classOrPackagep":"UNLINKED",
|
{"type":"STRUCTDTYPE","name":"m.my_struct","addr":"(K)","loc":"d,20:12,20:18","dtypep":"(K)","packed":true,"isFourstate":true,"generic":false,"classOrPackagep":"UNLINKED",
|
||||||
"membersp": [
|
"membersp": [
|
||||||
{"type":"MEMBERDTYPE","name":"clk","addr":"(SB)","loc":"d,21:19,21:22","dtypep":"(OB)","generic":false,"childDTypep": [],"valuep": []},
|
{"type":"MEMBERDTYPE","name":"clk","addr":"(SB)","loc":"d,21:19,21:22","dtypep":"(OB)","isConstrainedRand":false,"name":"clk","tag":"this is clk","generic":false,"refDTypep":"(OB)","childDTypep": [],"valuep": []},
|
||||||
{"type":"MEMBERDTYPE","name":"k","addr":"(TB)","loc":"d,22:19,22:20","dtypep":"(PB)","generic":false,"childDTypep": [],"valuep": []},
|
{"type":"MEMBERDTYPE","name":"k","addr":"(TB)","loc":"d,22:19,22:20","dtypep":"(PB)","isConstrainedRand":false,"name":"k","tag":"","generic":false,"refDTypep":"(PB)","childDTypep": [],"valuep": []},
|
||||||
{"type":"MEMBERDTYPE","name":"enable","addr":"(UB)","loc":"d,23:19,23:25","dtypep":"(QB)","generic":false,"childDTypep": [],"valuep": []},
|
{"type":"MEMBERDTYPE","name":"enable","addr":"(UB)","loc":"d,23:19,23:25","dtypep":"(QB)","isConstrainedRand":false,"name":"enable","tag":"enable","generic":false,"refDTypep":"(QB)","childDTypep": [],"valuep": []},
|
||||||
{"type":"MEMBERDTYPE","name":"data","addr":"(VB)","loc":"d,24:19,24:23","dtypep":"(RB)","generic":false,"childDTypep": [],"valuep": []}
|
{"type":"MEMBERDTYPE","name":"data","addr":"(VB)","loc":"d,24:19,24:23","dtypep":"(RB)","isConstrainedRand":false,"name":"data","tag":"data","generic":false,"refDTypep":"(RB)","childDTypep": [],"valuep": []}
|
||||||
]},
|
]},
|
||||||
{"type":"IFACEREFDTYPE","name":"","addr":"(O)","loc":"d,29:8,29:12","dtypep":"(O)","isPortDecl":false,"isVirtual":false,"cellName":"itop","ifaceName":"ifc","modportName":"","generic":false,"ifacep":"UNLINKED","cellp":"(L)","modportp":"UNLINKED","paramsp": []},
|
{"type":"IFACEREFDTYPE","name":"","addr":"(O)","loc":"d,29:8,29:12","dtypep":"(O)","isPortDecl":false,"isVirtual":false,"cellName":"itop","ifaceName":"ifc","modportName":"","generic":false,"ifacep":"UNLINKED","cellp":"(L)","modportp":"UNLINKED","paramsp": []},
|
||||||
{"type":"BASICDTYPE","name":"logic","addr":"(S)","loc":"d,31:27,31:28","dtypep":"(S)","keyword":"logic","range":"31:0","generic":true,"rangep": []},
|
{"type":"BASICDTYPE","name":"logic","addr":"(S)","loc":"d,31:27,31:28","dtypep":"(S)","keyword":"logic","range":"31:0","generic":true,"rangep": []},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue