Support assignments of stream expressions on queues to packed values (#4458)
This commit is contained in:
parent
6cdf8da3f7
commit
c40e34b134
|
|
@ -1534,6 +1534,20 @@ static inline void VL_ASSIGN_DYN_Q(VlQueue<T>& q, int elem_size, int lbits, QDat
|
||||||
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
|
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline QData VL_DYN_TO_Q(const VlQueue<T>& q, int elem_size) {
|
||||||
|
QData ret = 0;
|
||||||
|
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
// Thus we specify inputs must be clean, so we don't need to clean the output.
|
// Thus we specify inputs must be clean, so we don't need to clean the output.
|
||||||
// Note the bit shifts are always constants, so the adds in these constify out.
|
// Note the bit shifts are always constants, so the adds in these constify out.
|
||||||
|
|
|
||||||
|
|
@ -1013,6 +1013,20 @@ public:
|
||||||
// May return nullptr on parse failure.
|
// May return nullptr on parse failure.
|
||||||
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
|
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
|
||||||
};
|
};
|
||||||
|
class AstCvtDynArrayToPacked final : public AstNodeExpr {
|
||||||
|
// Cast from dynamic queue data type to packed array
|
||||||
|
// @astgen op1 := fromp : AstNodeExpr
|
||||||
|
public:
|
||||||
|
AstCvtDynArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp)
|
||||||
|
: ASTGEN_SUPER_CvtDynArrayToPacked(fl) {
|
||||||
|
this->fromp(fromp);
|
||||||
|
dtypeFrom(dtp);
|
||||||
|
}
|
||||||
|
ASTGEN_MEMBERS_AstCvtDynArrayToPacked;
|
||||||
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
|
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||||
|
bool cleanOut() const override { return true; }
|
||||||
|
};
|
||||||
class AstCvtPackedToDynArray final : public AstNodeExpr {
|
class AstCvtPackedToDynArray final : public AstNodeExpr {
|
||||||
// Cast from packed array to dynamic queue data type
|
// Cast from packed array to dynamic queue data type
|
||||||
// @astgen op1 := fromp : AstNodeExpr
|
// @astgen op1 := fromp : AstNodeExpr
|
||||||
|
|
|
||||||
|
|
@ -2146,14 +2146,19 @@ private:
|
||||||
return true;
|
return true;
|
||||||
} else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) {
|
} else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) {
|
||||||
// The right-streaming operator on rhs of assignment does not
|
// The right-streaming operator on rhs of assignment does not
|
||||||
// change the order of bits. Eliminate stream but keep its lhsp
|
// change the order of bits. Eliminate stream but keep its lhsp.
|
||||||
// Unlink the stuff
|
// Add a cast if needed.
|
||||||
AstNodeExpr* const srcp = VN_AS(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack();
|
AstStreamR* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack();
|
||||||
AstNode* const sizep = VN_AS(nodep->rhsp(), StreamR)->rhsp()->unlinkFrBack();
|
AstNodeExpr* srcp = streamp->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack();
|
AstNodeDType* const srcDTypep = srcp->dtypep();
|
||||||
|
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) {
|
||||||
|
if (nodep->lhsp()->widthMin() > 64) {
|
||||||
|
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};
|
||||||
|
}
|
||||||
nodep->rhsp(srcp);
|
nodep->rhsp(srcp);
|
||||||
// Cleanup
|
|
||||||
VL_DO_DANGLING(sizep->deleteTree(), sizep);
|
|
||||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
VL_DO_DANGLING(streamp->deleteTree(), 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;
|
||||||
|
|
@ -2186,7 +2191,6 @@ private:
|
||||||
// then we select bits from the left-most, not the right-most.
|
// then we select bits from the left-most, not the right-most.
|
||||||
AstNodeExpr* const streamp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* const streamp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack();
|
AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack();
|
||||||
AstNode* const sizep = VN_AS(streamp, StreamR)->rhsp()->unlinkFrBack();
|
|
||||||
AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack();
|
AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack();
|
||||||
const int sWidth = srcp->width();
|
const int sWidth = srcp->width();
|
||||||
const int dWidth = dstp->width();
|
const int dWidth = dstp->width();
|
||||||
|
|
@ -2197,11 +2201,23 @@ private:
|
||||||
}
|
}
|
||||||
nodep->lhsp(dstp);
|
nodep->lhsp(dstp);
|
||||||
nodep->rhsp(srcp);
|
nodep->rhsp(srcp);
|
||||||
// Cleanup
|
|
||||||
VL_DO_DANGLING(sizep->deleteTree(), sizep);
|
|
||||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
VL_DO_DANGLING(streamp->deleteTree(), 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;
|
||||||
|
} else if (m_doV && VN_IS(nodep->rhsp(), StreamL)) {
|
||||||
|
AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep();
|
||||||
|
AstStreamL* streamp = VN_AS(nodep->rhsp(), StreamL);
|
||||||
|
AstNodeExpr* const srcp = streamp->lhsp();
|
||||||
|
const AstNodeDType* const srcDTypep = srcp->dtypep();
|
||||||
|
if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) {
|
||||||
|
if (lhsDtypep->widthMin() > 64) {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic "
|
||||||
|
"array to a variable of size greater than 64");
|
||||||
|
}
|
||||||
|
srcp->unlinkFrBack();
|
||||||
|
streamp->lhsp(new AstCvtDynArrayToPacked{srcp->fileline(), srcp, lhsDtypep});
|
||||||
|
streamp->dtypeFrom(lhsDtypep);
|
||||||
|
}
|
||||||
} else if (m_doV && replaceAssignMultiSel(nodep)) {
|
} else if (m_doV && replaceAssignMultiSel(nodep)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,19 @@ public:
|
||||||
emitVarDecl(nodep);
|
emitVarDecl(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(AstCvtDynArrayToPacked* nodep) override {
|
||||||
|
puts("VL_DYN_TO_");
|
||||||
|
emitIQW(nodep);
|
||||||
|
puts("<");
|
||||||
|
const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep();
|
||||||
|
putbs(elemDTypep->cType("", false, false));
|
||||||
|
puts(">(");
|
||||||
|
iterateAndNextConstNull(nodep->fromp());
|
||||||
|
puts(", ");
|
||||||
|
puts(cvtToStr(elemDTypep->widthMin()));
|
||||||
|
puts(")");
|
||||||
|
}
|
||||||
|
|
||||||
void visit(AstNodeAssign* nodep) override {
|
void visit(AstNodeAssign* nodep) override {
|
||||||
bool paren = true;
|
bool paren = true;
|
||||||
bool decind = false;
|
bool decind = false;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
`define stop $stop
|
`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);
|
`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*/);
|
module t (/*AUTOARG*/);
|
||||||
|
|
@ -15,25 +16,44 @@ module t (/*AUTOARG*/);
|
||||||
bit [5:0] arr6[$];
|
bit [5:0] arr6[$];
|
||||||
string v;
|
string v;
|
||||||
bit [5:0] bit6 = 6'b111000;
|
bit [5:0] bit6 = 6'b111000;
|
||||||
|
bit [5:0] ans;
|
||||||
|
|
||||||
{ >> bit {arr}} = bit6;
|
{ >> bit {arr}} = bit6;
|
||||||
v = $sformatf("%p", arr); `checks(v, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} ");
|
v = $sformatf("%p", arr); `checks(v, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} ");
|
||||||
|
|
||||||
|
ans = { >> bit {arr} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
{ << bit {arr}} = bit6;
|
{ << bit {arr}} = bit6;
|
||||||
v = $sformatf("%p", arr); `checks(v, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} ");
|
v = $sformatf("%p", arr); `checks(v, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} ");
|
||||||
|
|
||||||
|
ans = { << bit {arr} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
{ >> bit[1:0] {arr2}} = bit6;
|
{ >> bit[1:0] {arr2}} = bit6;
|
||||||
v = $sformatf("%p", arr2); `checks(v, "'{'h0, 'h2, 'h3} ");
|
v = $sformatf("%p", arr2); `checks(v, "'{'h0, 'h2, 'h3} ");
|
||||||
|
|
||||||
|
ans = { >> bit[1:0] {arr2} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
{ << bit[1:0] {arr2}} = bit6;
|
{ << bit[1:0] {arr2}} = bit6;
|
||||||
v = $sformatf("%p", arr2); `checks(v, "'{'h3, 'h2, 'h0} ");
|
v = $sformatf("%p", arr2); `checks(v, "'{'h3, 'h2, 'h0} ");
|
||||||
|
|
||||||
|
ans = { << bit[1:0] {arr2} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
{ >> bit [5:0] {arr6} } = bit6;
|
{ >> bit [5:0] {arr6} } = bit6;
|
||||||
v = $sformatf("%p", arr6); `checks(v, "'{'h38} ");
|
v = $sformatf("%p", arr6); `checks(v, "'{'h38} ");
|
||||||
|
|
||||||
|
ans = { >> bit[5:0] {arr6} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
{ << bit [5:0] {arr6} } = bit6;
|
{ << bit [5:0] {arr6} } = bit6;
|
||||||
v = $sformatf("%p", arr6); `checks(v, "'{'h38} ");
|
v = $sformatf("%p", arr6); `checks(v, "'{'h38} ");
|
||||||
|
|
||||||
|
ans = { << bit[5:0] {arr6} };
|
||||||
|
`checkh(ans, bit6);
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
%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
|
||||||
|
: ... 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
|
||||||
|
: ... In instance t
|
||||||
|
17 | bit100 = { << bit {arr} };
|
||||||
|
| ^
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/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;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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
|
||||||
Loading…
Reference in New Issue