Support streaming operator on arrays and wide data (#5326)

Signed-off-by: Arkadiusz Kozdra <akozdra@antmicro.com>
This commit is contained in:
Arkadiusz Kozdra 2024-08-06 14:48:46 +02:00 committed by GitHub
parent 3b81654c72
commit a32b8d80f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 194 additions and 243 deletions

View File

@ -1586,46 +1586,68 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const
} }
template <typename T> template <typename T>
static inline void VL_ASSIGN_DYN_Q(VlQueue<T>& q, int elem_size, int lbits, QData from) { static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<T>& q) {
const int size = (lbits + elem_size - 1) / elem_size; IData ret = 0;
q.renew(size); for (size_t i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * lbits);
const QData mask = VL_MASK_Q(elem_size); return ret;
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
} }
template <typename T, std::size_t T_Depth> template <typename T, std::size_t T_Depth>
static inline void VL_ASSIGN_UNPACK_Q(VlUnpacked<T, T_Depth>& q, size_t elem_size, QData from) { static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<T, T_Depth>& q) {
const QData mask = VL_MASK_Q(elem_size); IData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * lbits);
return ret;
}
#define VL_PACK_QI VL_PACK_QQ
template <typename T>
static inline QData VL_PACK_QQ(int obits, int lbits, const VlQueue<T>& q) {
QData ret = 0;
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<QData>(q.at(i)) << (i * lbits);
return ret;
}
template <typename T, std::size_t T_Depth>
static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<T, T_Depth>& q) {
QData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < T_Depth; ++i)
q[i] = (T)((from >> ((T_Depth - 1 - i) * elem_size)) & mask); ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
}
template <typename T>
static inline IData VL_DYN_TO_I(const VlQueue<T>& q, int elem_size) {
IData ret = 0;
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
return ret; return ret;
} }
template <typename T> template <typename T>
static inline QData VL_DYN_TO_Q(const VlQueue<T>& q, int elem_size) { static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const VlQueue<T>& q) {
QData ret = 0; VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size); for (size_t i = 0; i < q.size(); ++i)
return ret; _vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
return owp;
} }
template <typename T, std::size_t T_Depth> template <typename T, std::size_t T_Depth>
static inline IData VL_UNPACK_TO_I(const VlUnpacked<T, T_Depth>& q, size_t elem_size) { static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
IData ret = 0; const VlUnpacked<T, T_Depth>& q) {
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * elem_size); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
return ret; for (size_t i = 0; i < T_Depth; ++i)
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp;
}
template <typename T>
static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp, const VlQueue<T>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < q.size(); ++i)
_vl_insert_WQ(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
return owp;
} }
template <typename T, std::size_t T_Depth> template <typename T, std::size_t T_Depth>
static inline QData VL_UNPACK_TO_Q(const VlUnpacked<T, T_Depth>& q, size_t elem_size) { static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp,
QData ret = 0; const VlUnpacked<T, T_Depth>& q) {
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * elem_size); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
return ret; for (size_t i = 0; i < T_Depth; ++i)
_vl_insert_WQ(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp;
} }
// Because concats are common and wide, it's valuable to always have a clean output. // Because concats are common and wide, it's valuable to always have a clean output.
@ -2067,6 +2089,70 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
//====================================================================== //======================================================================
// Expressions needing insert/select // Expressions needing insert/select
template <typename T>
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<T>& q, IData from) {
const size_t size = (rbits + lbits - 1) / lbits;
q.renew(size);
const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < size; ++i) q.at(i) = static_cast<T>((from >> (i * lbits)) & mask);
}
#define VL_UNPACK_IQ VL_UNPACK_QQ
template <typename T>
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlQueue<T>& q, QData from) {
const size_t size = (rbits + lbits - 1) / lbits;
q.renew(size);
const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < size; ++i) q.at(i) = static_cast<T>((from >> (i * lbits)) & mask);
}
template <typename T>
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<T>& q, WDataInP rwp) {
const int size = (rbits + lbits - 1) / lbits;
q.renew(size);
const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < size; ++i)
q.at(i) = static_cast<T>(VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask);
}
template <typename T>
static inline void VL_UNPACK_QW(int lbits, int rbits, VlQueue<T>& q, WDataInP rwp) {
const int size = (rbits + lbits - 1) / lbits;
q.renew(size);
const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < size; ++i)
q.at(i) = static_cast<T>(VL_SEL_QWII(rbits, rwp, i * lbits, lbits) & mask);
}
template <typename T, std::size_t T_Depth>
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<T, T_Depth>& q, QData from) {
const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i)
q[i] = static_cast<T>((from >> ((T_Depth - 1 - i) * lbits)) & mask);
}
template <typename T, std::size_t T_Depth>
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<T, T_Depth>& q, QData from) {
const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < T_Depth; ++i)
q[i] = static_cast<T>((from >> ((T_Depth - 1 - i) * lbits)) & mask);
}
template <typename T, std::size_t T_Depth>
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<T, T_Depth>& q, WDataInP rwp) {
const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i)
q[i] = static_cast<T>(VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask);
}
template <typename T, std::size_t T_Depth>
static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<T, T_Depth>& q, WDataInP rwp) {
const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < T_Depth; ++i)
q[i] = static_cast<T>(VL_SEL_QWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask);
}
// Return QData from double (numeric) // Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real // EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE { static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {

View File

@ -1124,58 +1124,30 @@ public:
string emitC() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
}; };
class AstCvtDynArrayToPacked final : public AstNodeExpr { class AstCvtArrayToPacked final : public AstNodeExpr {
// Cast from dynamic queue data type to packed array // Cast from dynamic queue data type to packed array
// @astgen op1 := fromp : AstNodeExpr // @astgen op1 := fromp : AstNodeExpr
public: public:
AstCvtDynArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp) AstCvtArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtDynArrayToPacked(fl) { : ASTGEN_SUPER_CvtArrayToPacked(fl) {
this->fromp(fromp); this->fromp(fromp);
dtypeFrom(dtp); dtypeFrom(dtp);
} }
ASTGEN_MEMBERS_AstCvtDynArrayToPacked; ASTGEN_MEMBERS_AstCvtArrayToPacked;
string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); } string emitC() override { return "VL_PACK_%nq%rq(%nw, %rw, %P, %li)"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
}; };
class AstCvtPackedToDynArray final : public AstNodeExpr { class AstCvtPackedToArray final : public AstNodeExpr {
// Cast from packed array to dynamic queue data type // Cast from packed array to dynamic/unpacked queue data type
// @astgen op1 := fromp : AstNodeExpr // @astgen op1 := fromp : AstNodeExpr
public: public:
AstCvtPackedToDynArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp) AstCvtPackedToArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtPackedToDynArray(fl) { : ASTGEN_SUPER_CvtPackedToArray(fl) {
this->fromp(fromp); this->fromp(fromp);
dtypeFrom(dtp); dtypeFrom(dtp);
} }
ASTGEN_MEMBERS_AstCvtPackedToDynArray; ASTGEN_MEMBERS_AstCvtPackedToArray;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtPackedToUnpackArray final : public AstNodeExpr {
// Cast from packed array to dynamic queue data type
// @astgen op1 := fromp : AstNodeExpr
public:
AstCvtPackedToUnpackArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtPackedToUnpackArray(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtPackedToUnpackArray;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstCvtUnpackArrayToPacked final : public AstNodeExpr {
// Cast from dynamic queue data type to packed array
// @astgen op1 := fromp : AstNodeExpr
public:
AstCvtUnpackArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_CvtUnpackArrayToPacked(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCvtUnpackArrayToPacked;
string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -4284,7 +4256,7 @@ public:
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; } bool cleanRhs() const override { return true; }
bool sizeMattersLhs() const override { return true; } bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; } bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; } int instrCount() const override { return widthInstrs() * 2; }
}; };
@ -4305,7 +4277,7 @@ public:
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; } bool cleanRhs() const override { return false; }
bool sizeMattersLhs() const override { return true; } bool sizeMattersLhs() const override { return false; }
bool sizeMattersRhs() const override { return false; } bool sizeMattersRhs() const override { return false; }
int instrCount() const override { return widthInstrs() * 2; } int instrCount() const override { return widthInstrs() * 2; }
}; };

View File

@ -2171,26 +2171,17 @@ class ConstVisitor final : public VNVisitor {
AstNodeExpr* srcp = streamp->lhsp()->unlinkFrBack(); AstNodeExpr* srcp = streamp->lhsp()->unlinkFrBack();
AstNodeDType* const srcDTypep = srcp->dtypep(); AstNodeDType* const srcDTypep = srcp->dtypep();
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) { if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) {
if (nodep->lhsp()->widthMin() > 64) { srcp = new AstCvtArrayToPacked{srcp->fileline(), srcp, nodep->dtypep()};
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic "
"array to a variable of size greater than 64");
}
srcp = new AstCvtDynArrayToPacked{srcp->fileline(), srcp, srcDTypep};
} else if (VN_IS(srcDTypep, UnpackArrayDType)) { } else if (VN_IS(srcDTypep, UnpackArrayDType)) {
if (nodep->lhsp()->widthMin() > 64) { srcp = new AstCvtArrayToPacked{srcp->fileline(), srcp, srcDTypep};
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic "
"array to a variable of size greater than 64");
}
srcp = new AstCvtUnpackArrayToPacked{srcp->fileline(), srcp,
nodep->lhsp()->dtypep()};
// Handling the case where lhs is wider than rhs by inserting zeros. StreamL does // Handling the case where lhs is wider than rhs by inserting zeros. StreamL does
// not require this, since the left streaming operator implicitly handles this. // not require this, since the left streaming operator implicitly handles this.
const uint32_t packedBits = nodep->lhsp()->widthMin(); const int packedBits = nodep->lhsp()->widthMin();
const uint32_t unpackBits const int unpackBits
= srcDTypep->arrayUnpackedElements() * srcDTypep->subDTypep()->widthMin(); = srcDTypep->arrayUnpackedElements() * srcDTypep->subDTypep()->widthMin();
const uint32_t offset = packedBits > unpackBits ? packedBits - unpackBits : 0; const uint32_t offset = packedBits > unpackBits ? packedBits - unpackBits : 0;
srcp = new AstShiftL{srcp->fileline(), srcp, srcp = new AstShiftL{srcp->fileline(), srcp,
new AstConst{srcp->fileline(), offset}, 64}; new AstConst{srcp->fileline(), offset}, packedBits};
} }
nodep->rhsp(srcp); nodep->rhsp(srcp);
VL_DO_DANGLING(pushDeletep(streamp), streamp); VL_DO_DANGLING(pushDeletep(streamp), streamp);
@ -2212,19 +2203,18 @@ class ConstVisitor final : public VNVisitor {
streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED); streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED);
} }
if (VN_IS(dstp->dtypep(), UnpackArrayDType)) { if (VN_IS(dstp->dtypep(), UnpackArrayDType)) {
streamp streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstp->dtypep()};
= new AstCvtPackedToUnpackArray{nodep->fileline(), streamp, dstp->dtypep()};
} else { } else {
UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier"); UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier");
if (dWidth == 0) { if (dWidth == 0) {
streamp streamp = new AstCvtPackedToArray{nodep->fileline(), streamp, dstp->dtypep()};
= new AstCvtPackedToDynArray{nodep->fileline(), streamp, dstp->dtypep()};
} else if (sWidth >= dWidth) { } else if (sWidth >= dWidth) {
streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth}; streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth};
} }
} }
nodep->lhsp(dstp); nodep->lhsp(dstp);
nodep->rhsp(streamp); nodep->rhsp(streamp);
nodep->dtypep(dstp->dtypep());
return true; return true;
} else if (m_doV && VN_IS(nodep->lhsp(), StreamR)) { } else if (m_doV && VN_IS(nodep->lhsp(), StreamR)) {
// The right stream operator on lhs of assignment statement does // The right stream operator on lhs of assignment statement does
@ -2245,17 +2235,18 @@ class ConstVisitor final : public VNVisitor {
srcp srcp
= new AstSel{streamp->fileline(), srcp, sWidth - dstBitWidth, dstBitWidth}; = new AstSel{streamp->fileline(), srcp, sWidth - dstBitWidth, dstBitWidth};
} }
srcp = new AstCvtPackedToUnpackArray{nodep->fileline(), srcp, dstp->dtypep()}; srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstp->dtypep()};
} else { } else {
UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier"); UASSERT(sWidth >= dWidth, "sWidth >= dWidth should have caused an error earlier");
if (dWidth == 0) { if (dWidth == 0) {
srcp = new AstCvtPackedToDynArray{nodep->fileline(), srcp, dstp->dtypep()}; srcp = new AstCvtPackedToArray{nodep->fileline(), srcp, dstp->dtypep()};
} else if (sWidth >= dWidth) { } else if (sWidth >= dWidth) {
srcp = new AstSel{streamp->fileline(), srcp, sWidth - dWidth, dWidth}; srcp = new AstSel{streamp->fileline(), srcp, sWidth - dWidth, dWidth};
} }
} }
nodep->lhsp(dstp); nodep->lhsp(dstp);
nodep->rhsp(srcp); nodep->rhsp(srcp);
nodep->dtypep(dstp->dtypep());
VL_DO_DANGLING(pushDeletep(streamp), streamp); VL_DO_DANGLING(pushDeletep(streamp), streamp);
// Further reduce, any of the nodes may have more reductions. // Further reduce, any of the nodes may have more reductions.
return true; return true;
@ -2264,21 +2255,10 @@ class ConstVisitor final : public VNVisitor {
AstStreamL* streamp = VN_AS(nodep->rhsp(), StreamL); AstStreamL* streamp = VN_AS(nodep->rhsp(), StreamL);
AstNodeExpr* const srcp = streamp->lhsp(); AstNodeExpr* const srcp = streamp->lhsp();
const AstNodeDType* const srcDTypep = srcp->dtypep(); const AstNodeDType* const srcDTypep = srcp->dtypep();
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) { if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)
if (lhsDtypep->widthMin() > 64) { || VN_IS(srcDTypep, UnpackArrayDType)) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic " streamp->lhsp(new AstCvtArrayToPacked{srcp->fileline(), srcp->unlinkFrBack(),
"array to a variable of size greater than 64"); nodep->dtypep()});
}
srcp->unlinkFrBack();
streamp->lhsp(new AstCvtDynArrayToPacked{srcp->fileline(), srcp, lhsDtypep});
streamp->dtypeFrom(lhsDtypep);
} else if (VN_IS(srcDTypep, UnpackArrayDType)) {
if (lhsDtypep->widthMin() > 64) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of unpacked "
"array to a variable of size greater than 64");
}
srcp->unlinkFrBack();
streamp->lhsp(new AstCvtUnpackArrayToPacked{srcp->fileline(), srcp, lhsDtypep});
streamp->dtypeFrom(lhsDtypep); streamp->dtypeFrom(lhsDtypep);
} }
} else if (m_doV && replaceAssignMultiSel(nodep)) { } else if (m_doV && replaceAssignMultiSel(nodep)) {

View File

@ -385,32 +385,9 @@ public:
emitVarDecl(nodep); emitVarDecl(nodep);
} }
void visit(AstCvtDynArrayToPacked* nodep) override { void visit(AstCvtArrayToPacked* nodep) override {
putns(nodep, "VL_DYN_TO_"); AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep();
emitIQW(nodep); emitOpName(nodep, nodep->emitC(), nodep->fromp(), elemDTypep, nullptr);
const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep();
putns(elemDTypep, "<");
putbs(elemDTypep->cType("", false, false));
puts(">(");
iterateAndNextConstNull(nodep->fromp());
puts(", ");
putns(elemDTypep, cvtToStr(elemDTypep->widthMin()));
puts(")");
}
void visit(AstCvtUnpackArrayToPacked* nodep) override {
putns(nodep, "VL_UNPACK_TO_");
emitIQW(nodep);
const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep();
putns(elemDTypep, "<");
putbs(elemDTypep->cType("", false, false));
puts(",");
puts(cvtToStr(nodep->fromp()->dtypep()->arrayUnpackedElements()));
puts(">(");
iterateAndNextConstNull(nodep->fromp());
puts(", ");
putns(elemDTypep, cvtToStr(elemDTypep->widthMin()));
puts(")");
} }
void visit(AstNodeAssign* nodep) override { void visit(AstNodeAssign* nodep) override {
@ -467,30 +444,24 @@ public:
puts(cvtToStr(nodep->widthMin()) + ","); puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
puts(", "); puts(", ");
} else if (const AstCvtPackedToDynArray* const castp } else if (const AstCvtPackedToArray* const castp
= VN_CAST(nodep->rhsp(), CvtPackedToDynArray)) { = VN_CAST(nodep->rhsp(), CvtPackedToArray)) {
putns(castp, "VL_ASSIGN_DYN_Q<"); putns(castp, "VL_UNPACK_");
emitIQW(nodep->dtypep()->subDTypep());
emitIQW(castp->fromp());
puts("<");
putbs(castp->dtypep()->subDTypep()->cType("", false, false)); putbs(castp->dtypep()->subDTypep()->cType("", false, false));
if (VN_IS(castp->dtypep(), UnpackArrayDType)) {
puts(", ");
puts(cvtToStr(castp->dtypep()->arrayUnpackedElements()));
}
puts(">("); puts(">(");
iterateAndNextConstNull(nodep->lhsp());
puts(", ");
putns(castp->dtypep(), cvtToStr(castp->dtypep()->subDTypep()->widthMin())); putns(castp->dtypep(), cvtToStr(castp->dtypep()->subDTypep()->widthMin()));
puts(", "); puts(", ");
puts(cvtToStr(castp->fromp()->widthMin())); puts(cvtToStr(castp->fromp()->widthMin()));
puts(", "); puts(", ");
rhs = false;
iterateAndNextConstNull(castp->fromp());
} else if (const AstCvtPackedToUnpackArray* const castp
= VN_CAST(nodep->rhsp(), CvtPackedToUnpackArray)) {
putns(castp, "VL_ASSIGN_UNPACK_Q<");
putbs(castp->dtypep()->subDTypep()->cType("", false, false));
puts(", ");
puts(cvtToStr(castp->dtypep()->arrayUnpackedElements()));
puts(">(");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
puts(", "); puts(", ");
putns(castp->dtypep(), cvtToStr(castp->dtypep()->subDTypep()->widthMin()));
puts(", ");
rhs = false; rhs = false;
iterateAndNextConstNull(castp->fromp()); iterateAndNextConstNull(castp->fromp());
} else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // } else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) //
@ -1298,8 +1269,7 @@ public:
return; return;
} }
} }
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(), emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr);
nullptr);
} }
void visit(AstCastDynamic* nodep) override { void visit(AstCastDynamic* nodep) override {
putnbs(nodep, "VL_CAST_DYNAMIC("); putnbs(nodep, "VL_CAST_DYNAMIC(");

View File

@ -274,6 +274,10 @@ class PremitVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
checkNode(nodep); checkNode(nodep);
} }
void visit(AstCvtArrayToPacked* nodep) override {
iterateChildren(nodep);
checkNode(nodep);
}
void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
iterateAndNextNull(nodep->fromp()); iterateAndNextNull(nodep->fromp());
{ // Only the 'from' is part of the assignment LHS { // Only the 'from' is part of the assignment LHS

View File

@ -228,7 +228,7 @@ class SliceVisitor final : public VNVisitor {
AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp(); AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp();
AstNode* stp = nodep->rhsp(); AstNode* stp = nodep->rhsp();
if (const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType)) { if (const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType)) {
if (!VN_IS(stp, CvtPackedToUnpackArray)) { if (!VN_IS(stp, CvtPackedToArray)) {
// Left and right could have different ascending/descending range, // Left and right could have different ascending/descending range,
// but #elements is common and all variables are realigned to start at zero // but #elements is common and all variables are realigned to start at zero
// Assign of an ascending range slice to a descending range one must reverse // Assign of an ascending range slice to a descending range one must reverse

View File

@ -20,6 +20,12 @@ module t (/*AUTOARG*/);
bit [5:0] arr6[$]; bit [5:0] arr6[$];
bit [5:0] bit6 = 6'b111000; bit [5:0] bit6 = 6'b111000;
bit [5:0] ans; bit [5:0] ans;
bit [3:0] arr4[] = '{25{4'b1000}};
bit [7:0] arr8[] = '{8{8'b00110011}};
bit [63:0] arr64[] = '{5{64'h0123456789abcdef}};
bit [63:0] bit64;
bit [99:0] bit100;
bit [319:0] bit320;
enum_t ans_enum; enum_t ans_enum;
{ >> bit {arr}} = bit6; { >> bit {arr}} = bit6;
@ -76,6 +82,35 @@ module t (/*AUTOARG*/);
ans_enum = enum_t'({ << bit[5:0] {arr6} }); ans_enum = enum_t'({ << bit[5:0] {arr6} });
`checkh(ans_enum, bit6); `checkh(ans_enum, bit6);
bit64 = { >> bit {arr8} };
`checkh(bit64[7:0], 8'b00110011);
bit64 = { << bit {arr8} };
`checkh(bit64[7:0], 8'b11001100);
{ >> bit {arr8} } = bit64;
`checkh(arr8[0], 8'b11001100);
{ << bit {arr8} } = bit64;
`checkh(arr8[0], 8'b00110011);
bit100 = { >> bit {arr4} };
`checkh(bit100[3:0], 4'b1000);
bit100 = { << bit {arr4} };
`checkh(bit100[3:0], 4'b0001);
bit320 = { >> byte {arr64} };
`checkh(bit320[63:0], 64'h0123456789abcdef);
bit320 = { << byte {arr64} };
`checkh(bit320[63:0], 64'hefcdab8967452301);
{ >> bit {arr4} } = bit100;
`checkh(arr4[0], 4'b0001);
{ << bit {arr4} } = bit100;
`checkh(arr4[0], 4'b1000);
{ >> byte {arr64} } = bit320;
`checkh(arr64[0], 64'hefcdab8967452301);
{ << byte {arr64} } = bit320;
`checkh(arr64[0], 64'h0123456789abcdef);
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end

View File

@ -1,10 +0,0 @@
%Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:15:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64
: ... note: In instance 't'
15 | bit100 = { >> bit {arr} };
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:17:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64
: ... note: In instance 't'
17 | bit100 = { << bit {arr} };
| ^
%Error: Exiting due to

View File

@ -1,19 +0,0 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2020 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(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -1,23 +0,0 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Antmicro Ltd.
// 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);
module t (/*AUTOARG*/);
initial begin
bit[3:0] arr[] = '{25{4'b1000}};
bit [99:0] bit100;
bit100 = { >> bit {arr} };
`checkh(bit100[3:0], 4'b1000);
bit100 = { << bit {arr} };
`checkh(bit100[3:0], 4'b0001);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
compile( compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
); );
execute( execute(
check_finished => 1, check_finished => 1,
) if !$Self->{vlt_all}; );
ok(1); ok(1);
1; 1;

View File

@ -1,42 +0,0 @@
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:120:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
120 | packed_data_128 = {<<32{int_in}};
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:121:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
121 | packed_data_128_i = {<<32{integer_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:122:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
122 | packed_data_256 = {<<64{longint_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:123:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
123 | packed_time_256 = {<<64{time_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:126:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
126 | v_packed_data_128 = {<<32{reg_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:152:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
152 | packed_data_128 = {<<int{int_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:153:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
153 | packed_data_128_i = {<<integer{integer_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:154:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
154 | packed_data_256 = {<<longint{longint_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:155:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
155 | packed_time_256 = {<<time{time_in}};
| ^
%Error-UNSUPPORTED: t/t_stream_integer_type_unsup.v:158:28: Unsupported: Assignment of stream of unpacked array to a variable of size greater than 64
: ... note: In instance 't'
158 | v_packed_data_128 = {<<test_word{reg_in}};
| ^
%Error: Exiting due to