mirror of
https://github.com/verilator/verilator.git
synced 2025-04-15 17:16:55 +00:00
Wildcard index type support for associative arrays (#3501).
Associative arrays that specify a wildcard index type may be indexed by integral expressions of any size, with leading zeros removed automatically. A natural representation for such expressions is a string, especially that the standard explicitly specifies automatic casts from string indices to bit vectors of equivalent size. The automatic cast part is done implicitly by the existing type system. A simpler way to just make this work would be to convert wildcard index type to a string type directly in the parser code, but several new AST classes are needed to make sure illegal method calls are detected. The verilated data structure implementation is reused, because there is no need for differentiating the behavior on C++ side.
This commit is contained in:
parent
1c5e5704f5
commit
542e324869
@ -673,6 +673,9 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
||||
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlQueue<" + sub.m_type + ">";
|
||||
@ -1683,6 +1686,10 @@ string AstQueueDType::prettyDTypeName() const {
|
||||
if (boundConst()) str += ":" + cvtToStr(boundConst());
|
||||
return str + "]";
|
||||
}
|
||||
void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "[*]";
|
||||
}
|
||||
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "[]";
|
||||
|
146
src/V3AstNodes.h
146
src/V3AstNodes.h
@ -278,6 +278,17 @@ public:
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstWildcardRange final : public AstNodeRange {
|
||||
// Wildcard range specification, for wildcard index type associative arrays
|
||||
public:
|
||||
explicit AstWildcardRange(FileLine* fl)
|
||||
: ASTGEN_SUPER_WildcardRange(fl) {}
|
||||
ASTNODE_NODE_FUNCS(WildcardRange)
|
||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitVerilog() { return "[*]"; }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstGatePin final : public AstNodeMath {
|
||||
// Possibly expand a gate primitive input pin value to match the range of the gate primitive
|
||||
public:
|
||||
@ -819,6 +830,62 @@ public:
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstWildcardArrayDType final : public AstNodeDType {
|
||||
// Wildcard index type associative array data type, ie "some_dtype var_name [*]"
|
||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||
private:
|
||||
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
|
||||
public:
|
||||
AstWildcardArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_WildcardArrayDType(fl) {
|
||||
childDTypep(dtp); // Only for parser
|
||||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(WildcardArrayDType)
|
||||
virtual const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
virtual void dumpSmall(std::ostream& str) const override;
|
||||
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
// op1 = Range of variable
|
||||
AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
virtual AstNodeDType* subDTypep() const override {
|
||||
return m_refDTypep ? m_refDTypep : childDTypep();
|
||||
}
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); }
|
||||
virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override {
|
||||
return sizeof(std::map<std::string, std::string>);
|
||||
}
|
||||
virtual int widthTotalBytes() const override {
|
||||
return sizeof(std::map<std::string, std::string>);
|
||||
}
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstBasicDType final : public AstNodeDType {
|
||||
// Builtin atomic/vectored data type
|
||||
// Children: RANGE (converted to constant in V3Width)
|
||||
@ -1686,6 +1753,44 @@ public:
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
};
|
||||
|
||||
class AstWildcardSel final : public AstNodeSel {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
private:
|
||||
void init(AstNode* fromp) {
|
||||
if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) {
|
||||
// Strip off array to find what array references
|
||||
dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AstWildcardSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
: ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) {
|
||||
init(fromp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(WildcardSel)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
return new AstWildcardSel{this->fileline(), lhsp, rhsp};
|
||||
}
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
V3ERROR_NA;
|
||||
}
|
||||
virtual string emitVerilog() override { return "%k(%l%f[%r])"; }
|
||||
virtual string emitC() override { return "%li%k[%ri]"; }
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual bool cleanLhs() const override { return false; }
|
||||
virtual bool cleanRhs() const override { return true; }
|
||||
virtual bool sizeMattersLhs() const override { return false; }
|
||||
virtual bool sizeMattersRhs() const override { return false; }
|
||||
virtual bool isGateOptimizable() const override {
|
||||
return true;
|
||||
} // esp for V3Const::ifSameAssign
|
||||
virtual bool isPredictOptimizable() const override { return false; }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
};
|
||||
|
||||
class AstWordSel final : public AstNodeSel {
|
||||
// Select a single word from a multi-word wide value
|
||||
public:
|
||||
@ -4887,6 +4992,47 @@ public:
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstConsWildcard final : public AstNodeMath {
|
||||
// Construct a wildcard assoc array and return object, '{}
|
||||
// Parents: math
|
||||
// Children: expression (elements or other queues)
|
||||
public:
|
||||
AstConsWildcard(FileLine* fl, AstNode* defaultp)
|
||||
: ASTGEN_SUPER_ConsWildcard(fl) {
|
||||
setNOp1p(defaultp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ConsWildcard)
|
||||
virtual string emitVerilog() override { return "'{}"; }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
AstNode* defaultp() const { return op1p(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
class AstSetWildcard final : public AstNodeMath {
|
||||
// Set a wildcard assoc array element and return object, '{}
|
||||
// Parents: math
|
||||
// Children: expression (elements or other queues)
|
||||
public:
|
||||
AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep)
|
||||
: ASTGEN_SUPER_SetWildcard(fl) {
|
||||
setOp1p(lhsp);
|
||||
setNOp2p(keyp);
|
||||
setOp3p(valuep);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(SetWildcard)
|
||||
virtual string emitVerilog() override { return "'{}"; }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
AstNode* keyp() const { return op2p(); }
|
||||
AstNode* valuep() const { return op3p(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstConsDynArray final : public AstNodeMath {
|
||||
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
|
||||
// Parents: math
|
||||
|
@ -88,6 +88,7 @@ private:
|
||||
if (VN_IS(nodep, Var)
|
||||
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|
||||
|
@ -611,6 +611,17 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
|
||||
emitSetVarConstant(varNameProtected + ".at(" + cvtToStr(itr.first) + ")",
|
||||
VN_AS(valuep, Const));
|
||||
}
|
||||
} else if (AstWildcardArrayDType* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
if (initarp->defaultp()) {
|
||||
emitSetVarConstant(varNameProtected + ".atDefault()",
|
||||
VN_AS(initarp->defaultp(), Const));
|
||||
}
|
||||
const auto& mapr = initarp->map();
|
||||
for (const auto& itr : mapr) {
|
||||
AstNode* const valuep = itr.second->valuep();
|
||||
emitSetVarConstant(varNameProtected + ".at(" + cvtToStr(itr.first) + ")",
|
||||
VN_AS(valuep, Const));
|
||||
}
|
||||
} else if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
if (initarp->defaultp()) {
|
||||
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
|
||||
@ -642,6 +653,11 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (AstWildcardArrayDType* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
|
||||
suffix + ".atDefault()" + cvtarray);
|
||||
} else if (VN_IS(dtypep, ClassRefDType)) {
|
||||
return ""; // Constructor does it
|
||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
|
@ -379,6 +379,14 @@ public:
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstWildcardSel* nodep) override {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
putbs(".at(");
|
||||
AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType);
|
||||
UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type");
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) override {
|
||||
const AstCFunc* const funcp = nodep->funcp();
|
||||
const AstNodeModule* const funcModp = EmitCParentModule::get(funcp);
|
||||
@ -1189,6 +1197,24 @@ public:
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstConsWildcard* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
puts("()");
|
||||
if (nodep->defaultp()) {
|
||||
putbs(".setDefault(");
|
||||
iterateAndNextNull(nodep->defaultp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSetWildcard* nodep) override {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putbs(".set(");
|
||||
iterateAndNextNull(nodep->keyp());
|
||||
puts(", ");
|
||||
putbs("");
|
||||
iterateAndNextNull(nodep->valuep());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstConsDynArray* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
if (!nodep->lhsp()) {
|
||||
|
@ -133,6 +133,11 @@ private:
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
virtual void visit(AstWildcardArrayDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->virtRefDTypep());
|
||||
});
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
|
||||
m_hash += nodep->keyword();
|
||||
|
@ -138,6 +138,8 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
||||
AstNode* const keyp = arangep->elementsp()->unlinkFrBack();
|
||||
arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
||||
keyp);
|
||||
} else if (VN_IS(nrangep, WildcardRange)) {
|
||||
arrayp = new AstWildcardArrayDType{nrangep->fileline(), VFlagChildDType{}, arrayp};
|
||||
} else {
|
||||
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
||||
}
|
||||
|
170
src/V3Width.cpp
170
src/V3Width.cpp
@ -981,6 +981,27 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstWildcardSel* nodep) override {
|
||||
// Signed/Real: Output type based on array-declared type; binary operator
|
||||
if (m_vup->prelim()) {
|
||||
const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp();
|
||||
const AstWildcardArrayDType* const adtypep = VN_CAST(fromDtp, WildcardArrayDType);
|
||||
if (!adtypep) {
|
||||
UINFO(1, " Related dtype: " << fromDtp << endl);
|
||||
nodep->v3fatalSrc("Wildcard array reference is not to wildcard array");
|
||||
}
|
||||
const AstBasicDType* const basicp = nodep->bitp()->dtypep()->skipRefp()->basicp();
|
||||
if (!basicp
|
||||
|| (basicp->keyword() != VBasicDTypeKwd::STRING
|
||||
&& !basicp->keyword().isIntNumeric())) {
|
||||
nodep->v3error("Wildcard index must be integral (IEEE 1800-2017 7.8.1)");
|
||||
}
|
||||
iterateCheckTyped(nodep, "Wildcard associative select", nodep->bitp(),
|
||||
adtypep->findStringDType(), BOTH);
|
||||
nodep->dtypeFrom(adtypep->subDTypep());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSliceSel* nodep) override {
|
||||
// Always creates as output an unpacked array
|
||||
if (m_vup->prelim()) {
|
||||
@ -1582,6 +1603,14 @@ private:
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4, "dtWidthed " << nodep << endl);
|
||||
}
|
||||
virtual void visit(AstWildcardArrayDType* nodep) override {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
||||
// Cleanup array size
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4, "dtWidthed " << nodep << endl);
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep) override {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->generic()) return; // Already perfect
|
||||
@ -2178,6 +2207,31 @@ private:
|
||||
EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConsWildcard* nodep) override {
|
||||
// Type computed when constructed here
|
||||
auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), WildcardArrayDType);
|
||||
UASSERT_OBJ(vdtypep, nodep, "ConsWildcard requires wildcard upper parent data type");
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
if (nodep->defaultp()) {
|
||||
iterateCheck(nodep, "default", nodep->defaultp(), CONTEXT, FINAL,
|
||||
vdtypep->subDTypep(), EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSetWildcard* nodep) override {
|
||||
// Type computed when constructed here
|
||||
auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), WildcardArrayDType);
|
||||
UASSERT_OBJ(vdtypep, nodep, "SetWildcard requires wildcard upper parent data type");
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, BOTH}.p());
|
||||
iterateCheck(nodep, "key", nodep->keyp(), CONTEXT, FINAL, vdtypep->findStringDType(),
|
||||
EXTEND_EXP);
|
||||
iterateCheck(nodep, "value", nodep->valuep(), CONTEXT, FINAL, vdtypep->subDTypep(),
|
||||
EXTEND_EXP);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConsDynArray* nodep) override {
|
||||
// Type computed when constructed here
|
||||
AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType);
|
||||
@ -2426,6 +2480,7 @@ private:
|
||||
}
|
||||
} else if (VN_IS(fromDtp, EnumDType) //
|
||||
|| VN_IS(fromDtp, AssocArrayDType) //
|
||||
|| VN_IS(fromDtp, WildcardArrayDType) //
|
||||
|| VN_IS(fromDtp, UnpackArrayDType) //
|
||||
|| VN_IS(fromDtp, DynArrayDType) //
|
||||
|| VN_IS(fromDtp, QueueDType) //
|
||||
@ -2523,6 +2578,8 @@ private:
|
||||
methodCallEnum(nodep, adtypep);
|
||||
} else if (AstAssocArrayDType* const adtypep = VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
methodCallAssoc(nodep, adtypep);
|
||||
} else if (AstWildcardArrayDType* const adtypep = VN_CAST(fromDtp, WildcardArrayDType)) {
|
||||
methodCallWildcard(nodep, adtypep);
|
||||
} else if (AstDynArrayDType* const adtypep = VN_CAST(fromDtp, DynArrayDType)) {
|
||||
methodCallDyn(nodep, adtypep);
|
||||
} else if (AstQueueDType* const adtypep = VN_CAST(fromDtp, QueueDType)) {
|
||||
@ -2684,6 +2741,89 @@ private:
|
||||
nodep->v3error("Unknown built-in enum method " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
void methodCallWildcard(AstMethodCall* nodep, AstWildcardArrayDType* adtypep) {
|
||||
AstCMethodHard* newp = nullptr;
|
||||
if (nodep->name() == "num" // function int num()
|
||||
|| nodep->name() == "size") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"size"}; // So don't need num()
|
||||
newp->dtypeSetSigned32();
|
||||
} else if (nodep->name() == "first" // function int first(ref index)
|
||||
|| nodep->name() == "last" //
|
||||
|| nodep->name() == "next" //
|
||||
|| nodep->name() == "prev" //
|
||||
|| nodep->name() == "unique_index" //
|
||||
|| nodep->name() == "find_index" || nodep->name() == "find_first_index"
|
||||
|| nodep->name() == "find_last_index") {
|
||||
nodep->v3error("Array method " << nodep->prettyNameQ()
|
||||
<< " not legal on wildcard associative arrays");
|
||||
} else if (nodep->name() == "exists") { // function int exists(input index)
|
||||
// IEEE really should have made this a "bit" return
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists",
|
||||
index_exprp->unlinkFrBack()};
|
||||
newp->dtypeSetSigned32();
|
||||
newp->pure(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"};
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack()};
|
||||
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* const withp
|
||||
= methodWithArgument(nodep, false, false, adtypep->subDTypep(),
|
||||
adtypep->findStringDType(), 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(withp ? withp->dtypep() : adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name()};
|
||||
newp->dtypeFrom(adtypep);
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "find" || nodep->name() == "find_first"
|
||||
|| nodep->name() == "find_last") {
|
||||
AstWith* const withp
|
||||
= methodWithArgument(nodep, true, false, nodep->findBitDType(),
|
||||
adtypep->findStringDType(), 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 {
|
||||
nodep->v3error("Unknown wildcard 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);
|
||||
}
|
||||
}
|
||||
void methodCallAssoc(AstMethodCall* nodep, AstAssocArrayDType* adtypep) {
|
||||
AstCMethodHard* newp = nullptr;
|
||||
if (nodep->name() == "num" // function int num()
|
||||
@ -2789,6 +2929,13 @@ private:
|
||||
VL_DANGLING(index_exprp); // May have been edited
|
||||
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||
}
|
||||
AstNode* methodCallWildcardIndexExpr(AstMethodCall* nodep, AstWildcardArrayDType* adtypep) {
|
||||
AstNode* const index_exprp = VN_CAST(nodep->pinsp(), Arg)->exprp();
|
||||
iterateCheck(nodep, "index", index_exprp, CONTEXT, FINAL, adtypep->findStringDType(),
|
||||
EXTEND_EXP);
|
||||
VL_DANGLING(index_exprp); // May have been edited
|
||||
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||
}
|
||||
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
|
||||
if (AstNodeVarRef* const varrefp = VN_CAST(childp, NodeVarRef)) {
|
||||
varrefp->access(access);
|
||||
@ -3393,6 +3540,8 @@ private:
|
||||
VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (auto* const vdtypep = VN_CAST(dtypep, AssocArrayDType)) {
|
||||
VL_DO_DANGLING(patternAssoc(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (auto* const vdtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
VL_DO_DANGLING(patternWildcard(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (auto* const vdtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
VL_DO_DANGLING(patternDynArray(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (auto* const vdtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
@ -3576,6 +3725,26 @@ private:
|
||||
// if (debug() >= 9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
void patternWildcard(AstPattern* nodep, AstWildcardArrayDType* arrayDtp,
|
||||
AstPatMember* defaultp) {
|
||||
AstNode* defaultValuep = nullptr;
|
||||
if (defaultp) defaultValuep = defaultp->lhssp()->unlinkFrBack();
|
||||
AstNode* newp = new AstConsWildcard{nodep->fileline(), defaultValuep};
|
||||
newp->dtypeFrom(arrayDtp);
|
||||
for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_AS(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayDtp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNode* const keyp = patp->keyp();
|
||||
auto* const newap
|
||||
= new AstSetWildcard{nodep->fileline(), newp, keyp->unlinkFrBack(), valuep};
|
||||
newap->dtypeFrom(arrayDtp);
|
||||
newp = newap;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
// if (debug() >= 9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember*) {
|
||||
AstNode* newp = new AstConsDynArray(nodep->fileline());
|
||||
newp->dtypeFrom(arrayp);
|
||||
@ -4092,6 +4261,7 @@ private:
|
||||
added = true;
|
||||
newFormat += "%g";
|
||||
} else if (VN_IS(dtypep, AssocArrayDType) //
|
||||
|| VN_IS(dtypep, WildcardArrayDType) //
|
||||
|| VN_IS(dtypep, ClassRefDType) //
|
||||
|| VN_IS(dtypep, DynArrayDType) //
|
||||
|| VN_IS(dtypep, QueueDType)) {
|
||||
|
@ -88,6 +88,7 @@ private:
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(ddtypep, NodeArrayDType)) {
|
||||
fromRange = adtypep->declRange();
|
||||
} else if (VN_IS(ddtypep, AssocArrayDType)) {
|
||||
} else if (VN_IS(ddtypep, WildcardArrayDType)) {
|
||||
} else if (VN_IS(ddtypep, DynArrayDType)) {
|
||||
} else if (VN_IS(ddtypep, QueueDType)) {
|
||||
} else if (const AstNodeUOrStructDType* const adtypep
|
||||
@ -257,6 +258,15 @@ private:
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstWildcardArrayDType* const adtypep
|
||||
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
||||
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
||||
AstNode* const subp = rhsp;
|
||||
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp};
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* const subp = rhsp;
|
||||
|
@ -2074,10 +2074,8 @@ variable_dimension<nodeRangep>: // ==IEEE: variable_dimension
|
||||
// // IEEE: associative_dimension (if data_type)
|
||||
// // Can't tell which until see if expr is data type or not
|
||||
| '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); }
|
||||
| yP_BRASTAR ']'
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); }
|
||||
| '[' '*' ']'
|
||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); }
|
||||
| yP_BRASTAR ']' { $$ = new AstWildcardRange{$1}; }
|
||||
| '[' '*' ']' { $$ = new AstWildcardRange{$1}; }
|
||||
// // IEEE: queue_dimension
|
||||
// // '[' '$' ']' -- $ is part of expr, see '[' constExpr ']'
|
||||
// // '[' '$' ':' expr ']' -- anyrange:expr:$
|
||||
|
21
test_regress/t/t_assoc_wildcard.pl
Executable file
21
test_regress/t/t_assoc_wildcard.pl
Executable 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 2019 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;
|
@ -22,26 +22,25 @@ module t (/*AUTOARG*/
|
||||
cyc <= cyc + 1;
|
||||
begin
|
||||
// Wildcard
|
||||
string a [*];
|
||||
string a [*] = '{default: "nope", "BBBBB": "fooing", 23'h434343: "baring"};
|
||||
int k;
|
||||
string v;
|
||||
|
||||
v = a["CCC"]; `checks(v, "baring");
|
||||
v = a["BBBBB"]; `checks(v, "fooing");
|
||||
|
||||
a[32'd1234] = "fooed";
|
||||
a[4'd3] = "bared";
|
||||
i = a.num(); `checkh(i, 2);
|
||||
i = a.size(); `checkh(i, 2);
|
||||
v = a[32'd1234]; `checks(v, "fooed");
|
||||
a[79'h4141] = "bazed";
|
||||
i = a.num(); `checkh(i, 5);
|
||||
i = a.size(); `checkh(i, 5);
|
||||
v = a[39'd1234]; `checks(v, "fooed");
|
||||
v = a["AA"]; `checks(v, "bazed");
|
||||
v = a[4'd3]; `checks(v, "bared");
|
||||
i = a.exists("baz"); `checkh(i, 0);
|
||||
i = a.exists(4'd3); `checkh(i, 1);
|
||||
i = a.first(k); `checkh(i, 1); `checks(k, 4'd3);
|
||||
i = a.next(k); `checkh(i, 1); `checks(k, 32'd1234);
|
||||
i = a.next(k); `checkh(i, 0);
|
||||
i = a.last(k); `checkh(i, 1); `checks(k, 32'd1234);
|
||||
i = a.prev(k); `checkh(i, 1); `checks(k, 4'd3);
|
||||
i = a.prev(k); `checkh(i, 0);
|
||||
a.delete(4'd3);
|
||||
i = a.size(); `checkh(i, 1);
|
||||
i = a.size(); `checkh(i, 4);
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
73
test_regress/t/t_assoc_wildcard_bad.out
Normal file
73
test_regress/t/t_assoc_wildcard_bad.out
Normal file
@ -0,0 +1,73 @@
|
||||
%Error: t/t_assoc_wildcard_bad.v:23:13: The 1 arguments passed to .num method does not match its requiring 0 arguments
|
||||
: ... In instance t
|
||||
23 | v = a.num("badarg");
|
||||
| ^~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:24:13: The 1 arguments passed to .size method does not match its requiring 0 arguments
|
||||
: ... In instance t
|
||||
24 | v = a.size("badarg");
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:25:13: The 0 arguments passed to .exists method does not match its requiring 1 arguments
|
||||
: ... In instance t
|
||||
25 | v = a.exists();
|
||||
| ^~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:26:13: The 2 arguments passed to .exists method does not match its requiring 1 arguments
|
||||
: ... In instance t
|
||||
26 | v = a.exists(k, "bad2");
|
||||
| ^~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:27:9: The 2 arguments passed to .delete method does not match its requiring 0 to 1 arguments
|
||||
: ... In instance t
|
||||
27 | a.delete(k, "bad2");
|
||||
| ^~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:29:9: Array method 'sort' not legal on associative arrays
|
||||
: ... In instance t
|
||||
29 | a.sort;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:30:9: Array method 'rsort' not legal on associative arrays
|
||||
: ... In instance t
|
||||
30 | a.rsort;
|
||||
| ^~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:31:9: Array method 'reverse' not legal on associative arrays
|
||||
: ... In instance t
|
||||
31 | a.reverse;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:32:9: Array method 'shuffle' not legal on associative arrays
|
||||
: ... In instance t
|
||||
32 | a.shuffle;
|
||||
| ^~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:34:9: Array method 'first' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
34 | a.first;
|
||||
| ^~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:35:9: Array method 'last' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
35 | a.last;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:36:9: Array method 'next' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
36 | a.next;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:37:9: Array method 'prev' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
37 | a.prev;
|
||||
| ^~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:38:9: Array method 'unique_index' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
38 | a.unique_index;
|
||||
| ^~~~~~~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:39:9: Array method 'find_index' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
39 | a.find_index;
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:40:9: Array method 'find_first_index' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
40 | a.find_first_index;
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:41:9: Array method 'find_last_index' not legal on wildcard associative arrays
|
||||
: ... In instance t
|
||||
41 | a.find_last_index;
|
||||
| ^~~~~~~~~~~~~~~
|
||||
%Error: t/t_assoc_wildcard_bad.v:43:8: Wildcard index must be integral (IEEE 1800-2017 7.8.1)
|
||||
: ... In instance t
|
||||
43 | a[x] = "bad";
|
||||
| ^
|
||||
%Error: Exiting due to
|
45
test_regress/t/t_assoc_wildcard_bad.v
Normal file
45
test_regress/t/t_assoc_wildcard_bad.v
Normal file
@ -0,0 +1,45 @@
|
||||
// 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
|
||||
|
||||
typedef class Cls;
|
||||
|
||||
class Cls;
|
||||
integer imembera;
|
||||
integer imemberb;
|
||||
endclass : Cls
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
initial begin
|
||||
string a [*];
|
||||
string k;
|
||||
string v;
|
||||
|
||||
Cls x;
|
||||
|
||||
v = a.num("badarg");
|
||||
v = a.size("badarg");
|
||||
v = a.exists(); // Bad
|
||||
v = a.exists(k, "bad2");
|
||||
a.delete(k, "bad2");
|
||||
|
||||
a.sort; // Not legal on assoc
|
||||
a.rsort; // Not legal on assoc
|
||||
a.reverse; // Not legal on assoc
|
||||
a.shuffle; // Not legal on assoc
|
||||
|
||||
a.first; // Not legal on wildcard
|
||||
a.last; // Not legal on wildcard
|
||||
a.next; // Not legal on wildcard
|
||||
a.prev; // Not legal on wildcard
|
||||
a.unique_index; // Not legal on wildcard
|
||||
a.find_index; // Not legal on wildcard
|
||||
a.find_first_index; // Not legal on wildcard
|
||||
a.find_last_index; // Not legal on wildcard
|
||||
|
||||
a[x] = "bad";
|
||||
end
|
||||
endmodule
|
21
test_regress/t/t_assoc_wildcard_method.pl
Executable file
21
test_regress/t/t_assoc_wildcard_method.pl
Executable 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;
|
127
test_regress/t/t_assoc_wildcard_method.v
Normal file
127
test_regress/t/t_assoc_wildcard_method.v
Normal file
@ -0,0 +1,127 @@
|
||||
// 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);
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
int q[*];
|
||||
int qe[*]; // Empty
|
||||
int qv[$]; // Value returns
|
||||
int qi[$]; // Index returns
|
||||
int i;
|
||||
string v;
|
||||
|
||||
q = '{"a":1, "b":2, "c":2, "d":4, "e":3};
|
||||
v = $sformatf("%p", q); `checks(v, "'{\"a\":'h1, \"b\":'h2, \"c\":'h2, \"d\":'h4, \"e\":'h3} ");
|
||||
|
||||
// NOT tested: with ... selectors
|
||||
|
||||
//q.sort; // Not legal on assoc - see t_assoc_meth_bad
|
||||
//q.rsort; // Not legal on assoc - see t_assoc_meth_bad
|
||||
//q.reverse; // Not legal on assoc - see t_assoc_meth_bad
|
||||
//q.shuffle; // Not legal on assoc - see t_assoc_meth_bad
|
||||
|
||||
v = $sformatf("%p", qe); `checks(v, "'{}");
|
||||
qv = q.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h1, 'h2, 'h4, 'h3} ");
|
||||
qv = qe.unique;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
||||
//q.unique_index; // Not legal on wildcard assoc - see t_assoc_wildcard_bad
|
||||
|
||||
// These require an with clause or are illegal
|
||||
qv = q.find with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} ");
|
||||
qv = q.find_first with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
qv = q.find_last with (item == 2);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h2} ");
|
||||
|
||||
qv = q.find with (item == 20);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
qv = q.find_first with (item == 20);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
qv = q.find_last with (item == 20);
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
||||
//q.find_index; // Not legal on wildcard assoc - see t_assoc_wildcard_bad
|
||||
//q.find_first_index; // Not legal on wildcard assoc - see t_assoc_wildcard_bad
|
||||
//q.find_last_index; // Not legal on wildcard assoc - see t_assoc_wildcard_bad
|
||||
|
||||
qv = q.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
|
||||
qv = q.max;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{'h4} ");
|
||||
|
||||
qv = qe.min;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
qv = qe.max;
|
||||
v = $sformatf("%p", qv); `checks(v, "'{}");
|
||||
|
||||
// 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 = 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 = qe.and;
|
||||
`checkh(i, 32'b0);
|
||||
i = qe.or;
|
||||
`checkh(i, 32'b0);
|
||||
i = qe.xor;
|
||||
`checkh(i, 32'b0);
|
||||
|
||||
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);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
@ -1,5 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_assoc_wildcard_unsup.v:25:19: Unsupported: [*] wildcard associative arrays
|
||||
25 | string a [*];
|
||||
| ^~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
Loading…
Reference in New Issue
Block a user