diff --git a/Changes b/Changes index a75d85837..5eaa1ea8a 100644 --- a/Changes +++ b/Changes @@ -7,7 +7,9 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Added new examples/ directory with appropriate examples. This replaces the old test_c and test_sc directories. -*** Add --getenv option. +*** Add --getenv option for simplifying Makefiles. + +*** Add --x-initial option for specifying initial value assignment behavior. **** The internal test_verilated test directory is moved to be part of test_regress. diff --git a/bin/verilator b/bin/verilator index 7552a7b53..fcd0f87ad 100755 --- a/bin/verilator +++ b/bin/verilator @@ -359,7 +359,8 @@ descriptions in the next sections for more information. -Wno-lint Disable all lint warnings -Wno-style Disable all style warnings -Wno-fatal Disable fatal exit on warnings - --x-assign Initially assign Xs to this value + --x-assign Assign non-initial Xs to this value + --x-initial Assign initial Xs to this value --x-initial-edge Enable initial X->0 and X->1 edge triggers -y Directory to search for modules @@ -429,9 +430,6 @@ C<+1364-1995ext+> etc. specify both the syntax I semantics to be used. Enable all assertions. -See also --x-assign and --x-initial-edge; setting "--x-assign unique" -and/or "--x-initial-edge" may be desirable. - =item --autoflush After every $display or $fdisplay, flush the output stream. This insures @@ -1307,7 +1305,30 @@ enable rerunning with that same seed so you can reproduce bugs. B This option applies only to variables which are explicitly assigned to X in the Verilog source code. Initial values of clocks are set to 0 unless --x-initial-edge is specified. Initial values of all other state holding -variables are set as though --x-assign unique had been specified. +variables are controlled with --x-initial. + +=item --x-initial 0 + +=item --x-initial fast + +=item --x-initial unique (default) + +Controls the two-state value that is used to initialize variables that are +not otherwise initialized. + +--x-initial=0, initializes all otherwise uninitialized variables to zero. + +--x-initial=unique, the default, initializes variables using a function, +which determines the value to use each initialization. This gives greatest +flexibility and allows finding reset bugs. See L + +--x-initial=fast, is best for performance, and initializes all variables to +a state Verilator determines is optimal. This may allow further code +optimizations, but will likely hide any code bugs relating to missing +resets. + +B This option applies only to initial values of variables. Initial +values of clocks are set to 0 unless --x-initial-edge is specified. =item --x-initial-edge @@ -1502,9 +1523,10 @@ the examples directory in the distribution. =head1 BENCHMARKING & OPTIMIZATION For best performance, run Verilator with the "-O3 --x-assign=fast ---noassert" flags. The -O3 flag will require longer compile times, and ---x-assign=fast may increase the risk of reset bugs in trade for -performance; see the above documentation for these flags. +--x-initial=fast --noassert" flags. The -O3 flag will require longer +compile times, and --x-assign=fast --x-initial=fast may increase the risk +of reset bugs in trade for performance; see the above documentation for +these flags. Minor Verilog code changes can also give big wins. You should not have any UNOPTFLAT warnings from Verilator. Fixing these warnings can result in @@ -2647,24 +2669,25 @@ value (see the --x-assign switch.) Thus if the value is actually used, the random value should cause downstream errors. Integers also randomize, even though the Verilog 2001 specification says they initialize to zero. -All variables are randomly initialized using a function. By running -several random simulation runs you can determine that reset is working -correctly. On the first run, the function initializes variables to zero. -On the second, have it initialize variables to one. On the third and -following runs have it initialize them randomly. If the results match, -reset works. (Note this is what the hardware will really do.) In -practice, just setting all variables to one at startup finds most problems. +All variables, depending on --x-initial setting, are typically randomly +initialized using a function. By running several random simulation runs +you can determine that reset is working correctly. On the first run, the +function initializes variables to zero. On the second, have it initialize +variables to one. On the third and following runs have it initialize them +randomly. If the results match, reset works. (Note this is what the +hardware will really do.) In practice, just setting all variables to one +at startup finds most problems (since typically control signals are +active-high). -B --x-assign applies to variables explicitly initialized or assigned to -X. Uninitialized clocks are initialized to zero, while all other state holding -variables are initialized to a random value. - -Event driven simulators will generally trigger an edge on a transition from X -to 1 (C) or X to 0 (C). However, by default, since clocks -are initialized to zero, Verilator will not trigger an initial negedge. Some -code (particularly for reset) may rely on X->0 triggering an edge. Verilator -provides a switch (see --x-initial-edge) to enable this behavior. Comparing -runs with and without this switch will find such problems. +--x-assign applies to variables explicitly initialized or assigned to +X. Uninitialized clocks are initialized to zero, while all other state +holding variables are initialized to a random value. Event driven +simulators will generally trigger an edge on a transition from X to 1 +(C) or X to 0 (C). However, by default, since clocks are +initialized to zero, Verilator will not trigger an initial negedge. Some +code (particularly for reset) may rely on X->0 triggering an edge. The +--x-initial-edge switch enables this behavior. Comparing runs with and +without this switch will find such problems. =head2 Tri/Inout diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 389e148c4..5a77b5e09 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1464,7 +1464,8 @@ void EmitCImp::emitVarReset(AstVar* varp) { } bool zeroit = (varp->attrFileDescr() // Zero it out, so we don't core dump if never call $fopen || (varp->basicp() && varp->basicp()->isZeroInit()) - || (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero())); + || (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero()) + || (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0")); if (varp->isWide()) { // DOCUMENT: We randomize everything. If the user wants a _var to be zero, // there should be a initial statement. (Different from verilator2.) diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 0078932f2..b6b95dc74 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -864,6 +864,9 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* // optimizing away this assignment, etc. consumerp = V3Const::constifyEdit(consumerp); if (debug()>=5) consumerp->dumpTree(cout,"\telimUseDne: "); + // Some previous input edges may have disappeared, perhaps all of them. + // If we remove the edges we can further optimize + // See e.g t_var_overzero.v. } } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 6f0802380..92befebac 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -993,6 +993,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char fl->v3fatal("Unknown setting for --x-assign: "<v3fatal("Unknown setting for --x-initial: "< ["--x-initial 0"], + ); + +execute ( + check_finished=>1, + ); + +file_grep_not ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/VL_RAND_RESET/); + +ok(1); +1; diff --git a/test_regress/t/t_flag_xinitial_0.v b/test_regress/t/t_flag_xinitial_0.v new file mode 100644 index 000000000..fed402a34 --- /dev/null +++ b/test_regress/t/t_flag_xinitial_0.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Outputs + value + ); + + output reg [63:0] value; + + initial begin +`ifdef VERILATOR + // Default is all ones, so we assume that here + if (value != '0) $stop; +`else + if (value != {64{1'bx}}) $stop; +`endif + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_xinitial_unique.pl b/test_regress/t/t_flag_xinitial_unique.pl new file mode 100755 index 000000000..1183667b0 --- /dev/null +++ b/test_regress/t/t_flag_xinitial_unique.pl @@ -0,0 +1,21 @@ +#!/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 => ["--x-initial unique"], + ); + +execute ( + check_finished=>1, + ); + +file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/VL_RAND_RESET/); + +ok(1); +1; diff --git a/test_regress/t/t_flag_xinitial_unique.v b/test_regress/t/t_flag_xinitial_unique.v new file mode 100644 index 000000000..a23f071ad --- /dev/null +++ b/test_regress/t/t_flag_xinitial_unique.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Outputs + value + ); + + output reg [63:0] value; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_var_overzero.pl b/test_regress/t/t_var_overzero.pl new file mode 100755 index 000000000..067f038a8 --- /dev/null +++ b/test_regress/t/t_var_overzero.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 => ["--x-initial fast"], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_overzero.v b/test_regress/t/t_var_overzero.v new file mode 100644 index 000000000..559f5d009 --- /dev/null +++ b/test_regress/t/t_var_overzero.v @@ -0,0 +1,172 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Outputs + dout, + // Inputs + clk, rstn, dval0, dval1 + ); + + input clk; + input rstn; + output wire [7:0] dout; + + input [7:0] dval0; + input [7:0] dval1; + wire [7:0] dbgsel_w = '0; + + tsub tsub (/*AUTOINST*/ + // Outputs + .dout (dout[7:0]), + // Inputs + .clk (clk), + .rstn (rstn), + .dval0 (dval0[7:0]), + .dval1 (dval1[7:0]), + .dbgsel_w (dbgsel_w[7:0])); + +endmodule + +module tsub (/*AUTOARG*/ + // Outputs + dout, + // Inputs + clk, rstn, dval0, dval1, dbgsel_w + ); + + input clk; + input rstn; + input [7:0] dval0; + input [7:0] dval1; + input [7:0] dbgsel_w; + output [7:0] dout; + + wire [7:0] dout = dout0 | dout1; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [7:0] dout0; // From sub0 of sub0.v + wire [7:0] dout1; // From sub1 of sub1.v + // End of automatics + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + + reg [7:0] dbgsel_msk; + always_comb begin + reg [7:0] mask; + mask = 8'hff; + dbgsel_msk = (dbgsel_w & mask); + end + + // TODO this should optimize away, but presently does not because + // V3Gate constifies then doesn't see all other input edges have disappeared + reg [7:0] dbgsel; + always @(posedge clk) begin + if ((rstn == 0)) begin + dbgsel <= 0; + end + else begin + dbgsel <= dbgsel_msk; + end + end + + sub0 sub0 (/*AUTOINST*/ + // Outputs + .dout0 (dout0[7:0]), + // Inputs + .rstn (rstn), + .clk (clk), + .dval0 (dval0[7:0]), + .dbgsel (dbgsel[7:0])); + sub1 sub1 (/*AUTOINST*/ + // Outputs + .dout1 (dout1[7:0]), + // Inputs + .rstn (rstn), + .clk (clk), + .dval1 (dval1[7:0]), + .dbgsel (dbgsel[7:0])); + +endmodule + +module sub0 + ( + /*AUTOARG*/ + // Outputs + dout0, + // Inputs + rstn, clk, dval0, dbgsel + ); + + input rstn; + input clk; + input [7:0] dval0; + input [7:0] dbgsel; + output reg [7:0] dout0; + + reg [7:0] dbgsel_d1r; + + always_comb begin + // verilator lint_off WIDTH + if (((dbgsel_d1r >= 34) && (dbgsel_d1r < 65))) begin + // verilator lint_on WIDTH + dout0 = dval0; + end + else begin + dout0 = 0; + end + end + + always @(posedge clk) begin + if ((rstn == 0)) begin + dbgsel_d1r <= 0; + end + else begin + dbgsel_d1r <= dbgsel; + end + end + +endmodule + +module sub1 + ( + /*AUTOARG*/ + // Outputs + dout1, + // Inputs + rstn, clk, dval1, dbgsel + ); + + input rstn; + input clk; + input [7:0] dval1; + input [7:0] dbgsel; + output reg [7:0] dout1; + + reg [7:0] dbgsel_d1r; + + always_comb begin + if (((dbgsel_d1r >= 84) && (dbgsel_d1r < 95))) begin + dout1 = dval1; + end + else begin + dout1 = 0; + end + end + + always @(posedge clk) begin + if ((rstn == 0)) begin + dbgsel_d1r <= 0; + end + else begin + dbgsel_d1r <= dbgsel; + end + end + +endmodule