parent
2358f5c2a2
commit
a80aa07de6
|
@ -382,8 +382,9 @@ public:
|
|||
|
||||
// Register associative array of non-struct types
|
||||
template <typename T_Key, typename T_Value>
|
||||
void write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
typename std::enable_if<!VlContainsCustomStruct<T_Value>::value, void>::type
|
||||
write_var(VlAssocArray<T_Key, T_Value>& 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;
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
||||
|
@ -394,8 +395,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Register associative array of structs
|
||||
|
||||
// Register associative array of structs
|
||||
template <typename T_Key, typename T_Value>
|
||||
typename std::enable_if<VlContainsCustomStruct<T_Value>::value, void>::type
|
||||
write_var(VlAssocArray<T_Key, T_Value>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (dimension > 0) record_struct_arr(var, name, dimension, {}, {});
|
||||
}
|
||||
// ----------------------------------------
|
||||
// --- Record Arrays: flat and struct ---
|
||||
// ----------------------------------------
|
||||
|
@ -476,10 +482,12 @@ public:
|
|||
std::vector<size_t> idxWidths) {
|
||||
std::ostringstream oss;
|
||||
for (size_t i = 0; i < indices.size(); ++i) {
|
||||
oss << std::hex << static_cast<int>(indices[i]);
|
||||
oss << std::hex << std::setw(int(idxWidths[i] / 4)) << std::setfill('0')
|
||||
<< static_cast<int>(indices[i]);
|
||||
if (i < indices.size() - 1) oss << ".";
|
||||
}
|
||||
write_var(var, 1ULL, (name + "." + oss.str()).c_str(), 1ULL);
|
||||
write_var(var, 1ULL,
|
||||
oss.str().length() > 0 ? (name + "." + oss.str()).c_str() : name.c_str(), 1ULL);
|
||||
}
|
||||
|
||||
// Recursively process VlUnpacked of structs
|
||||
|
@ -487,7 +495,8 @@ public:
|
|||
void record_struct_arr(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
|
||||
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||
if (dimension > 0 && N_Depth != 0) {
|
||||
idxWidths.push_back(32);
|
||||
constexpr size_t idx_width = 1 << VL_CLOG2_CE_Q(VL_CLOG2_CE_Q(N_Depth) + 1);
|
||||
idxWidths.push_back(idx_width);
|
||||
for (size_t i = 0; i < N_Depth; ++i) {
|
||||
indices.push_back(i);
|
||||
record_struct_arr(var.operator[](i), name, dimension - 1, indices, idxWidths);
|
||||
|
@ -510,9 +519,32 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Add support for associative arrays of structs
|
||||
// Recursively process associative arrays of structs
|
||||
template <typename T_Key, typename T_Value>
|
||||
void record_struct_arr(VlAssocArray<T_Key, T_Value>& var, const std::string name,
|
||||
int dimension, std::vector<IData> indices,
|
||||
std::vector<size_t> idxWidths) {
|
||||
if ((dimension > 0) && (!var.empty())) {
|
||||
for (auto it = var.begin(); it != var.end(); ++it) {
|
||||
const T_Key& key = it->first;
|
||||
const T_Value& value = it->second;
|
||||
|
||||
std::string indexed_name;
|
||||
std::vector<size_t> integral_index;
|
||||
size_t idx_width = 0;
|
||||
|
||||
process_key(key, indexed_name, integral_index, name, idx_width);
|
||||
std::ostringstream oss;
|
||||
for (int i = 0; i < integral_index.size(); ++i)
|
||||
oss << std::hex << static_cast<int>(integral_index[i]);
|
||||
|
||||
std::string result = oss.str();
|
||||
result.insert(result.begin(), int(idx_width / 4) - result.size(), '0');
|
||||
record_struct_arr(var.at(key), name + "." + result, dimension - 1, indices,
|
||||
idxWidths);
|
||||
}
|
||||
}
|
||||
}
|
||||
// --------------------------
|
||||
// --- Helper functions ---
|
||||
// --------------------------
|
||||
|
|
|
@ -969,6 +969,7 @@ public:
|
|||
|
||||
// Size of array. Verilog: function int size(), or int num()
|
||||
int size() const { return m_map.size(); }
|
||||
bool empty() const { return m_map.empty(); }
|
||||
// Clear array. Verilog: function void delete([input index])
|
||||
void clear() { m_map.clear(); }
|
||||
void erase(const T_Key& index) { m_map.erase(index); }
|
||||
|
@ -1265,7 +1266,7 @@ std::string VL_TO_STRING(const VlAssocArray<T_Key, T_Value>& obj) {
|
|||
}
|
||||
|
||||
template <typename T_Key, typename T_Value>
|
||||
struct VlContainsCustomStruct<VlAssocArray<T_Key, T_Value>> : VlContainsCustomStruct<T_Key> {};
|
||||
struct VlContainsCustomStruct<VlAssocArray<T_Key, T_Value>> : VlContainsCustomStruct<T_Value> {};
|
||||
|
||||
template <typename T_Key, typename T_Value>
|
||||
void VL_READMEM_N(bool hex, int bits, const std::string& filename,
|
||||
|
@ -1597,8 +1598,8 @@ std::string VL_TO_STRING(const VlUnpacked<T_Value, N_Depth>& obj) {
|
|||
return obj.to_string();
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
struct VlContainsCustomStruct<VlUnpacked<T, N>> : VlContainsCustomStruct<T> {};
|
||||
template <typename T_Value, std::size_t N_Depth>
|
||||
struct VlContainsCustomStruct<VlUnpacked<T_Value, N_Depth>> : VlContainsCustomStruct<T_Value> {};
|
||||
|
||||
//===================================================================
|
||||
// Helper to apply the given indices to a target expression
|
||||
|
|
|
@ -541,7 +541,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstSFormatF* const newp = new AstSFormatF{nodep->fileline(), smtExpr, false, argsp};
|
||||
if (m_structSel && newp->name() == "(select %@ %@)") {
|
||||
newp->name("%@.%@");
|
||||
newp->exprsp()->nextp()->name("%x");
|
||||
if (!VN_IS(nodep, AssocSel)) newp->exprsp()->nextp()->name("%x");
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
@ -734,8 +734,10 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
// Mark Random for structArray
|
||||
if (VN_IS(nodep->fromp(), ArraySel)) {
|
||||
AstNodeExpr* const fromp = VN_AS(nodep->fromp(), ArraySel)->fromp();
|
||||
if (VN_IS(nodep->fromp(), ArraySel) || VN_IS(nodep->fromp(), CMethodHard)) {
|
||||
AstNodeExpr* const fromp = VN_IS(nodep->fromp(), ArraySel)
|
||||
? VN_AS(nodep->fromp(), ArraySel)->fromp()
|
||||
: VN_AS(nodep->fromp(), CMethodHard)->fromp();
|
||||
AstStructDType* const dtypep
|
||||
= VN_AS(fromp->dtypep()->skipRefp()->subDTypep()->skipRefp(), StructDType);
|
||||
dtypep->markConstrainedRand(true);
|
||||
|
@ -755,7 +757,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
if (VN_AS(nodep->fromp(), SFormatF)->name() == "%@.%@") {
|
||||
newp = new AstSFormatF{fl, "%@.%@." + nodep->name(), false,
|
||||
VN_AS(nodep->fromp(), SFormatF)->exprsp()->cloneTreePure(true)};
|
||||
newp->exprsp()->nextp()->name("%x");
|
||||
if (newp->exprsp()->nextp()->name().rfind("#x", 0) == 0)
|
||||
newp->exprsp()->nextp()->name("%x"); // for #x%x to %x
|
||||
} else {
|
||||
newp = new AstSFormatF{fl, nodep->fromp()->name() + "." + nodep->name(), false,
|
||||
nullptr};
|
||||
|
@ -767,10 +770,11 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
void visit(AstAssocSel* nodep) override {
|
||||
if (editFormat(nodep)) return;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
// Adaptive formatting and type handling for associative array keys
|
||||
if (VN_IS(nodep->bitp(), VarRef) && VN_AS(nodep->bitp(), VarRef)->isString()) {
|
||||
VNRelinker handle;
|
||||
AstNodeExpr* const idxp
|
||||
= new AstSFormatF{fl, "#x%32p", false, nodep->bitp()->unlinkFrBack(&handle)};
|
||||
AstNodeExpr* const idxp = new AstSFormatF{fl, (m_structSel ? "%32p" : "#x%32p"), false,
|
||||
nodep->bitp()->unlinkFrBack(&handle)};
|
||||
handle.relink(idxp);
|
||||
editSMT(nodep, nodep->fromp(), idxp);
|
||||
} else if (VN_IS(nodep->bitp(), CvtPackString)
|
||||
|
@ -784,8 +788,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
<< stringSize << "bits, limit is 128 bits");
|
||||
}
|
||||
VNRelinker handle;
|
||||
AstNodeExpr* const idxp
|
||||
= new AstSFormatF{fl, "#x%32x", false, stringp->lhsp()->unlinkFrBack(&handle)};
|
||||
AstNodeExpr* const idxp = new AstSFormatF{fl, (m_structSel ? "%32x" : "#x%32x"), false,
|
||||
stringp->lhsp()->unlinkFrBack(&handle)};
|
||||
handle.relink(idxp);
|
||||
editSMT(nodep, nodep->fromp(), idxp);
|
||||
} else {
|
||||
|
@ -799,13 +803,13 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
std::string fmt;
|
||||
// Normalize to standard bit width
|
||||
if (actual_width <= 8) {
|
||||
fmt = "#x%2x";
|
||||
fmt = m_structSel ? "%2x" : "#x%2x";
|
||||
} else if (actual_width <= 16) {
|
||||
fmt = "#x%4x";
|
||||
fmt = m_structSel ? "%4x" : "#x%4x";
|
||||
} else {
|
||||
fmt = "#x%" + std::to_string(VL_WORDS_I(actual_width) * 8) + "x";
|
||||
fmt = (m_structSel ? "%" : "#x%")
|
||||
+ std::to_string(VL_WORDS_I(actual_width) * 8) + "x";
|
||||
}
|
||||
|
||||
AstNodeExpr* const idxp
|
||||
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
|
||||
handle.relink(idxp);
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
// any use, without warranty, 2025 by PlanV GmbH.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
|
||||
class ArrayStruct;
|
||||
/* verilator lint_off SIDEEFFECT */
|
||||
|
||||
// Struct with an unpacked array
|
||||
typedef int arr_3_t[3];
|
||||
typedef int arr_4_t[4];
|
||||
|
@ -51,19 +53,25 @@ class ArrayStruct;
|
|||
foreach (s1.arr[i]) s1.arr[i] inside {1, 2, 3, 4};
|
||||
foreach (s1.arr_3[i]) s1.arr_3[i] inside {11, 22, 33, 44, 55};
|
||||
}
|
||||
|
||||
constraint c_dynamic { foreach (s2.arr[i]) s2.arr[i] inside {[10:20]}; }
|
||||
|
||||
constraint c_queue { foreach (s3.arr[i]) s3.arr[i] inside {[100:200]}; }
|
||||
|
||||
constraint c_assoc {
|
||||
s4.arr["one"] inside {[10:50]};
|
||||
s4.arr["two"] inside {[51:100]};
|
||||
s4.arr["three"] inside {[101:150]};
|
||||
}
|
||||
|
||||
constraint c_multi_dim { foreach (s5.arr[i, j]) s5.arr[i][j] inside {[0:9]}; }
|
||||
|
||||
constraint c_mix {
|
||||
foreach (s6.mix_arr[i, j]) s6.mix_arr[i][j] inside {[50:100]};
|
||||
}
|
||||
|
||||
function new();
|
||||
|
||||
s1.arr = '{1, 2, 3};
|
||||
s1.arr_3 = '{1, 2, 3};
|
||||
s1.arr_4 = '{0, 2, 3, 4};
|
||||
|
@ -81,9 +89,11 @@ class ArrayStruct;
|
|||
foreach (s6.mix_arr[i]) begin
|
||||
s6.mix_arr[i] = new[i + 1];
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
function void print();
|
||||
|
||||
foreach (s1.arr[i]) $display("s1.arr[%0d] = %0d", i, s1.arr[i]);
|
||||
foreach (s1.arr_3[i]) $display("s1.arr_3[%0d] = %0d", i, s1.arr_3[i]);
|
||||
foreach (s1.arr_4[i]) $display("s1.arr_4[%0d] = %0d", i, s1.arr_4[i]);
|
||||
|
@ -92,10 +102,12 @@ class ArrayStruct;
|
|||
foreach (s4.arr[i]) $display("s4.arr[\"%s\"] = %0d", i, s4.arr[i]);
|
||||
foreach (s5.arr[i, j]) $display("s5.arr[%0d][%0d] = %0d", i, j, s5.arr[i][j]);
|
||||
foreach (s6.mix_arr[i, j]) $display("s6.mix_arr[%0d][%0d] = %0d", i, j, s6.mix_arr[i][j]);
|
||||
|
||||
endfunction
|
||||
|
||||
// Self-test function to verify constraints
|
||||
function void self_test();
|
||||
|
||||
foreach (s1.arr[i]) if (!(s1.arr[i] inside {1, 2, 3, 4})) $stop;
|
||||
foreach (s1.arr_3[i]) if (!(s1.arr_3[i] inside {11, 22, 33, 44, 55})) $stop;
|
||||
// Note: s1.arr_4[0] is not rand
|
||||
|
@ -108,6 +120,7 @@ class ArrayStruct;
|
|||
foreach (s5.arr[i, j]) if (!(s5.arr[i][j] inside {[0:9]})) $stop;
|
||||
foreach (s6.mix_arr[i]) if (s6.mix_arr[i].size() == 0) $stop;
|
||||
foreach (s6.mix_arr[i, j]) if (!(s6.mix_arr[i][j] inside {[50:100]})) $stop;
|
||||
|
||||
endfunction
|
||||
/* verilator lint_off SIDEEFFECT */
|
||||
endclass
|
||||
|
@ -115,66 +128,363 @@ endclass
|
|||
class StructArray;
|
||||
/* verilator lint_off WIDTHTRUNC */
|
||||
typedef struct {
|
||||
rand int arr[3];
|
||||
rand int arr[3]; // static unpacked array
|
||||
rand int a;
|
||||
rand bit [3:0] b;
|
||||
bit c;
|
||||
} struct_t;
|
||||
rand struct_t s_arr[2];
|
||||
|
||||
constraint c_structArray_0 {
|
||||
rand struct_t s_arr[2];
|
||||
rand struct_t s_2d_arr[2][3];
|
||||
rand struct_t s_dyn_arr[];
|
||||
rand struct_t s_que_arr[$];
|
||||
rand struct_t s_assoc_arr[string];
|
||||
rand struct_t s_assoc_arr_2[bit[5:0]];
|
||||
|
||||
constraint c_arr {
|
||||
foreach (s_arr[i])
|
||||
foreach (s_arr[i].arr[j])
|
||||
s_arr[i].arr[j] inside {[0:9]};
|
||||
foreach (s_2d_arr[i, j])
|
||||
foreach (s_2d_arr[i][j].arr[k])
|
||||
s_2d_arr[i][j].arr[k] inside {[9:19]};
|
||||
foreach (s_dyn_arr[i])
|
||||
foreach (s_dyn_arr[i].arr[j])
|
||||
s_dyn_arr[i].arr[j] inside {[19:29]};
|
||||
foreach (s_que_arr[i])
|
||||
foreach (s_que_arr[i].arr[j])
|
||||
s_que_arr[i].arr[j] inside {[29:39]};
|
||||
foreach (s_assoc_arr[i])
|
||||
foreach (s_assoc_arr[i].arr[j])
|
||||
s_assoc_arr[i].arr[j] inside {[39:49]};
|
||||
foreach (s_assoc_arr_2[i])
|
||||
foreach (s_assoc_arr_2[i].arr[j])
|
||||
s_assoc_arr_2[i].arr[j] inside {[49:59]};
|
||||
}
|
||||
constraint c_structArray_1 {
|
||||
foreach (s_arr[i]) s_arr[i].a inside {[10:20]};
|
||||
|
||||
constraint c_others {
|
||||
foreach (s_arr[i]) s_arr[i].a inside {[40:50]};
|
||||
foreach (s_arr[i]) s_arr[i].b inside {[0:7]};
|
||||
|
||||
foreach (s_2d_arr[i, j]) s_2d_arr[i][j].a inside {[50:60]};
|
||||
|
||||
foreach (s_dyn_arr[i]) s_dyn_arr[i].a inside {[60:70]};
|
||||
|
||||
foreach (s_que_arr[i]) s_que_arr[i].a inside {[70:80]};
|
||||
|
||||
foreach (s_assoc_arr[i]) s_assoc_arr[i].a inside {[80:90]};
|
||||
|
||||
foreach (s_assoc_arr_2[i]) s_assoc_arr_2[i].a inside {[90:100]};
|
||||
}
|
||||
|
||||
function new();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
foreach (s_arr[i].arr[j]) s_arr[i].arr[j] = 'h0 + j;
|
||||
s_arr[i].a = 'h10 + i;
|
||||
s_arr[i].b = 'h0 + i;
|
||||
s_arr[i].c = i;
|
||||
foreach (s_arr[i].arr[j])
|
||||
s_arr[i].arr[j] = j;
|
||||
s_arr[i].a = 40 + i;
|
||||
s_arr[i].b = i;
|
||||
s_arr[i].c = 0;
|
||||
end
|
||||
|
||||
foreach (s_2d_arr[i, j]) begin
|
||||
foreach (s_2d_arr[i][j].arr[k])
|
||||
s_2d_arr[i][j].arr[k] = k + 10;
|
||||
s_2d_arr[i][j].a = 50 + i + j;
|
||||
s_2d_arr[i][j].b = i + j;
|
||||
s_2d_arr[i][j].c = 0;
|
||||
end
|
||||
|
||||
foreach (s_dyn_arr[i]) begin
|
||||
s_dyn_arr = new[3];
|
||||
foreach (s_dyn_arr[i].arr[j])
|
||||
s_dyn_arr[i].arr[j] = j + 20;
|
||||
s_dyn_arr[i].a = 60 + i;
|
||||
s_dyn_arr[i].b = i;
|
||||
s_dyn_arr[i].c = 0;
|
||||
end
|
||||
|
||||
for (int i = 0; i < 3; i++) begin
|
||||
s_que_arr.push_back('{arr: '{30, 31, 32}, a: 70 + i, b: i, c: 0});
|
||||
end
|
||||
|
||||
// Associative array with string index
|
||||
foreach (s_assoc_arr["x"].arr[j])
|
||||
s_assoc_arr["x"].arr[j] = j + 40;
|
||||
foreach (s_assoc_arr["y"].arr[j])
|
||||
s_assoc_arr["y"].arr[j] = j + 50;
|
||||
foreach (s_assoc_arr["long_string_index"].arr[j])
|
||||
s_assoc_arr["long_string_index"].arr[j] = j + 60;
|
||||
s_assoc_arr["x"].a = 80;
|
||||
s_assoc_arr["x"].b = 0;
|
||||
s_assoc_arr["x"].c = 0;
|
||||
s_assoc_arr["y"].a = 90;
|
||||
s_assoc_arr["y"].b = 1;
|
||||
s_assoc_arr["y"].c = 0;
|
||||
s_assoc_arr["long_string_index"].a = 100;
|
||||
s_assoc_arr["long_string_index"].b = 2;
|
||||
s_assoc_arr["long_string_index"].c = 0;
|
||||
|
||||
foreach (s_assoc_arr_2[6'd30].arr[j])
|
||||
s_assoc_arr_2[6'd30].arr[j] = j + 70;
|
||||
foreach (s_assoc_arr_2[6'd7].arr[j])
|
||||
s_assoc_arr_2[6'd7].arr[j] = j + 80;
|
||||
s_assoc_arr_2[6'd30].a = 90;
|
||||
s_assoc_arr_2[6'd30].b = 0;
|
||||
s_assoc_arr_2[6'd30].c = 0;
|
||||
s_assoc_arr_2[6'd7].a = 100;
|
||||
s_assoc_arr_2[6'd7].b = 1;
|
||||
s_assoc_arr_2[6'd7].c = 0;
|
||||
|
||||
endfunction
|
||||
|
||||
function void print();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
foreach (s_arr[i].arr[j]) $display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]);
|
||||
foreach (s_arr[i].arr[j])
|
||||
$display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]);
|
||||
$display("s_arr[%0d].a = %0d", i, s_arr[i].a);
|
||||
$display("s_arr[%0d].b = %0d", i, s_arr[i].b);
|
||||
$display("s_arr[%0d].c = %0d", i, s_arr[i].c);
|
||||
end
|
||||
|
||||
foreach (s_2d_arr[i, j]) begin
|
||||
foreach (s_2d_arr[i][j].arr[k])
|
||||
$display("s_2d_arr[%0d][%0d].arr[%0d] = %0d", i, j, k, s_2d_arr[i][j].arr[k]);
|
||||
$display("s_2d_arr[%0d][%0d].a = %0d", i, j, s_2d_arr[i][j].a);
|
||||
$display("s_2d_arr[%0d][%0d].b = %0d", i, j, s_2d_arr[i][j].b);
|
||||
$display("s_2d_arr[%0d][%0d].c = %0d", i, j, s_2d_arr[i][j].c);
|
||||
end
|
||||
|
||||
foreach (s_dyn_arr[i]) begin
|
||||
foreach (s_dyn_arr[i].arr[j])
|
||||
$display("s_dyn_arr[%0d].arr[%0d] = %0d", i, j, s_dyn_arr[i].arr[j]);
|
||||
$display("s_dyn_arr[%0d].a = %0d", i, s_dyn_arr[i].a);
|
||||
$display("s_dyn_arr[%0d].b = %0d", i, s_dyn_arr[i].b);
|
||||
$display("s_dyn_arr[%0d].c = %0d", i, s_dyn_arr[i].c);
|
||||
end
|
||||
|
||||
foreach (s_que_arr[i]) begin
|
||||
foreach (s_que_arr[i].arr[j])
|
||||
$display("s_que_arr[%0d].arr[%0d] = %0d", i, j, s_que_arr[i].arr[j]);
|
||||
$display("s_que_arr[%0d].a = %0d", i, s_que_arr[i].a);
|
||||
$display("s_que_arr[%0d].b = %0d", i, s_que_arr[i].b);
|
||||
$display("s_que_arr[%0d].c = %0d", i, s_que_arr[i].c);
|
||||
end
|
||||
|
||||
foreach (s_assoc_arr["x"].arr[j])
|
||||
$display("s_assoc_arr[x].arr[%0d] = %0d", j, s_assoc_arr["x"].arr[j]);
|
||||
$display("s_assoc_arr[x].a = %0d", s_assoc_arr["x"].a);
|
||||
$display("s_assoc_arr[x].b = %0d", s_assoc_arr["x"].b);
|
||||
$display("s_assoc_arr[x].c = %0d", s_assoc_arr["x"].c);
|
||||
foreach (s_assoc_arr["y"].arr[j])
|
||||
$display("s_assoc_arr[y].arr[%0d] = %0d", j, s_assoc_arr["y"].arr[j]);
|
||||
$display("s_assoc_arr[y].a = %0d", s_assoc_arr["y"].a);
|
||||
$display("s_assoc_arr[y].b = %0d", s_assoc_arr["y"].b);
|
||||
$display("s_assoc_arr[y].c = %0d", s_assoc_arr["y"].c);
|
||||
foreach (s_assoc_arr["long_string_index"].arr[j])
|
||||
$display("s_assoc_arr[long_string_index].arr[%0d] = %0d", j, s_assoc_arr["long_string_index"].arr[j]);
|
||||
$display("s_assoc_arr[long_string_index].a = %0d", s_assoc_arr["long_string_index"].a);
|
||||
$display("s_assoc_arr[long_string_index].b = %0d", s_assoc_arr["long_string_index"].b);
|
||||
$display("s_assoc_arr[long_string_index].c = %0d", s_assoc_arr["long_string_index"].c);
|
||||
|
||||
foreach (s_assoc_arr_2[6'd30].arr[j])
|
||||
$display("s_assoc_arr_2[30].arr[%0d] = %0d", j, s_assoc_arr_2[6'd30].arr[j]);
|
||||
$display("s_assoc_arr_2[30].a = %0d", s_assoc_arr_2[6'd30].a);
|
||||
$display("s_assoc_arr_2[30].b = %0d", s_assoc_arr_2[6'd30].b);
|
||||
$display("s_assoc_arr_2[30].c = %0d", s_assoc_arr_2[6'd30].c);
|
||||
foreach (s_assoc_arr_2[6'd7].arr[j])
|
||||
$display("s_assoc_arr_2[7].arr[%0d] = %0d", j, s_assoc_arr_2[6'd7].arr[j]);
|
||||
$display("s_assoc_arr_2[7].a = %0d", s_assoc_arr_2[6'd7].a);
|
||||
$display("s_assoc_arr_2[7].b = %0d", s_assoc_arr_2[6'd7].b);
|
||||
$display("s_assoc_arr_2[7].c = %0d", s_assoc_arr_2[6'd7].c);
|
||||
|
||||
endfunction
|
||||
|
||||
function void self_test();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
foreach (s_arr[i].arr[j]) if (!(s_arr[i].arr[j] inside {[0:9]})) $stop;
|
||||
if (!(s_arr[i].a inside {[10:20]})) $stop;
|
||||
if (!(s_arr[0].c == 0)) $stop;
|
||||
if (!(s_arr[1].c == 1)) $stop;
|
||||
foreach (s_arr[i].arr[j])
|
||||
if (!(s_arr[i].arr[j] inside {[0:9]})) $stop;
|
||||
if (!(s_arr[i].a inside {[40:50]})) $stop;
|
||||
end
|
||||
|
||||
foreach (s_2d_arr[i, j]) begin
|
||||
foreach (s_2d_arr[i][j].arr[k])
|
||||
if (!(s_2d_arr[i][j].arr[k] inside {[9:19]})) $stop;
|
||||
if (!(s_2d_arr[i][j].a inside {[50:60]})) $stop;
|
||||
end
|
||||
|
||||
foreach (s_dyn_arr[i]) begin
|
||||
foreach (s_dyn_arr[i].arr[j])
|
||||
if (!(s_dyn_arr[i].arr[j] inside {[19:29]})) $stop;
|
||||
if (!(s_dyn_arr[i].a inside {[60:70]})) $stop;
|
||||
end
|
||||
|
||||
foreach (s_que_arr[i]) begin
|
||||
foreach (s_que_arr[i].arr[j])
|
||||
if (!(s_que_arr[i].arr[j] inside {[29:39]})) $stop;
|
||||
if (!(s_que_arr[i].a inside {[70:80]})) $stop;
|
||||
end
|
||||
|
||||
foreach (s_assoc_arr["x"].arr[j])
|
||||
if (!(s_assoc_arr["x"].arr[j] inside {[39:49]})) $stop;
|
||||
if (!(s_assoc_arr["x"].a inside {[80:90]})) $stop;
|
||||
foreach (s_assoc_arr["y"].arr[j])
|
||||
if (!(s_assoc_arr["y"].arr[j] inside {[39:49]})) $stop;
|
||||
if (!(s_assoc_arr["y"].a inside {[80:90]})) $stop;
|
||||
foreach (s_assoc_arr["long_string_index"].arr[j])
|
||||
if (!(s_assoc_arr["long_string_index"].arr[j] inside {[39:49]})) $stop;
|
||||
if (!(s_assoc_arr["long_string_index"].a inside {[80:90]})) $stop;
|
||||
|
||||
foreach (s_assoc_arr_2[6'd30].arr[j])
|
||||
if (!(s_assoc_arr_2[6'd30].arr[j] inside {[49:59]})) $stop;
|
||||
if (!(s_assoc_arr_2[6'd30].a inside {[90:100]})) $stop;
|
||||
foreach (s_assoc_arr_2[6'd7].arr[j])
|
||||
if (!(s_assoc_arr_2[6'd7].arr[j] inside {[49:59]})) $stop;
|
||||
if (!(s_assoc_arr_2[6'd7].a inside {[90:100]})) $stop;
|
||||
|
||||
endfunction
|
||||
|
||||
/* verilator lint_off WIDTHTRUNC */
|
||||
endclass
|
||||
|
||||
class MixedStructure;
|
||||
/* verilator lint_off WIDTHTRUNC */
|
||||
typedef struct {
|
||||
rand int arr[3]; // static unpacked array
|
||||
rand int dyn[]; // dynamic array
|
||||
rand int que[$]; // queue
|
||||
rand int assoc[string]; // associative array with string key
|
||||
rand int a;
|
||||
rand bit [3:0] b;
|
||||
bit c;
|
||||
} struct_t;
|
||||
|
||||
rand struct_t s_arr[2];
|
||||
|
||||
constraint c_static {
|
||||
foreach (s_arr[i])
|
||||
foreach (s_arr[i].arr[j])
|
||||
s_arr[i].arr[j] inside {[0:9]};
|
||||
}
|
||||
|
||||
constraint c_dyn {
|
||||
foreach (s_arr[i])
|
||||
foreach (s_arr[i].dyn[j])
|
||||
s_arr[i].dyn[j] inside {[10:19]};
|
||||
}
|
||||
|
||||
constraint c_queue {
|
||||
foreach (s_arr[i])
|
||||
foreach (s_arr[i].que[j])
|
||||
s_arr[i].que[j] inside {[20:29]};
|
||||
}
|
||||
|
||||
constraint c_assoc {
|
||||
foreach (s_arr[i]) {
|
||||
s_arr[i].assoc["x"] inside {[30:39]};
|
||||
s_arr[i].assoc["y"] inside {[30:39]};
|
||||
}
|
||||
}
|
||||
|
||||
constraint c_other {
|
||||
foreach (s_arr[i]) s_arr[i].a inside {[40:50]};
|
||||
}
|
||||
|
||||
function new();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
s_arr[i].dyn = new[2];
|
||||
s_arr[i].que = {0, 0};
|
||||
s_arr[i].assoc = '{"x": 0, "y": 0};
|
||||
|
||||
foreach (s_arr[i].arr[j])
|
||||
s_arr[i].arr[j] = j;
|
||||
foreach (s_arr[i].dyn[j])
|
||||
s_arr[i].dyn[j] = 10 + j;
|
||||
foreach (s_arr[i].que[j])
|
||||
s_arr[i].que[j] = 20 + j;
|
||||
|
||||
s_arr[i].assoc["x"] = i + 30;
|
||||
s_arr[i].assoc["y"] = i + 31;
|
||||
s_arr[i].a = 40 + i;
|
||||
s_arr[i].b = i;
|
||||
s_arr[i].c = i;
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
function void print();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
foreach (s_arr[i].arr[j])
|
||||
$display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]);
|
||||
foreach (s_arr[i].dyn[j])
|
||||
$display("s_arr[%0d].dyn[%0d] = %0d", i, j, s_arr[i].dyn[j]);
|
||||
foreach (s_arr[i].que[j])
|
||||
$display("s_arr[%0d].que[%0d] = %0d", i, j, s_arr[i].que[j]);
|
||||
|
||||
$display("s_arr[%0d].assoc[\"x\"] = %0d", i, s_arr[i].assoc["x"]);
|
||||
$display("s_arr[%0d].assoc[\"y\"] = %0d", i, s_arr[i].assoc["y"]);
|
||||
$display("s_arr[%0d].a = %0d", i, s_arr[i].a);
|
||||
$display("s_arr[%0d].b = %0d", i, s_arr[i].b);
|
||||
$display("s_arr[%0d].c = %0d", i, s_arr[i].c);
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
function void self_test();
|
||||
|
||||
foreach (s_arr[i]) begin
|
||||
foreach (s_arr[i].arr[j])
|
||||
if (!(s_arr[i].arr[j] inside {[0:9]})) $stop;
|
||||
foreach (s_arr[i].dyn[j])
|
||||
if (!(s_arr[i].dyn[j] inside {[10:19]})) $stop;
|
||||
foreach (s_arr[i].que[j])
|
||||
if (!(s_arr[i].que[j] inside {[20:29]})) $stop;
|
||||
if (!(s_arr[i].assoc.exists("x") && s_arr[i].assoc["x"] inside {[30:39]})) $stop;
|
||||
if (!(s_arr[i].assoc.exists("y") && s_arr[i].assoc["y"] inside {[30:39]})) $stop;
|
||||
if (!(s_arr[i].a inside {[40:50]})) $stop;
|
||||
if (i == 0 && s_arr[i].c != 0) $stop;
|
||||
if (i == 1 && s_arr[i].c != 1) $stop;
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
/* verilator lint_off WIDTHTRUNC */
|
||||
endclass
|
||||
|
||||
module t_constraint_struct_complex;
|
||||
|
||||
int success;
|
||||
ArrayStruct as_c;
|
||||
StructArray sa_c;
|
||||
MixedStructure mixed_c;
|
||||
|
||||
initial begin
|
||||
as_c = new();
|
||||
sa_c = new();
|
||||
mixed_c = new();
|
||||
|
||||
success = as_c.randomize();
|
||||
if (success != 1) $stop;
|
||||
as_c.self_test();
|
||||
// as_c.print();
|
||||
// $display(" ArrayStruct passed! \n");
|
||||
|
||||
success = sa_c.randomize();
|
||||
if (success != 1) $stop;
|
||||
sa_c.self_test();
|
||||
// sa_c.print();
|
||||
// $display(" StructArray passed! \n");
|
||||
|
||||
success = mixed_c.randomize();
|
||||
if (success != 1) $stop;
|
||||
mixed_c.self_test();
|
||||
// mixed_c.print();
|
||||
// $display(" MixedStructure passed! \n");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue