mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Support basic constrained random for multi-dimensional dynamic array and queue (#5591)
This commit is contained in:
parent
61d2284eab
commit
a173883b2d
@ -22,6 +22,7 @@
|
||||
|
||||
#include "verilated_random.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <streambuf>
|
||||
@ -281,37 +282,6 @@ std::string parseNestedSelect(const std::string& nested_select_expr,
|
||||
indices.push_back(idx);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string flattenIndices(const std::vector<std::string>& indices, const VlRandomVar* const var) {
|
||||
int flattenedIndex = 0;
|
||||
int multiplier = 1;
|
||||
for (int i = indices.size() - 1; i >= 0; --i) {
|
||||
int indexValue = 0;
|
||||
std::string trimmedIndex = indices[i];
|
||||
|
||||
trimmedIndex.erase(0, trimmedIndex.find_first_not_of(" \t"));
|
||||
trimmedIndex.erase(trimmedIndex.find_last_not_of(" \t") + 1);
|
||||
|
||||
if (trimmedIndex.find("#x") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 16);
|
||||
} else if (trimmedIndex.find("#b") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 2);
|
||||
} else {
|
||||
indexValue = std::strtoul(trimmedIndex.c_str(), nullptr, 10);
|
||||
}
|
||||
const int length = var->getLength(i);
|
||||
if (length == -1) {
|
||||
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||
"Internal: Wrong Call: Only RandomArray can call getLength()");
|
||||
break;
|
||||
}
|
||||
flattenedIndex += indexValue * multiplier;
|
||||
multiplier *= length;
|
||||
}
|
||||
std::string hexString = std::to_string(flattenedIndex);
|
||||
while (hexString.size() < 8) { hexString.insert(0, "0"); }
|
||||
return "#x" + hexString;
|
||||
}
|
||||
//======================================================================
|
||||
// VlRandomizer:: Methods
|
||||
|
||||
@ -404,7 +374,11 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
||||
f << "(define-fun __Vbv ((b Bool)) (_ BitVec 1) (ite b #b1 #b0))\n";
|
||||
f << "(define-fun __Vbool ((v (_ BitVec 1))) Bool (= #b1 v))\n";
|
||||
for (const auto& var : m_vars) {
|
||||
f << "(declare-fun " << var.second->name() << " () ";
|
||||
if (var.second->dimension() > 0) {
|
||||
auto arrVarsp = std::make_shared<const ArrayInfoMap>(m_arr_vars);
|
||||
var.second->setArrayInfo(arrVarsp);
|
||||
}
|
||||
f << "(declare-fun " << var.first << " () ";
|
||||
var.second->emitType(f);
|
||||
f << ")\n";
|
||||
}
|
||||
@ -444,9 +418,14 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
}
|
||||
|
||||
f << "(get-value (";
|
||||
for (const auto& var : m_vars) var.second->emitGetValue(f);
|
||||
for (const auto& var : m_vars) {
|
||||
if (var.second->dimension() > 0) {
|
||||
auto arrVarsp = std::make_shared<const ArrayInfoMap>(m_arr_vars);
|
||||
var.second->setArrayInfo(arrVarsp);
|
||||
}
|
||||
var.second->emitGetValue(f);
|
||||
}
|
||||
f << "))\n";
|
||||
|
||||
// Quasi-parse S-expression of the form ((x #xVALUE) (y #bVALUE) (z #xVALUE))
|
||||
char c;
|
||||
f >> c;
|
||||
@ -455,7 +434,6 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
"Internal: Unable to parse solver's response: invalid S-expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
f >> c;
|
||||
if (c == ')') break;
|
||||
@ -471,7 +449,6 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
if (name == "(select") {
|
||||
const std::string selectExpr = readUntilBalanced(f);
|
||||
name = parseNestedSelect(selectExpr, indices);
|
||||
idx = indices[0];
|
||||
}
|
||||
std::getline(f, value, ')');
|
||||
const auto it = m_vars.find(name);
|
||||
@ -480,12 +457,34 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
if (m_randmode && !varr.randModeIdxNone()) {
|
||||
if (!(m_randmode->at(varr.randModeIdx()))) continue;
|
||||
}
|
||||
if (indices.size() > 1) {
|
||||
const std::string flattenedIndex = flattenIndices(indices, &varr);
|
||||
varr.set(flattenedIndex, value);
|
||||
} else {
|
||||
varr.set(idx, value);
|
||||
if (!indices.empty()) {
|
||||
std::ostringstream oss;
|
||||
oss << varr.name();
|
||||
for (const auto& hex_index : indices) {
|
||||
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");
|
||||
continue;
|
||||
}
|
||||
const int index = std::stoi(hex_index.substr(start + 2), nullptr, 16);
|
||||
oss << "[" << index << "]";
|
||||
}
|
||||
const std::string indexed_name = oss.str();
|
||||
const auto it = std::find_if(m_arr_vars.begin(), m_arr_vars.end(),
|
||||
[&indexed_name](const auto& entry) {
|
||||
return entry.second->m_name == indexed_name;
|
||||
});
|
||||
if (it != m_arr_vars.end()) {
|
||||
std::ostringstream ss;
|
||||
ss << "#x" << std::hex << std::setw(8) << std::setfill('0') << it->second->m_index;
|
||||
idx = ss.str();
|
||||
} else {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||
"Error: indexed_name not found in m_arr_vars");
|
||||
}
|
||||
}
|
||||
varr.set(idx, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -27,10 +27,25 @@
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||
class ArrayInfo final {
|
||||
public:
|
||||
const std::string
|
||||
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
|
||||
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
|
||||
|
||||
ArrayInfo(const std::string& name, void* datap, int index, const std::vector<size_t>& indices)
|
||||
: m_name(name)
|
||||
, m_datap(datap)
|
||||
, m_index(index)
|
||||
, m_indices(indices) {}
|
||||
};
|
||||
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
||||
|
||||
class VlRandomVar VL_NOT_FINAL {
|
||||
const char* const m_name; // Variable name
|
||||
@ -58,7 +73,22 @@ public:
|
||||
virtual void emitExtract(std::ostream& s, int i) const;
|
||||
virtual void emitType(std::ostream& s) const;
|
||||
virtual int totalWidth() const;
|
||||
virtual int getLength(int dimension) const { return -1; }
|
||||
mutable std::shared_ptr<const ArrayInfoMap> m_arrVarsRefp;
|
||||
void setArrayInfo(const std::shared_ptr<const ArrayInfoMap>& arrVarsRefp) const {
|
||||
m_arrVarsRefp = arrVarsRefp;
|
||||
}
|
||||
mutable std::map<std::string, int> count_cache;
|
||||
int countMatchingElements(const ArrayInfoMap& arr_vars, const std::string& base_name) const {
|
||||
if (VL_LIKELY(count_cache.find(base_name) != count_cache.end()))
|
||||
return count_cache[base_name];
|
||||
int count = 0;
|
||||
for (int index = 0; arr_vars.find(base_name + std::to_string(index)) != arr_vars.end();
|
||||
++index) {
|
||||
++count;
|
||||
}
|
||||
count_cache[base_name] = count;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -68,52 +98,12 @@ public:
|
||||
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);
|
||||
}
|
||||
void emitSelect(std::ostream& s, int i) const {
|
||||
s << " (select " << name() << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) s << "0123456789abcdef"[(i >> j) & 0xf];
|
||||
s << ')';
|
||||
}
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
for (int i = 0; i < length; i++) emitSelect(s, i);
|
||||
}
|
||||
void emitType(std::ostream& s) const override {
|
||||
s << "(Array (_ BitVec 32) (_ BitVec " << width() << "))";
|
||||
}
|
||||
int totalWidth() const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
return width() * length;
|
||||
}
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, j);
|
||||
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 {
|
||||
if (idx < 0) return &static_cast<T*>(VlRandomVar::datap(0))->operator[](0);
|
||||
std::vector<size_t> indices(dimension());
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
const int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
return &static_cast<T*>(VlRandomVar::datap(0))->find_element(indices);
|
||||
}
|
||||
|
||||
void emitSelect(std::ostream& s, const std::vector<int>& indices) const {
|
||||
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) {
|
||||
@ -124,33 +114,17 @@ public:
|
||||
s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int getLength(int dimension) const override {
|
||||
const auto var = static_cast<const T*>(datap(-1));
|
||||
const int lenth = var->find_length(dimension);
|
||||
return lenth;
|
||||
}
|
||||
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int total_dimensions = dimension();
|
||||
std::vector<int> lengths;
|
||||
for (int dim = 0; dim < total_dimensions; dim++) {
|
||||
const int len = getLength(dim);
|
||||
lengths.push_back(len);
|
||||
}
|
||||
std::vector<int> indices(total_dimensions, 0);
|
||||
while (true) {
|
||||
emitSelect(s, indices);
|
||||
int currentDimension = total_dimensions - 1;
|
||||
while (currentDimension >= 0
|
||||
&& ++indices[currentDimension] >= lengths[currentDimension]) {
|
||||
indices[currentDimension] = 0;
|
||||
--currentDimension;
|
||||
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);
|
||||
}
|
||||
if (currentDimension < 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
void emitType(std::ostream& s) const override {
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
@ -158,29 +132,79 @@ public:
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int totalWidth() const override {
|
||||
int totalLength = 1;
|
||||
for (int dim = 0; dim < dimension(); ++dim) {
|
||||
const int length = getLength(dim);
|
||||
if (length == -1) return 0;
|
||||
totalLength *= length;
|
||||
}
|
||||
return width() * totalLength;
|
||||
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();
|
||||
std::vector<int> indices(dimension());
|
||||
int idx = j;
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, indices);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
s << ')';
|
||||
}
|
||||
};
|
||||
@ -192,6 +216,7 @@ class VlRandomizer final {
|
||||
std::vector<std::string> m_constraints; // Solver-dependent constraints
|
||||
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
|
||||
const VlQueue<CData>* m_randmode; // rand_mode state;
|
||||
|
||||
// PRIVATE METHODS
|
||||
@ -220,6 +245,10 @@ public:
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomQueueVar<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
record_arr_table(var, name, dimension, {});
|
||||
}
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
void write_var(VlUnpacked<T, N>& var, int width, const char* name, int dimension,
|
||||
@ -227,6 +256,60 @@ public:
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVar<VlUnpacked<T, N>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
record_arr_table(var, name, dimension, {});
|
||||
}
|
||||
}
|
||||
int idx = 0;
|
||||
std::string generateKey(const std::string& name, int idx) {
|
||||
if (!name.empty() && name[0] == '\\') {
|
||||
const size_t space_pos = name.find(' ');
|
||||
return (space_pos != std::string::npos ? name.substr(0, space_pos) : name)
|
||||
+ std::to_string(idx);
|
||||
}
|
||||
const size_t bracket_pos = name.find('[');
|
||||
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) {
|
||||
const std::string key = generateKey(name, idx);
|
||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices);
|
||||
idx += 1;
|
||||
}
|
||||
template <typename T>
|
||||
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
if ((dimension > 0) && (var.size() != 0)) {
|
||||
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);
|
||||
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>
|
||||
void record_arr_table(VlUnpacked<T, N>& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
if ((dimension > 0) && (N != 0)) {
|
||||
for (size_t i = 0; i < N; ++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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
void hard(std::string&& constraint);
|
||||
void clear();
|
||||
|
@ -618,7 +618,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
VAccess::READWRITE},
|
||||
"write_var"};
|
||||
uint32_t dimension = 0;
|
||||
if (VN_IS(varp->dtypep(), UnpackArrayDType)) {
|
||||
if (VN_IS(varp->dtypep(), UnpackArrayDType) || VN_IS(varp->dtypep(), DynArrayDType)
|
||||
|| VN_IS(varp->dtypep(), QueueDType)) {
|
||||
const std::pair<uint32_t, uint32_t> dims
|
||||
= varp->dtypep()->dimensions(/*includeBasic=*/true);
|
||||
const uint32_t unpackedDimensions = dims.second;
|
||||
@ -631,8 +632,11 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
varRefp->classOrPackagep(classOrPackagep);
|
||||
methodp->addPinsp(varRefp);
|
||||
size_t width = varp->width();
|
||||
if (VN_IS(varp->dtypep(), DynArrayDType) || VN_IS(varp->dtypep(), QueueDType))
|
||||
width = varp->dtypep()->subDTypep()->width();
|
||||
AstNodeDType* tmpDtypep = varp->dtypep();
|
||||
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
||||
|| VN_IS(tmpDtypep, QueueDType))
|
||||
tmpDtypep = tmpDtypep->subDTypep();
|
||||
width = tmpDtypep->width();
|
||||
methodp->addPinsp(
|
||||
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, width});
|
||||
AstNodeExpr* const varnamep
|
||||
|
21
test_regress/t/t_constraint_dyn_queue_basic.py
Executable file
21
test_regress/t/t_constraint_dyn_queue_basic.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()
|
113
test_regress/t/t_constraint_dyn_queue_basic.v
Executable file
113
test_regress/t/t_constraint_dyn_queue_basic.v
Executable file
@ -0,0 +1,113 @@
|
||||
// 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
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
class ConstrainedDynamicQueueArray;
|
||||
rand int queue_1d[$];
|
||||
rand int queue[$][$];
|
||||
rand int dyn[][];
|
||||
rand int queue_dyn[$][];
|
||||
rand int dyn_queue[][$];
|
||||
rand int queue_unp[$][3];
|
||||
rand int unp_queue[3][$];
|
||||
rand int \array_w[ith_es]cape [3][2];
|
||||
|
||||
// Constraints for the queues and dynamic arrays
|
||||
constraint queue_constraints {
|
||||
foreach (queue_1d[i]) queue_1d[i] == i + 2;
|
||||
foreach (queue[i, j]) queue[i][j] == (2 * i) + j;
|
||||
}
|
||||
|
||||
constraint dyn_constraints {
|
||||
dyn[0][0] == 10;
|
||||
dyn[1][0] inside {20, 30, 40};
|
||||
dyn[1][1] > 50;
|
||||
dyn[0][1] < 100;
|
||||
dyn[0][2] inside {5, 15, 25};
|
||||
}
|
||||
|
||||
constraint queue_dyn_constraints {
|
||||
foreach (queue_dyn[i, j]) queue_dyn[i][j] == i + j + 3;
|
||||
}
|
||||
|
||||
constraint dyn_queue_constraints {
|
||||
foreach (dyn_queue[i, j]) dyn_queue[i][j] == (3 * i) + j + 2;
|
||||
}
|
||||
|
||||
constraint unp_queue_constraints {
|
||||
foreach (unp_queue[i, j]) unp_queue[i][j] == (i * 5) + j + 1;
|
||||
}
|
||||
|
||||
constraint array_with_escape_constraints {
|
||||
\array_w[ith_es]cape [0][0] == 6;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
function new();
|
||||
queue_1d = {1, 2, 3, 4};
|
||||
queue = '{ '{1, 2}, '{3, 4, 5}, '{6}};
|
||||
dyn = new[2];
|
||||
dyn[0] = new[3];
|
||||
dyn[1] = new[4];
|
||||
|
||||
queue_dyn = {};
|
||||
queue_dyn[0] = new[3];
|
||||
queue_dyn[1] = new[4];
|
||||
|
||||
dyn_queue = new[2];
|
||||
dyn_queue[0] = {7, 8, 9};
|
||||
dyn_queue[1] = {10};
|
||||
|
||||
queue_unp = {};
|
||||
|
||||
unp_queue[0] = {17, 18};
|
||||
unp_queue[1] = {19};
|
||||
unp_queue[2] = {20};
|
||||
endfunction
|
||||
|
||||
// Self-check function
|
||||
function void check();
|
||||
foreach (queue_1d[i]) `checkh(queue_1d[i], i + 2)
|
||||
|
||||
foreach (queue[i, j]) `checkh(queue[i][j], (2 * i) + j)
|
||||
|
||||
`checkh(dyn[0][0], 10)
|
||||
`checkh(dyn[1][0] inside {20, 30, 40}, 1'b1)
|
||||
`checkh(dyn[1][1] > 50, 1'b1)
|
||||
`checkh(dyn[0][1] < 100, 1'b1)
|
||||
`checkh(dyn[0][2] inside {5, 15, 25}, 1'b1)
|
||||
|
||||
foreach (queue_dyn[i, j]) `checkh(queue_dyn[i][j], i + j + 3)
|
||||
|
||||
foreach (dyn_queue[i, j]) `checkh(dyn_queue[i][j], (3 * i) + j + 2)
|
||||
|
||||
`checkh(unp_queue[0][0], (0 * 5) + 0 + 1)
|
||||
`checkh(unp_queue[0][1], (0 * 5) + 1 + 1)
|
||||
`checkh(unp_queue[1][0], (1 * 5) + 0 + 1)
|
||||
`checkh(unp_queue[2][0], (2 * 5) + 0 + 1)
|
||||
|
||||
`checkh(\array_w[ith_es]cape [0][0], 6)
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t_constraint_dyn_queue_basic;
|
||||
ConstrainedDynamicQueueArray array_test;
|
||||
int success;
|
||||
initial begin
|
||||
$display("Test: Randomization for dynamic and mixed queues and arrays:");
|
||||
array_test = new();
|
||||
repeat(2) begin
|
||||
success = array_test.randomize();
|
||||
`checkh(success, 1)
|
||||
array_test.check();
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user