Support array max (#4275)

This commit is contained in:
Aleksander Kiryk 2023-06-07 04:44:21 -07:00 committed by GitHub
parent c248318958
commit 6cb0335d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 349 additions and 223 deletions

View File

@ -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 = "'{";

View File

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

View File

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

View File

@ -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;

View File

@ -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;

View 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

View 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;

View 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

View 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

View 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;

View 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