1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  sc_trace_file_base.cpp - Shared internal tracing implementation
23
24  Original Author: Philipp A. Hartmann, OFFIS, 2013-11-15
25
26  CHANGE LOG AT END OF FILE
27 *****************************************************************************/
28
29/*****************************************************************************
30
31   Acknowledgement: The tracing mechanism is based on the tracing
32   mechanism developed at Infineon (formerly Siemens HL). Though this
33   code is somewhat different, and significantly enhanced, the basics
34   are identical to what was originally contributed by Infineon.  The
35   contribution of Infineon in the development of this tracing
36   technology is hereby acknowledged.
37
38 *****************************************************************************/
39
40#include <ctime>
41
42#include "sysc/tracing/sc_trace_file_base.h"
43#include "sysc/kernel/sc_simcontext.h"
44#include "sysc/kernel/sc_simcontext_int.h"
45
46#if SC_TRACING_PHASE_CALLBACKS_
47#  include "sysc/kernel/sc_object_int.h"
48#endif
49
50namespace sc_core {
51
52bool sc_trace_file_base::tracing_initialized_ = false;
53
54
55sc_trace_file_base::sc_trace_file_base( const char* name, const char* extension )
56  : sc_trace_file()
57#if SC_TRACING_PHASE_CALLBACKS_
58  , sc_object( sc_gen_unique_name("$$$$kernel_tracefile$$$$") )
59#endif
60  , fp(0)
61  , timescale_unit()
62  , timescale_set_by_user(false)
63  , filename_()
64  , initialized_(false)
65  , trace_delta_cycles_(false)
66{
67    if( !name || !*name ) {
68        SC_REPORT_ERROR( SC_ID_TRACING_FOPEN_FAILED_, "no name given" );
69        return;
70    } else {
71        std::stringstream ss;
72        ss << name << "." << extension;
73        ss.str().swap( filename_ );
74    }
75
76#if SC_TRACING_PHASE_CALLBACKS_ == 1
77    // remove from hierarchy
78    sc_object::detach();
79    // register regular (non-delta) callbacks
80    sc_object::register_simulation_phase_callback(
81        // Note: Usually, one would expect to dump the initial values
82        //       of the traced variables at the end of the initialization
83        //       phase.  The "non-callback" implementation dumps those
84        //       values only after the first delta cycle, though.
85        // SC_END_OF_INITIALIZATION |
86        SC_BEFORE_TIMESTEP |
87        SC_PAUSED | SC_STOPPED
88    );
89#else // explicitly register with simcontext
90    sc_get_curr_simcontext()->add_trace_file( this );
91#endif
92}
93
94sc_trace_file_base::~sc_trace_file_base()
95{
96    if( fp )
97        fclose(fp);
98
99#if SC_TRACING_PHASE_CALLBACKS_ == 0
100    // unregister from simcontext
101    sc_get_curr_simcontext()->remove_trace_file( this );
102#endif
103}
104
105/*****************************************************************************/
106// simulation phase callback based trigger
107//
108//  The tracing updates are triggered
109//    (- at the end of the initialization phase [disabled for now])
110//    - before an update of the simulation time
111//    - before returning to sc_start (via sc_pause() or sc_stop())
112//    - after an update phase (if delta cycles need to be traced)
113//
114#if SC_TRACING_PHASE_CALLBACKS_
115void
116sc_trace_file_base::simulation_phase_callback()
117{
118    // delta cycle is traced at the end of an update phase
119    cycle( simcontext()->get_status() == SC_END_OF_UPDATE );
120}
121#endif // SC_TRACING_PHASE_CALLBACKS_
122
123/*****************************************************************************/
124
125bool
126sc_trace_file_base::initialize()
127{
128    if( initialized_ )
129      return false;
130
131    initialized_ = true;
132
133    if( !tracing_initialized_ ) {
134        tracing_initialized_ = true;
135        bool running_regression = ( getenv( "SYSTEMC_REGRESSION" ) != NULL );
136
137        // hide some messages during regression
138        if( running_regression ) {
139          sc_report_handler::set_actions( SC_ID_TRACING_TIMESCALE_DEFAULT_
140                                        , SC_INFO,    SC_DO_NOTHING );
141          sc_report_handler::set_actions( SC_ID_TRACING_VCD_DUPLICATE_TIME_
142                                        , SC_WARNING, SC_DO_NOTHING );
143        }
144    }
145
146    // open trace file
147    if(!fp) open_fp();
148
149    // setup timescale
150    if( !timescale_set_by_user )
151    {
152        timescale_unit = sc_get_time_resolution().to_seconds();
153
154        std::stringstream ss;
155        ss << sc_get_time_resolution() << " (" << filename_ << ")";
156        SC_REPORT_INFO( SC_ID_TRACING_TIMESCALE_DEFAULT_
157                      , ss.str().c_str() );
158    }
159
160    // initialize derived tracing implementation class (VCD/WIF)
161    do_initialize();
162
163    return initialized_;
164}
165
166void
167sc_trace_file_base::open_fp()
168{
169    sc_assert( !fp );
170    fp = fopen( filename(), "w" );
171    if( !fp ) {
172        SC_REPORT_ERROR( SC_ID_TRACING_FOPEN_FAILED_, filename() );
173        std::terminate(); // can't recover from here
174    }
175}
176
177void
178sc_trace_file_base::delta_cycles( bool flag )
179{
180    trace_delta_cycles_ = flag;
181#if SC_TRACING_PHASE_CALLBACKS_
182    if( trace_delta_cycles_ ) {
183        sc_object::register_simulation_phase_callback( SC_END_OF_UPDATE );
184    } else {
185        sc_object::unregister_simulation_phase_callback( SC_END_OF_UPDATE );
186    }
187#endif
188}
189
190void
191sc_trace_file_base::set_time_unit( double v, sc_time_unit tu )
192{
193    if( initialized_ )
194    {
195        std::stringstream ss;
196        ss << filename_ << "\n"
197           "\tTimescale unit cannot be changed once tracing has begun.\n"
198           "\tTo change the scale, create a new trace file.";
199        SC_REPORT_ERROR( SC_ID_TRACING_ALREADY_INITIALIZED_
200                       , ss.str().c_str() );
201        return;
202    }
203
204    switch ( tu )
205    {
206      case SC_FS:  v = v * 1e-15; break;
207      case SC_PS:  v = v * 1e-12; break;
208      case SC_NS:  v = v * 1e-9;  break;
209      case SC_US:  v = v * 1e-6;  break;
210      case SC_MS:  v = v * 1e-3;  break;
211      case SC_SEC:                break;
212      default: {
213            std::stringstream ss;
214            ss << "unknown time unit:" << tu
215               << " (" << filename_ << ")";
216            SC_REPORT_WARNING( SC_ID_TRACING_TIMESCALE_UNIT_
217                             , ss.str().c_str() );
218        }
219    }
220
221    timescale_set_by_user = true;
222    timescale_unit = v;
223
224    // EMIT ADVISORY MESSAGE ABOUT CHANGE IN TIME SCALE:
225    {
226      std::stringstream ss;
227      ss << sc_time( timescale_unit, SC_SEC )
228         << " (" << filename_ << ")";
229      SC_REPORT_INFO( SC_ID_TRACING_TIMESCALE_UNIT_, ss.str().c_str() );
230    }
231}
232
233bool
234sc_trace_file_base::add_trace_check( const std::string & name ) const
235{
236    if( !initialized_ ) return true;
237
238    std::stringstream ss;
239    ss << "sc_trace() failed:\n"
240         "\tNo traces can be added to "
241         "'" << filename_  << "'"
242         " once trace recording has started.\n"
243         "\tTo add tracing of '" << name << "', create a new trace file.";
244
245    SC_REPORT_ERROR( SC_ID_TRACING_ALREADY_INITIALIZED_
246                   , ss.str().c_str() );
247    return false;
248}
249
250// obtain formatted time string
251std::string localtime_string()
252{
253    char buf[200];
254    time_t long_time;
255    time(&long_time);
256    struct tm* p_tm = localtime(&long_time);
257    strftime(buf, 199, "%b %d, %Y       %H:%M:%S", p_tm);
258    return buf;
259}
260
261
262} // namespace sc_core
263
264/*****************************************************************************
265
266  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
267  changes you are making here.
268
269      Name, Affiliation, Date:
270  Description of Modification:
271
272 *****************************************************************************/
273// Taf!
274