Support queue of arrays
This commit is contained in:
parent
0ca72f8098
commit
517fdb7587
|
|
@ -96,7 +96,7 @@ public:
|
|||
// simply use a C style array (which is just a pointer).
|
||||
|
||||
template <std::size_t T_Words> class VlWide final {
|
||||
WData m_storage[T_Words];
|
||||
EData m_storage[T_Words];
|
||||
|
||||
public:
|
||||
// cppcheck-suppress uninitVar
|
||||
|
|
@ -104,11 +104,17 @@ public:
|
|||
~VlWide() = default;
|
||||
VlWide(const VlWide&) = default;
|
||||
VlWide(VlWide&&) = default;
|
||||
|
||||
// OPERATOR METHODS
|
||||
VlWide& operator=(const VlWide&) = default;
|
||||
VlWide& operator=(VlWide&&) = default;
|
||||
const EData& operator[](size_t index) const { return m_storage[index]; };
|
||||
EData& operator[](size_t index) { return m_storage[index]; };
|
||||
operator WDataOutP() { return &m_storage[0]; }
|
||||
|
||||
// METHODS
|
||||
const WData& at(size_t index) const { return m_storage[index]; }
|
||||
WData& at(size_t index) { return m_storage[index]; }
|
||||
const EData& at(size_t index) const { return m_storage[index]; }
|
||||
EData& at(size_t index) { return m_storage[index]; }
|
||||
WData* data() { return &m_storage[0]; }
|
||||
const WData* data() const { return &m_storage[0]; }
|
||||
bool operator<(const VlWide<T_Words>& rhs) const {
|
||||
|
|
@ -788,6 +794,41 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
|||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Verilog packed array container
|
||||
// For when a standard C++[] array is not sufficient, e.g. an
|
||||
// array under a queue, or methods operating on the array
|
||||
|
||||
template <class T_Value, std::size_t T_Depth> class VlUnpacked final {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::array<T_Value, T_Depth> Array;
|
||||
|
||||
public:
|
||||
typedef typename Array::const_iterator const_iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
Array m_array; // State of the assoc array
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlUnpacked() = default;
|
||||
~VlUnpacked() = default;
|
||||
VlUnpacked(const VlUnpacked&) = default;
|
||||
VlUnpacked(VlUnpacked&&) = default;
|
||||
VlUnpacked& operator=(const VlUnpacked&) = default;
|
||||
VlUnpacked& operator=(VlUnpacked&&) = default;
|
||||
|
||||
// METHODS
|
||||
// Raw access
|
||||
WData* data() { return &m_array[0]; }
|
||||
const WData* data() const { return &m_array[0]; }
|
||||
|
||||
T_Value& operator[](size_t index) { return m_array[index]; };
|
||||
const T_Value& operator[](size_t index) const { return m_array[index]; };
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog class reference container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
|
|
|
|||
|
|
@ -2388,7 +2388,13 @@ public:
|
|||
virtual void dump(std::ostream& str) const override;
|
||||
virtual void dumpSmall(std::ostream& str) const;
|
||||
virtual bool hasDType() const override { return true; }
|
||||
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
|
||||
/// Require VlUnpacked, instead of [] for POD elements.
|
||||
/// A non-POD object is always compound, but some POD elements
|
||||
/// are compound when methods calls operate on object, or when
|
||||
/// under another compound-requiring object e.g. class
|
||||
virtual bool isCompound() const = 0;
|
||||
// (Slow) recurse down to find basic data type
|
||||
virtual AstBasicDType* basicp() const = 0;
|
||||
// recurses over typedefs/const/enum to next non-typeref type
|
||||
virtual AstNodeDType* skipRefp() const = 0;
|
||||
// recurses over typedefs to next non-typeref-or-const type
|
||||
|
|
@ -2480,6 +2486,7 @@ public:
|
|||
ASTNODE_BASE_FUNCS(NodeUOrStructDType)
|
||||
virtual const char* broken() const override;
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
virtual bool isCompound() const { return false; } // Because don't support unpacked
|
||||
// For basicp() we reuse the size to indicate a "fake" basic type of same size
|
||||
virtual AstBasicDType* basicp() const override {
|
||||
return (isFourstate()
|
||||
|
|
|
|||
|
|
@ -653,12 +653,16 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
|||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
|
||||
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
||||
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
|
||||
if (compound) {
|
||||
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
|
||||
}
|
||||
if (adtypep->isCompound()) compound = true;
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
||||
if (compound) {
|
||||
info.m_type = "VlUnpacked<" + sub.m_type;
|
||||
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
|
||||
info.m_type += ">";
|
||||
} else {
|
||||
info.m_type = sub.m_type;
|
||||
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
|
||||
}
|
||||
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
|
||||
// We don't print msb()/lsb() as multidim packed would require recursion,
|
||||
// and may confuse users as C++ data is stored always with bit 0 used
|
||||
|
|
@ -1387,15 +1391,17 @@ void AstNodeDType::dumpSmall(std::ostream& str) const {
|
|||
}
|
||||
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
if (VN_IS(this, PackArrayDType)) {
|
||||
str << "p";
|
||||
if (auto* adtypep = VN_CAST_CONST(this, UnpackArrayDType)) {
|
||||
// uc = packed compound object, u = unpacked POD
|
||||
str << (adtypep->isCompound() ? "uc" : "u");
|
||||
} else {
|
||||
str << "u";
|
||||
str << "p";
|
||||
}
|
||||
str << declRange();
|
||||
}
|
||||
void AstNodeArrayDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
if (isCompound()) str << " [COMPOUND]";
|
||||
str << " " << declRange();
|
||||
}
|
||||
string AstPackArrayDType::prettyDTypeName() const {
|
||||
|
|
|
|||
|
|
@ -407,6 +407,10 @@ public:
|
|||
AstVarType varType() const { return m_varType; } // * = Type of variable
|
||||
bool isParam() const { return true; }
|
||||
bool isGParam() const { return (varType() == AstVarType::GPARAM); }
|
||||
virtual bool isCompound() const override {
|
||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AstTypedef final : public AstNode {
|
||||
|
|
@ -507,6 +511,7 @@ public:
|
|||
virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
virtual string name() const override { return m_name; }
|
||||
virtual void name(const string& flag) override { m_name = flag; }
|
||||
virtual bool isCompound() const override { return false; }
|
||||
};
|
||||
|
||||
class AstAssocArrayDType final : public AstNodeDType {
|
||||
|
|
@ -578,6 +583,7 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstBracketArrayDType final : public AstNodeDType {
|
||||
|
|
@ -608,6 +614,7 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
virtual int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstDynArrayDType final : public AstNodeDType {
|
||||
|
|
@ -667,6 +674,7 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstPackArrayDType final : public AstNodeArrayDType {
|
||||
|
|
@ -693,12 +701,14 @@ public:
|
|||
}
|
||||
ASTNODE_NODE_FUNCS(PackArrayDType)
|
||||
virtual string prettyDTypeName() const override;
|
||||
virtual bool isCompound() const override { return false; }
|
||||
};
|
||||
|
||||
class AstUnpackArrayDType final : public AstNodeArrayDType {
|
||||
// Array data type, ie "some_dtype var_name [2:0]"
|
||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||
// Children: RANGE (array bounds)
|
||||
bool m_isCompound = false; // Non-POD subDType, or parent requires compound
|
||||
public:
|
||||
AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
|
|
@ -721,8 +731,14 @@ public:
|
|||
}
|
||||
ASTNODE_NODE_FUNCS(UnpackArrayDType)
|
||||
virtual string prettyDTypeName() const override;
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstUnpackArrayDType* sp = static_cast<const AstUnpackArrayDType*>(samep);
|
||||
return m_isCompound == sp->m_isCompound;
|
||||
}
|
||||
// Outer dimension comes first. The first element is this node.
|
||||
std::vector<AstUnpackArrayDType*> unpackDimensions();
|
||||
void isCompound(bool flag) { m_isCompound = flag; }
|
||||
virtual bool isCompound() const override { return m_isCompound; }
|
||||
};
|
||||
|
||||
class AstUnsizedArrayDType final : public AstNodeDType {
|
||||
|
|
@ -775,6 +791,7 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstBasicDType final : public AstNodeDType {
|
||||
|
|
@ -930,6 +947,7 @@ public:
|
|||
rangep(nullptr);
|
||||
}
|
||||
}
|
||||
virtual bool isCompound() const override { return isString(); }
|
||||
};
|
||||
|
||||
class AstConstDType final : public AstNodeDType {
|
||||
|
|
@ -982,6 +1000,10 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool isCompound() const override {
|
||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AstClassRefDType final : public AstNodeDType {
|
||||
|
|
@ -1033,6 +1055,7 @@ public:
|
|||
AstClass* classp() const { return m_classp; }
|
||||
void classp(AstClass* nodep) { m_classp = nodep; }
|
||||
AstPin* paramsp() const { return VN_CAST(op4p(), Pin); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstIfaceRefDType final : public AstNodeDType {
|
||||
|
|
@ -1088,6 +1111,7 @@ public:
|
|||
AstModport* modportp() const { return m_modportp; }
|
||||
void modportp(AstModport* modportp) { m_modportp = modportp; }
|
||||
bool isModport() { return !m_modportName.empty(); }
|
||||
virtual bool isCompound() const override { return true; } // But not relevant
|
||||
};
|
||||
|
||||
class AstQueueDType final : public AstNodeDType {
|
||||
|
|
@ -1158,6 +1182,7 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
virtual bool isCompound() const override { return true; }
|
||||
};
|
||||
|
||||
class AstRefDType final : public AstNodeDType {
|
||||
|
|
@ -1259,6 +1284,10 @@ public:
|
|||
AstNode* typeofp() const { return op2p(); }
|
||||
AstNode* classOrPackageOpp() const { return op3p(); }
|
||||
AstPin* paramsp() const { return VN_CAST(op4p(), Pin); }
|
||||
virtual bool isCompound() const override {
|
||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AstStructDType final : public AstNodeUOrStructDType {
|
||||
|
|
@ -1341,6 +1370,10 @@ public:
|
|||
virtual string tag() const override { return m_tag; }
|
||||
int lsb() const { return m_lsb; }
|
||||
void lsb(int lsb) { m_lsb = lsb; }
|
||||
virtual bool isCompound() const override {
|
||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AstVoidDType final : public AstNodeDType {
|
||||
|
|
@ -1368,6 +1401,7 @@ public:
|
|||
virtual int widthAlignBytes() const override { return 1; }
|
||||
virtual int widthTotalBytes() const override { return 1; }
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool isCompound() const override { return false; }
|
||||
};
|
||||
|
||||
class AstEnumItem final : public AstNode {
|
||||
|
|
@ -1489,6 +1523,7 @@ public:
|
|||
for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++;
|
||||
return count;
|
||||
}
|
||||
virtual bool isCompound() const override { return false; }
|
||||
};
|
||||
|
||||
class AstParseTypeDType final : public AstNodeDType {
|
||||
|
|
@ -1510,6 +1545,10 @@ public:
|
|||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return 0; }
|
||||
virtual int widthTotalBytes() const override { return 0; }
|
||||
virtual bool isCompound() const override {
|
||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ class SliceVisitor final : public AstNVisitor {
|
|||
? snodep->declRange().elements() - 1 - offset
|
||||
: offset));
|
||||
newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset);
|
||||
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)) {
|
||||
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)
|
||||
|| VN_IS(nodep, CMethodHard)) {
|
||||
UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl);
|
||||
int leOffset = !arrayp->rangep()->littleEndian()
|
||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
||||
|
|
|
|||
|
|
@ -1451,9 +1451,10 @@ private:
|
|||
// Cleanup array size
|
||||
userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
if (VN_IS(nodep, UnpackArrayDType)) {
|
||||
if (auto* adtypep = VN_CAST(nodep, UnpackArrayDType)) {
|
||||
// Historically array elements have width of the ref type not the full array
|
||||
nodep->widthFromSub(nodep->subDTypep());
|
||||
if (nodep->subDTypep()->skipRefp()->isCompound()) adtypep->isCompound(true);
|
||||
} else {
|
||||
int width = nodep->subDTypep()->width() * nodep->rangep()->elementsConst();
|
||||
nodep->widthForce(width, width);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// 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
|
||||
|
||||
`define stop $stop
|
||||
`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;
|
||||
|
||||
typedef string sarray_t[2];
|
||||
typedef sarray_t q_sarray_t[$];
|
||||
|
||||
typedef bit [95:0] wide_t;
|
||||
typedef wide_t warray_t[2];
|
||||
typedef warray_t q_warray_t[$];
|
||||
|
||||
initial begin
|
||||
begin
|
||||
q_sarray_t iq;
|
||||
sarray_t a;
|
||||
sarray_t b0;
|
||||
sarray_t b1;
|
||||
|
||||
a[0] = "hello";
|
||||
a[1] = "world";
|
||||
iq.push_back(a);
|
||||
a[0] = "bye";
|
||||
a[1] = "world";
|
||||
iq.push_back(a);
|
||||
|
||||
b0 = iq[0];
|
||||
b1 = iq[1];
|
||||
`checks(b0[0], "hello");
|
||||
`checks(b0[1], "world");
|
||||
`checks(b1[0], "bye");
|
||||
`checks(b1[1], "world");
|
||||
end
|
||||
|
||||
`ifndef verilator
|
||||
// Need wide conversion into VlUnpacked types
|
||||
|
||||
// If we convert all arrays to VlUnpacked it works, so we need to track
|
||||
// data types and insert conversions perhaps in V3Cast, but we currently
|
||||
// don't know the output datatypes, so work needed.
|
||||
begin
|
||||
q_warray_t iq;
|
||||
warray_t a;
|
||||
warray_t b0;
|
||||
|
||||
a[0] = "abcdefg_ijkl";
|
||||
a[1] = "012123123128";
|
||||
iq.push_back(a);
|
||||
|
||||
b0 = iq[0];
|
||||
`checks(b0[0], "abcdefg_ijkl");
|
||||
`checks(b0[1], "012123123128");
|
||||
end
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue