diff --git a/bin/verilator b/bin/verilator index 696f7ff82..ec24d9502 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3847,6 +3847,43 @@ as an unpacked struct or a large unpacked array. This typically occurs when The solution is to break the loop, as described for UNOPTFLAT. +=item DIDNOTCONVERGE + +Error at runtime when model did not properly settle. + +Verilator sometimes has to evaluate combinatorial logic multiple times, +usually around code where a UNOPTFLAT warning was issued, but disabled. +For example: + + always_comb b = ~a; + always_comb a = b + +This code will toggle forever, and thus to prevent an infinite loop, the +executable will give the didn't converge error. + +To debug this, first is to review any UNOPTFLAT warnings that were ignored. +Though typically it is safe to ignore UNOPTFLAT (at a performance cost), at +the time of issuing a UNOPTFLAT Verilator didn't know if they would +eventually converge and assumed the would. + +Next, run Verilator with --prof-cfuncs. Run make on the generated files +with "CPP_FLAGS=-DVL_DEBUG", to allow enabling runtime debug messages. +Rerun the test. Now just before the convergence error you should see +additional output similar to this: + + CHANGE: filename.v:1: b + CHANGE: filename.v:2: a + +This means that signal b and signal a keep changing, inspect the code that +modifies these signals. Note if many signals are getting printed then most +likely all of them are oscillating. It may also be that e.g. "a" may be +oscillating, then "a" feeds signal "c" which then is also reported as +oscillating. + +Finally, rare, more difficult cases can be debugged like a "C" program; +either enter GDB and use its tracing facilities, or edit the generated C++ +code to add appropriate prints to see what is going on. + =item ENDLABEL Warns that a label attached to a "end"-something statement does not match @@ -4378,42 +4415,6 @@ warnings or errors, submit a bug report. This error indicates that you are using a Verilog language construct that is not yet supported in Verilator. See the Limitations chapter. -=item Verilated model didn't converge - -Verilator sometimes has to evaluate combinatorial logic multiple times, -usually around code where a UNOPTFLAT warning was issued, but disabled. -For example: - - always @ (a) b=~a; - 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, first is to review any UNOPTFLAT warnings that were ignored, -though typically these can be ignored (at a performance cost), convergence -issues can also be flagged with this warning as Verilator didn't know if -they would eventually converge. - -Next, run Verilator with --prof-cfuncs. Run make on the generated -files with "OPT=-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 variables that causes the problem. For the program -above: - - CHANGE: filename.v:1: b - CHANGE: filename.v:2: a - -If many signals are getting printed then most likely each are oscillating -(or there is a bug). It may also be that e.g. "a" may be oscillating, then -"a" feeds signal "c" which then is also reported as oscillating. - -Finally, rare more difficult cases can be debugged like a "C" program; -either enter GDB and use its tracing facilities, or edit the generated C++ -code to add appropriate prints to see what is going on. - =back diff --git a/include/verilated.cpp b/include/verilated.cpp index b4e2097c2..f6de2b26b 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1785,7 +1785,8 @@ void Verilated::debug(int level) VL_MT_SAFE { " Message prefix indicates {,}.\n");); #else VL_PRINTF_MT("- Verilated::debug attempted," - " but compiled without VL_DEBUG, so messages suppressed.\n"); + " but compiled without VL_DEBUG, so messages suppressed.\n" + "- Suggest remake using 'make ... CPPFLAGS=-DVL_DEBUG'\n"); #endif } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index abe27d15f..34a6d5874 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1196,7 +1196,7 @@ class EmitCImp : EmitCStmts { puts(")) VL_DBG_MSGF(\" CHANGE: "); puts(protect(nodep->fileline()->filename())); puts(":"+cvtToStr(nodep->fileline()->lineno())); - puts(": "+varname+"\\n\"); );\n"); + puts(varname+"\\n\"); );\n"); } } } @@ -2056,7 +2056,7 @@ void EmitCImp::emitStaticDecl(AstNodeModule* modp) { void EmitCImp::emitTextSection(AstType type) { int last_line = -999; - for (AstNode* nodep = m_modp->stmtsp(); nodep != NULL; nodep = nodep->nextp()) { + for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstNodeText* textp = VN_CAST(nodep, NodeText)) { if (nodep->type() == type) { if (last_line != nodep->fileline()->lineno()) { @@ -2131,7 +2131,7 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) { puts("int __VclockLoop = 0;\n"); puts("QData __Vchange = 1;\n"); puts("do {\n"); - puts( eval_call + "\n"); + puts( eval_call+"\n"); puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit()) +")) {\n"); puts( "// About to fail, so enable debug to see what's not settling.\n"); @@ -2140,9 +2140,15 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) { puts( "Verilated::debug(1);\n"); puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n"); puts( "Verilated::debug(__Vsaved_debug);\n"); - puts( "VL_FATAL_MT(__FILE__, __LINE__, __FILE__, \"Verilated model didn't "); + puts( "VL_FATAL_MT("); + putsQuoted(protect(m_modp->fileline()->filename())); + puts(", "); + puts(cvtToStr(m_modp->fileline()->lineno())); + puts(", \"\",\n"); + puts("\"Verilated model didn't "); if (initial) puts("DC "); - puts( "converge\");\n"); + puts("converge\\n\"\n"); + puts("\"- See DIDNOTCONVERGE in the Verilator manual\");\n"); puts( "} else {\n"); puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n"); puts( "}\n"); diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 1f3094748..dcc44f5cc 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1960,6 +1960,7 @@ sub files_identical { } @l1; @l1 = map { s/(Internal Error: [^\n]+\.cpp):[0-9]+:/$1:#:/; + s/^-V\{t[0-9]+,[0-9]+\}/-V{t#,#}/; # --vlt vs --vltmt run differences $_; } @l1; for (my $l=0; $l<=$#l1; ++$l) { diff --git a/test_regress/t/t_unopt_converge_initial_run_bad.out b/test_regress/t/t_unopt_converge_initial_run_bad.out new file mode 100644 index 000000000..3c8924f4f --- /dev/null +++ b/test_regress/t/t_unopt_converge_initial_run_bad.out @@ -0,0 +1,5 @@ +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_unopt_converge_initial_run_bad::_change_request +-V{t#,#} CHANGE: t/t_unopt_converge_initial.v:18: x +%Error: t/t_unopt_converge_initial.v:6: Verilated model didn't DC converge +Aborting... diff --git a/test_regress/t/t_unopt_converge_initial_run_bad.pl b/test_regress/t/t_unopt_converge_initial_run_bad.pl index 5a8ed7eb0..b680fe33d 100755 --- a/test_regress/t/t_unopt_converge_initial_run_bad.pl +++ b/test_regress/t/t_unopt_converge_initial_run_bad.pl @@ -17,7 +17,7 @@ compile( execute( fails => 1, - expect => '%Error: \S+:\d+: Verilated model didn\'t DC converge', + expect_filename => $Self->{golden_filename}, ) if $Self->{vlt_all}; ok(1); diff --git a/test_regress/t/t_unopt_converge_ndbg_bad.out b/test_regress/t/t_unopt_converge_ndbg_bad.out new file mode 100644 index 000000000..1484d8577 --- /dev/null +++ b/test_regress/t/t_unopt_converge_ndbg_bad.out @@ -0,0 +1,2 @@ +%Error: t/t_unopt_converge.v:6: Verilated model didn't converge +Aborting... diff --git a/test_regress/t/t_unopt_converge_ndbg_bad.pl b/test_regress/t/t_unopt_converge_ndbg_bad.pl new file mode 100755 index 000000000..a2cc6c968 --- /dev/null +++ b/test_regress/t/t_unopt_converge_ndbg_bad.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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 +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1); + +top_filename("t/t_unopt_converge.v"); + +compile( + v_flags2 => ['+define+ALLOW_UNOPT'], + make_flags => 'CPPFLAGS_ADD=-UVL_DEBUG', + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ) if $Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_unopt_converge_print_bad.out b/test_regress/t/t_unopt_converge_print_bad.out new file mode 100644 index 000000000..3cc147cb3 --- /dev/null +++ b/test_regress/t/t_unopt_converge_print_bad.out @@ -0,0 +1,5 @@ +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_unopt_converge_print_bad::_change_request +-V{t#,#} CHANGE: t/t_unopt_converge.v:18: x +%Error: t/t_unopt_converge.v:6: Verilated model didn't converge +Aborting... diff --git a/test_regress/t/t_unopt_converge_print_bad.pl b/test_regress/t/t_unopt_converge_print_bad.pl index 67c9ea5e9..b2d9c3bfe 100755 --- a/test_regress/t/t_unopt_converge_print_bad.pl +++ b/test_regress/t/t_unopt_converge_print_bad.pl @@ -19,7 +19,7 @@ compile( execute( fails => 1, - expect => '%Error: \S+:\d+: Verilated model didn\'t converge', + expect_filename => $Self->{golden_filename}, ) if $Self->{vlt_all}; ok(1); diff --git a/test_regress/t/t_unopt_converge_run_bad.out b/test_regress/t/t_unopt_converge_run_bad.out new file mode 100644 index 000000000..bd3150508 --- /dev/null +++ b/test_regress/t/t_unopt_converge_run_bad.out @@ -0,0 +1,5 @@ +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_unopt_converge_run_bad::_change_request +-V{t#,#} CHANGE: t/t_unopt_converge.v:18: x +%Error: t/t_unopt_converge.v:6: Verilated model didn't converge +Aborting... diff --git a/test_regress/t/t_unopt_converge_run_bad.pl b/test_regress/t/t_unopt_converge_run_bad.pl index 437291957..b6a17767b 100755 --- a/test_regress/t/t_unopt_converge_run_bad.pl +++ b/test_regress/t/t_unopt_converge_run_bad.pl @@ -17,7 +17,7 @@ compile( execute( fails => 1, - expect => '%Error: \S+:\d+: Verilated model didn\'t converge', + expect_filename => $Self->{golden_filename}, ) if $Self->{vlt_all}; ok(1); diff --git a/test_regress/t/t_verilated_debug.out b/test_regress/t/t_verilated_debug.out index fbfd8e09a..f1bcca561 100644 --- a/test_regress/t/t_verilated_debug.out +++ b/test_regress/t/t_verilated_debug.out @@ -1,24 +1,24 @@ --V{t0,1}- Verilated::debug is on. Message prefix indicates {,}. --V{t0,2}+ Vt_verilated_debug::_ctor_var_reset +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_verilated_debug::_ctor_var_reset internalsDump: Version: Verilator ### Argv: obj_vlt/t_verilated_debug/Vt_verilated_debug scopesDump: --V{t0,3}+++++TOP Evaluate Vt_verilated_debug::eval --V{t0,4}+ Vt_verilated_debug::_eval_debug_assertions --V{t0,5}+ Vt_verilated_debug::_eval_initial --V{t0,6}+ Vt_verilated_debug::_eval_settle --V{t0,7}+ Vt_verilated_debug::_eval --V{t0,8}+ Vt_verilated_debug::_change_request --V{t0,9}+ Clock loop --V{t0,10}+ Vt_verilated_debug::_eval --V{t0,11}+ Vt_verilated_debug::_change_request --V{t0,12}+++++TOP Evaluate Vt_verilated_debug::eval --V{t0,13}+ Vt_verilated_debug::_eval_debug_assertions --V{t0,14}+ Clock loop --V{t0,15}+ Vt_verilated_debug::_eval --V{t0,16}+ Vt_verilated_debug::_sequent__TOP__1 +-V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval +-V{t#,#}+ Vt_verilated_debug::_eval_debug_assertions +-V{t#,#}+ Vt_verilated_debug::_eval_initial +-V{t#,#}+ Vt_verilated_debug::_eval_settle +-V{t#,#}+ Vt_verilated_debug::_eval +-V{t#,#}+ Vt_verilated_debug::_change_request +-V{t#,#}+ Clock loop +-V{t#,#}+ Vt_verilated_debug::_eval +-V{t#,#}+ Vt_verilated_debug::_change_request +-V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval +-V{t#,#}+ Vt_verilated_debug::_eval_debug_assertions +-V{t#,#}+ Clock loop +-V{t#,#}+ Vt_verilated_debug::_eval +-V{t#,#}+ Vt_verilated_debug::_sequent__TOP__1 *-* All Finished *-* --V{t0,17}+ Vt_verilated_debug::_change_request --V{t0,18}+ Vt_verilated_debug::final +-V{t#,#}+ Vt_verilated_debug::_change_request +-V{t#,#}+ Vt_verilated_debug::final