diff --git a/Changes b/Changes index fb84803db..f02b98f78 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix not tracing modules following primitives, bug837. [Jie Xu] +**** Fix trace overflow on huge arrays, bug834. [Geoff Barrett] + * Verilator 3.864 2014-09-21 diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 3919c4035..8aa36e291 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -261,6 +261,20 @@ void VerilatedVcd::printTime (vluint64_t timeui) { printQuad(timeui); } +void VerilatedVcd::bufferResize(vluint64_t minsize) { + // minsize is size of largest write. We buffer at least 8 times as much data, + // writing when we are 3/4 full (with thus 2*minsize remaining free) + if (VL_UNLIKELY(minsize > m_wrChunkSize)) { + char* oldbufp = m_wrBufp; + m_wrChunkSize = minsize*2; + m_wrBufp = new char [m_wrChunkSize * 8]; + memcpy(m_wrBufp, oldbufp, m_writep - oldbufp); + m_writep = m_wrBufp + (m_writep - oldbufp); + m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; + delete oldbufp; oldbufp=NULL; + } +} + void VerilatedVcd::bufferFlush () { // We add output data to m_writep. // When it gets nearly full we dump it using this routine which calls write() @@ -444,6 +458,9 @@ void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up } + // Make sure write buffer is large enough (one character per bit), plus header + bufferResize(bits+1024); + // Save declaration info VerilatedVcdSig sig = VerilatedVcdSig(code, bits); m_sigs.push_back(sig); @@ -522,7 +539,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum void VerilatedVcd::fullDouble (vluint32_t code, const double newval) { (*((double*)&m_sigs_oldvalp[code])) = newval; - // Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes) + // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", newval); m_writep += strlen(m_writep); *m_writep++=' '; printCode(code); *m_writep++='\n'; @@ -530,7 +547,7 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) { } void VerilatedVcd::fullFloat (vluint32_t code, const float newval) { (*((float*)&m_sigs_oldvalp[code])) = newval; - // Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes) + // Buffer can't overflow before sprintf; we sized during declaration sprintf(m_writep, "r%.16g", (double)newval); m_writep += strlen(m_writep); *m_writep++=' '; printCode(code); *m_writep++='\n'; diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index f6c62ef26..daf4c3b2f 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -77,7 +77,9 @@ private: vluint64_t m_timeLastDump; ///< Last time we did a dump char* m_wrBufp; ///< Output buffer + char* m_wrFlushp; ///< Output buffer flush trigger location char* m_writep; ///< Write pointer into output buffer + vluint64_t m_wrChunkSize; ///< Output buffer size vluint64_t m_wroteBytes; ///< Number of bytes written to this file vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values @@ -87,13 +89,12 @@ private: NameMap* m_namemapp; ///< List of names for the header static vector s_vcdVecp; ///< List of all created traces - inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation - inline static size_t bufferInsertSize() { return 16*1024; } + void bufferResize(vluint64_t minsize); void bufferFlush(); - void bufferCheck() { + inline void bufferCheck() { // Flush the write buffer if there's not enough space left for new information // We only call this once per vector, so we need enough slop for a very wide "b###" line - if (VL_UNLIKELY(m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize())))) { + if (VL_UNLIKELY(m_writep > m_wrFlushp)) { bufferFlush(); } } @@ -135,17 +136,19 @@ protected: public: // CREATORS VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) { - m_wrBufp = new char [bufferSize()]; - m_writep = m_wrBufp; m_namemapp = NULL; m_timeRes = m_timeUnit = 1e-9; m_timeLastDump = 0; m_sigs_oldvalp = NULL; m_evcd = false; m_scopeEscape = '.'; // Backward compatibility - m_wroteBytes = 0; m_fd = 0; m_fullDump = true; + m_wrChunkSize = 8*1024; + m_wrBufp = new char [m_wrChunkSize*8]; + m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; + m_writep = m_wrBufp; + m_wroteBytes = 0; } ~VerilatedVcd(); diff --git a/test_regress/t/t_trace_array.pl b/test_regress/t/t_trace_array.pl new file mode 100755 index 000000000..12e9fb138 --- /dev/null +++ b/test_regress/t/t_trace_array.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-2009 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 => ['--cc --trace --trace-structs'], + ); + +execute ( + check_finished=>1, + ); + +file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); + +ok(1); +1; diff --git a/test_regress/t/t_trace_array.v b/test_regress/t/t_trace_array.v new file mode 100644 index 000000000..6cf6ce82e --- /dev/null +++ b/test_regress/t/t_trace_array.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2014 by Wilson Snyder. + +module t (clk); + input clk; + integer cyc=0; + + // Trace would overflow at 256KB which is 256 kb dump, 16 kb in a chunk + + typedef struct packed { + logic [1024*1024:0] d; + } s1_t; // 128 b + + s1_t biggie; + + always @ (posedge clk) begin + cyc <= cyc + 1; + biggie [ cyc +: 32 ] <= 32'hfeedface; + if (cyc == 5) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule