Add --x-initial option

This commit is contained in:
Wilson Snyder 2017-10-01 21:31:40 -04:00
commit 33780a09df
12 changed files with 340 additions and 27 deletions

View File

@ -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.

View File

@ -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 <mode> Initially assign Xs to this value
--x-assign <mode> Assign non-initial Xs to this value
--x-initial <mode> Assign initial Xs to this value
--x-initial-edge Enable initial X->0 and X->1 edge triggers
-y <dir> Directory to search for modules
@ -429,9 +430,6 @@ C<+1364-1995ext+> etc. specify both the syntax I<and> 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<Note.> 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</"Unknown states">
--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<Note.> 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<Note.> --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<posedge>) or X to 0 (C<negedge>). 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<posedge>) or X to 0 (C<negedge>). 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

View File

@ -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.)

View File

@ -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.
}
}

View File

@ -993,6 +993,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
fl->v3fatal("Unknown setting for --x-assign: "<<argv[i]);
}
}
else if ( !strcmp (sw, "-x-initial") && (i+1)<argc) {
shift;
if (!strcmp (argv[i], "0")) { m_xInitial="0"; }
else if (!strcmp (argv[i], "fast")) { m_xInitial="fast"; }
else if (!strcmp (argv[i], "unique")) { m_xInitial="unique"; }
else {
fl->v3fatal("Unknown setting for --x-initial: "<<argv[i]);
}
}
else if ( !strcmp (sw, "-y") && (i+1)<argc ) {
shift; addIncDirUser (parseFileArg(optdir,string (argv[i])));
}

View File

@ -133,6 +133,7 @@ class V3Options {
string m_topModule; // main switch: --top-module
string m_unusedRegexp; // main switch: --unused-regexp
string m_xAssign; // main switch: --x-assign
string m_xInitial; // main switch: --x-initial
// Language is now held in FileLine, on a per-node basis. However we still
// have a concept of the default language at a global level.
@ -274,6 +275,7 @@ class V3Options {
string topModule() const { return m_topModule; }
string unusedRegexp() const { return m_unusedRegexp; }
string xAssign() const { return m_xAssign; }
string xInitial() const { return m_xInitial; }
const V3StringSet& cppFiles() const { return m_cppFiles; }
const V3StringList& cFlags() const { return m_cFlags; }

View File

@ -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 0"],
);
execute (
check_finished=>1,
);
file_grep_not ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/VL_RAND_RESET/);
ok(1);
1;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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