diff --git a/Changes b/Changes index 9b87414aa..0ce774704 100644 --- a/Changes +++ b/Changes @@ -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 diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 78622792c..c23f0c208 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -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)) { diff --git a/test_regress/t/t_inst_slice_part_select.pl b/test_regress/t/t_inst_slice_part_select.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_inst_slice_part_select.pl @@ -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; diff --git a/test_regress/t/t_inst_slice_part_select.v b/test_regress/t/t_inst_slice_part_select.v new file mode 100644 index 000000000..3c837e0df --- /dev/null +++ b/test_regress/t/t_inst_slice_part_select.v @@ -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 diff --git a/test_regress/t/t_mem_multi_ref_bad.out b/test_regress/t/t_mem_multi_ref_bad.out index d7aad1413..e37aa73f6 100644 --- a/test_regress/t/t_mem_multi_ref_bad.out +++ b/test_regress/t/t_mem_multi_ref_bad.out @@ -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; diff --git a/test_regress/t/t_select_bad_tri.out b/test_regress/t/t_select_bad_tri.out index fd015e9f8..9405b76e2 100644 --- a/test_regress/t/t_select_bad_tri.out +++ b/test_regress/t/t_select_bad_tri.out @@ -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 diff --git a/test_regress/t/t_unpacked_slice.pl b/test_regress/t/t_unpacked_slice.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_unpacked_slice.pl @@ -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; diff --git a/test_regress/t/t_unpacked_slice.v b/test_regress/t/t_unpacked_slice.v new file mode 100644 index 000000000..ea76566d9 --- /dev/null +++ b/test_regress/t/t_unpacked_slice.v @@ -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 diff --git a/test_regress/t/t_unroll_forfor.v b/test_regress/t/t_unroll_forfor.v index b43f64ecf..a37ad75eb 100644 --- a/test_regress/t/t_unroll_forfor.v +++ b/test_regress/t/t_unroll_forfor.v @@ -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