Support queue and associative array 'with' statements. (#2616)

This commit is contained in:
Wilson Snyder 2020-11-01 10:56:07 -05:00
parent c1e8337fc1
commit 2aedc91151
26 changed files with 935 additions and 507 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()));
}

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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