diff --git a/Changes b/Changes index 78c5b3c5d..e428484f5 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Add --trace-depth option for minimizing VCD file size. [Emerson Suguimoto] +*** With VL_DEBUG, show wires causing convergance errors. [Mike Shinkarovsky] + **** Fix isolate_assignments when many signals per always. [Mike Shinkarovsky] **** Fix isolate_assignments across task/func temporaries. [Mike Shinkarovsky] diff --git a/bin/verilator b/bin/verilator index 03a8cd2a2..3855f1aa1 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1635,12 +1635,18 @@ For example: always @ (b) a=b will toggle forever and thus the executable will give the didn't converge -error to prevent an infinite loop. To debug this, compile the Verilated -.cpp files with -DVL_DEBUG, then call Verilated::debug(1) in your main.cpp. -This will cause each module to print a message when it's invoked. From -that it should be obvious what routine(s) are part of the infinite loop. -Then in Gdb, add a break point at the routine entry point and "print *this" -on each loop so you can see what variables are changing each invocation. +error to prevent an infinite loop. + +To debug this, run Verilator with --profile-cfuncs. Run make on the +generated files with "CPPFLAGS_ADD=-DVL_DEBUG". Then call +Verilated::debug(1) in your main.cpp. + +This will cause each change in a variable to print a message. Near the +bottom you'll see the code and variable that causes the problem. For the +program above: + + CHANGE: filename.v:1: b + CHANGE: filename.v:2: a =back diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index bb1b8b7a8..b65ce1bdb 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -687,6 +687,21 @@ class EmitCImp : EmitCStmts { if (gotOne) { puts(");\n"); //puts("VL_DEBUG_IF( if (__req) cout<<\"\tCLOCKREQ );"); + for (vector::iterator it = m_blkChangeDetVec.begin(); + it != m_blkChangeDetVec.end(); ++it) { + AstChangeDet* nodep = *it; + if (nodep->lhsp()) { + puts("VL_DEBUG_IF( if(__req && ("); + bool gotOneIgnore = false; + doubleOrDetect(nodep, gotOneIgnore); + string varname; + if (nodep->lhsp()->castVarRef()) { + varname = ": "+nodep->lhsp()->castVarRef()->varp()->prettyName(); + } + puts(")) cout<<\"\tCHANGE: "+nodep->fileline()->ascii() + +varname+"\"<accept(*this); + // Check results if (!m_substTreep) { clearSimple("No assignment found\n"); } + for (GateVarRefList::const_iterator it = rhsVarRefs().begin(); + it != rhsVarRefs().end(); ++it) { + if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) { + clearSimple("Circular logic\n"); // Oh my, we'll get a UNOPTFLAT much later. + } + } if (debug()>=9 && !m_isSimple) { nodep->dumpTree(cout,"\tgate!Ok: "); } @@ -224,6 +232,7 @@ private: //Entire netlist: // AstVarScope::userp -> GateVarVertex* for usage var, 0=not set yet // {statement}Node::userp -> GateLogicVertex* for this statement + // STATE V3Graph m_graph; // Scoreboard of var usages/dependencies GateLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored @@ -458,6 +467,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { } } } + // Process it if (!doit) { if (allowMultiIn && (debug()>=9)) { UINFO(9, "Not ok simp"< 0, verilator_flags => [split(/\s+/,"-cc")], verilator_make_gcc => 1, + verilated_debug => $Opt_Verilated_Debug, stdout_filename => undef, # Redirect stdout @_}; bless $self, $class; @@ -545,7 +546,7 @@ sub _make_main { print $fh "int main(int argc, char **argv, char **env) {\n"; print $fh " double sim_time = 1000;\n"; } - print $fh " Verilated::debug(".($Opt_Verilated_Debug?1:0).");\n"; + print $fh " Verilated::debug(".($self->{verilated_debug}?1:0).");\n"; print $fh " topp = new $VM_PREFIX (\"TOP\");\n"; my $set; if ($self->sp) { diff --git a/test_regress/t/t_unopt_converge.v b/test_regress/t/t_unopt_converge.v new file mode 100644 index 000000000..ed827962f --- /dev/null +++ b/test_regress/t/t_unopt_converge.v @@ -0,0 +1,26 @@ +// $Id$ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2007 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Outputs + x, + // Inputs + clk + ); + +`ifdef ALLOW_UNOPT + /*verilator lint_off UNOPTFLAT*/ +`endif + + input clk; + output x; // Avoid eliminating x + + reg x; + always @* begin + x = ~x; + end + +endmodule diff --git a/test_regress/t/t_unopt_converge_print_bad.pl b/test_regress/t/t_unopt_converge_print_bad.pl new file mode 100755 index 000000000..e6aaba8f9 --- /dev/null +++ b/test_regress/t/t_unopt_converge_print_bad.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2007 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +top_filename("t/t_unopt_converge.v"); +#$Last_Self->{verilated_debug} = 1; + +compile ( + v_flags2 => ['+define+ALLOW_UNOPT'], + make_flags => 'CPPFLAGS_ADD=-DVL_DEBUG', + ); + +execute ( + fails=>1, + expect=> '%Error: \S+:\d+: Verilated model didn\'t converge', + ) if $Last_Self->{v3}; + +ok(1); +1; diff --git a/test_regress/t/t_unopt_converge_run_bad.pl b/test_regress/t/t_unopt_converge_run_bad.pl new file mode 100755 index 000000000..477b101a9 --- /dev/null +++ b/test_regress/t/t_unopt_converge_run_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2007 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +top_filename("t/t_unopt_converge.v"); + +compile ( + v_flags2 => ['+define+ALLOW_UNOPT'], + ); + +execute ( + fails=>1, + expect=> '%Error: \S+:\d+: Verilated model didn\'t converge', + ) if $Last_Self->{v3}; + +ok(1); +1; diff --git a/test_regress/t/t_unopt_converge_unopt_bad.pl b/test_regress/t/t_unopt_converge_unopt_bad.pl new file mode 100755 index 000000000..45f504971 --- /dev/null +++ b/test_regress/t/t_unopt_converge_unopt_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2007 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +top_filename("t/t_unopt_converge.v"); + +compile ( + fails=>1, + expect=> '%Warning-UNOPT: t/t_unopt_converge.v:\d+: Signal unoptimizable: Feedback to public clock or circular logic: TOP->x +.* +%Error: Exiting due to ' + ) if $Last_Self->{v3}; + +ok(1); +1;