From 4591f35b7cf70709e7e063e33999a60e48021c2b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 16 Jul 2008 14:06:08 -0400 Subject: [PATCH] Add --autoflush option --- Changes | 2 ++ bin/verilator | 7 +++++++ src/V3EmitC.cpp | 14 +++++++++----- src/V3LinkResolve.cpp | 4 +++- src/V3Options.cpp | 2 ++ src/V3Options.h | 2 ++ src/V3Premit.cpp | 23 +++++++++++++++++++++++ src/V3Width.cpp | 6 ++++-- test_regress/t/t_sys_file_autoflush.pl | 22 ++++++++++++++++++++++ test_regress/t/t_sys_file_basic.pl | 1 + test_regress/t/t_sys_file_basic.v | 8 +++++++- 11 files changed, 82 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_sys_file_autoflush.pl diff --git a/Changes b/Changes index 699506b6c..4167db0f7 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,8 @@ indicates the contributor was also the author of the fix; Thanks! ** Add --x-assign=fast option, and make it the default. This chooses performance over reset debugging. See the manual. +** Add --autoflush, for flushing streams after $display. [Steve Tong] + *** Add $feof, $fgetc, $fgets, $fflush, $fscanf, $sscanf. [Holger Waechtler] *** Add $stime. [Holger Waechtler] diff --git a/bin/verilator b/bin/verilator index 8f7b6d653..1bc30279d 100755 --- a/bin/verilator +++ b/bin/verilator @@ -177,6 +177,7 @@ descriptions in the next sections for more information. {file.c/cc/cpp} Optional C++ files to link in --assert Enable all assertions + --autoflush Flush streams after all $displays --bin Override Verilator binary --cc Create C++ output --compiler Tune for specified C++ compiler @@ -254,6 +255,12 @@ desired, but other assertions are, use --assert --nopsl.) See also --x-assign; setting "--x-assign unique" may be desirable. +=item --autoflush + +After every $display or $fdisplay, flush the output stream. This insures +that messages will appear immediately but may reduce performance. Defaults +off, which will buffer output as provided by the normal C stdio calls. + =item --bin I Rarely needed. Override the default filename for Verilator itself. When a diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index a01030586..03f4e996d 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -306,11 +306,15 @@ public: puts("=0; }\n"); } virtual void visit(AstFFlush* nodep, AstNUser*) { - puts("if ("); - nodep->filep()->iterateAndNext(*this); - puts(") { fflush (VL_CVT_Q_FP("); - nodep->filep()->iterateAndNext(*this); - puts(")); "); + if (!nodep->filep()) { + puts("fflush (stdout);\n"); + } else { + puts("if ("); + nodep->filep()->iterateAndNext(*this); + puts(") { fflush (VL_CVT_Q_FP("); + nodep->filep()->iterateAndNext(*this); + puts(")); }\n"); + } } virtual void visit(AstWhile* nodep, AstNUser*) { nodep->precondsp()->iterateAndNext(*this); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 48132181f..85750d6e8 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -368,7 +368,9 @@ private: } virtual void visit(AstFFlush* nodep, AstNUser*) { nodep->iterateChildren(*this); - expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); + if (nodep->filep()) { + expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); + } } virtual void visit(AstFGetC* nodep, AstNUser*) { nodep->iterateChildren(*this); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 28b41968d..a6fc660a5 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -563,6 +563,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) { else if ( onoff (sw, "-MMD", flag/*ref*/) ) { m_makeDepend = flag; } else if ( onoff (sw, "-MP", flag/*ref*/) ) { m_makePhony = flag; } else if ( onoff (sw, "-assert", flag/*ref*/) ) { m_assert = flag; m_psl = flag; } + else if ( onoff (sw, "-autoflush", flag/*ref*/) ) { m_autoflush = flag; } else if ( !strcmp (sw, "-cc") ) { m_outFormatOk = true; m_systemC = false; m_systemPerl = false; } else if ( onoff (sw, "-coverage", flag/*ref*/) ) { coverage(flag); } else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; } @@ -793,6 +794,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename) { V3Options::V3Options() { m_impp = new V3OptionsImp; + m_autoflush = false; m_coverageLine = false; m_coverageUser = false; m_debugCheck = false; diff --git a/src/V3Options.h b/src/V3Options.h index 1d73d60ff..b7f4990f3 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -86,6 +86,7 @@ class V3Options { bool m_makeDepend; // main switch: -MMD bool m_makePhony; // main switch: -MP bool m_assert; // main switch: --assert + bool m_autoflush; // main switch: --autoflush bool m_coverageLine; // main switch: --coverage-block bool m_coverageUser; // main switch: --coverage-func bool m_debugCheck; // main switch: --debug-check @@ -182,6 +183,7 @@ class V3Options { bool skipIdentical() const { return m_skipIdentical; } bool stats() const { return m_stats; } bool assertOn() const { return m_assert; } // assertOn as "assert" may be defined + bool autoflush() const { return m_autoflush; } bool coverage() const { return m_coverageUser || m_coverageLine; } bool coverageLine() const { return m_coverageLine; } bool coverageUser() const { return m_coverageUser; } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index c06db3532..071a8e854 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -23,6 +23,9 @@ // For each wide OP, make a a temporary variable with the wide value // For each deep expression, assign expression to temporary. // +// Each display (independant transformation; here as Premit is a good point) +// If autoflush, insert a flush +// //************************************************************************* #include "config_build.h" @@ -264,6 +267,26 @@ private: checkNode(nodep); } + // Autoflush + virtual void visit(AstDisplay* nodep, AstNUser* vup) { + startStatement(nodep); + nodep->iterateChildren(*this); + m_stmtp = NULL; + if (v3Global.opt.autoflush()) { + AstNode* searchp = nodep->nextp(); + while (searchp && searchp->castComment()) searchp = searchp->nextp(); + if (searchp + && searchp->castDisplay() + && nodep->filep()->sameTree(searchp->castDisplay()->filep())) { + // There's another display next; we can just wait to flush + } else { + UINFO(4,"Autoflush "<addNextHere(new AstFFlush(nodep->fileline(), + nodep->filep()->cloneTree(true))); + } + } + } + //-------------------- // Default: Just iterate virtual void visit(AstVar* nodep, AstNUser*) {} // Don't hit varrefs under vars diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 4bfb0e9ac..2a4ec3303 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -586,8 +586,10 @@ private: widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); } virtual void visit(AstFFlush* nodep, AstNUser*) { - nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); - widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); + if (nodep->filep()) { + nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); + widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); + } } virtual void visit(AstFGetC* nodep, AstNUser* vup) { nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); diff --git a/test_regress/t/t_sys_file_autoflush.pl b/test_regress/t/t_sys_file_autoflush.pl new file mode 100755 index 000000000..4e23b0ab0 --- /dev/null +++ b/test_regress/t/t_sys_file_autoflush.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.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 +# General Public License or the Perl Artistic License. + +top_filename("t/t_sys_file_basic.v"); + +compile ( + v_flags2 => ['+incdir+../include', + '+define+AUTOFLUSH'], + verilator_flags2 => ['--autoflush'], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_sys_file_basic.pl b/test_regress/t/t_sys_file_basic.pl index 9ea9ad00a..132ac60c5 100755 --- a/test_regress/t/t_sys_file_basic.pl +++ b/test_regress/t/t_sys_file_basic.pl @@ -9,6 +9,7 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } unlink("obj_dir/t_sys_file_basic_test.log"); compile ( + v_flags2 => ['+incdir+../include'], ); execute ( diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index c4a3d7d7f..00f2eaed1 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -28,7 +28,13 @@ module t; if (!$feof(file)) $stop; `endif - file = $fopen("obj_dir/t_sys_file_basic_test.log","w"); // The "w" is required so we get a FD not a MFD +`ifdef AUTOFLUSH + // The "w" is required so we get a FD not a MFD + file = $fopen("obj_dir/t_sys_file_autoflush.log","w"); +`else + // The "w" is required so we get a FD not a MFD + file = $fopen("obj_dir/t_sys_file_basic_test.log","w"); +`endif if ($feof(file)) $stop; $fdisplay(file, "[%0t] hello v=%x", $time, 32'h12345667);