diff --git a/Changes b/Changes index 487c8ec48..1d2cb42ed 100644 --- a/Changes +++ b/Changes @@ -10,6 +10,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix false warnings on non-power-2 enums using .next/.prev. +**** Fix comparison of unpacked arrays, bug1071. [Andrew Bardsley] + **** Fix compiler warning in GCC 6. [David Horton] diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 6a5b0dbf0..2be2706f1 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -471,6 +471,62 @@ class SliceVisitor : public AstNVisitor { expandUniOp(nodep); } + void expandBiOp(AstNodeBiop* nodep) { + if (!nodep->user1()) { + nodep->user1(true); + // If it's a unpacked array, blow it up into comparing each element + AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp(); + UINFO(9, " Bi-Eq/Neq expansion "<castUnpackArrayDType()) { + AstNodeBiop* logp = NULL; + for (int index = adtypep->rangep()->lsbConst(); + index <= adtypep->rangep()->msbConst(); ++index) { + // EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1]) + AstNodeBiop* clonep = nodep->cloneType + (new AstArraySel(nodep->fileline(), + nodep->lhsp()->cloneTree(false), + index), + new AstArraySel(nodep->fileline(), + nodep->rhsp()->cloneTree(false), + index))->castNodeBiop(); + if (!logp) logp = clonep; + else { + switch (nodep->type()) { + case AstType::atEQ: // FALLTHRU + case AstType::atEQCASE: + logp = new AstLogAnd(nodep->fileline(), logp, clonep); + break; + case AstType::atNEQ: // FALLTHRU + case AstType::atNEQCASE: + logp = new AstLogOr(nodep->fileline(), logp, clonep); + break; + default: + nodep->v3fatalSrc("Unknown node type processing array slice"); + break; + } + } + } + if (!logp) nodep->v3fatalSrc("Unpacked array with empty indices range"); + nodep->replaceWith(logp); + pushDeletep(nodep); VL_DANGLING(nodep); + nodep = logp; + } + nodep->iterateChildren(*this); + } + } + virtual void visit(AstEq* nodep, AstNUser*) { + expandBiOp(nodep); + } + virtual void visit(AstNeq* nodep, AstNUser*) { + expandBiOp(nodep); + } + virtual void visit(AstEqCase* nodep, AstNUser*) { + expandBiOp(nodep); + } + virtual void visit(AstNeqCase* nodep, AstNUser*) { + expandBiOp(nodep); + } + virtual void visit(AstNode* nodep, AstNUser*) { // Default: Just iterate nodep->iterateChildren(*this); diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 8d4970ebc..10a006518 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2015 by ____YOUR_NAME_HERE____. +// without warranty, 2016 by ____YOUR_NAME_HERE____. module t (/*AUTOARG*/ // Inputs diff --git a/test_regress/t/t_array_compare.pl b/test_regress/t/t_array_compare.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_array_compare.pl @@ -0,0 +1,18 @@ +#!/usr/bin/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. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_array_compare.v b/test_regress/t/t_array_compare.v new file mode 100644 index 000000000..7060d1e01 --- /dev/null +++ b/test_regress/t/t_array_compare.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2016 by Andrew Bardsley. + +// bug1071 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + reg [3:0] array_1 [2:0]; + reg [3:0] array_2 [2:0]; + reg [3:0] array_3 [3:1]; + + reg [3:0] elem; + + reg array_1_ne_array_2; + reg array_1_eq_array_2; + reg array_1_ne_array_3; + reg array_1_eq_array_3; + + initial begin + array_1[0] = 4'b1000; + array_1[1] = 4'b1000; + array_1[2] = 4'b1000; + + array_2[0] = 4'b1000; + array_2[1] = 4'b1000; + array_2[2] = 4'b1000; + + array_3[1] = 4'b1000; + array_3[2] = 4'b0100; + array_3[3] = 4'b0100; + + // Comparisons only compare elements 0 + array_1_ne_array_2 = array_1 != array_2; // 0 + array_1_eq_array_2 = array_1 == array_2; // 0 + array_1_ne_array_3 = array_1 != array_3; // 1 + array_1_eq_array_3 = array_1 == array_3; // 1 + +`ifdef TEST_VERBOSE + $write("array_1_ne_array2==%0d\n", array_1_ne_array_2); + $write("array_1_ne_array3==%0d\n", array_1_ne_array_3); +`endif + + if (array_1_ne_array_2 !== 0) $stop; + if (array_1_eq_array_2 !== 1) $stop; + if (array_1_ne_array_3 !== 1) $stop; + if (array_1_eq_array_3 !== 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule