split_var supports assignment of unpacked arrays.

This commit is contained in:
Yutetsu TAKATSUKASA 2020-01-15 23:01:13 +09:00
parent a1b3d57fe2
commit e9fcd6eb25
5 changed files with 95 additions and 78 deletions

View File

@ -4411,8 +4411,6 @@ Possible reasons are
The datatype is not supported for splitting. (e.g. real)
The access pattern of the variable can not be determined statically. (e.g. memory)
The unpacked array is accessed other than subscript.
slicing (unpacked_array[lsb:msb]) and accessing without subscript are not supported yet.
=item STMTDLY

View File

@ -73,13 +73,6 @@
// </pre>
//
//
// Limitations: (planned to be resolved)
// - Unpacked array must be accessed via AstArraySel.
// e.g. unpacked_array[3] : supported
// unpacked_array[0:1] : not supported because AstSliceSel is used
// unpacked_array : not supported
// to allow such access, concatenate op node to build unpacked array is necessary on AST.
//
//*************************************************************************
#include "config_build.h"
@ -107,6 +100,18 @@ static AstConst* constifyIfNot(AstNode* nodep) {
return constp;
}
// returns <msb,lsb> of outer most dimension of an unpacked array
static std::pair<int, int> outerMostSizeOfUnpackedArray(AstVar* nodep) {
AstUnpackArrayDType* const dtypep = VN_CAST(nodep->dtypep(), UnpackArrayDType);
AstConst* const lsbp = constifyIfNot(dtypep->rangep()->lsbp());
AstConst* const msbp = constifyIfNot(dtypep->rangep()->msbp());
UASSERT_OBJ(lsbp, dtypep->rangep()->lsbp(), "must be constant");
UASSERT_OBJ(msbp, dtypep->rangep()->msbp(), "must be constant");
const vlsint32_t lsb = lsbp->toSInt(), msb = msbp->toSInt();
UASSERT_OBJ(lsb <= msb, dtypep->rangep(), "lsb must not greater than msb");
return std::make_pair(msb, lsb);
}
//######################################################################
// Find a variable with pragma
@ -200,6 +205,57 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
" Such access is not supported yet.\n");
m_refs.erase(varp);
}
static void splitSimpleAssign(AstNodeAssign* asnp, AstVarRef* lhsp, AstVarRef *rhsp, int lstart, int rstart, int num) {
for (int i = 0; i < num; ++i) {
AstVarRef* const lrefp = new AstVarRef(lhsp->fileline(), lhsp->varp(), true);
AstVarRef* const rrefp = new AstVarRef(rhsp->fileline(), rhsp->varp(), false);
AstArraySel* const lselp = new AstArraySel(lhsp->fileline(), lrefp, lstart + i);
AstArraySel* const rselp = new AstArraySel(rhsp->fileline(), rrefp, rstart + i);
// the added new assignment statement will be visited later.
asnp->addNext(asnp->cloneType(lselp, rselp));
}
}
// Unroll assignments of SliceSel or entire unpacked array to multiple assignment
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
AstSliceSel* lsel = VN_CAST(nodep->lhsp(), SliceSel);
AstSliceSel* rsel = VN_CAST(nodep->rhsp(), SliceSel);
AstVarRef* const lhsp = VN_CAST(lsel ? lsel->fromp() : nodep->lhsp(), VarRef);
AstVarRef* const rhsp = VN_CAST(rsel ? rsel->fromp() : nodep->rhsp(), VarRef);
// unless simple assignment, nothing to do in this function
if (!lhsp || !rhsp) {
iterateChildren(nodep);
return;
}
// if nodep is a simple assignment of variables without split_var pragma, quick exit
if (m_refs.find(lhsp->varp()) == m_refs.end() &&
m_refs.find(rhsp->varp()) == m_refs.end()) return;
int lstart, lnum, rstart, rnum;
if (lsel) {
lstart = lsel->declRange().lo();
lnum = lsel->declRange().elements();
} else { // LHS is entire array
const std::pair<int, int> lrange = outerMostSizeOfUnpackedArray(lhsp->varp());
lstart = 0;
lnum = lrange.first - lrange.second + 1;
}
if (rsel) {
rstart = rsel->declRange().lo();
rnum = rsel->declRange().elements();
} else { // RHS is entire array
const std::pair<int, int> rrange = outerMostSizeOfUnpackedArray(rhsp->varp());
rstart = 0;
rnum = rrange.first - rrange.second + 1;
}
if (lnum != rnum) return; // strange. V3Slice will show proper diagnosis
splitSimpleAssign(nodep, lhsp, rhsp, lstart, rstart, lnum);
nodep->unlinkFrBack()->deleteTree();
VL_DANGLING(nodep);
}
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
AstVarRef* const vrefp = VN_CAST(nodep->fromp(), VarRef);
if (!vrefp) {
@ -224,18 +280,6 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
m_refs.erase(varp);
}
}
virtual void visit(AstSliceSel* nodep) VL_OVERRIDE {
AstVarRef* const vrefp = VN_CAST(nodep->fromp(), VarRef);
if (!vrefp) return;
AstVar* const varp = vrefp->varp();
if (m_refs.find(varp) == m_refs.end()) return; // variable without split_var pragma
if (m_firstRun)
nodep->v3warn(SPLITVAR, "Variable " << vrefp->prettyNameQ()
<< " will not be split because slicing an "
"unpacked array is not supported yet.");
m_refs.erase(varp);
}
// The actual splitting operation is done in this function.
void split() {
for (vl_unordered_map<AstVar*, std::vector<AstArraySel*> >::iterator it = m_refs.begin(),
@ -249,12 +293,8 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
AstUnpackArrayDType* const dtypep = VN_CAST(varp->dtypep(), UnpackArrayDType);
std::vector<AstVar*> vars;
// Add the split variables
AstConst* const lsbp = constifyIfNot(dtypep->rangep()->lsbp());
AstConst* const msbp = constifyIfNot(dtypep->rangep()->msbp());
UASSERT_OBJ(lsbp, dtypep->rangep()->lsbp(), "must be constant");
UASSERT_OBJ(msbp, dtypep->rangep()->msbp(), "must be constant");
const vlsint32_t lsb = lsbp->toSInt(), msb = msbp->toSInt();
UASSERT_OBJ(lsb <= msb, dtypep->rangep(), "lsb must not greater than msb");
const std::pair<int, int> arraySize = outerMostSizeOfUnpackedArray(varp);
const int msb = arraySize.first, lsb = arraySize.second;
for (vlsint32_t i = 0; i <= msb - lsb; ++i) {
// const std::string name = varp->name() + "__BRA__" + AstNode::encodeNumber(i + lsb) + "__KET__";
// unpacked array is traced as var(idx).

View File

@ -47,23 +47,46 @@ module barshift_2d_unpacked #(parameter depth = 2, localparam width = 2**depth)
localparam offset = 1;
localparam n = 3;
reg [width-1:0]tmp[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp0[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp1[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp2[depth+offset:offset][offset:offset+n-1];
reg [width-1:0]tmp3[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp4[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp5[depth+offset:offset][offset:offset+n-1];
reg [width-1:0]tmp6[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp7[depth+offset+1:offset+1][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp8[depth+offset+3:offset-1][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp9[depth+offset+3:offset+3][offset:offset+n-1]; /*verilator split_var*/
reg [width-1:0]tmp10[depth+offset:offset][offset:offset+n-1]; /*verilator split_var*/
generate
for(genvar i = 0; i < depth; ++i) begin
for(genvar j = offset; j < n + offset; ++j) begin
always_comb
if (shift[i]) begin
tmp[i+1+offset][j] = {tmp[i+offset][j][(1 << i)-1:0], tmp[i+offset][j][width-1:(2**i)]};
tmp0[i+1+offset][j] = {tmp0[i+offset][j][(1 << i)-1:0], tmp0[i+offset][j][width-1:(2**i)]};
end else begin
tmp[i+1+offset][j] = tmp[i+offset][j];
tmp0[i+1+offset][j] = tmp0[i+offset][j];
end
end
end
for(genvar j = offset; j < n + offset; ++j) begin
assign tmp[0 + offset][j] = in;
assign tmp0[0 + offset][j] = in;
end
endgenerate
assign out = tmp[depth+offset][offset];
assign tmp1 = tmp0; // split both side
assign tmp2 = tmp1; // split only rhs
assign tmp3 = tmp2; // split only lhs
always_comb tmp4 = tmp3; // split both side
always_comb tmp5 = tmp4; // split only rhs
always_comb tmp6 = tmp5; // split only lhs
assign tmp7 = tmp6;
assign tmp8[depth+offset+1:offset+1] = tmp7;
assign tmp9 = tmp8[depth+offset+1:offset+1];
assign tmp10[depth+offset:offset] = tmp9[depth+offset+3:offset+3];
assign out = tmp10[depth+offset][offset];
endmodule

View File

@ -3,26 +3,10 @@
/*verilator split_var*/
^~~~~~~~~~~~~~~~~~~~~~~
... Use "/* verilator lint_off SPLITVAR */" and lint_on around source to disable this message.
%Warning-SPLITVAR: t/t_split_var_1_bad.v:31: Variable 'cannot_split' will not be split because index cannot be determined statically.
%Warning-SPLITVAR: t/t_split_var_1_bad.v:28: Variable 'cannot_split' will not be split because index cannot be determined statically.
: ... In instance t.i_sub0
rd_data = cannot_split[addr];
^~~~
%Warning-SPLITVAR: t/t_split_var_1_bad.v:41: Variable 'cannot_split0' will not be split because the entire unpacked array is referred. Such access is not supported yet.
: ... In instance t.i_sub1
cannot_split1 = cannot_split0;
^~~~~~~~~~~~~
%Warning-SPLITVAR: t/t_split_var_1_bad.v:41: Variable 'cannot_split1' will not be split because the entire unpacked array is referred. Such access is not supported yet.
: ... In instance t.i_sub1
cannot_split1 = cannot_split0;
^~~~~~~~~~~~~
%Warning-SPLITVAR: t/t_split_var_1_bad.v:63: Variable 'cannot_split1' will not be split because slicing an unpacked array is not supported yet.
: ... In instance t.i_sub3
cannot_split1[0:1] = cannot_split1[2:3];
^
%Warning-SPLITVAR: t/t_split_var_1_bad.v:64: Variable 'cannot_split0' will not be split because the entire unpacked array is referred. Such access is not supported yet.
: ... In instance t.i_sub3
cannot_split1 = cannot_split0;
^~~~~~~~~~~~~
%Warning-SPLITVAR: t/t_split_var_1_bad.v:5: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic.
: ... In instance t
real should_show_warning0; /*verilator split_var*/
@ -35,7 +19,7 @@
: ... In instance t
wire should_show_warning2; /*verilator split_var*/
^~~~~~~~~~~~~~~~~~~~~~~
%Warning-SPLITVAR: t/t_split_var_1_bad.v:52: Variable 'cannot_split' will not be split because bit range cannot be determined statically.
%Warning-SPLITVAR: t/t_split_var_1_bad.v:37: Variable 'cannot_split' will not be split because bit range cannot be determined statically.
: ... In instance t.i_sub2
rd_data = cannot_split[addr];
^

View File

@ -10,10 +10,7 @@ module t();
logic [7:0] rd_data0, rd_data1, rd_data2;
sub0 i_sub0(.addr(addr), .rd_data(rd_data0));
sub1 i_sub1( .rd_data(rd_data1));
sub2 i_sub2(.addr(addr), .rd_data(rd_data2));
sub3 i_sub3();
initial begin
addr = 0;
@ -33,18 +30,6 @@ module sub0(input [3:0]addr, output logic [7:0] rd_data);
endmodule
module sub1(output logic [7:0] rd_data);
logic [7:0] cannot_split0[0:15]; /*verilator split_var*/
logic [7:0] cannot_split1[0:15]; /*verilator split_var*/
always_comb begin
cannot_split1 = cannot_split0;
rd_data = cannot_split1[0];
end
endmodule
module sub2(input [3:0]addr, output logic [7:0] rd_data);
logic [15:0] [7:0] cannot_split; /*verilator split_var*/
@ -53,16 +38,3 @@ module sub2(input [3:0]addr, output logic [7:0] rd_data);
endmodule
module sub3();
logic cannot_split0 [15:0] [7:0] ; /*verilator split_var*/
logic cannot_split1 [0:15] [7:0] ; /*verilator split_var*/
/* verilator lint_off ALWCOMBORDER */
always_comb begin
cannot_split1[0:1] = cannot_split1[2:3];
cannot_split1 = cannot_split0;
end
/* verilator lint_on ALWCOMBORDER */
endmodule