Fix constrained random for > 64-bit associative arrays (#5670) (#5682)

This commit is contained in:
Yilou Wang 2025-01-09 14:33:38 +01:00 committed by GitHub
parent 44f49669a3
commit 0380a36c76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 312 additions and 82 deletions

View File

@ -282,6 +282,7 @@ std::string parseNestedSelect(const std::string& nested_select_expr,
indices.push_back(idx); indices.push_back(idx);
return name; return name;
} }
//====================================================================== //======================================================================
// VlRandomizer:: Methods // VlRandomizer:: Methods
@ -467,10 +468,19 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
"hex_index contains invalid format"); "hex_index contains invalid format");
continue; continue;
} }
const long long index = std::stoll(hex_index.substr(start + 2), nullptr, 16); std::string trimmed_hex = hex_index.substr(start + 2);
oss << "[" << index << "]";
if (trimmed_hex.size() <= 8) { // Small numbers: <= 32 bits
// Convert to decimal and output directly
oss << "[" << std::to_string(std::stoll(trimmed_hex, nullptr, 16)) << "]";
} else { // Large numbers: > 32 bits
// Trim leading zeros and handle empty case
trimmed_hex.erase(0, trimmed_hex.find_first_not_of('0'));
oss << "[" << (trimmed_hex.empty() ? "0" : trimmed_hex) << "]";
}
} }
const std::string indexed_name = oss.str(); const std::string indexed_name = oss.str();
const auto it = std::find_if(m_arr_vars.begin(), m_arr_vars.end(), const auto it = std::find_if(m_arr_vars.begin(), m_arr_vars.end(),
[&indexed_name](const auto& entry) { [&indexed_name](const auto& entry) {
return entry.second->m_name == indexed_name; return entry.second->m_name == indexed_name;

View File

@ -27,8 +27,10 @@
#include "verilated.h" #include "verilated.h"
#include <iomanip>
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include <sstream>
//============================================================================= //=============================================================================
// VlRandomExpr and subclasses represent expressions for the constraint solver. // VlRandomExpr and subclasses represent expressions for the constraint solver.
@ -38,10 +40,10 @@ public:
m_name; // Name of the array variable, including index notation (e.g., arr[2][1]) m_name; // Name of the array variable, including index notation (e.g., arr[2][1])
void* const m_datap; // Reference to the array variable data void* const m_datap; // Reference to the array variable data
const int m_index; // Flattened (1D) index of the array element const int m_index; // Flattened (1D) index of the array element
const std::vector<size_t> m_indices; // Multi-dimensional indices of the array element const std::vector<IData> m_indices; // Multi-dimensional indices of the array element
const std::vector<size_t> m_idxWidths; // Multi-dimensional indices' bit widths const std::vector<size_t> m_idxWidths; // Multi-dimensional indices' bit widths
ArrayInfo(const std::string& name, void* datap, int index, const std::vector<size_t>& indices, ArrayInfo(const std::string& name, void* datap, int index, const std::vector<IData>& indices,
const std::vector<size_t>& idxWidths) const std::vector<size_t>& idxWidths)
: m_name(name) : m_name(name)
, m_datap(datap) , m_datap(datap)
@ -110,16 +112,31 @@ public:
return nullptr; return nullptr;
} }
} }
void emitSelect(std::ostream& s, const std::vector<size_t>& indices, void emitHexs(std::ostream& s, const std::vector<IData>& indices, const size_t bit_width,
size_t idx) const {
for (int j = bit_width - 4; j >= 0; j -= 4) {
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
}
}
void emitSelect(std::ostream& s, const std::vector<IData>& indices,
const std::vector<size_t>& idxWidths) const { const std::vector<size_t>& idxWidths) const {
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select "; const size_t num_indices = idxWidths.size();
size_t wide_size = 0;
for (size_t idx = 0; idx < num_indices; ++idx) s << "(select ";
s << name(); s << name();
for (size_t idx = 0; idx < indices.size(); ++idx) {
s << " #x"; for (size_t idx = 0; idx < num_indices; ++idx) {
const size_t bit_width = idxWidths[idx]; const size_t bit_width = idxWidths[idx];
for (int j = bit_width - 4; j >= 0; j -= 4) { s << " #x";
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
const size_t emit_count = (bit_width > 32) ? (idxWidths[idx] / 32) : 1;
for (size_t i = 0; i < emit_count; ++i) {
emitHexs(s, indices, (bit_width > 32) ? 32 : bit_width, wide_size + i);
} }
wide_size += (idxWidths[idx] > 32) ? (idxWidths[idx] / 32) : 1;
s << ")"; s << ")";
} }
} }
@ -129,7 +146,7 @@ public:
const std::string indexed_name = name() + std::to_string(i); const std::string indexed_name = name() + std::to_string(i);
const auto it = m_arrVarsRefp->find(indexed_name); const auto it = m_arrVarsRefp->find(indexed_name);
if (it != m_arrVarsRefp->end()) { if (it != m_arrVarsRefp->end()) {
const std::vector<size_t>& indices = it->second->m_indices; const std::vector<IData>& indices = it->second->m_indices;
const std::vector<size_t>& idxWidths = it->second->m_idxWidths; const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
emitSelect(s, indices, idxWidths); emitSelect(s, indices, idxWidths);
} else { } else {
@ -165,7 +182,7 @@ public:
const std::string indexed_name = name() + std::to_string(j); const std::string indexed_name = name() + std::to_string(j);
const auto it = m_arrVarsRefp->find(indexed_name); const auto it = m_arrVarsRefp->find(indexed_name);
if (it != m_arrVarsRefp->end()) { if (it != m_arrVarsRefp->end()) {
const std::vector<size_t>& indices = it->second->m_indices; const std::vector<IData>& indices = it->second->m_indices;
const std::vector<size_t>& idxWidths = it->second->m_idxWidths; const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
emitSelect(s, indices, idxWidths); emitSelect(s, indices, idxWidths);
} else { } else {
@ -176,7 +193,6 @@ public:
}; };
//============================================================================= //=============================================================================
// VlRandomizer is the object holding constraints and variable references. // VlRandomizer is the object holding constraints and variable references.
class VlRandomizer final { class VlRandomizer final {
// MEMBERS // MEMBERS
std::vector<std::string> m_constraints; // Solver-dependent constraints std::vector<std::string> m_constraints; // Solver-dependent constraints
@ -200,45 +216,89 @@ public:
bool next(VlRNG& rngr); bool next(VlRNG& rngr);
template <typename T_Key> template <typename T_Key>
typename std::enable_if<std::is_integral<T_Key>::value>::type typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) <= 4)>::type
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
const std::string& base_name, size_t& idx_width) { const std::string& base_name, size_t& idx_width) {
integral_index = static_cast<size_t>(key); integral_index.push_back(static_cast<size_t>(key));
indexed_name = base_name + "[" + std::to_string(integral_index) + "]"; indexed_name
= base_name + "[" + std::to_string(integral_index[integral_index.size() - 1]) + "]";
idx_width = sizeof(T_Key) * 8; idx_width = sizeof(T_Key) * 8;
} }
template <typename T_Key> template <typename T_Key>
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) > 4)>::type
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
const std::string& base_name, size_t& idx_width) { const std::string& base_name, size_t& idx_width) {
integral_index = string_to_integral(key); constexpr size_t segment_bits = 32;
indexed_name = base_name + "[" + std::to_string(integral_index) + "]"; constexpr T_Key mask = (static_cast<T_Key>(1) << segment_bits) - 1;
idx_width = 64; // 64-bit mask integral_index.push_back(static_cast<size_t>(key >> segment_bits));
integral_index.push_back(static_cast<size_t>(key & mask));
std::ostringstream hex_stream;
hex_stream << std::hex << key;
std::string index_string = hex_stream.str();
index_string.erase(0, index_string.find_first_not_of('0'));
index_string = index_string.empty() ? "0" : index_string;
indexed_name = base_name + "[" + index_string + "]";
idx_width = sizeof(T_Key) * 8;
}
template <typename T_Key>
typename std::enable_if<VlIsVlWide<T_Key>::value>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
const std::string& base_name, size_t& idx_width) {
std::ostringstream hex_stream;
for (size_t i = key.size(); i > 0; --i) {
const size_t segment_value = key.at(i - 1);
hex_stream << std::hex << segment_value;
integral_index.push_back(segment_value);
}
std::string index_string = hex_stream.str();
index_string.erase(0, index_string.find_first_not_of('0'));
index_string = index_string.empty() ? "0" : index_string;
indexed_name = base_name + "[" + index_string + "]";
idx_width = key.size() * 32;
}
template <typename T_Key>
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
const std::string& base_name, size_t& idx_width) {
// Convert the input string to its ASCII hexadecimal representation
std::ostringstream oss;
for (unsigned char c : key) {
oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c);
}
std::string hex_str = oss.str();
// Ensure the hex string is exactly 128 bits (32 hex characters)
hex_str = hex_str.size() > 32 ? hex_str.substr(0, 32)
: std::string(32 - hex_str.size(), '0') + hex_str;
// Split the hex string into 4 segments (32-bit per segment)
integral_index.clear();
for (size_t i = 0; i < hex_str.size(); i += 8) {
integral_index.push_back(std::stoul(hex_str.substr(i, 8), nullptr, 16));
}
indexed_name = base_name + "["
+ (hex_str.find_first_not_of('0') == std::string::npos
? "0"
: hex_str.substr(hex_str.find_first_not_of('0')))
+ "]";
idx_width = 128;
} }
template <typename T_Key> template <typename T_Key>
typename std::enable_if<!std::is_integral<T_Key>::value typename std::enable_if<!std::is_integral<T_Key>::value
&& !std::is_same<T_Key, std::string>::value>::type && !std::is_same<T_Key, std::string>::value
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, && !VlIsVlWide<T_Key>::value>::type
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
const std::string& base_name, size_t& idx_width) { const std::string& base_name, size_t& idx_width) {
VL_FATAL_MT(__FILE__, __LINE__, "randomize", VL_FATAL_MT(__FILE__, __LINE__, "randomize",
"Unsupported: Only integral and string index of associative array is " "Unsupported: Only integral and string index of associative array is "
"supported currently."); "supported currently.");
} }
uint64_t string_to_integral(const std::string& str) {
uint64_t result = 0;
for (char c : str) { result = (result << 8) | static_cast<uint64_t>(c); }
#ifdef VL_DEBUG
if (seen_values.count(result) > 0 && seen_values[result] != str)
VL_WARN_MT(__FILE__, __LINE__, "randomize",
"Conflict detected: Different strings mapped to the same 64-bit index.");
seen_values[result] = str;
#endif
return result;
}
template <typename T> template <typename T>
void write_var(T& var, int width, const char* name, int dimension, void write_var(T& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) { std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
@ -296,14 +356,14 @@ public:
template <typename T> template <typename T>
void record_arr_table(T& var, const std::string name, int dimension, void record_arr_table(T& var, const std::string name, int dimension,
std::vector<size_t> indices, std::vector<size_t> idxWidths) { 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;
} }
template <typename T> template <typename T>
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension, void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
std::vector<size_t> indices, std::vector<size_t> idxWidths) { std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (var.size() != 0)) { if ((dimension > 0) && (var.size() != 0)) {
idxWidths.push_back(32); idxWidths.push_back(32);
for (size_t i = 0; i < var.size(); ++i) { for (size_t i = 0; i < var.size(); ++i) {
@ -316,7 +376,7 @@ public:
} }
template <typename T, std::size_t N_Depth> template <typename T, std::size_t N_Depth>
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension, void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
std::vector<size_t> indices, std::vector<size_t> idxWidths) { std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (N_Depth != 0)) { if ((dimension > 0) && (N_Depth != 0)) {
idxWidths.push_back(32); idxWidths.push_back(32);
for (size_t i = 0; i < N_Depth; ++i) { for (size_t i = 0; i < N_Depth; ++i) {
@ -330,20 +390,27 @@ public:
} }
template <typename T_Key, typename T_Value> template <typename T_Key, typename T_Value>
void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension, void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension,
std::vector<size_t> indices, std::vector<size_t> idxWidths) { std::vector<IData> indices, std::vector<size_t> idxWidths) {
if ((dimension > 0) && (var.size() != 0)) { if ((dimension > 0) && (var.size() != 0)) {
for (auto it = var.begin(); it != var.end(); ++it) { for (auto it = var.begin(); it != var.end(); ++it) {
const T_Key& key = it->first; const T_Key& key = it->first;
const T_Value& value = it->second; const T_Value& value = it->second;
std::string indexed_name; std::string indexed_name;
size_t integral_index; std::vector<size_t> integral_index;
size_t idx_width; size_t idx_width = 0;
process_key(key, indexed_name, integral_index, name, idx_width); process_key(key, indexed_name, integral_index, name, idx_width);
// Update indices and widths
idxWidths.push_back(idx_width); idxWidths.push_back(idx_width);
indices.push_back(integral_index); indices.insert(indices.end(), integral_index.begin(), integral_index.end());
record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths); record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths);
// Cleanup indices and widths
idxWidths.pop_back(); idxWidths.pop_back();
indices.pop_back(); indices.resize(indices.size() - integral_index.size());
} }
} }
} }

View File

@ -451,6 +451,7 @@ struct VlWide final {
// METHODS // METHODS
const EData& at(size_t index) const { return m_storage[index]; } const EData& at(size_t index) const { return m_storage[index]; }
EData& at(size_t index) { return m_storage[index]; } EData& at(size_t index) { return m_storage[index]; }
size_t size() const { return N_Words; }
WData* data() { return &m_storage[0]; } WData* data() { return &m_storage[0]; }
const WData* data() const { return &m_storage[0]; } const WData* data() const { return &m_storage[0]; }
bool operator<(const VlWide<N_Words>& rhs) const { bool operator<(const VlWide<N_Words>& rhs) const {

View File

@ -710,15 +710,19 @@ class ConstraintExprVisitor final : public VNVisitor {
if (editFormat(nodep)) return; if (editFormat(nodep)) return;
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
if (VN_IS(nodep->bitp(), CvtPackString)) { if (VN_IS(nodep->bitp(), CvtPackString)) {
// Extract and truncate the string index to fit within 64 bits
AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString); AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString);
const size_t stringSize = VN_AS(stringp->lhsp(), Const)->width();
if (stringSize > 128) {
stringp->v3warn(
CONSTRAINTIGN,
"Unsupported: Constrained randomization of associative array keys of "
<< stringSize << "bits, limit is 128 bits");
}
VNRelinker handle; VNRelinker handle;
AstNodeExpr* const strIdxp = new AstSFormatF{ AstNodeExpr* const idxp
fl, "#x%16x", false, = new AstSFormatF{fl, "#x%32x", false, stringp->lhsp()->unlinkFrBack(&handle)};
new AstAnd{fl, stringp->lhsp()->unlinkFrBack(&handle), handle.relink(idxp);
new AstConst(fl, AstConst::Unsized64{}, 0xFFFFFFFFFFFFFFFF)}}; editSMT(nodep, nodep->fromp(), idxp);
handle.relink(strIdxp);
editSMT(nodep, nodep->fromp(), strIdxp);
} else { } else {
VNRelinker handle; VNRelinker handle;
const int actual_width = nodep->bitp()->width(); const int actual_width = nodep->bitp()->width();
@ -728,16 +732,10 @@ class ConstraintExprVisitor final : public VNVisitor {
fmt = "#x%2x"; fmt = "#x%2x";
} else if (actual_width <= 16) { } else if (actual_width <= 16) {
fmt = "#x%4x"; fmt = "#x%4x";
} else if (actual_width <= 32) {
fmt = "#x%8x";
} else if (actual_width <= 64) {
fmt = "#x%16x";
} else { } else {
nodep->v3warn(CONSTRAINTIGN, fmt = "#x%" + std::to_string(VL_WORDS_I(actual_width) * 8) + "x";
"Unsupported: Associative array index "
"widths of more than 64 bits during constraint randomization.");
return;
} }
AstNodeExpr* const idxp AstNodeExpr* const idxp
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)}; = new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
handle.relink(idxp); handle.relink(idxp);
@ -1450,11 +1448,8 @@ class RandomizeVisitor final : public VNVisitor {
AstNodeStmt* stmtsp = nullptr; AstNodeStmt* stmtsp = nullptr;
auto createLoopIndex = [&](AstNodeDType* tempDTypep) { auto createLoopIndex = [&](AstNodeDType* tempDTypep) {
if (VN_IS(tempDTypep, AssocArrayDType)) { if (VN_IS(tempDTypep, AssocArrayDType)) {
return new AstVar{ return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""),
fl, VVarType::VAR, uniqueNamep->get(""), VN_AS(tempDTypep, AssocArrayDType)->keyDTypep()};
dtypep->findBasicDType(
((AstBasicDType*)VN_AS(tempDTypep, AssocArrayDType)->keyDTypep())
->keyword())};
} }
return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""), return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""),
dtypep->findBasicDType(VBasicDTypeKwd::UINT32)}; dtypep->findBasicDType(VBasicDTypeKwd::UINT32)};

View File

@ -1,9 +1,6 @@
%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:14:22: Unsupported: Associative array index widths of more than 64 bits during constraint randomization. %Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:12:20: Unsupported: Constrained randomization of associative array keys of 144bits, limit is 128 bits
14 | bit_index_arr[79'd66] == 65; 12 | string_arr["a_very_long_string"] == 65;
| ^ | ^~~~~~~~~~~~~~~~~~~~
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest ... 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. ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:15:24: Unsupported: Associative array index widths of more than 64 bits during constraint randomization.
15 | logic_index_arr[65'd3] == 70;
| ^
%Error: Exiting due to %Error: Exiting due to

10
test_regress/t/t_constraint_assoc_arr_bad.v Normal file → Executable file
View File

@ -4,19 +4,15 @@
// any use, without warranty, 2024 by PlanV GmbH. // any use, without warranty, 2024 by PlanV GmbH.
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
class AssocArrayWarningTest; class AssocArrayWarningTest;
rand int bit_index_arr [bit[78:0]]; rand int string_arr [string];
rand int logic_index_arr [logic[64:0]];
constraint c { constraint c {
bit_index_arr[79'd66] == 65; string_arr["a_very_long_string"] == 65;
logic_index_arr[65'd3] == 70;
} }
function new(); function new();
bit_index_arr = '{79'd66:0}; string_arr["a_very_long_string"] = 0;
logic_index_arr = '{65'd3:0};
endfunction endfunction
endclass endclass

View File

@ -147,11 +147,33 @@ class constrained_2d_associative_array;
/* verilator lint_off SIDEEFFECT */ /* verilator lint_off SIDEEFFECT */
endclass endclass
class AssocArray64bitMoreTest;
rand int bit_index_arr [bit[78:0]];
rand int logic_index_arr [logic[64:0]];
constraint c {
bit_index_arr[79'd66] == 65;
logic_index_arr[65'd3] == 70;
}
function new();
bit_index_arr = '{79'd66:0};
logic_index_arr = '{65'd3:0};
endfunction
function void self_check();
if (bit_index_arr[79'd66] != 65) $stop;
if (logic_index_arr[65'd3] != 70) $stop;
endfunction
endclass
module t_constraint_assoc_arr_basic; module t_constraint_assoc_arr_basic;
constrained_associative_array_basic my_array; constrained_associative_array_basic my_array;
constrained_1d_associative_array my_1d_array; constrained_1d_associative_array my_1d_array;
constrained_2d_associative_array my_2d_array; constrained_2d_associative_array my_2d_array;
AssocArray64bitMoreTest test_obj;
int success; int success;
initial begin initial begin
@ -165,10 +187,16 @@ module t_constraint_assoc_arr_basic;
if (success == 0) $stop; if (success == 0) $stop;
my_1d_array.self_check(); my_1d_array.self_check();
my_1d_array = new(); my_2d_array = new();
success = my_1d_array.randomize(); success = my_2d_array.randomize();
if (success == 0) $stop; if (success == 0) $stop;
my_1d_array.self_check(); my_2d_array.self_check();
test_obj = new();
repeat(2) begin
success = test_obj.randomize();
if (success != 1) $stop;
end
// my_1d_array.debug_display(); // my_1d_array.debug_display();
// my_2d_array.debug_display(); // my_2d_array.debug_display();

View File

@ -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()

View File

@ -0,0 +1,115 @@
// 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
class AssocIntegralWide;
rand bit [31:0] assoc_array[bit[64:0]];
rand bit [31:0] assoc_array_128[bit[128:0]];
rand bit [31:0] assoc_array_2d[bit[64:0]][bit[128:0]];
constraint valid_entries {
assoc_array[65'd6] == 32'd8;
assoc_array[65'h1FFFFFFFFFFFFFFFF] == 32'hDEADBEEF;
assoc_array_128[129'd6] == 32'd16;
assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] == 32'hCAFEBABE;
assoc_array_2d[65'd6][129'd6] == 32'd32;
assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] == 32'hBADF00D;
}
// Constructor to initialize arrays
function new();
assoc_array[65'd0] = 32'd0;
assoc_array[65'd6] = 32'd0;
assoc_array[65'h1FFFFFFFFFFFFFFFF] = 32'd0;
assoc_array_128[129'd0] = 32'd0;
assoc_array_128[129'd6] = 32'd0;
assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] = 32'd0;
assoc_array_2d[65'd6][129'd6] = 32'd0;
assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] = 32'd0;
endfunction
// Self-check function to verify constraints
function void self_check();
if (assoc_array[65'd6] != 32'd8)
$stop;
if (assoc_array[65'h1FFFFFFFFFFFFFFFF] != 32'hDEADBEEF)
$stop;
if (assoc_array_128[129'd6] != 32'd16)
$stop;
if (assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] != 32'hCAFEBABE)
$stop;
if (assoc_array_2d[65'd6][129'd6] != 32'd32)
$stop;
if (assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] != 32'hBADF00D)
$stop;
endfunction
endclass
class AssocStringWide;
rand bit [31:0] array_32[string];
rand bit [31:0] array_64[string];
rand bit [31:0] array_96[string];
rand bit [31:0] array_128[string];
constraint valid_entries {
// <= 32 bits
array_32["pv"] == 32'd10;
// > 32 and <= 64 bits
array_64["verilog"] == 32'd20;
// > 32 and <= 64 bits
array_96["verilator"] == 32'd30;
// > 64 and <= 96 bits
array_128["systemverilog"] == 32'd40;
}
function new();
array_32["pv"] = 32'd0;
array_64["verilog"] = 32'd0;
array_96["verilator"] = 32'd0;
array_128["systemverilog"] = 32'd0;
endfunction
function void self_check();
if (array_32["pv"] != 32'd10) $stop;
if (array_64["verilog"] != 32'd20) $stop;
if (array_96["verilator"] != 32'd30) $stop;
if (array_128["systemverilog"] != 32'd40) $stop;
endfunction
endclass
module t_constraint_assoc_arr_wide;
AssocIntegralWide integral_wide;
AssocStringWide string_wide;
int success;
initial begin
integral_wide = new();
string_wide = new();
success = integral_wide.randomize();
if (success != 1) $stop;
integral_wide.self_check();
success = string_wide.randomize();
if (success != 1) $stop;
string_wide.self_check();
$write("*-* All Finished *-*\n");
$finish;
end
endmodule