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_clock.cpp -- The clock channel.
23
24  Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21
25
26  CHANGE LOG IS AT THE END OF THE FILE
27 *****************************************************************************/
28
29// using notify_delayed().
30//
31// Revision 1.4  2006/01/18 21:42:26  acg
32// Andy Goodrich: Changes for check writer support, and tightening up sc_clock
33// port usage.
34//
35// Revision 1.3  2006/01/13 18:47:41  acg
36// Added $Log command so that CVS comments are reproduced in the source.
37//
38
39#include "sysc/communication/sc_clock.h"
40#include "sysc/communication/sc_communication_ids.h"
41#include "sysc/kernel/sc_simcontext.h"
42#include "sysc/kernel/sc_process.h"
43#include "sysc/kernel/sc_spawn.h"
44#include "sysc/utils/sc_utils_ids.h"
45
46namespace sc_core {
47
48// ----------------------------------------------------------------------------
49//  CLASS : sc_clock
50//
51//  The clock channel.
52// ----------------------------------------------------------------------------
53
54// constructors
55
56sc_clock::sc_clock() :
57    base_type( sc_gen_unique_name( "clock" ) ),
58    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
59    m_posedge_time(), m_negedge_time(),
60    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
61                          "_next_posedge_event").c_str()),
62    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
63                          "_next_negedge_event").c_str())
64
65{
66    init( sc_time::from_value(simcontext()->m_time_params->default_time_unit),
67	  0.5,
68	  SC_ZERO_TIME,
69	  true );
70
71    m_next_posedge_event.notify_internal( m_start_time );
72}
73
74sc_clock::sc_clock( const char* name_ ) :
75    base_type( name_ ),
76    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
77    m_posedge_time(), m_negedge_time(),
78    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
79			   std::string(name_) + "_next_posedge_event").c_str()),
80    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
81			   std::string(name_) + "_next_negedge_event").c_str())
82{
83    init( sc_time::from_value(simcontext()->m_time_params->default_time_unit),
84	  0.5,
85	  SC_ZERO_TIME,
86	  true );
87
88    m_next_posedge_event.notify_internal( m_start_time );
89}
90
91sc_clock::sc_clock( const char* name_,
92		    const sc_time& period_,
93		    double         duty_cycle_,
94		    const sc_time& start_time_,
95		    bool           posedge_first_ ) :
96    base_type( name_ ),
97    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
98    m_posedge_time(), m_negedge_time(),
99    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
100			   std::string(name_) + "_next_posedge_event").c_str()),
101    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
102			   std::string(name_) + "_next_negedge_event").c_str())
103{
104    init( period_,
105	  duty_cycle_,
106	  start_time_,
107	  posedge_first_ );
108
109    if( posedge_first_ ) {
110	// posedge first
111	m_next_posedge_event.notify_internal( m_start_time );
112    } else {
113	// negedge first
114	m_next_negedge_event.notify_internal( m_start_time );
115    }
116}
117
118sc_clock::sc_clock( const char* name_,
119		    double         period_v_,
120		    sc_time_unit   period_tu_,
121		    double         duty_cycle_ ) :
122    base_type( name_ ),
123    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
124    m_posedge_time(), m_negedge_time(),
125    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
126			   std::string(name_) + "_next_posedge_event").c_str()),
127    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
128			   std::string(name_) + "_next_negedge_event").c_str())
129{
130    init( sc_time( period_v_, period_tu_, simcontext() ),
131	  duty_cycle_,
132	  SC_ZERO_TIME,
133	  true );
134
135    // posedge first
136    m_next_posedge_event.notify_internal( m_start_time );
137}
138
139sc_clock::sc_clock( const char* name_,
140		    double         period_v_,
141		    sc_time_unit   period_tu_,
142		    double         duty_cycle_,
143		    double         start_time_v_,
144		    sc_time_unit   start_time_tu_,
145		    bool           posedge_first_ ) :
146    base_type( name_ ),
147    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
148    m_posedge_time(), m_negedge_time(),
149    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
150			   std::string(name_) + "_next_posedge_event").c_str()),
151    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
152			   std::string(name_) + "_next_negedge_event").c_str())
153{
154    init( sc_time( period_v_, period_tu_, simcontext() ),
155	  duty_cycle_,
156	  sc_time( start_time_v_, start_time_tu_, simcontext() ),
157	  posedge_first_ );
158
159    if( posedge_first_ ) {
160	// posedge first
161	m_next_posedge_event.notify_internal( m_start_time );
162    } else {
163	// negedge first
164	m_next_negedge_event.notify_internal( m_start_time );
165    }
166}
167
168// for backward compatibility with 1.0
169sc_clock::sc_clock( const char* name_,
170		    double         period_,      // in default time units
171		    double         duty_cycle_,
172		    double         start_time_,  // in default time units
173		    bool           posedge_first_ ) :
174    base_type( name_ ),
175    m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(),
176    m_posedge_time(), m_negedge_time(),
177    m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
178			   std::string(name_) + "_next_posedge_event").c_str()),
179    m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) +
180			   std::string(name_) + "_next_negedge_event").c_str())
181{
182    static bool warn_sc_clock=true;
183    if ( warn_sc_clock )
184    {
185        warn_sc_clock = false;
186	SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
187	   "\n    sc_clock(const char*, double, double, double, bool)\n"
188	   "    is deprecated use a form that includes sc_time or\n"
189	   "    sc_time_unit");
190    }
191
192    sc_time default_time =
193      sc_time::from_value( simcontext()->m_time_params->default_time_unit );
194
195    init( ( period_ * default_time ),
196	  duty_cycle_,
197	  ( start_time_ * default_time ),
198	  posedge_first_ );
199
200    if( posedge_first_ ) {
201	// posedge first
202	m_next_posedge_event.notify_internal( m_start_time );
203    } else {
204	// negedge first
205	m_next_negedge_event.notify_internal( m_start_time );
206    }
207}
208
209
210//------------------------------------------------------------------------------
211//"sc_clock::before_end_of_elaboration"
212//
213// This callback is used to spawn the edge processes for this object instance.
214// The processes are created here rather than the constructor for the object
215// so that the processes are registered with the global simcontext rather
216// than the scope of the clock's parent.
217//------------------------------------------------------------------------------
218#if ( defined(_MSC_VER) && _MSC_VER < 1300 ) //VC++6.0 doesn't support sc_spawn with functor.
219#   define sc_clock_posedge_callback(ptr) sc_clock_posedge_callback
220
221#   define sc_clock_negedge_callback(ptr) sc_clock_negedge_callback
222
223#   define sc_spawn(a,b,c) { \
224        sc_process_handle result(new sc_spawn_object<a>(a(this),b,c)); \
225    }
226#endif // ( defined(_MSC_VER) && _MSC_VER < 1300 )
227
228void sc_clock::before_end_of_elaboration()
229{
230    std::string gen_base;
231    sc_spawn_options posedge_options;	// Options for posedge process.
232    sc_spawn_options negedge_options;	// Options for negedge process.
233
234    posedge_options.spawn_method();
235    posedge_options.dont_initialize();
236    posedge_options.set_sensitivity(&m_next_posedge_event);
237    gen_base = basename();
238    gen_base += "_posedge_action";
239    sc_spawn(sc_clock_posedge_callback(this),
240	sc_gen_unique_name( gen_base.c_str() ), &posedge_options);
241
242    negedge_options.spawn_method();
243    negedge_options.dont_initialize();
244    negedge_options.set_sensitivity(&m_next_negedge_event);
245    gen_base = basename();
246    gen_base += "_negedge_action";
247    sc_spawn( sc_clock_negedge_callback(this),
248    	sc_gen_unique_name( gen_base.c_str() ), &negedge_options );
249}
250
251//clear VC++6.0 macros
252#undef sc_clock_posedge_callback
253#undef sc_clock_negedge_callback
254#undef sc_spawn
255
256// destructor (does nothing)
257
258sc_clock::~sc_clock()
259{}
260
261void sc_clock::register_port( sc_port_base& /*port*/, const char* if_typename_ )
262{
263    std::string nm( if_typename_ );
264    if( nm == typeid( sc_signal_inout_if<bool> ).name() ) {
265	    SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_BIND_CLOCK_TO_OUTPUT_, "");
266    }
267}
268
269void
270sc_clock::write( const bool& /* value */ )
271{
272    SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_WRITE_TO_CLOCK_, "");
273}
274
275// interface methods
276
277// get the current time
278
279const sc_time&
280sc_clock::time_stamp()
281{
282    return sc_time_stamp();
283}
284
285
286// error reporting
287
288void
289sc_clock::report_error( const char* id, const char* add_msg ) const
290{
291    char msg[BUFSIZ];
292    if( add_msg != 0 ) {
293	std::sprintf( msg, "%s: clock '%s'", add_msg, name() );
294    } else {
295	std::sprintf( msg, "clock '%s'", name() );
296    }
297    SC_REPORT_ERROR( id, msg );
298}
299
300
301void
302sc_clock::init( const sc_time& period_,
303		double         duty_cycle_,
304		const sc_time& start_time_,
305		bool           posedge_first_ )
306{
307    if( period_ == SC_ZERO_TIME ) {
308	report_error( SC_ID_CLOCK_PERIOD_ZERO_,
309		      "increase the period" );
310    }
311    m_period = period_;
312    m_posedge_first = posedge_first_;
313
314    if( duty_cycle_ <= 0.0 || duty_cycle_ >= 1.0 ) {
315	m_duty_cycle = 0.5;
316    } else {
317	m_duty_cycle = duty_cycle_;
318    }
319
320    m_negedge_time = m_period * m_duty_cycle;
321    m_posedge_time = m_period - m_negedge_time;
322
323    if( m_negedge_time == SC_ZERO_TIME ) {
324	report_error( SC_ID_CLOCK_HIGH_TIME_ZERO_,
325		      "increase the period or increase the duty cycle" );
326    }
327    if( m_posedge_time == SC_ZERO_TIME ) {
328	report_error( SC_ID_CLOCK_LOW_TIME_ZERO_,
329		      "increase the period or decrease the duty cycle" );
330    }
331
332    if( posedge_first_ ) {
333	this->m_cur_val = false;
334	this->m_new_val = false;
335    } else {
336	this->m_cur_val = true;
337	this->m_new_val = true;
338    }
339
340    m_start_time = start_time_;
341
342}
343
344} // namespace sc_core
345
346/*****************************************************************************
347
348  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
349  changes you are making here.
350
351      Name, Affiliation, Date: Bishnupriya Bhattacharya, Cadence Design Systems,
352                               Andy Goodrich, Forte Design Systems,
353                               3 October, 2003
354  Description of Modification: sc_clock inherits from sc_signal<bool> only
355                               instead of sc_signal_in_if<bool> and sc_module.
356                               The 2 methods posedge_action() and
357                               negedge_action() are created using sc_spawn().
358                               boost::bind() is not required, instead a local
359                               bind function can be used since the signatures
360                               of the spawned functions are statically known.
361
362      Name, Affiliation, Date:
363  Description of Modification:
364
365 *****************************************************************************/
366
367// $Log: sc_clock.cpp,v $
368// Revision 1.7  2011/08/26 20:45:39  acg
369//  Andy Goodrich: moved the modification log to the end of the file to
370//  eliminate source line number skew when check-ins are done.
371//
372// Revision 1.6  2011/08/24 22:05:35  acg
373//  Torsten Maehne: initialization changes to remove warnings.
374//
375// Revision 1.5  2011/08/15 16:43:24  acg
376//  Torsten Maehne: changes to remove unused argument warnings.
377//
378// Revision 1.4  2011/03/12 21:07:42  acg
379//  Andy Goodrich: changes to kernel generated event support.
380//
381// Revision 1.3  2011/03/06 15:55:08  acg
382//  Andy Goodrich: Changes for named events.
383//
384// Revision 1.2  2011/02/18 20:23:45  acg
385//  Andy Goodrich: Copyright update.
386//
387// Revision 1.1.1.1  2006/12/15 20:20:04  acg
388// SystemC 2.3
389//
390// Revision 1.8  2006/04/18 23:36:50  acg
391//  Andy Goodrich: made add_trace_internal public until I can figure out
392//  how to do a friend specification for sc_trace in an environment where
393//  there are partial template and full template specifications for its
394//  arguments.
395//
396// Revision 1.7  2006/04/17 16:38:42  acg
397//  Andy Goodrich: added more context to the deprecation message for the
398//  sc_clock constructor.
399//
400// Revision 1.6  2006/01/25 00:31:11  acg
401//  Andy Goodrich: Changed over to use a standard message id of
402//  SC_ID_IEEE_1666_DEPRECATION for all deprecation messages.
403//
404// Revision 1.5  2006/01/24 20:43:24  acg
405// Andy Goodrich: convert notify_delayed() calls into notify_internal() calls.
406// notify_internal() is an implementation dependent version of notify_delayed()
407// that is simpler, and does not trigger the deprecation warning one would get
408
409// Taf!
410