forked from github/verilator
Add support for dynamic arrays, #379.
This commit is contained in:
parent
8054fc47ea
commit
e70cba77e6
2
Changes
2
Changes
@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
** Add support for $dumpfile and $dumpvars, #2126. [Alexander Grobman]
|
||||
|
||||
** Add support for dynamic arrays, #379.
|
||||
|
||||
*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel]
|
||||
|
||||
*** Add check for assertOn for asserts, #2162. [Tobias Wölfel]
|
||||
|
@ -245,11 +245,12 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog queue container
|
||||
// Verilog queue and dynamic array container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
//
|
||||
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
|
||||
// For dynamic arrays it is always zero
|
||||
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
|
||||
private:
|
||||
// TYPES
|
||||
@ -279,6 +280,21 @@ public:
|
||||
void clear() { m_deque.clear(); }
|
||||
void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); }
|
||||
|
||||
// Dynamic array new[] becomes a renew()
|
||||
void renew(size_t size) {
|
||||
clear();
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
// Dynamic array new[]() becomes a renew_copy()
|
||||
void renew_copy(size_t size, const VlQueue<T_Value,T_MaxSize>& rhs) {
|
||||
if (size == 0) {
|
||||
clear();
|
||||
} else {
|
||||
*this = rhs;
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
}
|
||||
|
||||
// function void q.push_front(value)
|
||||
void push_front(const T_Value& value) {
|
||||
m_deque.push_front(value);
|
||||
@ -304,6 +320,7 @@ public:
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(size_t index) {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
return s_throwAway;
|
||||
@ -313,6 +330,7 @@ public:
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(size_t index) const {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) return atDefault();
|
||||
else return m_deque[index];
|
||||
}
|
||||
|
@ -278,6 +278,17 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT
|
||||
VlArgTypeRecursed info;
|
||||
info.m_oprefix = out;
|
||||
return info;
|
||||
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
|
||||
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
|
||||
string out = "VlQueue<";
|
||||
out += sub.m_oprefix;
|
||||
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
|
||||
out += " " + sub.m_osuffix + sub.m_oref;
|
||||
}
|
||||
out += "> ";
|
||||
VlArgTypeRecursed info;
|
||||
info.m_oprefix = out;
|
||||
return info;
|
||||
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
|
||||
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true);
|
||||
VlArgTypeRecursed info;
|
||||
@ -1168,6 +1179,13 @@ void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
||||
string AstAssocArrayDType::prettyDTypeName() const {
|
||||
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
||||
}
|
||||
void AstDynArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str<<"[]";
|
||||
}
|
||||
string AstDynArrayDType::prettyDTypeName() const {
|
||||
return subDTypep()->prettyDTypeName() + "[]";
|
||||
}
|
||||
void AstQueueDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str<<"[queue]";
|
||||
|
@ -451,6 +451,56 @@ public:
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
};
|
||||
|
||||
class AstDynArrayDType : public AstNodeDType {
|
||||
// Dynamic array data type, ie "[]"
|
||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||
private:
|
||||
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
|
||||
public:
|
||||
AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
childDTypep(dtp); // Only for parser
|
||||
refDTypep(NULL);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
}
|
||||
AstDynArrayDType(FileLine* fl, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
refDTypep(dtp);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(DynArrayDType)
|
||||
virtual const char* broken() const {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
return NULL; }
|
||||
virtual void cloneRelink() {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
return subDTypep() == asamep->subDTypep(); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual string prettyDTypeName() const;
|
||||
virtual void dumpSmall(std::ostream& str) const;
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() const { return NULL; } // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
};
|
||||
|
||||
class AstPackArrayDType : public AstNodeArrayDType {
|
||||
// Packed array data type, ie "some_dtype [2:0] var_name"
|
||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||
|
@ -88,6 +88,7 @@ private:
|
||||
if (!nodep->user2() && nodep->hasDType()) {
|
||||
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(), DynArrayDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|
||||
|
@ -1503,6 +1503,9 @@ class EmitCImp : EmitCStmts {
|
||||
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1,
|
||||
".atDefault()" + cvtarray);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
||||
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()");
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()");
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
|
104
src/V3Width.cpp
104
src/V3Width.cpp
@ -457,7 +457,7 @@ private:
|
||||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullp();
|
||||
if (vdtypep && (VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, QueueDType))) {
|
||||
nodep->v3error("Unsupported: Concatenation to form "
|
||||
<< vdtypep->prettyDTypeNameQ() << "data type");
|
||||
@ -536,7 +536,9 @@ private:
|
||||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullp();
|
||||
if (vdtypep
|
||||
&& (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, QueueDType)
|
||||
&& (VN_IS(vdtypep, AssocArrayDType)
|
||||
|| VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, QueueDType)
|
||||
|| VN_IS(vdtypep, UnpackArrayDType))) {
|
||||
nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ()
|
||||
<< " data type");
|
||||
@ -1219,6 +1221,14 @@ private:
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4,"dtWidthed "<<nodep<<endl);
|
||||
}
|
||||
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
|
||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
UINFO(4,"dtWidthed "<<nodep<<endl);
|
||||
}
|
||||
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
|
||||
@ -1445,9 +1455,13 @@ private:
|
||||
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
|
||||
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
|
||||
if (VN_IS(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
|
||||
if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
|
||||
if (!(m_ftaskp && m_ftaskp->dpiImport())) {
|
||||
nodep->v3error("Unsized/open arrays ('[]') are only supported in DPI imports");
|
||||
UINFO(9, "Unsized becomes dynamic array " << nodep << endl);
|
||||
AstDynArrayDType* newp
|
||||
= new AstDynArrayDType(unsizedp->fileline(), unsizedp->subDTypep());
|
||||
nodep->dtypep(newp);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newp);
|
||||
}
|
||||
}
|
||||
else if (nodep->isIO() && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType)
|
||||
@ -1778,6 +1792,7 @@ private:
|
||||
if (memberSelStruct(nodep, adtypep)) return;
|
||||
} else if (VN_IS(fromDtp, EnumDType)
|
||||
|| VN_IS(fromDtp, AssocArrayDType)
|
||||
|| VN_IS(fromDtp, DynArrayDType)
|
||||
|| VN_IS(fromDtp, QueueDType)
|
||||
|| VN_IS(fromDtp, BasicDType)) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
@ -1849,6 +1864,9 @@ private:
|
||||
else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
methodCallAssoc(nodep, adtypep);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(fromDtp, DynArrayDType)) {
|
||||
methodCallDyn(nodep, adtypep);
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) {
|
||||
methodCallQueue(nodep, adtypep);
|
||||
}
|
||||
@ -2059,6 +2077,41 @@ private:
|
||||
if (lvalue) varrefp->lvalue(true);
|
||||
}
|
||||
}
|
||||
void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) {
|
||||
AstCMethodHard* newp = NULL;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
methodCallLValue(nodep, nodep->fromp(), true);
|
||||
newp = new AstCMethodHard(nodep->fileline(),
|
||||
nodep->fromp()->unlinkFrBack(),
|
||||
"at", NULL);
|
||||
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", NULL);
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
} else if (nodep->name() == "delete") { // function void delete()
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
methodCallLValue(nodep, nodep->fromp(), true);
|
||||
newp = new AstCMethodHard(nodep->fileline(),
|
||||
nodep->fromp()->unlinkFrBack(),
|
||||
"clear", NULL);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
nodep->v3error("Unsupported/unknown built-in dynamic array method "
|
||||
<< nodep->prettyNameQ());
|
||||
}
|
||||
if (newp) {
|
||||
newp->didWidth(true);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) {
|
||||
AstCMethodHard* newp = NULL;
|
||||
if (nodep->name() == "at") { // Created internally for []
|
||||
@ -2305,7 +2358,26 @@ private:
|
||||
}
|
||||
virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
nodep->v3error("Unsupported: Dynamic array new");
|
||||
AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType);
|
||||
if (!adtypep) { // e.g. int a = new;
|
||||
if (adtypep) UINFO(1, "Got adtypep " << adtypep << endl);
|
||||
nodep->v3error("dynamic new() not expected in this context (data type must be dynamic array)");
|
||||
return;
|
||||
}
|
||||
// The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it
|
||||
if (!VN_IS(nodep->backp(), NodeAssign)) {
|
||||
if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl);
|
||||
nodep->v3error("dynamic new() not expected in this context (expected under an assign)");
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(adtypep);
|
||||
if (m_vup && m_vup->prelim()) {
|
||||
iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH);
|
||||
}
|
||||
if (nodep->rhsp()) {
|
||||
iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep->subDTypep(),
|
||||
BOTH);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPattern* nodep) VL_OVERRIDE {
|
||||
@ -2727,6 +2799,23 @@ private:
|
||||
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
|
||||
//if (debug()) nodep->dumpTree(cout, " AssignOut: ");
|
||||
}
|
||||
if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) {
|
||||
UINFO(9, "= new[] -> .resize(): " << nodep);
|
||||
AstCMethodHard* newp;
|
||||
if (!dynp->rhsp()) {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
"renew", dynp->sizep()->unlinkFrBack());
|
||||
} else {
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
"renew_copy", dynp->sizep()->unlinkFrBack());
|
||||
newp->addPinsp(dynp->rhsp()->unlinkFrBack());
|
||||
}
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
|
||||
@ -2772,6 +2861,7 @@ private:
|
||||
added = true;
|
||||
newFormat += "%g";
|
||||
} else if (VN_IS(dtypep, AssocArrayDType)
|
||||
|| VN_IS(dtypep, DynArrayDType)
|
||||
|| VN_IS(dtypep, QueueDType)) {
|
||||
added = true;
|
||||
newFormat += "%@";
|
||||
@ -4225,8 +4315,8 @@ private:
|
||||
|
||||
AstNode* checkCvtUS(AstNode* nodep) {
|
||||
if (nodep && nodep->isDouble()) {
|
||||
nodep->v3error("Expected integral (non-real) input to "
|
||||
<<nodep->backp()->prettyTypeName());
|
||||
nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName()
|
||||
<< ") input to " << nodep->backp()->prettyTypeName());
|
||||
nodep = spliceCvtS(nodep, true);
|
||||
}
|
||||
return nodep;
|
||||
|
@ -93,6 +93,8 @@ private:
|
||||
}
|
||||
else if (VN_IS(ddtypep, AssocArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, DynArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, QueueDType)) {
|
||||
}
|
||||
else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
|
||||
@ -260,6 +262,15 @@ private:
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
|
||||
fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
|
@ -1,9 +0,0 @@
|
||||
%Error: t/t_dpi_openreg_bad.v:13: Unsized/open arrays ('[]') are only supported in DPI imports
|
||||
: ... In instance t
|
||||
reg a [];
|
||||
^
|
||||
%Error: t/t_dpi_openreg_bad.v:14: Unsized/open arrays ('[]') are only supported in DPI imports
|
||||
: ... In instance t
|
||||
input b [];
|
||||
^
|
||||
%Error: Exiting due to
|
@ -1,20 +0,0 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 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.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
b
|
||||
);
|
||||
|
||||
reg a [];
|
||||
input b [];
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
end
|
||||
|
||||
endmodule
|
20
test_regress/t/t_dynarray.pl
Executable file
20
test_regress/t/t_dynarray.pl
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/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.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
108
test_regress/t/t_dynarray.v
Normal file
108
test_regress/t/t_dynarray.v
Normal file
@ -0,0 +1,108 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Wilson Snyder.
|
||||
|
||||
`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*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
|
||||
integer i;
|
||||
string v;
|
||||
|
||||
// verilator lint_off UNUSED
|
||||
integer unused[];
|
||||
// verilator lint_on UNUSED
|
||||
|
||||
typedef bit [7:0] byte_t;
|
||||
byte_t a[];
|
||||
byte_t b[];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
begin
|
||||
`checkh(a.size, 0);
|
||||
v = $sformatf("%p", a); `checks(v, "'{} ");
|
||||
|
||||
a = new [3];
|
||||
`checkh(a.size, 3);
|
||||
a[0] = 10;
|
||||
a[1] = 11;
|
||||
a[2] = 12;
|
||||
`checkh(a[0], 10);
|
||||
`checkh(a[1], 11);
|
||||
`checkh(a[2], 12);
|
||||
v = $sformatf("%p", a); `checks(v, "'{'ha, 'hb, 'hc} ");
|
||||
a.delete;
|
||||
`checkh(a.size, 0);
|
||||
|
||||
a = new [2];
|
||||
`ifdef verilator // Unsupported pattern assignment
|
||||
a[0] = 15; a[1] = 16;
|
||||
`else
|
||||
a = '{15, 16};
|
||||
`endif
|
||||
`checkh(a.size, 2);
|
||||
`checkh(a[0], 15);
|
||||
`checkh(a[1], 16)
|
||||
|
||||
`ifdef verilator // Unsupported pattern assignment
|
||||
a = new [1];
|
||||
a[0] = 17;
|
||||
`else
|
||||
a = '{17};
|
||||
`endif
|
||||
`checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern
|
||||
`checkh(a[0], 17);
|
||||
|
||||
a = new[2];
|
||||
a[0] = 5;
|
||||
a[1] = 6;
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
a = new[2];
|
||||
`checkh(a[0], 0);
|
||||
`checkh(a[1], 0);
|
||||
|
||||
a[0] = 5;
|
||||
a[1] = 6;
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
|
||||
b = new [4](a);
|
||||
`checkh(b.size, 4);
|
||||
`checkh(b[0], 5);
|
||||
`checkh(b[1], 6);
|
||||
`checkh(b[2], 0);
|
||||
`checkh(b[3], 0);
|
||||
|
||||
a = b;
|
||||
`checkh(a.size, 4);
|
||||
`checkh(a[0], 5);
|
||||
`checkh(a[1], 6);
|
||||
`checkh(a[2], 0);
|
||||
`checkh(a[3], 0);
|
||||
|
||||
a = new [0];
|
||||
`checkh(a.size, 0);
|
||||
b = new [4](a);
|
||||
`checkh(b.size, 4);
|
||||
`checkh(b[0], 0);
|
||||
`checkh(b[1], 0);
|
||||
`checkh(b[2], 0);
|
||||
`checkh(b[4], 0);
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
6
test_regress/t/t_dynarray_bad.out
Normal file
6
test_regress/t/t_dynarray_bad.out
Normal file
@ -0,0 +1,6 @@
|
||||
%Warning-WIDTH: t/t_dynarray_bad.v:14: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits.
|
||||
: ... In instance t
|
||||
a = new [s];
|
||||
^~~
|
||||
... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.
|
||||
%Error: Internal Error: ../V3Number.cpp:#: Number operation called with non-logic (double or string) argument: '"str""
|
@ -2,7 +2,7 @@
|
||||
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
|
||||
# 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.
|
||||
@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => $Self->{vlt_all},
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
17
test_regress/t/t_dynarray_bad.v
Normal file
17
test_regress/t/t_dynarray_bad.v
Normal file
@ -0,0 +1,17 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2020 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
integer a[];
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
s = "str";
|
||||
a = new [s]; // Bad
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user