Fix +: and -: on unpacked arrays. (#2304)

This commit is contained in:
Wilson Snyder 2020-05-04 19:40:50 -04:00
parent 98889b3f4e
commit a41ea180fa
9 changed files with 243 additions and 16 deletions

View File

@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix FST tracing of little bit endian signals. [Geza Lore]
**** Fix +: and -: on unpacked arrays. (#2304) [engr248]
* Verilator 4.034 2020-05-03

View File

@ -191,6 +191,13 @@ private:
}
}
void warnTri(AstNode* nodep) {
if (VN_IS(nodep, Const) && VN_CAST(nodep, Const)->num().isFourState()) {
nodep->v3error(
"Selection index is constantly unknown or tristated: " << nodep->name());
}
}
// VISITORS
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
@ -451,6 +458,7 @@ private:
UINFO(6, "SELPLUS/MINUS " << nodep << endl);
// Below 2 lines may change nodep->widthp()
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM0: ");
V3Const::constifyEdit(nodep->rhsp()); // May relink pointed to node, ok if not const
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM3: ");
@ -458,6 +466,7 @@ private:
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
warnTri(rhsp);
int width = VN_CAST(widthp, Const)->toSInt();
if (width > (1 << 28)) {
nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "
@ -467,9 +476,35 @@ private:
FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|| (VN_IS(ddtypep, NodeUOrStructDType)
&& VN_CAST(ddtypep, NodeUOrStructDType)->packedUnsup())) {
if (VN_IS(ddtypep, UnpackArrayDType)) {
// Slice +: and -: extraction
if (fromRange.elements() == width && VN_IS(rhsp, Const)
&& VN_CAST(rhsp, Const)->toSInt()
== fromRange.lo()) { // Extracting whole of original array
nodep->replaceWith(fromp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (fromRange.elements() == 1) { // Extracting single element
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, rhsp);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(rhsp, Const)) { // Slice
vlsint32_t rhs = VN_CAST(rhsp, Const)->toSInt();
// down array: lsb/lo +: width
// down array: msb/hi -: width
// up array: msb/lo +: width
// up array: lsb/hi -: width
vlsint32_t msb = VN_IS(nodep, SelPlus) ? rhs + width - 1 : rhs;
vlsint32_t lsb = VN_IS(nodep, SelPlus) ? rhs : rhs - width + 1;
AstSliceSel* newp = new AstSliceSel(nodep->fileline(), fromp,
VNumRange(msb, lsb, fromRange.littleEndian()));
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else {
nodep->v3error("Unsupported: Slice of non-constant bounds");
}
} else if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|| (VN_IS(ddtypep, NodeUOrStructDType)
&& VN_CAST(ddtypep, NodeUOrStructDType)->packedUnsup())) {
int elwidth = 1;
AstNode* newwidthp = widthp;
if (const AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {

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,93 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by engr248.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
wire [31:0] in = 0;
wire [31:0] out;
Test test(
.out(out[31:0]),
.clk(clk),
.in (in[31:0])
);
always @ (posedge clk) begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
interface Intf ();
endinterface
module Select
#(
parameter int NUM_MASTER = 1
)
(
Intf Upstream,
Intf Downstream[NUM_MASTER]
);
endmodule
module Crossbar
#(
parameter int NUM_MASTER = 1,
parameter int NUM_SLAVE = 1
)
(
Intf Masters[NUM_MASTER]
);
Intf selectOut[(NUM_MASTER * (NUM_SLAVE))-1 : 0]();
genvar i;
for (i = 0; i < NUM_MASTER; i = i + 1) begin
Select #(
.NUM_MASTER(NUM_SLAVE)
)
select_inst (
.Upstream(Masters[i]),
// Following line seems to trigger a bad calculation for dimension where port
// is calculated as width 1 (correctly) and expression is calculated as NUM_MASTER*NUM_SLAVE rather than NUM_SLAVE
.Downstream(selectOut[(i)*(NUM_SLAVE) +: (NUM_SLAVE)])
// The following line works as intended and should be functionally identical to the above line
// .Downstream(selectOut[(i+1)*(NUM_SLAVE)-1 : i*(NUM_SLAVE)])
);
end
endmodule
module Test
(
input clk,
input [31:0] in,
output reg [31:0] out
);
always @(posedge clk) begin
out <= in;
end
Intf MST[10]();
Crossbar #(
.NUM_MASTER(10),
.NUM_SLAVE(1)
)
xbar_inst (
.Masters(MST)
);
endmodule

View File

@ -23,10 +23,10 @@
: ... In instance t
17 | dim1[1][1][1] = 0;
| ^
%Error: t/t_mem_multi_ref_bad.v:19:11: Illegal +: or -: select; type already selected, or bad dimension: data type is 'logic[1:0]$[1:0][1:0]'
: ... In instance t
%Warning-SELRANGE: t/t_mem_multi_ref_bad.v:19:19: Selection index out of range: 1 outside 0:0
: ... In instance t
19 | dim2[0 +: 1][1] = 0;
| ^
| ^
%Error: t/t_mem_multi_ref_bad.v:23:16: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic'
: ... In instance t
23 | dim0nv[1][1] = 0;

View File

@ -1,5 +1,4 @@
%Error: t/t_select_bad_tri.v:11:13: Selection index is constantly unknown or tristated: lsb=7'bxxxxxxx width=32'sh47
: ... In instance t
%Error: t/t_select_bad_tri.v:11:24: Selection index is constantly unknown or tristated: 1'bx
11 | if (in[( (1'h0 / 1'b0) )+:71] != 71'h0) $stop;
| ^
%Error: Exiting due to
| ^
%Error: Internal Error: ../V3Number.cpp:#: toUInt with 4-state 1'bx

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 2003 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,57 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`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*/);
parameter int sliceddn[7:0] = '{'h100, 'h101, 'h102, 'h103, 'h104, 'h105, 'h106, 'h107};
parameter int slicedup[0:7] = '{'h100, 'h101, 'h102, 'h103, 'h104, 'h105, 'h106, 'h107};
int alldn[7:0];
int allup[0:7];
int twodn[1:0];
int twoup[0:1];
initial begin
`checkh(sliceddn[7], 'h100);
alldn[7:0] = sliceddn[7:0];
`checkh(alldn[7], 'h100);
alldn[7:0] = sliceddn[0 +: 8]; // down: lsb/lo +: width
`checkh(alldn[7], 'h100);
alldn[7:0] = sliceddn[7 -: 8]; // down: msb/hi -: width
`checkh(alldn[7], 'h100);
twodn[1:0] = sliceddn[6:5];
`checkh(twodn[1], 'h101);
`checkh(twodn[0], 'h102);
twodn[1:0] = sliceddn[4 +: 2];
`checkh(twodn[1], 'h102);
`checkh(twodn[0], 'h103);
twodn[1:0] = sliceddn[4 -: 2];
`checkh(twodn[1], 'h103);
`checkh(twodn[0], 'h104);
`checkh(slicedup[7], 'h107);
allup[0:7] = slicedup[0:7];
`checkh(alldn[7], 'h100);
allup[0:7] = slicedup[0 +: 8]; // up: msb/lo +: width
`checkh(alldn[7], 'h100);
allup[0:7] = slicedup[7 -: 8]; // up: lsb/hi -: width
`checkh(alldn[7], 'h100);
twoup[0:1] = slicedup[5:6];
`checkh(twoup[1], 'h106);
`checkh(twoup[0], 'h105);
twoup[0:1] = slicedup[4 +: 2];
`checkh(twoup[1], 'h105);
`checkh(twoup[0], 'h104);
twoup[0:1] = slicedup[4 -: 2];
`checkh(twoup[1], 'h104);
`checkh(twoup[0], 'h103);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -24,12 +24,11 @@ module t (/*AUTOARG*/
byte i, j;
// bug1044
for ( i = 0; i < 9; i = i + 1 )
for ( j=0; j<(TEST_PARAM[i*8+:8]); j=j+1 )
begin
// verilator lint_off WIDTH
in_tmp[TEST_PARAM[i*8+:8]+j] = in[TEST_PARAM[i*8+:8]+j];
// verilator lint_on WIDTH
end
// verilator lint_off WIDTH
for ( j=0; j<(TEST_PARAM[i*8+:8]); j=j+1) begin
in_tmp[TEST_PARAM[i*8+:8]+j] = in[TEST_PARAM[i*8+:8]+j];
end
// verilator lint_on WIDTH
$write("*-* All Finished *-*\n");
$finish;
end