diff --git a/Changes b/Changes index 54834688b..76222524d 100644 --- a/Changes +++ b/Changes @@ -12,6 +12,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Add SELRANGE as warning instead of error, bug477. [Alex Solomatnikov] +**** Fix change detections on arrays. [Alex Solomatnikov] + **** Fix signed array warning, bug456. [Alex Solomatnikov] **** Fix genvar and begin under generate, bug461. [Alex Solomatnikov] diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 7240def90..5e941ec5c 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -59,6 +59,12 @@ private: AstScope* m_scopetopp; // Scope under TOPSCOPE AstCFunc* m_chgFuncp; // Change function we're building + // CONSTANTS + enum MiscConsts { + DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error + // Ok to increase this, but may result in much slower model + }; + // METHODS static int debug() { static int level = -1; @@ -66,14 +72,33 @@ private: return level; } + AstNode* aselIfNeeded(bool isArray, int index, AstNode* childp) { + if (isArray) { + return new AstArraySel(childp->fileline(), childp, + new AstConst(childp->fileline(), index)); + } else { + return childp; + } + } + void genChangeDet(AstVarScope* vscp) { #ifdef NEW_ORDERING vscp->v3fatalSrc("Not applicable\n"); #endif AstVar* varp = vscp->varp(); vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<dtypeSkipRefp()->castBasicDType()) { - vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<prettyName()); + AstArrayDType* arrayp = varp->dtypeSkipRefp()->castArrayDType(); + bool isArray = arrayp; + int msb = isArray ? arrayp->msb() : 0; + int lsb = isArray ? arrayp->lsb() : 0; + if (isArray && ((msb - lsb + 1) > DETECTARRAY_MAX_INDEXES)) { + vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<prettyName()); + vscp->v3warn(E_DETECTARRAY, "... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<dtypeSkipRefp()->castBasicDType()) { + if (debug()) varp->dumpTree(cout,"-DETECTARRAY-"); + vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<prettyName()); } else { string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName(); // Create: VARREF(_last) @@ -84,17 +109,23 @@ private: m_topModp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); m_scopetopp->addVarp(newvscp); - AstChangeDet* changep - = new AstChangeDet (vscp->fileline(), - new AstVarRef(vscp->fileline(), vscp, false), - new AstVarRef(vscp->fileline(), newvscp, false), - false); - m_chgFuncp->addStmtsp(changep); - AstAssign* initp - = new AstAssign (vscp->fileline(), - new AstVarRef(vscp->fileline(), newvscp, true), - new AstVarRef(vscp->fileline(), vscp, false)); - m_chgFuncp->addFinalsp(initp); + for (int index=lsb; index<=msb; ++index) { + AstChangeDet* changep + = new AstChangeDet (vscp->fileline(), + aselIfNeeded(isArray, index, + new AstVarRef(vscp->fileline(), vscp, false)), + aselIfNeeded(isArray, index, + new AstVarRef(vscp->fileline(), newvscp, false)), + false); + m_chgFuncp->addStmtsp(changep); + AstAssign* initp + = new AstAssign (vscp->fileline(), + aselIfNeeded(isArray, index, + new AstVarRef(vscp->fileline(), newvscp, true)), + aselIfNeeded(isArray, index, + new AstVarRef(vscp->fileline(), vscp, false))); + m_chgFuncp->addFinalsp(initp); + } } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index f36fd913f..4a68b82b2 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -661,10 +661,10 @@ class EmitCImp : EmitCStmts { changep->lhsp()->iterateAndNext(*this); } else { - AstVarRef* lhsp = changep->lhsp()->castVarRef(); - AstVarRef* rhsp = changep->rhsp()->castVarRef(); - if (!lhsp) changep->v3fatalSrc("Not ref?"); - if (!rhsp) changep->v3fatalSrc("Not ref?"); + AstNode* lhsp = changep->lhsp(); + AstNode* rhsp = changep->rhsp(); + if (!lhsp->castVarRef() && !lhsp->castArraySel()) changep->v3fatalSrc("Not ref?"); + if (!rhsp->castVarRef() && !rhsp->castArraySel()) changep->v3fatalSrc("Not ref?"); for (int word=0; wordlhsp()->widthWords(); word++) { if (!gotOne) { gotOne = true; diff --git a/test_regress/t/t_unopt_array.pl b/test_regress/t/t_unopt_array.pl new file mode 100755 index 000000000..d4d101b66 --- /dev/null +++ b/test_regress/t/t_unopt_array.pl @@ -0,0 +1,19 @@ +#!/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 ( + verilator_flags2=>["-Wno-UNOPTFLAT"], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unopt_array.v b/test_regress/t/t_unopt_array.v new file mode 100644 index 000000000..ab2faede7 --- /dev/null +++ b/test_regress/t/t_unopt_array.v @@ -0,0 +1,90 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2012 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [31:0] in = crc[31:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [31:0] out; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out[31:0]), + // Inputs + .clk (clk), + .in (in[31:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {32'h0, out}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= 64'h0; + end + else if (cyc<10) begin + sum <= 64'h0; + 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 64'h458c2de282e30f8b + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + output wire [31:0] out; + + reg [31:0] stage [3:0]; + + genvar g; + + generate + for (g=0; g<4; g++) begin + always_comb begin + if (g==0) stage[g] = in; + else stage[g] = {stage[g-1][30:0],1'b1}; + end + end + endgenerate + + assign out = stage[3]; +endmodule