parent
44f49669a3
commit
0380a36c76
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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,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
|
||||||
Loading…
Reference in New Issue