mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
This commit is contained in:
parent
32f9cf072b
commit
54ef9ad31c
@ -464,10 +464,10 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
const size_t start = hex_index.find_first_not_of(" ");
|
||||
if (start == std::string::npos || hex_index.substr(start, 2) != "#x") {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"Error: hex_index contains invalid format");
|
||||
"hex_index contains invalid format");
|
||||
continue;
|
||||
}
|
||||
const int index = std::stoi(hex_index.substr(start + 2), nullptr, 16);
|
||||
const long long index = std::stoll(hex_index.substr(start + 2), nullptr, 16);
|
||||
oss << "[" << index << "]";
|
||||
}
|
||||
const std::string indexed_name = oss.str();
|
||||
@ -481,7 +481,7 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
idx = ss.str();
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"Error: indexed_name not found in m_arr_vars");
|
||||
"indexed_name not found in m_arr_vars");
|
||||
}
|
||||
}
|
||||
varr.set(idx, value);
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||
class ArrayInfo final {
|
||||
@ -38,12 +39,15 @@ public:
|
||||
void* const m_datap; // Reference to the array variable data
|
||||
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<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<size_t>& indices,
|
||||
const std::vector<size_t>& idxWidths)
|
||||
: m_name(name)
|
||||
, m_datap(datap)
|
||||
, m_index(index)
|
||||
, m_indices(indices) {}
|
||||
, m_indices(indices)
|
||||
, m_idxWidths(idxWidths) {}
|
||||
};
|
||||
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
||||
|
||||
@ -90,25 +94,30 @@ public:
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VlRandomQueueVar final : public VlRandomVar {
|
||||
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomQueueVar(const char* name, int width, void* datap, int dimension,
|
||||
VlRandomArrayVarTemplate(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
void* datap(int idx) const override {
|
||||
const std::string indexed_name = name() + std::to_string(idx);
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) return it->second->m_datap;
|
||||
return &static_cast<T*>(VlRandomVar::datap(idx))->atWrite(idx);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
return it->second->m_datap;
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
|
||||
return nullptr;
|
||||
}
|
||||
void emitSelect(std::ostream& s, const std::vector<size_t>& indices) const {
|
||||
}
|
||||
void emitSelect(std::ostream& s, const std::vector<size_t>& indices,
|
||||
const std::vector<size_t>& idxWidths) const {
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select ";
|
||||
s << name();
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) {
|
||||
s << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) {
|
||||
const size_t bit_width = idxWidths[idx];
|
||||
for (int j = bit_width - 4; j >= 0; j -= 4) {
|
||||
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
||||
}
|
||||
s << ")";
|
||||
@ -121,15 +130,28 @@ public:
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
const std::vector<size_t>& indices = it->second->m_indices;
|
||||
emitSelect(s, indices);
|
||||
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
||||
emitSelect(s, indices, idxWidths);
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"indexed_name not found in m_arr_vars");
|
||||
}
|
||||
}
|
||||
}
|
||||
void emitType(std::ostream& s) const override {
|
||||
const std::string indexed_name = name() + std::to_string(0);
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
for (int i = 0; i < dimension(); ++i) {
|
||||
s << "(Array (_ BitVec " << idxWidths[i] << ") ";
|
||||
}
|
||||
s << "(_ BitVec " << width() << ")";
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
for (int i = 0; i < dimension(); ++i) { s << ")"; }
|
||||
}
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
|
||||
}
|
||||
}
|
||||
int totalWidth() const override {
|
||||
@ -144,66 +166,10 @@ public:
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
const std::vector<size_t>& indices = it->second->m_indices;
|
||||
emitSelect(s, indices);
|
||||
}
|
||||
s << ')';
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class VlRandomArrayVar final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomArrayVar(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
void* datap(int idx) const override {
|
||||
const std::string indexed_name = name() + std::to_string(idx);
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) return it->second->m_datap;
|
||||
return &static_cast<T*>(VlRandomVar::datap(idx))->operator[](idx);
|
||||
}
|
||||
void emitSelect(std::ostream& s, const std::vector<size_t>& indices) const {
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select ";
|
||||
s << name();
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) {
|
||||
s << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) {
|
||||
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
||||
}
|
||||
s << ")";
|
||||
}
|
||||
}
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int elementCounts = countMatchingElements(*m_arrVarsRefp, name());
|
||||
for (int i = 0; i < elementCounts; i++) {
|
||||
const std::string indexed_name = name() + std::to_string(i);
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
const std::vector<size_t>& indices = it->second->m_indices;
|
||||
emitSelect(s, indices);
|
||||
}
|
||||
}
|
||||
}
|
||||
void emitType(std::ostream& s) const override {
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
s << "(_ BitVec " << width() << ")";
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
}
|
||||
}
|
||||
int totalWidth() const override {
|
||||
const int elementCounts = countMatchingElements(*m_arrVarsRefp, name());
|
||||
return width() * elementCounts;
|
||||
}
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
const std::string indexed_name = name() + std::to_string(j);
|
||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||
if (it != m_arrVarsRefp->end()) {
|
||||
const std::vector<size_t>& indices = it->second->m_indices;
|
||||
emitSelect(s, indices);
|
||||
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
||||
emitSelect(s, indices, idxWidths);
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize", "indexed_name not found in m_arr_vars");
|
||||
}
|
||||
s << ')';
|
||||
}
|
||||
@ -217,6 +183,7 @@ class VlRandomizer final {
|
||||
std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
|
||||
// variables
|
||||
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration
|
||||
std::map<size_t, std::string> seen_values; // Record String Index to avoid conflicts
|
||||
const VlQueue<CData>* m_randmode; // rand_mode state;
|
||||
|
||||
// PRIVATE METHODS
|
||||
@ -231,6 +198,47 @@ public:
|
||||
// METHODS
|
||||
// Finds the next solution satisfying the constraints
|
||||
bool next(VlRNG& rngr);
|
||||
|
||||
template <typename T_Key>
|
||||
typename std::enable_if<std::is_integral<T_Key>::value>::type
|
||||
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index,
|
||||
const std::string& base_name, size_t& idx_width) {
|
||||
integral_index = static_cast<size_t>(key);
|
||||
indexed_name = base_name + "[" + std::to_string(integral_index) + "]";
|
||||
idx_width = sizeof(T_Key) * 8;
|
||||
}
|
||||
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, size_t& integral_index,
|
||||
const std::string& base_name, size_t& idx_width) {
|
||||
integral_index = string_to_integral(key);
|
||||
indexed_name = base_name + "[" + std::to_string(integral_index) + "]";
|
||||
idx_width = 64; // 64-bit mask
|
||||
}
|
||||
template <typename T_Key>
|
||||
typename std::enable_if<!std::is_integral<T_Key>::value
|
||||
&& !std::is_same<T_Key, std::string>::value>::type
|
||||
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index,
|
||||
const std::string& base_name, size_t& idx_width) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"Unsupported: Only integral and string index of associative array is "
|
||||
"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>
|
||||
void write_var(T& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
@ -243,25 +251,38 @@ public:
|
||||
void write_var(VlQueue<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;
|
||||
m_vars[name] = std::make_shared<const VlRandomQueueVar<VlQueue<T>>>(
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
record_arr_table(var, name, dimension, {});
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
}
|
||||
}
|
||||
template <typename T, std::size_t N_Depth>
|
||||
void write_var(VlUnpacked<T, N_Depth>& 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 VlRandomArrayVar<VlUnpacked<T, N_Depth>>>(
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVarTemplate<VlUnpacked<T, N_Depth>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
record_arr_table(var, name, dimension, {});
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
}
|
||||
}
|
||||
int idx = 0;
|
||||
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()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomArrayVarTemplate<VlAssocArray<T_Key, T_Value>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
record_arr_table(var, name, dimension, {}, {});
|
||||
}
|
||||
}
|
||||
|
||||
int idx;
|
||||
std::string generateKey(const std::string& name, int idx) {
|
||||
if (!name.empty() && name[0] == '\\') {
|
||||
const size_t space_pos = name.find(' ');
|
||||
@ -272,45 +293,61 @@ public:
|
||||
return (bracket_pos != std::string::npos ? name.substr(0, bracket_pos) : name)
|
||||
+ std::to_string(idx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void record_arr_table(T& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
||||
const std::string key = generateKey(name, idx);
|
||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices);
|
||||
idx += 1;
|
||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
|
||||
++idx;
|
||||
}
|
||||
template <typename T>
|
||||
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
||||
if ((dimension > 0) && (var.size() != 0)) {
|
||||
idxWidths.push_back(32);
|
||||
for (size_t i = 0; i < var.size(); ++i) {
|
||||
const std::string indexed_name = name + "[" + std::to_string(i) + "]";
|
||||
indices.push_back(i);
|
||||
record_arr_table(var.atWrite(i), indexed_name, dimension - 1, indices);
|
||||
record_arr_table(var.atWrite(i), indexed_name, dimension - 1, indices, idxWidths);
|
||||
indices.pop_back();
|
||||
}
|
||||
} else {
|
||||
const std::string key = generateKey(name, idx);
|
||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
template <typename T, std::size_t N_Depth>
|
||||
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
||||
if ((dimension > 0) && (N_Depth != 0)) {
|
||||
idxWidths.push_back(32);
|
||||
for (size_t i = 0; i < N_Depth; ++i) {
|
||||
const std::string indexed_name = name + "[" + std::to_string(i) + "]";
|
||||
indices.push_back(i);
|
||||
record_arr_table(var.operator[](i), indexed_name, dimension - 1, indices);
|
||||
record_arr_table(var.operator[](i), indexed_name, dimension - 1, indices,
|
||||
idxWidths);
|
||||
indices.pop_back();
|
||||
}
|
||||
} else {
|
||||
const std::string key = generateKey(name, idx);
|
||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
template <typename T_Key, typename T_Value>
|
||||
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) {
|
||||
if ((dimension > 0) && (var.size() != 0)) {
|
||||
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;
|
||||
size_t integral_index;
|
||||
size_t idx_width;
|
||||
process_key(key, indexed_name, integral_index, name, idx_width);
|
||||
idxWidths.push_back(idx_width);
|
||||
indices.push_back(integral_index);
|
||||
record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths);
|
||||
idxWidths.pop_back();
|
||||
indices.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hard(std::string&& constraint);
|
||||
void clear();
|
||||
void set_randmode(const VlQueue<CData>& randmode) { m_randmode = &randmode; }
|
||||
|
@ -4191,6 +4191,7 @@ public:
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l%f[%r])"; }
|
||||
string emitC() override { return "%li%k[%ri]"; }
|
||||
string emitSMT() const override { return "(select %l %r)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
|
@ -641,7 +641,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
"write_var"};
|
||||
uint32_t dimension = 0;
|
||||
if (VN_IS(varp->dtypep(), UnpackArrayDType) || VN_IS(varp->dtypep(), DynArrayDType)
|
||||
|| VN_IS(varp->dtypep(), QueueDType)) {
|
||||
|| VN_IS(varp->dtypep(), QueueDType) || VN_IS(varp->dtypep(), AssocArrayDType)) {
|
||||
const std::pair<uint32_t, uint32_t> dims
|
||||
= varp->dtypep()->dimensions(/*includeBasic=*/true);
|
||||
const uint32_t unpackedDimensions = dims.second;
|
||||
@ -656,7 +656,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
size_t width = varp->width();
|
||||
AstNodeDType* tmpDtypep = varp->dtypep();
|
||||
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
||||
|| VN_IS(tmpDtypep, QueueDType))
|
||||
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
|
||||
tmpDtypep = tmpDtypep->subDTypep();
|
||||
width = tmpDtypep->width();
|
||||
methodp->addPinsp(
|
||||
@ -724,6 +724,44 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
|
||||
editSMT(nodep, nodep->fromp(), lsbp, msbp);
|
||||
}
|
||||
void visit(AstAssocSel* nodep) override {
|
||||
if (editFormat(nodep)) return;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
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);
|
||||
VNRelinker handle;
|
||||
AstNodeExpr* const strIdxp = new AstSFormatF{
|
||||
fl, "#x%16x", false,
|
||||
new AstAnd{fl, stringp->lhsp()->unlinkFrBack(&handle),
|
||||
new AstConst(fl, AstConst::Unsized64{}, 0xFFFFFFFFFFFFFFFF)}};
|
||||
handle.relink(strIdxp);
|
||||
editSMT(nodep, nodep->fromp(), strIdxp);
|
||||
} else {
|
||||
VNRelinker handle;
|
||||
const int actual_width = nodep->bitp()->width();
|
||||
std::string fmt;
|
||||
// Normalize to standard bit width
|
||||
if (actual_width <= 8) {
|
||||
fmt = "#x%2x";
|
||||
} else if (actual_width <= 16) {
|
||||
fmt = "#x%4x";
|
||||
} else if (actual_width <= 32) {
|
||||
fmt = "#x%8x";
|
||||
} else if (actual_width <= 64) {
|
||||
fmt = "#x%16x";
|
||||
} else {
|
||||
nodep->v3warn(CONSTRAINTIGN,
|
||||
"Unsupported: Associative array index "
|
||||
"widths of more than 64 bits during constraint randomization.");
|
||||
return;
|
||||
}
|
||||
AstNodeExpr* const idxp
|
||||
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
|
||||
handle.relink(idxp);
|
||||
editSMT(nodep, nodep->fromp(), idxp);
|
||||
}
|
||||
}
|
||||
void visit(AstArraySel* nodep) override {
|
||||
if (editFormat(nodep)) return;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
|
9
test_regress/t/t_constraint_assoc_arr_bad.out
Normal file
9
test_regress/t/t_constraint_assoc_arr_bad.out
Normal file
@ -0,0 +1,9 @@
|
||||
%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:14:22: Unsupported: Associative array index widths of more than 64 bits during constraint randomization.
|
||||
14 | bit_index_arr[79'd66] == 65;
|
||||
| ^
|
||||
... 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.
|
||||
%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
|
16
test_regress/t/t_constraint_assoc_arr_bad.py
Executable file
16
test_regress/t/t_constraint_assoc_arr_bad.py
Executable file
@ -0,0 +1,16 @@
|
||||
#!/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')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
38
test_regress/t/t_constraint_assoc_arr_bad.v
Normal file
38
test_regress/t/t_constraint_assoc_arr_bad.v
Normal file
@ -0,0 +1,38 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by PlanV GmbH.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
|
||||
class AssocArrayWarningTest;
|
||||
|
||||
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
|
||||
|
||||
endclass
|
||||
|
||||
module t_constraint_assoc_arr_bad;
|
||||
|
||||
AssocArrayWarningTest test_obj;
|
||||
|
||||
initial begin
|
||||
test_obj = new();
|
||||
repeat(2) begin
|
||||
int success;
|
||||
success = test_obj.randomize();
|
||||
if (success != 1) $stop;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
180
test_regress/t/t_constraint_assoc_arr_basic.v
Normal file
180
test_regress/t/t_constraint_assoc_arr_basic.v
Normal file
@ -0,0 +1,180 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by PlanV GmbH.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class constrained_associative_array_basic;
|
||||
|
||||
rand int int_index_arr [int];
|
||||
rand int string_index_arr [string];
|
||||
/* verilator lint_off SIDEEFFECT */
|
||||
// Constraints for both arrays
|
||||
constraint int_index_constraints {
|
||||
foreach (int_index_arr[i]) int_index_arr[i] inside {10, 20, 30, 40, 50};
|
||||
}
|
||||
constraint string_index_constraints {
|
||||
string_index_arr["Alice"] == 35;
|
||||
string_index_arr["Bob"] inside {50, 60};
|
||||
string_index_arr["Charlie"] > 25;
|
||||
}
|
||||
|
||||
// Constructor to initialize arrays
|
||||
function new();
|
||||
int_index_arr = '{1: 0, 8: 0, 7: 0};
|
||||
string_index_arr = '{"Alice": 25, "Bob": 50, "Charlie": 45};
|
||||
endfunction
|
||||
|
||||
// Function to check and display the arrays
|
||||
function void self_check();
|
||||
foreach (int_index_arr[i]) begin
|
||||
if (!(int_index_arr[i] inside {10, 20, 30, 40, 50})) $stop;
|
||||
end
|
||||
foreach (string_index_arr[name]) begin
|
||||
if ((name == "Alice" && string_index_arr[name] != 35) ||
|
||||
(name == "Bob" && !(string_index_arr[name] inside {50, 60})) ||
|
||||
(name == "Charlie" && string_index_arr[name] <= 25)) $stop;
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class constrained_1d_associative_array;
|
||||
|
||||
rand int string_index_arr [string];
|
||||
rand int int_index_arr [int];
|
||||
rand int shortint_index_arr [shortint];
|
||||
rand int longint_index_arr[longint];
|
||||
rand int byte_index_arr [byte];
|
||||
rand int bit_index_arr [bit[5:0]];
|
||||
rand int logic_index_arr [logic[3:0]];
|
||||
rand int bit_index_arr_1 [bit[55:0]];
|
||||
|
||||
// Constraints
|
||||
constraint associative_array_constraints {
|
||||
string_index_arr["key1"] == 100;
|
||||
string_index_arr["key2"] inside {200, 300, 400};
|
||||
int_index_arr[40000] + int_index_arr[2000000000] == 2;
|
||||
shortint_index_arr[2000] == 200;
|
||||
longint_index_arr[64'd4000000000] == 300;
|
||||
byte_index_arr[8'd255] == 50;
|
||||
bit_index_arr[6'd30] - bit_index_arr_1[56'd66] == 3;
|
||||
logic_index_arr[4'b0011] == 70;
|
||||
}
|
||||
|
||||
function new();
|
||||
string_index_arr = '{"key1":0, "key2":0};
|
||||
int_index_arr = '{40000:0, 2000000000:0};
|
||||
shortint_index_arr = '{2000:0};
|
||||
longint_index_arr = '{64'd4000000000:0};
|
||||
byte_index_arr = '{8'd255:0};
|
||||
bit_index_arr = '{6'd30:0};
|
||||
bit_index_arr_1 = '{56'd66:0};
|
||||
logic_index_arr = '{4'd3:0};
|
||||
endfunction
|
||||
|
||||
function void self_check();
|
||||
if (string_index_arr["key1"] != 100) $stop;
|
||||
if (!(string_index_arr["key2"] inside {200, 300, 400})) $stop;
|
||||
if ((int_index_arr[40000] + int_index_arr[2000000000]) != 2) $stop;
|
||||
if (shortint_index_arr[2000] != 200) $stop;
|
||||
if (longint_index_arr[64'd4000000000] != 300) $stop;
|
||||
if (byte_index_arr[8'd255] != 50) $stop;
|
||||
if (bit_index_arr[6'd30] - bit_index_arr_1[56'd66] != 3) $stop;
|
||||
if (logic_index_arr[4'd3] != 70) $stop;
|
||||
endfunction
|
||||
|
||||
function void debug_display();
|
||||
$display("string_index_arr[\"key1\"] = %0d", string_index_arr["key1"]);
|
||||
$display("string_index_arr[\"key2\"] = %0d", string_index_arr["key2"]);
|
||||
$display("int_index_arr[40000] = %0d", int_index_arr[40000]);
|
||||
$display("int_index_arr[2000000000] = %0d", int_index_arr[2000000000]);
|
||||
$display("shortint_index_arr[2000] = %0d", shortint_index_arr[2000]);
|
||||
$display("longint_index_arr[4000000000] = %0d", longint_index_arr[64'd4000000000]);
|
||||
$display("byte_index_arr[255] = %0d", byte_index_arr[8'd255]);
|
||||
$display("bit_index_arr[30] = %0d", bit_index_arr[6'd30]);
|
||||
$display("bit_index_arr_1[66] = %0d", bit_index_arr_1[56'd66]);
|
||||
$display("logic_index_arr[3] = %0d", logic_index_arr[4'd3]);
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class constrained_2d_associative_array;
|
||||
|
||||
rand int string_int_index_arr [string][int];
|
||||
rand int int_bit_index_arr [int][bit[5:0]];
|
||||
rand int string_bit_index_arr [string][bit[7:0]];
|
||||
rand int unpacked_assoc_array_2d [string][2];
|
||||
|
||||
// Constraints
|
||||
constraint associative_array_constraints {
|
||||
string_int_index_arr["key1"][2000] == 100;
|
||||
string_int_index_arr["key2"][3000] inside {200, 300, 400};
|
||||
int_bit_index_arr[40000][6'd30] == 60;
|
||||
int_bit_index_arr[50000][6'd40] inside {100, 200};
|
||||
string_bit_index_arr["key3"][8'd100] == 150;
|
||||
string_bit_index_arr["key4"][8'd200] inside {250, 350};
|
||||
unpacked_assoc_array_2d["key5"][0] == 7;
|
||||
}
|
||||
|
||||
function new();
|
||||
string_int_index_arr = '{"key1":'{2000:0}, "key2":'{3000:0}};
|
||||
int_bit_index_arr = '{40000:'{6'd30:0}, 50000:'{6'd40:0}};
|
||||
string_bit_index_arr = '{"key3":'{8'd100:0}, "key4":'{8'd200:0}};
|
||||
unpacked_assoc_array_2d["key5"][0] = 0;
|
||||
unpacked_assoc_array_2d["key5"][1] = 0;
|
||||
endfunction
|
||||
|
||||
function void self_check();
|
||||
if (string_int_index_arr["key1"][2000] != 100) $stop;
|
||||
if (!(string_int_index_arr["key2"][3000] inside {200, 300, 400})) $stop;
|
||||
if (int_bit_index_arr[40000][6'd30] != 60) $stop;
|
||||
if (!(int_bit_index_arr[50000][6'd40] inside {100, 200})) $stop;
|
||||
if (string_bit_index_arr["key3"][8'd100] != 150) $stop;
|
||||
if (!(string_bit_index_arr["key4"][8'd200] inside {250, 350})) $stop;
|
||||
if (unpacked_assoc_array_2d["key5"][0] != 7) $stop;
|
||||
endfunction
|
||||
|
||||
function void debug_display();
|
||||
$display("string_int_index_arr[\"key1\"][2000] = %0d", string_int_index_arr["key1"][2000]);
|
||||
$display("string_int_index_arr[\"key2\"][3000] = %0d", string_int_index_arr["key2"][3000]);
|
||||
$display("int_bit_index_arr[40000][30] = %0d", int_bit_index_arr[40000][6'd30]);
|
||||
$display("int_bit_index_arr[50000][40] = %0d", int_bit_index_arr[50000][6'd40]);
|
||||
$display("string_bit_index_arr[\"key3\"][100] = %0d", string_bit_index_arr["key3"][8'd100]);
|
||||
$display("string_bit_index_arr[\"key4\"][200] = %0d", string_bit_index_arr["key4"][8'd200]);
|
||||
$display("unpacked_assoc_array_2d[\"key5\"][0] = %0d", unpacked_assoc_array_2d["key5"][0]);
|
||||
endfunction
|
||||
/* verilator lint_off SIDEEFFECT */
|
||||
endclass
|
||||
|
||||
module t_constraint_assoc_arr_basic;
|
||||
|
||||
constrained_associative_array_basic my_array;
|
||||
constrained_1d_associative_array my_1d_array;
|
||||
constrained_2d_associative_array my_2d_array;
|
||||
int success;
|
||||
|
||||
initial begin
|
||||
my_array = new();
|
||||
success = my_array.randomize();
|
||||
if (success == 0) $stop;
|
||||
my_array.self_check();
|
||||
|
||||
my_1d_array = new();
|
||||
success = my_1d_array.randomize();
|
||||
if (success == 0) $stop;
|
||||
my_1d_array.self_check();
|
||||
|
||||
my_1d_array = new();
|
||||
success = my_1d_array.randomize();
|
||||
if (success == 0) $stop;
|
||||
my_1d_array.self_check();
|
||||
|
||||
// my_1d_array.debug_display();
|
||||
// my_2d_array.debug_display();
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
21
test_regress/t/t_constraint_unpacked_array.py
Executable file
21
test_regress/t/t_constraint_unpacked_array.py
Executable 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()
|
@ -125,7 +125,7 @@ class con_rand_3d_array_test;
|
||||
endclass
|
||||
|
||||
|
||||
module t_randomize_array_constraints;
|
||||
module t_constraint_unpacked_array;
|
||||
con_rand_1d_array_test rand_test_1;
|
||||
con_rand_2d_array_test rand_test_2;
|
||||
con_rand_3d_array_test rand_test_3;
|
Loading…
Reference in New Issue
Block a user