Support queue of arrays

This commit is contained in:
Wilson Snyder 2020-12-12 19:19:16 -05:00
parent 0ca72f8098
commit 517fdb7587
9 changed files with 205 additions and 15 deletions

View File

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

View File

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

View File

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

View File

@ -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;
}
};
//######################################################################

View File

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

View File

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

21
test_regress/t/t_queue_array.pl Executable file
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 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;

View File

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