Support queue and associative array 'with' statements. (#2616)
This commit is contained in:
parent
c1e8337fc1
commit
2aedc91151
2
Changes
2
Changes
|
|
@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
|||
|
||||
* Verilator 4.103 devel
|
||||
|
||||
**** Support queue and associative array 'with' statements. (#2616)
|
||||
|
||||
**** Support queue slicing (#2326).
|
||||
|
||||
**** Support associative array pattern assignments and defaults.
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@
|
|||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
//===================================================================
|
||||
|
|
@ -230,6 +232,162 @@ public:
|
|||
const_iterator begin() const { return m_deque.begin(); }
|
||||
const_iterator end() const { return m_deque.end(); }
|
||||
|
||||
// Methods
|
||||
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
|
||||
template <typename Func> void sort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.begin(), m_deque.end(),
|
||||
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
|
||||
}
|
||||
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
|
||||
template <typename Func> void rsort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.rbegin(), m_deque.rend(),
|
||||
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
|
||||
}
|
||||
void reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
|
||||
void shuffle() {
|
||||
std::random_shuffle(m_deque.begin(), m_deque.end(),
|
||||
[=](int) { return VL_RANDOM_I(32) % m_deque.size(); });
|
||||
}
|
||||
VlQueue unique() const {
|
||||
VlQueue out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<IData> unique_index() const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find(Func with_func) const {
|
||||
VlQueue out;
|
||||
for (const auto& i : m_deque)
|
||||
if (with_func(i)) out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(i)) out.push_back(index);
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find_first(Func with_func) const {
|
||||
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
|
||||
if (it == m_deque.end()) return VlQueue{};
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
|
||||
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
|
||||
if (it == m_deque.end()) return VlQueue<IData>{};
|
||||
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it));
|
||||
}
|
||||
template <typename Func> VlQueue find_last(Func with_func) const {
|
||||
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
|
||||
if (it == m_deque.rend()) return VlQueue{};
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
|
||||
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
|
||||
if (it == m_deque.rend()) return VlQueue<IData>{};
|
||||
// Return index must be relative to beginning
|
||||
return VlQueue<IData>::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it));
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
VlQueue min() const {
|
||||
if (m_deque.empty()) return VlQueue();
|
||||
const auto it = std::min_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
VlQueue max() const {
|
||||
if (m_deque.empty()) return VlQueue();
|
||||
const auto it = std::max_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out += i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out += with_func(i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out *= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{with_func(*it)};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out *= with_func(*it);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out &= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
T_Value out{with_func(*it)};
|
||||
++it;
|
||||
for (; it != m_deque.end(); ++it) out &= with_func(*it);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out |= with_func(i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out ^= with_func(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
if (m_deque.empty()) return "'{}"; // No trailing space
|
||||
|
|
@ -355,7 +513,8 @@ public:
|
|||
T_Value& at(const T_Key& index) {
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
const auto pit = m_map.insert(std::make_pair(index, m_defaultValue));
|
||||
std::pair<typename Map::iterator, bool> pit
|
||||
= m_map.insert(std::make_pair(index, m_defaultValue));
|
||||
return pit.first->second;
|
||||
}
|
||||
return it->second;
|
||||
|
|
@ -383,6 +542,159 @@ public:
|
|||
const_iterator begin() const { return m_map.begin(); }
|
||||
const_iterator end() const { return m_map.end(); }
|
||||
|
||||
// Methods
|
||||
VlQueue<T_Value> unique() const {
|
||||
VlQueue<T_Value> out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_map) {
|
||||
auto it = saw.find(i.second);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i.second);
|
||||
out.push_back(i.second);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<T_Key> unique_index() const {
|
||||
VlQueue<T_Key> out;
|
||||
std::set<T_Key> saw;
|
||||
for (const auto& i : m_map) {
|
||||
auto it = saw.find(i.second);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i.second);
|
||||
out.push_back(i.first);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.second)) out.push_back(i.second);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.second)) out.push_back(i.first);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.second);
|
||||
});
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.second);
|
||||
});
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
VlQueue<T_Value> min() const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::min_element(
|
||||
m_map.begin(), m_map.end(),
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
VlQueue<T_Value> max() const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::max_element(
|
||||
m_map.begin(), m_map.end(),
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out += i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out += with_func(i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out *= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->second)};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out *= with_func(it->second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out &= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->second)};
|
||||
++it;
|
||||
for (; it != m_map.end(); ++it) out &= with_func(it->second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out |= with_func(i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out ^= with_func(i.second);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
if (m_map.empty()) return "'{}"; // No trailing space
|
||||
|
|
|
|||
|
|
@ -1261,6 +1261,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
|||
AstNodeDType* AstNode::findVoidDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
|
||||
}
|
||||
AstNodeDType* AstNode::findQueueIndexDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor
|
||||
|
|
|
|||
|
|
@ -696,8 +696,7 @@ public:
|
|||
STMTTEMP,
|
||||
XTEMP,
|
||||
IFACEREF, // Used to link Interfaces between modules
|
||||
MEMBER,
|
||||
WITH
|
||||
MEMBER
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstVarType()
|
||||
|
|
@ -712,7 +711,7 @@ public:
|
|||
static const char* const names[] = {
|
||||
"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT",
|
||||
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER", "WITH"};
|
||||
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
return names[m_e];
|
||||
}
|
||||
bool isSignal() const {
|
||||
|
|
@ -728,7 +727,7 @@ public:
|
|||
bool isProcAssignable() const {
|
||||
return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP
|
||||
|| m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF
|
||||
|| m_e == MEMBER || m_e == WITH);
|
||||
|| m_e == MEMBER);
|
||||
}
|
||||
bool isTemp() const {
|
||||
return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
|
||||
|
|
@ -1736,6 +1735,7 @@ public:
|
|||
AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); }
|
||||
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); }
|
||||
AstNodeDType* findVoidDType() const;
|
||||
AstNodeDType* findQueueIndexDType() const;
|
||||
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||
|
|
|
|||
|
|
@ -875,6 +875,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|||
return m_voidp;
|
||||
}
|
||||
|
||||
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
||||
if (VL_UNLIKELY(!m_queueIndexp)) {
|
||||
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
||||
addTypesp(newp);
|
||||
m_queueIndexp = newp;
|
||||
}
|
||||
return m_queueIndexp;
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
|
||||
if (m_basicps[kwd]) return m_basicps[kwd];
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1100,6 +1100,12 @@ public:
|
|||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
setNOp2p(boundp);
|
||||
refDTypep(dtp);
|
||||
dtypep(dtp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(QueueDType)
|
||||
virtual const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|
|
@ -3091,6 +3097,29 @@ public:
|
|||
AstNode* exprp() const { return op2p(); }
|
||||
};
|
||||
|
||||
class AstLambdaArgRef : public AstNodeMath {
|
||||
// Lambda argument usage
|
||||
// These are not AstVarRefs because we need to be able to delete/clone lambdas during
|
||||
// optimizations and AstVar's are painful to remove.
|
||||
private:
|
||||
string m_name; // Name of variable
|
||||
|
||||
public:
|
||||
AstLambdaArgRef(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER(fl)
|
||||
, m_name{name} {}
|
||||
ASTNODE_NODE_FUNCS(LambdaArgRef)
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
virtual string emitVerilog() override { return name(); }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const { return true; }
|
||||
virtual bool hasDType() const override { return true; }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
virtual string name() const override { return m_name; } // * = Var name
|
||||
virtual void name(const string& name) override { m_name = name; }
|
||||
};
|
||||
|
||||
class AstWith : public AstNodeStmt {
|
||||
// Used as argument to method, then to AstCMethodHard
|
||||
// dtypep() contains the with lambda's return dtype
|
||||
|
|
@ -3098,17 +3127,21 @@ class AstWith : public AstNodeStmt {
|
|||
// Children: VAR that declares the index variable
|
||||
// Children: math (equation establishing the with)
|
||||
public:
|
||||
AstWith(FileLine* fl, AstVar* varp, AstNode* exprp)
|
||||
AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
addOp1p(varp);
|
||||
addOp1p(argrefp);
|
||||
addNOp2p(exprp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(With)
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
virtual bool hasDType() const override { return true; }
|
||||
virtual const char* broken() const override {
|
||||
BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype
|
||||
return nullptr;
|
||||
}
|
||||
//
|
||||
AstVar* varp() const { return VN_CAST(op1p(), Var); }
|
||||
AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); }
|
||||
AstNode* exprp() const { return op2p(); }
|
||||
};
|
||||
|
||||
|
|
@ -9028,6 +9061,7 @@ class AstTypeTable : public AstNode {
|
|||
// Container for hash of standard data types
|
||||
// Children: NODEDTYPEs
|
||||
AstVoidDType* m_voidp = nullptr;
|
||||
AstQueueDType* m_queueIndexp = nullptr;
|
||||
AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX];
|
||||
//
|
||||
typedef std::map<VBasicTypeKey, AstBasicDType*> DetailedMap;
|
||||
|
|
@ -9042,6 +9076,7 @@ public:
|
|||
AstNodeDType* typesp() const { return VN_CAST(op1p(), NodeDType); } // op1 = List of dtypes
|
||||
void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); }
|
||||
AstVoidDType* findVoidDType(FileLine* fl);
|
||||
AstQueueDType* findQueueIndexDType(FileLine* fl);
|
||||
AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd);
|
||||
AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin,
|
||||
VSigning numeric);
|
||||
|
|
|
|||
|
|
@ -285,6 +285,11 @@ private:
|
|||
ensureCleanAndNext(nodep->pinsp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstWith* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->exprp());
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstIntfRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
|
|
|
|||
|
|
@ -425,6 +425,18 @@ public:
|
|||
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
|
||||
"Statement of non-void data type");
|
||||
}
|
||||
virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
|
||||
virtual void visit(AstWith* nodep) override {
|
||||
// With uses a C++11 lambda
|
||||
putbs("[=](");
|
||||
if (auto* argrefp = nodep->argrefp()) {
|
||||
putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false));
|
||||
}
|
||||
// Probably fragile, V3Task may need to convert to a AstCReturn
|
||||
puts(") { return ");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
puts("; }\n");
|
||||
}
|
||||
virtual void visit(AstIntfRef* nodep) override {
|
||||
putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@ public:
|
|||
};
|
||||
class LinkNodeMatcherVar : public VNodeMatcher {
|
||||
public:
|
||||
virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var); }
|
||||
virtual bool nodeMatch(const AstNode* nodep) const override {
|
||||
return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef);
|
||||
}
|
||||
};
|
||||
class LinkNodeMatcherVarIO : public VNodeMatcher {
|
||||
public:
|
||||
|
|
@ -1270,9 +1272,9 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp);
|
||||
}
|
||||
// Type depends on the method used, let V3Width figure it out later
|
||||
auto* varp = new AstVar(argFl, AstVarType::WITH, name, VFlagChildDType(),
|
||||
new AstParseTypeDType(nodep->fileline()));
|
||||
auto* newp = new AstWith(nodep->fileline(), varp, nodep->exprp()->unlinkFrBackWithNext());
|
||||
auto* argrefp = new AstLambdaArgRef(argFl, name);
|
||||
auto* newp
|
||||
= new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext());
|
||||
funcrefp->addPinsp(newp);
|
||||
nodep->replaceWith(funcrefp->unlinkFrBack());
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -1287,7 +1289,9 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
|
||||
m_packagep);
|
||||
m_curSymp->fallbackp(oldCurSymp);
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref");
|
||||
// Insert argref's name into symbol table
|
||||
m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1539,6 +1543,11 @@ class LinkDotScopeVisitor : public AstNVisitor {
|
|||
symp->fallbackp(m_modSymp);
|
||||
// No recursion, we don't want to pick up variables
|
||||
}
|
||||
virtual void visit(AstWith* nodep) override {
|
||||
VSymEnt* symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
|
||||
symp->fallbackp(m_modSymp);
|
||||
// No recursion, we don't want to pick up variables
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
|
||||
// we'll need to replace it with a VARXREF(aliased_to)
|
||||
|
|
@ -2279,6 +2288,14 @@ private:
|
|||
ok = true;
|
||||
m_ds.m_dotText = "";
|
||||
}
|
||||
} else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) {
|
||||
if (allowVar) {
|
||||
AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
ok = true;
|
||||
m_ds.m_dotText = "";
|
||||
}
|
||||
}
|
||||
//
|
||||
if (!ok) {
|
||||
|
|
|
|||
228
src/V3Width.cpp
228
src/V3Width.cpp
|
|
@ -193,6 +193,7 @@ private:
|
|||
// TYPES
|
||||
typedef std::map<std::pair<const AstNodeDType*, AstAttrType>, AstVar*> TableMap;
|
||||
typedef std::map<int, AstPatMember*> PatVecMap;
|
||||
typedef std::map<const AstNodeDType*, AstQueueDType*> DTypeQMap;
|
||||
|
||||
// STATE
|
||||
WidthVP* m_vup = nullptr; // Current node state
|
||||
|
|
@ -201,11 +202,13 @@ private:
|
|||
= nullptr; // Range for arrayed instantiations, nullptr for normal instantiations
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeProcedure* m_procedurep = nullptr; // Current final/always
|
||||
AstLambdaArgRef* m_lambdaArgRefp = nullptr; // Argument to above lambda
|
||||
AstFunc* m_funcp = nullptr; // Current function
|
||||
AstAttrOf* m_attrp = nullptr; // Current attribute
|
||||
bool m_doGenerate; // Do errors later inside generate statement
|
||||
int m_dtTables = 0; // Number of created data type tables
|
||||
TableMap m_tableMap; // Created tables so can remove duplicates
|
||||
DTypeQMap m_queueDTypeIndexed; // Queues with given index type
|
||||
|
||||
// ENUMS
|
||||
enum ExtendRule : uint8_t {
|
||||
|
|
@ -2322,6 +2325,7 @@ private:
|
|||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : nullptr;
|
||||
UINFO(9, " from dt " << fromDtp << endl);
|
||||
userIterateAndNext(fromDtp, WidthVP(SELF, BOTH).p());
|
||||
if (AstEnumDType* adtypep = VN_CAST(fromDtp, EnumDType)) {
|
||||
methodCallEnum(nodep, adtypep);
|
||||
} else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
|
|
@ -2345,6 +2349,20 @@ private:
|
|||
<< nodep->fromp()->dtypep()->prettyTypeName() << "'");
|
||||
}
|
||||
}
|
||||
AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn,
|
||||
AstNodeDType* returnDtp, AstNodeDType* argDtp) {
|
||||
UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type");
|
||||
if (AstWith* withp = VN_CAST(nodep->pinsp(), With)) {
|
||||
withp->argrefp()->dtypep(argDtp);
|
||||
userIterate(withp, WidthVP(returnDtp, BOTH).p());
|
||||
withp->unlinkFrBack();
|
||||
return withp;
|
||||
} else if (required) {
|
||||
nodep->v3error("'with' statement is required for ." << nodep->prettyName()
|
||||
<< " method");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) {
|
||||
int narg = 0;
|
||||
for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) {
|
||||
|
|
@ -2490,8 +2508,6 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
|
||||
nullptr); // So don't need num()
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
} else if (nodep->name() == "first" // function int first(ref index)
|
||||
|| nodep->name() == "last" //
|
||||
|| nodep->name() == "next" //
|
||||
|
|
@ -2502,8 +2518,6 @@ private:
|
|||
nodep->name(), // first/last/next/prev
|
||||
index_exprp->unlinkFrBack());
|
||||
newp->dtypeSetSigned32();
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
} else if (nodep->name() == "exists") { // function int exists(input index)
|
||||
// IEEE really should have made this a "bit" return
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
|
|
@ -2512,32 +2526,72 @@ private:
|
|||
index_exprp->unlinkFrBack());
|
||||
newp->dtypeSetSigned32();
|
||||
newp->pure(true);
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
} else if (nodep->name() == "delete") { // function void delete([input integer index])
|
||||
methodOkArguments(nodep, 0, 1);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
if (!nodep->pinsp()) {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"clear", nullptr);
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
AstNode* index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
}
|
||||
} else if (nodep->name() == "sort" || nodep->name() == "rsort"
|
||||
|| nodep->name() == "reverse" || nodep->name() == "shuffle") {
|
||||
nodep->v3error("Array method " << nodep->prettyNameQ()
|
||||
<< " not legal on associative arrays");
|
||||
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|
||||
|| nodep->name() == "sum" || nodep->name() == "product") {
|
||||
// All value return
|
||||
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
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->makeStatement(); }
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), nullptr);
|
||||
if (nodep->name() == "unique_index") {
|
||||
newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep()));
|
||||
} else {
|
||||
newp->dtypeFrom(adtypep);
|
||||
}
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "find" || nodep->name() == "find_first"
|
||||
|| nodep->name() == "find_last") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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->makeStatement();
|
||||
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|
||||
|| nodep->name() == "find_last_index") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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(queueDTypeIndexedBy(adtypep->keyDTypep()));
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else {
|
||||
nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ());
|
||||
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
|
||||
}
|
||||
if (newp) {
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -2571,27 +2625,78 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
|
||||
nullptr);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
} else if (nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
|
||||
nullptr);
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
} 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",
|
||||
nullptr);
|
||||
newp->makeStatement();
|
||||
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|
||||
|| nodep->name() == "sum" || nodep->name() == "product") {
|
||||
// All value return
|
||||
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
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->makeStatement(); }
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
AstWith* withp = NULL;
|
||||
if (nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep());
|
||||
}
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp);
|
||||
newp->makeStatement();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), nullptr);
|
||||
if (nodep->name() == "unique_index") {
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
} else {
|
||||
newp->dtypeFrom(adtypep);
|
||||
}
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "find" || nodep->name() == "find_first"
|
||||
|| nodep->name() == "find_last" || nodep->name() == "find_index") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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->makeStatement();
|
||||
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|
||||
|| nodep->name() == "find_last_index") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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->makeStatement();
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method "
|
||||
<< nodep->prettyNameQ());
|
||||
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
|
||||
}
|
||||
if (newp) {
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -2605,23 +2710,18 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
|
||||
nullptr);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
} else if (nodep->name() == "num" // function int num()
|
||||
|| nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
|
||||
nullptr);
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
} else if (nodep->name() == "delete") { // function void delete([input integer index])
|
||||
methodOkArguments(nodep, 0, 1);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
if (!nodep->pinsp()) {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"clear", nullptr);
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
AstNode* index_exprp = methodCallQueueIndexExpr(nodep);
|
||||
|
|
@ -2629,14 +2729,10 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"pop_front", nullptr);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
newp->makeStatement();
|
||||
}
|
||||
}
|
||||
|
|
@ -2649,13 +2745,11 @@ private:
|
|||
if (index_exprp->isZero()) { // insert(0, ...) is a push_front
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"push_front", argp->exprp()->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), index_exprp->unlinkFrBack());
|
||||
newp->addPinsp(argp->exprp()->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
}
|
||||
} else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") {
|
||||
|
|
@ -2664,8 +2758,6 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), nullptr);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
if (!nodep->firstAbovep()) { newp->makeStatement(); }
|
||||
} else if (nodep->name() == "push_back" || nodep->name() == "push_front") {
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
|
|
@ -2674,14 +2766,67 @@ private:
|
|||
iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), argp->exprp()->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|
||||
|| nodep->name() == "sum" || nodep->name() == "product") {
|
||||
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
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->makeStatement(); }
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
AstWith* withp = NULL;
|
||||
if (nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep());
|
||||
}
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), withp);
|
||||
newp->makeStatement();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), nullptr);
|
||||
if (nodep->name() == "unique_index") {
|
||||
newp->dtypep(newp->findQueueIndexDType());
|
||||
} else {
|
||||
newp->dtypeFrom(adtypep);
|
||||
}
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "find" || nodep->name() == "find_first"
|
||||
|| nodep->name() == "find_last") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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->makeStatement();
|
||||
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|
||||
|| nodep->name() == "find_last_index") {
|
||||
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
|
||||
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->makeStatement();
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported/unknown built-in queue method " << nodep->prettyNameQ());
|
||||
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
|
||||
}
|
||||
if (newp) {
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -2884,6 +3029,18 @@ private:
|
|||
nodep->v3error("Unknown built-in string method " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
AstQueueDType* queueDTypeIndexedBy(AstNodeDType* indexDTypep) {
|
||||
// Return a Queue data type with the specified index, remembering so can use again if
|
||||
// needed
|
||||
if (AstQueueDType* queuep = m_queueDTypeIndexed[indexDTypep]) {
|
||||
return queuep;
|
||||
} else {
|
||||
auto* newp = new AstQueueDType(indexDTypep->fileline(), indexDTypep, nullptr);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
m_queueDTypeIndexed[indexDTypep] = newp;
|
||||
return newp;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNew* nodep) override {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
|
|
@ -4179,7 +4336,24 @@ private:
|
|||
}
|
||||
virtual void visit(AstWith* nodep) override {
|
||||
// Should otherwise be underneath a method call
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements in this context");
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
VL_RESTORER(m_lambdaArgRefp);
|
||||
{
|
||||
m_lambdaArgRefp = nodep->argrefp();
|
||||
userIterateChildren(nodep->argrefp(), nullptr);
|
||||
if (vdtypep) {
|
||||
userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p());
|
||||
} else { // 'sort with' allows arbitrary type
|
||||
userIterateAndNext(nodep->exprp(), WidthVP(SELF, PRELIM).p());
|
||||
}
|
||||
nodep->dtypeFrom(nodep->exprp());
|
||||
iterateCheckAssign(nodep, "'with' return value", nodep->exprp(), FINAL,
|
||||
nodep->dtypep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstLambdaArgRef* nodep) override {
|
||||
UASSERT_OBJ(m_lambdaArgRefp, nodep, "LambdaArgRef not underneath with lambda");
|
||||
nodep->dtypeFrom(m_lambdaArgRefp);
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@
|
|||
: ... In instance t
|
||||
38 | qi = q.unique_index; qi.sort;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_array_method.v:38:31: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... 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;
|
||||
|
|
@ -70,10 +66,6 @@
|
|||
: ... In instance t
|
||||
61 | qi = q.find_index with (item == 2); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_array_method.v:61:46: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... 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);
|
||||
|
|
@ -86,10 +78,6 @@
|
|||
: ... In instance t
|
||||
68 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_array_method.v:68:47: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... 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);
|
||||
|
|
|
|||
|
|
@ -1,153 +0,0 @@
|
|||
%Error: t/t_assoc_method.v:31:14: Unknown built-in associative array method 'unique'
|
||||
: ... In instance t
|
||||
31 | qv = q.unique;
|
||||
| ^~~~~~
|
||||
%Error: t/t_assoc_method.v:33:15: Unknown built-in associative array method 'unique'
|
||||
: ... In instance t
|
||||
33 | qv = qe.unique;
|
||||
| ^~~~~~
|
||||
%Error: t/t_assoc_method.v:35:14: Unknown built-in associative array method 'unique_index'
|
||||
: ... In instance t
|
||||
35 | qi = q.unique_index; qi.sort;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_assoc_method.v:35:31: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
35 | qi = q.unique_index; qi.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_method.v:37:15: Unknown built-in associative array method 'unique_index'
|
||||
: ... In instance t
|
||||
37 | qv = qe.unique_index;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:42:14: Unknown built-in associative array method 'find'
|
||||
: ... In instance t
|
||||
42 | qv = q.find with (item == 2);
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_method.v:44:14: Unknown built-in associative array method 'find_first'
|
||||
: ... In instance t
|
||||
44 | qv = q.find_first with (item == 2);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:46:14: Unknown built-in associative array method 'find_last'
|
||||
: ... In instance t
|
||||
46 | qv = q.find_last with (item == 2);
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:49:14: Unknown built-in associative array method 'find'
|
||||
: ... In instance t
|
||||
49 | qv = q.find with (item == 20);
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_method.v:51:14: Unknown built-in associative array method 'find_first'
|
||||
: ... In instance t
|
||||
51 | qv = q.find_first with (item == 20);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:53:14: Unknown built-in associative array method 'find_last'
|
||||
: ... In instance t
|
||||
53 | qv = q.find_last with (item == 20);
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:56:14: Unknown built-in associative array method 'find_index'
|
||||
: ... In instance t
|
||||
56 | qi = q.find_index with (item == 2); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_assoc_method.v:56:46: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
56 | qi = q.find_index with (item == 2); qi.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_method.v:58:14: Unknown built-in associative array method 'find_first_index'
|
||||
: ... In instance t
|
||||
58 | qi = q.find_first_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:60:14: Unknown built-in associative array method 'find_last_index'
|
||||
: ... In instance t
|
||||
60 | qi = q.find_last_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:63:14: Unknown built-in associative array method 'find_index'
|
||||
: ... In instance t
|
||||
63 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_assoc_method.v:63:47: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
63 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_method.v:65:14: Unknown built-in associative array method 'find_first_index'
|
||||
: ... In instance t
|
||||
65 | qi = q.find_first_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:67:14: Unknown built-in associative array method 'find_last_index'
|
||||
: ... In instance t
|
||||
67 | qi = q.find_last_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_method.v:70:14: Unknown built-in associative array method 'min'
|
||||
: ... In instance t
|
||||
70 | qv = q.min;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:72:14: Unknown built-in associative array method 'max'
|
||||
: ... In instance t
|
||||
72 | qv = q.max;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:75:15: Unknown built-in associative array method 'min'
|
||||
: ... In instance t
|
||||
75 | qv = qe.min;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:77:15: Unknown built-in associative array method 'max'
|
||||
: ... In instance t
|
||||
77 | qv = qe.max;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:82:13: Unknown built-in associative array method 'sum'
|
||||
: ... In instance t
|
||||
82 | i = q.sum; do if ((i) !== (32'hc)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",82, (i), (32'hc)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:83:13: Unknown built-in associative array method 'sum'
|
||||
: ... 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_assoc_method.v",83, (i), (32'h11)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:84:13: Unknown built-in associative array method 'product'
|
||||
: ... In instance t
|
||||
84 | i = q.product; do if ((i) !== (32'h30)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",84, (i), (32'h30)); $stop; end while(0);;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_assoc_method.v:85:13: Unknown built-in associative array method 'product'
|
||||
: ... 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_assoc_method.v",85, (i), (32'h168)); $stop; end while(0);;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_assoc_method.v:87:14: Unknown built-in associative array method 'sum'
|
||||
: ... In instance t
|
||||
87 | i = qe.sum; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",87, (i), (32'h0)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:88:14: Unknown built-in associative array method 'product'
|
||||
: ... In instance t
|
||||
88 | i = qe.product; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'h0)); $stop; end while(0);;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_assoc_method.v:91:13: Unknown built-in associative array method 'and'
|
||||
: ... In instance t
|
||||
91 | i = q.and; do if ((i) !== (32'b1000)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",91, (i), (32'b1000)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:92:13: Unknown built-in associative array method 'and'
|
||||
: ... In instance t
|
||||
92 | 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_assoc_method.v",92, (i), (32'b1001)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:93:13: Unknown built-in associative array method 'or'
|
||||
: ... In instance t
|
||||
93 | i = q.or; do if ((i) !== (32'b1110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",93, (i), (32'b1110)); $stop; end while(0);;
|
||||
| ^~
|
||||
%Error: t/t_assoc_method.v:94:13: Unknown built-in associative array method 'or'
|
||||
: ... In instance t
|
||||
94 | 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_assoc_method.v",94, (i), (32'b1111)); $stop; end while(0);;
|
||||
| ^~
|
||||
%Error: t/t_assoc_method.v:95:13: Unknown built-in associative array method 'xor'
|
||||
: ... In instance t
|
||||
95 | i = q.xor; do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",95, (i), (32'b0110)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:96:13: Unknown built-in associative array method 'xor'
|
||||
: ... In instance t
|
||||
96 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",96, (i), (32'b0110)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:98:14: Unknown built-in associative array method 'and'
|
||||
: ... In instance t
|
||||
98 | i = qe.and; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",98, (i), (32'b0)); $stop; end while(0);;
|
||||
| ^~~
|
||||
%Error: t/t_assoc_method.v:99:14: Unknown built-in associative array method 'or'
|
||||
: ... In instance t
|
||||
99 | i = qe.or; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",99, (i), (32'b0)); $stop; end while(0);;
|
||||
| ^~
|
||||
%Error: t/t_assoc_method.v:100:14: Unknown built-in associative array method 'xor'
|
||||
: ... In instance t
|
||||
100 | i = qe.xor; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",100, (i), (32'b0)); $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;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module t (/*AUTOARG*/);
|
|||
string v;
|
||||
|
||||
q = '{10:1, 11:2, 12:2, 13:4, 14:3};
|
||||
v = $sformatf("%p", q); `checks(v, "'{0xa:1, 0xb:2, 0xc:2, 0xd:4, 0xe:3} ");
|
||||
v = $sformatf("%p", q); `checks(v, "'{'ha:'h1, 'hb:'h2, 'hc:'h2, 'hd:'h4, 'he:'h3} ");
|
||||
|
||||
// NOT tested: with ... selectors
|
||||
|
||||
|
|
@ -29,22 +29,22 @@ module t (/*AUTOARG*/);
|
|||
|
||||
v = $sformatf("%p", qe); `checks(v, "'{}");
|
||||
qv = q.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{1, 2, 4, 3} ");
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h1, 'h2, 'h4, 'h3} ");
|
||||
qv = qe.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
qi = q.unique_index; qi.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{10, 11, 13, 14} ");
|
||||
qv = qe.unique_index;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'ha, 'hb, 'hd, 'he} ");
|
||||
qi = qe.unique_index;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{}");
|
||||
|
||||
// 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, "'{}");
|
||||
|
|
@ -54,11 +54,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, "'{11, 12} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'hb, 'hc} ");
|
||||
qi = q.find_first_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{11} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'hb} ");
|
||||
qi = q.find_last_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{12} ");
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'hc} ");
|
||||
|
||||
qi = q.find_index with (item == 20); qi.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{}");
|
||||
|
|
@ -68,9 +68,9 @@ 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} ");
|
||||
|
||||
qv = qe.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
|
@ -79,25 +79,40 @@ module t (/*AUTOARG*/);
|
|||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
i = qe.sum; `checkh(i, 32'h0);
|
||||
i = qe.product; `checkh(i, 32'h0);
|
||||
i = qe.sum;
|
||||
`checkh(i, 32'h0);
|
||||
i = qe.product;
|
||||
`checkh(i, 32'h0);
|
||||
|
||||
q = '{10:32'b1100, 11: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'b0110);
|
||||
i = q.xor with (item + 1); `checkh(i, 32'b0110);
|
||||
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'b0110);
|
||||
i = q.xor with (item + 1);
|
||||
`checkh(i, 32'b0110);
|
||||
|
||||
i = qe.and; `checkh(i, 32'b0);
|
||||
i = qe.or; `checkh(i, 32'b0);
|
||||
i = qe.xor; `checkh(i, 32'b0);
|
||||
i = qe.and;
|
||||
`checkh(i, 32'b0);
|
||||
i = qe.or;
|
||||
`checkh(i, 32'b0);
|
||||
i = qe.xor;
|
||||
`checkh(i, 32'b0);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2019 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);
|
||||
|
||||
`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
string s[] = { "hello", "sad", "sad", "world" };
|
||||
|
||||
initial begin
|
||||
int d[];
|
||||
int de[]; // Empty
|
||||
int qv[$]; // Value returns
|
||||
int qvunused[$]; // Value returns (unused)
|
||||
int qi[$]; // Index returns
|
||||
int i;
|
||||
string v;
|
||||
|
||||
d = '{1, 2, 2, 4, 3};
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} ");
|
||||
d = {1, 2, 2, 4, 3};
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} ");
|
||||
|
||||
// sort/rsort with clause is the field to use for the sorting
|
||||
d.sort;
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
d.sort with (10 - item);
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} ");
|
||||
d.sort(x) with (10 - x);
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} ");
|
||||
de.sort(x) with (10 - x);
|
||||
v = $sformatf("%p", de); `checks(v, "'{}");
|
||||
d.rsort;
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} ");
|
||||
d.rsort with (10 - item);
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
de.rsort(x) with (10 - x);
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
|
||||
d = '{2, 2, 4, 1, 3};
|
||||
qv = d.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h4, 'h1, 'h3} ");
|
||||
qv = de.unique;
|
||||
`checkh(qv.size(), 0);
|
||||
qi = d.unique_index; qv.sort;
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h2, 'h3, 'h4} ");
|
||||
qi = de.unique_index;
|
||||
`checkh(qi.size(), 0);
|
||||
|
||||
d.reverse;
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h3, 'h1, 'h4, 'h2, 'h2} ");
|
||||
de.reverse;
|
||||
`checkh(de.size(), 0);
|
||||
d.shuffle(); d.sort;
|
||||
v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} ");
|
||||
de.shuffle();
|
||||
`checkh(de.size(), 0);
|
||||
|
||||
// These require an with clause or are illegal
|
||||
// TODO add a lint check that with clause is provided
|
||||
qv = d.find with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} ");
|
||||
qv = d.find_first with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
qv = d.find_last with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
|
||||
qv = d.find with (item == 20);
|
||||
`checkh(qv.size, 0);
|
||||
qv = d.find_first with (item == 20);
|
||||
`checkh(qv.size, 0);
|
||||
qv = d.find_last with (item == 20);
|
||||
`checkh(qv.size, 0);
|
||||
|
||||
// Check gate eater with Lambda variable removal
|
||||
qvunused = d.find with (item == 20);
|
||||
|
||||
qi = d.find_index with (item == 2);
|
||||
qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} ");
|
||||
qi = d.find_first_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h1} ");
|
||||
qi = d.find_last_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h2} ");
|
||||
|
||||
i = 2;
|
||||
qi = d.find_index with (item == i);
|
||||
qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} ");
|
||||
|
||||
qi = d.find_index with (item == 20); qi.sort;
|
||||
`checkh(qi.size, 0);
|
||||
qi = d.find_first_index with (item == 20);
|
||||
`checkh(qi.size, 0);
|
||||
qi = d.find_last_index with (item == 20);
|
||||
`checkh(qi.size, 0);
|
||||
|
||||
qv = d.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
|
||||
qv = d.max;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h4} ");
|
||||
qv = de.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
qv = de.max;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
||||
// Reduction methods
|
||||
i = d.sum;
|
||||
`checkh(i, 32'hc);
|
||||
i = d.sum with (item + 1);
|
||||
`checkh(i, 32'h11);
|
||||
i = d.sum(myi) with (myi + 1);
|
||||
`checkh(i, 32'h11);
|
||||
i = d.sum with (1); // unused 'index'
|
||||
`checkh(i, 32'h5);
|
||||
i = d.sum(unused) with (1); // unused 'unused'
|
||||
`checkh(i, 32'h5);
|
||||
|
||||
i = d.product;
|
||||
`checkh(i, 32'h30);
|
||||
i = d.product with (item + 1);
|
||||
`checkh(i, 32'h168);
|
||||
|
||||
i = de.sum;
|
||||
`checkh(i, 32'h0);
|
||||
|
||||
i = de.product;
|
||||
`checkh(i, 32'h0);
|
||||
|
||||
d = '{32'b1100, 32'b1010};
|
||||
|
||||
i = d.and;
|
||||
`checkh(i, 32'b1000);
|
||||
i = d.and with (item + 1);
|
||||
`checkh(i, 32'b1001);
|
||||
i = d.or;
|
||||
`checkh(i, 32'b1110);
|
||||
i = d.or with (item + 1);
|
||||
`checkh(i, 32'b1111);
|
||||
i = d.xor;
|
||||
`checkh(i, 32'b0110);
|
||||
i = d.xor with (item + 1);
|
||||
`checkh(i, 32'b0110);
|
||||
|
||||
i = de.and;
|
||||
`checkh(i, 32'b0);
|
||||
i = de.or;
|
||||
`checkh(i, 32'b0);
|
||||
i = de.xor;
|
||||
`checkh(i, 32'b0);
|
||||
|
||||
`checks(s[1], "sad");
|
||||
qi = s.find_first_index with (item == "sad");
|
||||
`checkh(qi.size, 1);
|
||||
`checkh(qi[0], 1);
|
||||
qi = s.find_last_index with (item == "sad");
|
||||
`checkh(qi.size, 1);
|
||||
`checkh(qi[0], 2);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_queue_method.v:26:9: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
26 | q.sort;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:28:9: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
28 | q.sort with (10 - item);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:30:9: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
30 | q.sort(x) with (10 - x);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:32:10: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
32 | qe.sort(x) with (10 - x);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:34:9: Unsupported/unknown built-in queue method 'rsort'
|
||||
: ... In instance t
|
||||
34 | q.rsort;
|
||||
| ^~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:36:9: Unsupported/unknown built-in queue method 'rsort'
|
||||
: ... In instance t
|
||||
36 | q.rsort with (10 - item);
|
||||
| ^~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:38:10: Unsupported/unknown built-in queue method 'rsort'
|
||||
: ... In instance t
|
||||
38 | qe.rsort(x) with (10 - x);
|
||||
| ^~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:42:14: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
42 | qv = q.unique;
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:44:15: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
44 | qv = qe.unique;
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:46:14: Unsupported/unknown built-in queue method 'unique_index'
|
||||
: ... In instance t
|
||||
46 | qi = q.unique_index; qv.sort;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:46:31: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
46 | qi = q.unique_index; qv.sort;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:48:15: Unsupported/unknown built-in queue method 'unique_index'
|
||||
: ... In instance t
|
||||
48 | qi = qe.unique_index;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:51:9: Unsupported/unknown built-in queue method 'reverse'
|
||||
: ... In instance t
|
||||
51 | q.reverse;
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:53:10: Unsupported/unknown built-in queue method 'reverse'
|
||||
: ... In instance t
|
||||
53 | qe.reverse;
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:55:9: Unsupported/unknown built-in queue method 'shuffle'
|
||||
: ... In instance t
|
||||
55 | q.shuffle(); q.sort;
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:55:22: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
55 | q.shuffle(); q.sort;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:57:10: Unsupported/unknown built-in queue method 'shuffle'
|
||||
: ... In instance t
|
||||
57 | qe.shuffle();
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:62:14: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
62 | qv = q.find with (item == 2);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:64:14: Unsupported/unknown built-in queue method 'find_first'
|
||||
: ... In instance t
|
||||
64 | qv = q.find_first with (item == 2);
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:66:14: Unsupported/unknown built-in queue method 'find_last'
|
||||
: ... In instance t
|
||||
66 | qv = q.find_last with (item == 2);
|
||||
| ^~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:69:14: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
69 | qv = q.find with (item == 20);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:71:14: Unsupported/unknown built-in queue method 'find_first'
|
||||
: ... In instance t
|
||||
71 | qv = q.find_first with (item == 20);
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:73:14: Unsupported/unknown built-in queue method 'find_last'
|
||||
: ... In instance t
|
||||
73 | qv = q.find_last with (item == 20);
|
||||
| ^~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:76:14: Unsupported/unknown built-in queue method 'find_index'
|
||||
: ... In instance t
|
||||
76 | qi = q.find_index with (item == 2);
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:77:10: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
77 | qi.sort; v = $sformatf("%p", qi); do if ((v) !== ("'{'h1, 'h2} ")) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", "t/t_queue_method.v",77, (v), ("'{'h1, 'h2} ")); $stop; end while(0);;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:78:14: Unsupported/unknown built-in queue method 'find_first_index'
|
||||
: ... In instance t
|
||||
78 | qi = q.find_first_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:80:14: Unsupported/unknown built-in queue method 'find_last_index'
|
||||
: ... In instance t
|
||||
80 | qi = q.find_last_index with (item == 2);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:83:14: Unsupported/unknown built-in queue method 'find_index'
|
||||
: ... In instance t
|
||||
83 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:83:47: Unsupported/unknown built-in queue method 'sort'
|
||||
: ... In instance t
|
||||
83 | qi = q.find_index with (item == 20); qi.sort;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:85:14: Unsupported/unknown built-in queue method 'find_first_index'
|
||||
: ... In instance t
|
||||
85 | qi = q.find_first_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:87:14: Unsupported/unknown built-in queue method 'find_last_index'
|
||||
: ... In instance t
|
||||
87 | qi = q.find_last_index with (item == 20);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:90:14: Unsupported/unknown built-in queue method 'min'
|
||||
: ... In instance t
|
||||
90 | qv = q.min;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:92:14: Unsupported/unknown built-in queue method 'max'
|
||||
: ... In instance t
|
||||
92 | qv = q.max;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:94:15: Unsupported/unknown built-in queue method 'min'
|
||||
: ... In instance t
|
||||
94 | qv = qe.min;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:96:15: Unsupported/unknown built-in queue method 'max'
|
||||
: ... In instance t
|
||||
96 | qv = qe.max;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:100:13: Unsupported/unknown built-in queue method 'sum'
|
||||
: ... In instance t
|
||||
100 | i = q.sum;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:102:13: Unsupported/unknown built-in queue method 'sum'
|
||||
: ... In instance t
|
||||
102 | i = q.sum with (item + 1);
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:104:13: Unsupported/unknown built-in queue method 'product'
|
||||
: ... In instance t
|
||||
104 | i = q.product;
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:106:13: Unsupported/unknown built-in queue method 'product'
|
||||
: ... In instance t
|
||||
106 | i = q.product with (item + 1);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:109:14: Unsupported/unknown built-in queue method 'sum'
|
||||
: ... In instance t
|
||||
109 | i = qe.sum;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:111:14: Unsupported/unknown built-in queue method 'product'
|
||||
: ... In instance t
|
||||
111 | i = qe.product;
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:115:13: Unsupported/unknown built-in queue method 'and'
|
||||
: ... In instance t
|
||||
115 | i = q.and;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:117:13: Unsupported/unknown built-in queue method 'and'
|
||||
: ... In instance t
|
||||
117 | i = q.and with (item + 1);
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:119:13: Unsupported/unknown built-in queue method 'or'
|
||||
: ... In instance t
|
||||
119 | i = q.or;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:121:13: Unsupported/unknown built-in queue method 'or'
|
||||
: ... In instance t
|
||||
121 | i = q.or with (item + 1);
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:123:13: Unsupported/unknown built-in queue method 'xor'
|
||||
: ... In instance t
|
||||
123 | i = q.xor;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:125:13: Unsupported/unknown built-in queue method 'xor'
|
||||
: ... In instance t
|
||||
125 | i = q.xor with (item + 1);
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:128:14: Unsupported/unknown built-in queue method 'and'
|
||||
: ... In instance t
|
||||
128 | i = qe.and;
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:130:14: Unsupported/unknown built-in queue method 'or'
|
||||
: ... In instance t
|
||||
130 | i = qe.or;
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_queue_method.v:132:14: Unsupported/unknown built-in queue method 'xor'
|
||||
: ... In instance t
|
||||
132 | i = qe.xor;
|
||||
| ^~~
|
||||
%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;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ module t (/*AUTOARG*/);
|
|||
int q[$];
|
||||
int qe[$]; // Empty
|
||||
int qv[$]; // Value returns
|
||||
int qvunused[$]; // Value returns (unused)
|
||||
int qi[$]; // Index returns
|
||||
int i;
|
||||
string v;
|
||||
|
|
@ -73,6 +74,9 @@ module t (/*AUTOARG*/);
|
|||
qv = q.find_last with (item == 20);
|
||||
`checkh(qv.size, 0);
|
||||
|
||||
// Check gate eater with Lambda variable removal
|
||||
qvunused = q.find with (item == 20);
|
||||
|
||||
qi = q.find_index with (item == 2);
|
||||
qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} ");
|
||||
qi = q.find_first_index with (item == 2);
|
||||
|
|
@ -80,6 +84,10 @@ module t (/*AUTOARG*/);
|
|||
qi = q.find_last_index with (item == 2);
|
||||
v = $sformatf("%p", qi); `checks(v, "'{'h2} ");
|
||||
|
||||
i = 2;
|
||||
qi = q.find_index with (item == i);
|
||||
qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} ");
|
||||
|
||||
qi = q.find_index with (item == 20); qi.sort;
|
||||
`checkh(qi.size, 0);
|
||||
qi = q.find_first_index with (item == 20);
|
||||
|
|
@ -101,6 +109,13 @@ module t (/*AUTOARG*/);
|
|||
`checkh(i, 32'hc);
|
||||
i = q.sum with (item + 1);
|
||||
`checkh(i, 32'h11);
|
||||
i = q.sum(myi) with (myi + 1);
|
||||
`checkh(i, 32'h11);
|
||||
i = q.sum with (1); // unused 'index'
|
||||
`checkh(i, 32'h5);
|
||||
i = q.sum(unused) with (1); // unused 'unused'
|
||||
`checkh(i, 32'h5);
|
||||
|
||||
i = q.product;
|
||||
`checkh(i, 32'h30);
|
||||
i = q.product with (item + 1);
|
||||
|
|
@ -108,6 +123,7 @@ module t (/*AUTOARG*/);
|
|||
|
||||
i = qe.sum;
|
||||
`checkh(i, 32'h0);
|
||||
|
||||
i = qe.product;
|
||||
`checkh(i, 32'h0);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:15:14: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:15:21: 'with' not legal on this method
|
||||
: ... In instance t
|
||||
15 | qv = q.unique with (1);
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:16:9: Unsupported/unknown built-in queue method 'reverse'
|
||||
: ... In instance t
|
||||
| ^~~~
|
||||
%Error: t/t_queue_method_bad.v:16:9: The 1 arguments passed to .reverse method does not match its requiring 0 arguments
|
||||
: ... In instance t
|
||||
16 | q.reverse(1);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:17:9: Unsupported/unknown built-in queue method 'shuffle'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:17:9: The 1 arguments passed to .shuffle method does not match its requiring 0 arguments
|
||||
: ... In instance t
|
||||
17 | q.shuffle(1);
|
||||
| ^~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:18:14: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:18:14: 'with' statement is required for .find method
|
||||
: ... In instance t
|
||||
18 | qv = q.find;
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:19:14: Unsupported/unknown built-in queue method 'find_first'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:19:14: 'with' statement is required for .find_first method
|
||||
: ... In instance t
|
||||
19 | qv = q.find_first;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:20:14: Unsupported/unknown built-in queue method 'find_last'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:20:14: 'with' statement is required for .find_last method
|
||||
: ... In instance t
|
||||
20 | qv = q.find_last;
|
||||
| ^~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:21:14: Unsupported/unknown built-in queue method 'find_index'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:21:14: 'with' statement is required for .find_index method
|
||||
: ... In instance t
|
||||
21 | qi = q.find_index;
|
||||
| ^~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:22:14: Unsupported/unknown built-in queue method 'find_first_index'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:22:14: 'with' statement is required for .find_first_index method
|
||||
: ... In instance t
|
||||
22 | qi = q.find_first_index;
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_queue_method_bad.v:23:14: Unsupported/unknown built-in queue method 'find_last_index'
|
||||
: ... In instance t
|
||||
%Error: t/t_queue_method_bad.v:23:14: 'with' statement is required for .find_last_index method
|
||||
: ... In instance t
|
||||
23 | qi = q.find_last_index;
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_queue_method_bad.v:25:19: 'with' not legal on this method
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_with.v:19:23: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
19 | found = aliases.find(i) with (i == tofind);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:21:15: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
21 | aliases.find(i) with (i == tofind);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:24:23: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
24 | found = aliases.find with (item == i);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:25:15: Unsupported/unknown built-in queue method 'find'
|
||||
: ... In instance t
|
||||
25 | aliases.find with (item == i);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:29:23: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
29 | found = aliases.unique with (id);
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:30:23: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
30 | found = aliases.unique() with (id);
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:31:23: Unsupported/unknown built-in queue method 'unique'
|
||||
: ... In instance t
|
||||
31 | found = aliases.unique(i) with (id);
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:32:19: Unsupported/unknown built-in queue method 'or'
|
||||
: ... In instance t
|
||||
32 | i = aliases.or(v) with (v);
|
||||
| ^~
|
||||
%Error-UNSUPPORTED: t/t_with.v:33:19: Unsupported/unknown built-in queue method 'and'
|
||||
: ... In instance t
|
||||
33 | i = aliases.and(v) with (v);
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_with.v:34:19: Unsupported/unknown built-in queue method 'xor'
|
||||
: ... In instance t
|
||||
34 | i = aliases.xor(v) with (v);
|
||||
| ^~~
|
||||
%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;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ module t (/*AUTOARG*/);
|
|||
int found[$];
|
||||
int id;
|
||||
int i;
|
||||
|
||||
aliases = '{ 1, 4, 6, 8};
|
||||
tofind = 6;
|
||||
found = aliases.find(i) with (i == tofind);
|
||||
found = aliases.find with (item == 1);
|
||||
found = aliases.find(j) with (j == tofind);
|
||||
// And as function
|
||||
aliases.find(i) with (i == tofind);
|
||||
|
||||
|
|
@ -26,9 +28,9 @@ module t (/*AUTOARG*/);
|
|||
|
||||
// Unique (array method)
|
||||
id = 4;
|
||||
found = aliases.unique with (id);
|
||||
found = aliases.unique() with (id);
|
||||
found = aliases.unique(i) with (id);
|
||||
found = aliases.find with (id);
|
||||
found = aliases.find() with (item == id);
|
||||
found = aliases.find(i) with (i == id);
|
||||
i = aliases.or(v) with (v);
|
||||
i = aliases.and(v) with (v);
|
||||
i = aliases.xor(v) with (v);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
%Error: t/t_with_suggest_bad.v:16:25: Can't find definition of variable: 'itemm'
|
||||
: ... Suggested alternative: 'item'
|
||||
16 | qv = q.find with (itemm == 2);
|
||||
| ^~~~~
|
||||
%Error: t/t_with_suggest_bad.v:18:37: Can't find definition of variable: 'misspelledd'
|
||||
: ... Suggested alternative: 'misspelled'
|
||||
18 | qv = q.find(misspelled) with (misspelledd == 2);
|
||||
| ^~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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(vlt => 1);
|
||||
|
||||
lint(
|
||||
verilator_flags2 => ["--lint-only --language 1800-2017"],
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias'
|
||||
//
|
||||
// Simple bi-directional alias test.
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
initial begin
|
||||
int q[$];
|
||||
int qv[$]; // Value returns
|
||||
q = '{1, 2, 2, 4, 3};
|
||||
|
||||
qv = q.find with (itemm == 2);
|
||||
|
||||
qv = q.find(misspelled) with (misspelledd == 2);
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue