diff --git a/Changes b/Changes index e0c5b1002..ee38ea3e6 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix duplicate anonymous structures in $root, bug788. [Bob Newgard] +**** Fix mis-optimization of bit-swap in wide signal, bug800. [Jie Xu] + * Verilator 3.862 2014-06-10 diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 68cbcbba7..481d3f61c 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -40,6 +40,60 @@ #include "V3Premit.h" #include "V3Ast.h" + +//###################################################################### +// Structure for global state + +class PremitAssignVisitor : public AstNVisitor { +private: + // NODE STATE + // AstVar::user4() // bool; occurs on LHS of current assignment + AstUser4InUse m_inuser4; + + // STATE + bool m_noopt; // Disable optimization of variables in this block + + // METHODS + static int debug() { + static int level = -1; + if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); + return level; + } + + // VISITORS + virtual void visit(AstNodeAssign* nodep, AstNUser*) { + //AstNode::user4ClearTree(); // Implied by AstUser4InUse + // LHS first as fewer varrefs + nodep->lhsp()->iterateAndNext(*this); + // Now find vars marked as lhs + nodep->rhsp()->iterateAndNext(*this); + } + virtual void visit(AstVarRef* nodep, AstNUser*) { + // it's LHS var is used so need a deep temporary + if (nodep->lvalue()) { + nodep->varp()->user4(true); + } else { + if (nodep->varp()->user4()) { + if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "<iterateChildren(*this); + } + +public: + // CONSTRUCTORS + PremitAssignVisitor(AstNodeAssign* nodep) { + UINFO(4," PremitAssignVisitor on "<accept(*this); + } + virtual ~PremitAssignVisitor() {} + bool noOpt() const { return m_noopt; } +}; + //###################################################################### // Premit state, as a visitor of each AstNode @@ -49,6 +103,7 @@ private: // AstNodeMath::user() -> bool. True if iterated already // AstShiftL::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional + // *::user4() -> See PremitAssignVisitor AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; @@ -174,6 +229,14 @@ private: } virtual void visit(AstNodeAssign* nodep, AstNUser*) { startStatement(nodep); + { + bool noopt = PremitAssignVisitor(nodep).noOpt(); + if (noopt && !nodep->user1()) { + // Need to do this even if not wide, as e.g. a select may be on a wide operator + UINFO(4,"Deep temp for LHS/RHS\n"); + createDeepTemp(nodep->rhsp()); + } + } nodep->rhsp()->iterateAndNext(*this); m_assignLhs = true; nodep->lhsp()->iterateAndNext(*this); diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 784431341..207594652 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -54,10 +54,10 @@ module t (/*AUTOARG*/ if (cyc==0) begin // Setup crc <= 64'h5aef0c8d_d70a4497; - sum <= 64'h0; + sum <= '0; end else if (cyc<10) begin - sum <= 64'h0; + sum <= '0; end else if (cyc<90) begin end diff --git a/test_regress/t/t_var_assign_landr.pl b/test_regress/t/t_var_assign_landr.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_var_assign_landr.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_var_assign_landr.v b/test_regress/t/t_var_assign_landr.v new file mode 100644 index 000000000..e03dedba1 --- /dev/null +++ b/test_regress/t/t_var_assign_landr.v @@ -0,0 +1,102 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Use this file as a template for submitting bugs, etc. +// This module takes a single clock input, and should either +// $write("*-* All Finished *-*\n"); +// $finish; +// on success, or $stop. +// +// The code as shown applies a random vector to the Test +// module, then calculates a CRC on the Test module's outputs. +// +// **If you do not wish for your code to be released to the public +// please note it here, otherwise:** +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2014 by ____YOUR_NAME_HERE____. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [255:0] sum; + + // Take CRC data and apply to testblock inputs + wire [127:0] in = {~crc[63:0], crc[63:0]}; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [127:0] o1; // From test of Test.v + wire [127:0] o2; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .o1 (o1[127:0]), + .o2 (o2[127:0]), + // Inputs + .in (in[127:0])); + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x %x\n",$time, cyc, crc, o1, o2); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= {o1,o2} ^ {sum[254:0],sum[255]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc<10) begin + sum <= '0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 256'h008a080aaa000000140550404115dc7b008a080aaae7c8cd897bc1ca49c9350a + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Outputs + o1, o2, + // Inputs + in + ); + + input [127:0] in; + output logic [127:0] o1; + output logic [127:0] o2; + + always_comb begin: b_test + logic [127:0] tmpp; + logic [127:0] tmp; + tmp = '0; + tmpp = '0; + + tmp[63:0] = in[63:0]; + tmpp[63:0] = in[63:0]; + + tmpp[63:0] = {tmp[0+:32], tmp[32+:32]}; + tmp[63:0] = {tmp[0+:32], tmp[32+:32]}; + + o1 = tmp; + o2 = tmpp; + end + +endmodule