mirror of
https://github.com/verilator/verilator.git
synced 2025-07-31 07:56:10 +00:00
Support array max (#4275)
This commit is contained in:
parent
c248318958
commit
6cb0335d28
@ -1040,9 +1040,15 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
|
||||
template <class T_Value, std::size_t T_Depth>
|
||||
struct VlUnpacked final {
|
||||
private:
|
||||
// TYPES
|
||||
using T_Key = IData; // Index type, for uniformity with other containers
|
||||
using Unpacked = T_Value[T_Depth];
|
||||
|
||||
public:
|
||||
// MEMBERS
|
||||
// This should be the only data member, otherwise generated static initializers need updating
|
||||
T_Value m_storage[T_Depth]; // Contents of the unpacked array
|
||||
Unpacked m_storage; // Contents of the unpacked array
|
||||
|
||||
// CONSTRUCTORS
|
||||
// Default constructors and destructor are used. Note however that C++20 requires that
|
||||
@ -1053,6 +1059,7 @@ struct VlUnpacked final {
|
||||
// Default copy assignment operators are used.
|
||||
|
||||
// METHODS
|
||||
public:
|
||||
// Raw access
|
||||
WData* data() { return &m_storage[0]; }
|
||||
const WData* data() const { return &m_storage[0]; }
|
||||
@ -1065,10 +1072,167 @@ struct VlUnpacked final {
|
||||
bool neq(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(*this, that); }
|
||||
// Similar to 'neq' above, *this = that used for change detection
|
||||
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
|
||||
|
||||
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
|
||||
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) { return neq(that); }
|
||||
|
||||
void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); }
|
||||
template <typename Func>
|
||||
void sort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(std::begin(m_storage), std::end(m_storage),
|
||||
[=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaningless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
void rsort() { std::sort(std::rbegin(m_storage), std::rend(m_storage)); }
|
||||
template <typename Func>
|
||||
void rsort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(std::rbegin(m_storage), std::rend(m_storage),
|
||||
[=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaningless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
void reverse() { std::reverse(std::begin(m_storage), std::end(m_storage)); }
|
||||
void shuffle() { std::shuffle(std::begin(m_storage), std::end(m_storage), VlURNG{}); }
|
||||
VlQueue<T_Value> unique() const {
|
||||
VlQueue<T_Value> out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_storage) {
|
||||
const auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> unique(Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_storage) {
|
||||
const auto i_mapped = with_func(0, i);
|
||||
const auto it = saw.find(i_mapped);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i_mapped);
|
||||
out.push_back(i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<T_Key> unique_index() const {
|
||||
VlQueue<T_Key> out;
|
||||
IData index = 0;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_storage) {
|
||||
const auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> unique_index(Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
IData index = 0;
|
||||
std::unordered_set<T_Value> saw;
|
||||
for (const auto& i : m_storage) {
|
||||
const auto i_mapped = with_func(index, i);
|
||||
auto it = saw.find(i_mapped);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i_mapped);
|
||||
out.push_back(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find(Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) out.push_back(i);
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_index(Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) out.push_back(index);
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_first(Func with_func) const {
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) return VlQueue<T_Value>::cons(i);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::cons(index);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::cons(m_storage[i]);
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<IData>::cons(i);
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
VlQueue<T_Value> min() const {
|
||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> min(Func with_func) const {
|
||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
}
|
||||
VlQueue<T_Value> max() const {
|
||||
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> max(Func with_func) const {
|
||||
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
|
123
src/V3Width.cpp
123
src/V3Width.cpp
@ -3273,36 +3273,11 @@ private:
|
||||
<< nodep->prettyName() << "'");
|
||||
}
|
||||
}
|
||||
void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) {
|
||||
AstCMethodHard* methodCallArray(AstMethodCall* nodep, AstNodeDType* adtypep) {
|
||||
AstCMethodHard* newp = nullptr;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at"};
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
} else if (nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size"};
|
||||
newp->dtypeSetSigned32();
|
||||
} else if (nodep->name() == "delete") { // function void delete()
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"};
|
||||
newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|
||||
|| nodep->name() == "sum" || nodep->name() == "product") {
|
||||
// All value return
|
||||
AstWith* const withp
|
||||
= methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"r_" + nodep->name(), withp};
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
|
||||
if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort"
|
||||
|| nodep->name() == "rsort") {
|
||||
AstWith* withp = nullptr;
|
||||
if (nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(),
|
||||
@ -3315,10 +3290,12 @@ private:
|
||||
newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
AstWith* const withp = methodWithArgument(
|
||||
nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name()};
|
||||
nodep->name(), withp};
|
||||
if (nodep->name() == "unique_index") {
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
} else {
|
||||
@ -3347,6 +3324,38 @@ private:
|
||||
nodep->name(), withp};
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) {
|
||||
AstCMethodHard* newp = nullptr;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at"};
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
} else if (nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size"};
|
||||
newp->dtypeSetSigned32();
|
||||
} else if (nodep->name() == "delete") { // function void delete()
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"};
|
||||
newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|
||||
|| nodep->name() == "sum" || nodep->name() == "product") {
|
||||
// All value return
|
||||
AstWith* const withp
|
||||
= methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"r_" + nodep->name(), withp};
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if ((newp = methodCallArray(nodep, adtypep))) {
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method "
|
||||
<< nodep->prettyNameQ());
|
||||
@ -3434,54 +3443,7 @@ private:
|
||||
"r_" + nodep->name(), withp};
|
||||
newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
AstWith* withp = nullptr;
|
||||
if (nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(),
|
||||
adtypep->subDTypep());
|
||||
}
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp};
|
||||
newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
AstWith* const withp = methodWithArgument(
|
||||
nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp};
|
||||
if (nodep->name() == "unique_index") {
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
} else {
|
||||
newp->dtypeFrom(adtypep);
|
||||
}
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "find" || nodep->name() == "find_first"
|
||||
|| nodep->name() == "find_last") {
|
||||
AstWith* const withp
|
||||
= methodWithArgument(nodep, true, false, nodep->findBitDType(),
|
||||
nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp};
|
||||
newp->dtypeFrom(adtypep);
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|
||||
|| nodep->name() == "find_last_index") {
|
||||
AstWith* const withp
|
||||
= methodWithArgument(nodep, true, false, nodep->findBitDType(),
|
||||
nodep->findUInt32DType(), adtypep->subDTypep());
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp};
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
|
||||
} else if ((newp = methodCallArray(nodep, adtypep))) {
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported/unknown built-in queue method " << nodep->prettyNameQ());
|
||||
@ -3653,6 +3615,11 @@ private:
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (AstCMethodHard* newp = methodCallArray(nodep, adtypep)) {
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else {
|
||||
nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ());
|
||||
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
|
||||
|
@ -1,117 +0,0 @@
|
||||
%Error: t/t_array_method.v:24:9: Unknown built-in array method 'sort'
|
||||
: ... In instance t
|
||||
24 | q.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:26:9: Unknown built-in array method 'sort'
|
||||
: ... In instance t
|
||||
26 | q.sort with (item == 2);
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:28:9: Unknown built-in array method 'sort'
|
||||
: ... In instance t
|
||||
28 | q.sort(x) with (x == 3);
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:31:9: Unknown built-in array method 'rsort'
|
||||
: ... In instance t
|
||||
31 | q.rsort;
|
||||
| ^~~~~
|
||||
%Error: t/t_array_method.v:33:9: Unknown built-in array method 'rsort'
|
||||
: ... In instance t
|
||||
33 | q.rsort with (item == 2);
|
||||
| ^~~~~
|
||||
%Error: t/t_array_method.v:36:14: Unknown built-in array method 'unique'
|
||||
: ... In instance t
|
||||
36 | qv = q.unique;
|
||||
| ^~~~~~
|
||||
%Error: t/t_array_method.v:38:14: Unknown built-in array method 'unique_index'
|
||||
: ... In instance t
|
||||
38 | qi = q.unique_index; qi.sort;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_array_method.v:40:9: Unknown built-in array method 'reverse'
|
||||
: ... In instance t
|
||||
40 | q.reverse;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_array_method.v:42:9: Unknown built-in array method 'shuffle'
|
||||
: ... In instance t
|
||||
42 | q.shuffle(); q.sort;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_array_method.v:42:22: Unknown built-in array method 'sort'
|
||||
: ... In instance t
|
||||
42 | q.shuffle(); q.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:47:14: Unknown built-in array method 'find'
|
||||
: ... In instance t
|
||||
47 | qv = q.find with (item == 2);
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:49:14: Unknown built-in array method 'find_first'
|
||||
: ... In instance t
|
||||
49 | qv = q.find_first with (item == 2);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_array_method.v:51:14: Unknown built-in array method 'find_last'
|
||||
: ... In instance t
|
||||
51 | qv = q.find_last with (item == 2);
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_array_method.v:54:14: Unknown built-in array method 'find'
|
||||
: ... In instance t
|
||||
54 | qv = q.find with (item == 20);
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:56:14: Unknown built-in array method 'find_first'
|
||||
: ... In instance t
|
||||
56 | qv = q.find_first with (item == 20);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_array_method.v:58:14: Unknown built-in array method 'find_last'
|
||||
: ... In instance t
|
||||
58 | qv = q.find_last with (item == 20);
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_array_method.v:61:14: Unknown built-in array method 'find_index'
|
||||
: ... In instance t
|
||||
61 | qi = q.find_index with (item == 2); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_array_method.v:63:14: Unknown built-in array method 'find_first_index'
|
||||
: ... In instance t
|
||||
63 | qi = q.find_first_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error: t/t_array_method.v:65:14: Unknown built-in array method 'find_last_index'
|
||||
: ... In instance t
|
||||
65 | qi = q.find_last_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_array_method.v:68:14: Unknown built-in array method 'find_index'
|
||||
: ... In instance t
|
||||
68 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_array_method.v:70:14: Unknown built-in array method 'find_first_index'
|
||||
: ... In instance t
|
||||
70 | qi = q.find_first_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error: t/t_array_method.v:72:14: Unknown built-in array method 'find_last_index'
|
||||
: ... In instance t
|
||||
72 | qi = q.find_last_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_array_method.v:75:14: Unknown built-in array method 'min'
|
||||
: ... In instance t
|
||||
75 | qv = q.min;
|
||||
| ^~~
|
||||
%Error: t/t_array_method.v:77:14: Unknown built-in array method 'max'
|
||||
: ... In instance t
|
||||
77 | qv = q.max;
|
||||
| ^~~
|
||||
%Error: t/t_array_method.v:83:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",83, (i), (32'h11)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:85:21: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",85, (i), (32'h168)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:89:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
89 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",89, (i), (32'b1001)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:91:16: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
91 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",91, (i), (32'b1111)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method.v:93:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
93 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",93, (i), (32'hb)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -17,39 +17,39 @@ module t (/*AUTOARG*/);
|
||||
string v;
|
||||
|
||||
q = '{1, 2, 2, 4, 3};
|
||||
v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} ");
|
||||
|
||||
// NOT tested: with ... selectors
|
||||
|
||||
q.sort;
|
||||
v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
q.sort with (item == 2);
|
||||
v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h3, 'h4, 'h2, 'h2} ");
|
||||
q.sort(x) with (x == 3);
|
||||
v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h4, 'h2, 'h2, 'h3} ");
|
||||
|
||||
q.rsort;
|
||||
v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} ");
|
||||
q.rsort with (item == 2);
|
||||
v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h2, 'h2, 'h4, 'h3, 'h1} ");
|
||||
|
||||
qv = q.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h4, 'h3, 'h1} ");
|
||||
qi = q.unique_index; qi.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{0, 2, 3, 4} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h2, 'h3, 'h4} ");
|
||||
q.reverse;
|
||||
v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h3, 'h4, 'h2, 'h2} ");
|
||||
q.shuffle(); q.sort;
|
||||
v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
|
||||
// These require an with clause or are illegal
|
||||
// TODO add a lint check that with clause is provided
|
||||
qv = q.find with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{2, 2} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} ");
|
||||
qv = q.find_first with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{2} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
qv = q.find_last with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{2} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
|
||||
qv = q.find with (item == 20);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
@ -59,11 +59,11 @@ module t (/*AUTOARG*/);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
||||
qi = q.find_index with (item == 2); qi.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{1, 2} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} ");
|
||||
qi = q.find_first_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{1} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h1} ");
|
||||
qi = q.find_last_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{2} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h2} ");
|
||||
|
||||
qi = q.find_index with (item == 20); qi.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{}");
|
||||
@ -73,24 +73,19 @@ module t (/*AUTOARG*/);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{}");
|
||||
|
||||
qv = q.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{1} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
|
||||
qv = q.max;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{4} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h4} ");
|
||||
|
||||
// Reduction methods
|
||||
|
||||
i = q.sum; `checkh(i, 32'hc);
|
||||
i = q.sum with (item + 1); `checkh(i, 32'h11);
|
||||
i = q.product; `checkh(i, 32'h30);
|
||||
i = q.product with (item + 1); `checkh(i, 32'h168);
|
||||
|
||||
q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010};
|
||||
i = q.and; `checkh(i, 32'b1000);
|
||||
i = q.and with (item + 1); `checkh(i, 32'b1001);
|
||||
i = q.or; `checkh(i, 32'b1110);
|
||||
i = q.or with (item + 1); `checkh(i, 32'b1111);
|
||||
i = q.xor; `checkh(i, 32'ha);
|
||||
i = q.xor with (item + 1); `checkh(i, 32'hb);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
5
test_regress/t/t_array_method_bad.out
Normal file
5
test_regress/t/t_array_method_bad.out
Normal file
@ -0,0 +1,5 @@
|
||||
%Error: t/t_array_method_bad.v:11:9: Unknown built-in array method 'mex'
|
||||
: ... In instance t
|
||||
11 | q.mex;
|
||||
| ^~~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_array_method_bad.pl
Executable file
19
test_regress/t/t_array_method_bad.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2023 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
16
test_regress/t/t_array_method_bad.v
Normal file
16
test_regress/t/t_array_method_bad.v
Normal file
@ -0,0 +1,16 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int q[5];
|
||||
|
||||
q.mex;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
21
test_regress/t/t_array_method_unsup.out
Normal file
21
test_regress/t/t_array_method_unsup.out
Normal file
@ -0,0 +1,21 @@
|
||||
%Error: t/t_array_method_unsup.v:24:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
24 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",24, (i), (32'h11)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method_unsup.v:25:21: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
25 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",25, (i), (32'h168)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method_unsup.v:28:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
28 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",28, (i), (32'b1001)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method_unsup.v:29:16: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
29 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",29, (i), (32'b1111)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: t/t_array_method_unsup.v:30:17: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
30 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",30, (i), (32'hb)); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
23
test_regress/t/t_array_method_unsup.pl
Executable file
23
test_regress/t/t_array_method_unsup.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2023 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
|
||||
ok(1);
|
||||
1;
|
35
test_regress/t/t_array_method_unsup.v
Normal file
35
test_regress/t/t_array_method_unsup.v
Normal file
@ -0,0 +1,35 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2023 by Wilson Snyder.
|
||||
// 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);
|
||||
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
int q[5];
|
||||
int qv[$]; // Value returns
|
||||
int qi[$]; // Index returns
|
||||
int i;
|
||||
string v;
|
||||
|
||||
q = '{1, 2, 2, 4, 3};
|
||||
v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} ");
|
||||
|
||||
// Reduction methods
|
||||
|
||||
i = q.sum with (item + 1); `checkh(i, 32'h11);
|
||||
i = q.product with (item + 1); `checkh(i, 32'h168);
|
||||
|
||||
q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010};
|
||||
i = q.and with (item + 1); `checkh(i, 32'b1001);
|
||||
i = q.or with (item + 1); `checkh(i, 32'b1111);
|
||||
i = q.xor with (item + 1); `checkh(i, 32'hb);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user