Skip to content

Commit

Permalink
Fix change detections on arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
wsnyder committed Apr 10, 2012
1 parent 323f019 commit 4a5e775
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 17 deletions.
2 changes: 2 additions & 0 deletions Changes
Expand Up @@ -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]
Expand Down
57 changes: 44 additions & 13 deletions src/V3Changed.cpp
Expand Up @@ -59,21 +59,46 @@ class ChangedVisitor : public AstNVisitor {
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;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
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: "<<vscp);
if (!varp->dtypeSkipRefp()->castBasicDType()) {
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<<varp->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 "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
vscp->v3warn(E_DETECTARRAY, "... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(msb-lsb+1));
} else if (!isArray
&& !varp->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): "<<varp->prettyName());
} else {
string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
// Create: VARREF(_last)
Expand All @@ -84,17 +109,23 @@ class ChangedVisitor : public AstNVisitor {
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);
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/V3EmitC.cpp
Expand Up @@ -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; word<changep->lhsp()->widthWords(); word++) {
if (!gotOne) {
gotOne = true;
Expand Down
19 changes: 19 additions & 0 deletions 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;
90 changes: 90 additions & 0 deletions 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

0 comments on commit 4a5e775

Please sign in to comment.