SystemC 3.0.0
Accellera SystemC proof-of-concept library
sc_runnable_int.h
Go to the documentation of this file.
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_runnable_int.h -- For inline definitions of some utility functions.
23 DO NOT EXPORT THIS INCLUDE FILE. Include this file
24 after "sc_process_int.h" so that we can get the base
25 class right.
26
27 Original Author: Bishnupriya Bhattacharya , Cadence Design, 28th July, 2003
28
29 CHANGE LOG AT THE END OF THE FILE
30 ******************************************************************************/
31
32#ifndef SC_RUNNABLE_INT_H
33#define SC_RUNNABLE_INT_H
34
35
39
40// DEBUGGING MACROS:
41//
42// DEBUG_MSG(NAME,P,MSG)
43// MSG = message to print
44// NAME = name that must match the process for the message to print, or
45// null if the message should be printed unconditionally.
46// P = pointer to process message is for, or NULL in which case the
47// message will not print.
48#if 0
49# include <cstring>
50# define DEBUG_NAME ""
51# define DEBUG_MSG(NAME,P,MSG) \
52 { \
53 if ( P && ( (std::strlen(NAME)==0) || !std::strcmp(NAME,P->name())) ) \
54 std::cout << "**** " << sc_time_stamp() << " (" \
55 << sc_get_current_process_name("** NONE **") << "): " << MSG \
56 << " - " << P->name() << std::endl; \
57 }
58#else
59# define DEBUG_MSG(NAME,P,MSG)
60#endif
61
62namespace sc_core {
63
64// The address of the queue heads for the method and thread runnable queuss
65// are used as the "end of queue" values in the m_execute_p field of an
66// sc_process_b instance. The queues are processed by walking the m_execute_p
67// values of the sc_process_b instances in the queue. When the m_execute_p value
68// is the queue head that indicates that sc_process_b instance is the last entry
69// in the queue.
70//
71// This allows a null m_execute_p field in an sc_process_b instance to
72// indicate that the instance has not on the queued. That prevents an sc_process_b
73// instance from being queued twice.
74//
75// Not using a separate field in a runnable entry to indicate when it is queued
76// saves instructions in a piece of code that gets executed millions of times in
77// a simulation.
78
79#define SC_NO_METHODS m_methods_push_head
80#define SC_NO_THREADS m_threads_push_head
81
82
83//------------------------------------------------------------------------------
84//"sc_runnable::dump"
85//
86// This method dumps the contents of this object instance.
87//------------------------------------------------------------------------------
88inline void sc_runnable::dump() const
89{
90 // Dump the thread queues:
91
92 std::cout << "thread pop queue: " << std::endl;
93 for ( sc_thread_handle p = m_threads_pop; p != SC_NO_THREADS;
94 p = p->next_runnable() )
95 {
96 std::cout << " " << p << std::endl;
97 }
98
99 std::cout << "thread push queue: " << std::endl;
100 for ( sc_thread_handle p = m_threads_push_head->next_runnable();
101 p != SC_NO_THREADS; p = p->next_runnable() )
102 {
103 std::cout << " " << p << std::endl;
104 }
105}
106
107//------------------------------------------------------------------------------
108//"sc_runnable::execute_method_next"
109//
110// This method pushes the the supplied method to execute as the next process.
111// This is done by pushing it onto the front of the m_methods_pop.
112// method_h -> method process to add to the queue.
113//------------------------------------------------------------------------------
115{
116 DEBUG_MSG(DEBUG_NAME,method_h,"pushing this method to execute next");
117 method_h->set_next_runnable( m_methods_pop );
118 m_methods_pop = method_h;
119}
120
121//------------------------------------------------------------------------------
122//"sc_runnable::execute_thread_next"
123//
124// This method pushes the the supplied thread to execute as the next process.
125// This is done by pushing it onto the front of the m_threads_pop.
126// thread_h -> thread process to add to the queue.
127//------------------------------------------------------------------------------
129{
130 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing this thread to execute next");
131 thread_h->set_next_runnable( m_threads_pop );
132 m_threads_pop = thread_h;
133}
134
135//------------------------------------------------------------------------------
136//"sc_runnable::init"
137//
138// This method initializes this object instance. Note we allocate the queue
139// heads if necessary. This is done here rather than in the constructor for
140// this class to eliminate CTOR processing errors with gcc.
141//------------------------------------------------------------------------------
142inline void sc_runnable::init()
143{
144 if ( !m_methods_push_head )
145 {
146 m_methods_push_head = new sc_method_process("methods_push_head", true,
147 sc_entry_func(), 0, 0);
148 m_methods_push_head->dont_initialize(true);
149 m_methods_push_head->detach();
150 }
151 m_methods_pop = SC_NO_METHODS;
152 m_methods_push_tail = m_methods_push_head;
153 m_methods_push_head->set_next_runnable(SC_NO_METHODS);
154
155 if ( !m_threads_push_head )
156 {
157 m_threads_push_head = new sc_thread_process("threads_push_head", true,
158 sc_entry_func(), 0, 0);
159 m_threads_push_head->dont_initialize(true);
160 m_threads_push_head->detach();
161 }
162 m_threads_pop = SC_NO_THREADS;
163 m_threads_push_head->set_next_runnable(SC_NO_THREADS);
164 m_threads_push_tail = m_threads_push_head;
165}
166
167
168//------------------------------------------------------------------------------
169//"sc_runnable::is_empty"
170//
171// This method returns true if the push queue is empty, or false if not.
172//------------------------------------------------------------------------------
173inline bool sc_runnable::is_empty() const
174{
175 return m_methods_push_head->next_runnable() == SC_NO_METHODS &&
176 m_methods_pop == SC_NO_METHODS &&
177 m_threads_push_head->next_runnable() == SC_NO_THREADS &&
178 m_threads_pop == SC_NO_THREADS;
179}
180
181
182//------------------------------------------------------------------------------
183//"sc_runnable::is_initialized"
184//
185// This method returns true if the push queue is already initialized.
186//------------------------------------------------------------------------------
188{
189 return m_methods_push_head && m_threads_push_head;
190}
191
192
193//------------------------------------------------------------------------------
194//"sc_runnable::push_back_method"
195//
196// This method pushes the supplied method process onto the back of the queue of
197// runnable method processes.
198// method_h -> method process to add to the queue.
199//------------------------------------------------------------------------------
201{
202 // sc_assert( method_h->next_runnable() == 0 ); // Can't queue twice.
203 DEBUG_MSG(DEBUG_NAME,method_h,"pushing back method");
204 method_h->set_next_runnable(SC_NO_METHODS);
205 m_methods_push_tail->set_next_runnable(method_h);
206 m_methods_push_tail = method_h;
207}
208
209
210//------------------------------------------------------------------------------
211//"sc_runnable::push_back_thread"
212//
213// This method pushes the supplied thread process onto the back of the queue of
214// runnable thread processes.
215// thread_h -> thread process to add to the queue.
216//------------------------------------------------------------------------------
218{
219 // sc_assert( thread_h->next_runnable() == 0 ); // Can't queue twice.
220 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing back thread");
221 thread_h->set_next_runnable(SC_NO_THREADS);
222 m_threads_push_tail->set_next_runnable(thread_h);
223 m_threads_push_tail = thread_h;
224}
225
226
227//------------------------------------------------------------------------------
228//"sc_runnable::push_front_method"
229//
230// This method pushes the supplied method process onto the front of the queue of
231// runnable method processes. If the queue is empty the process is the tail
232// also.
233// method_h -> method process to add to the queue.
234//------------------------------------------------------------------------------
236{
237 // sc_assert( method_h->next_runnable() == 0 ); // Can't queue twice.
238 DEBUG_MSG(DEBUG_NAME,method_h,"pushing front method");
239 method_h->set_next_runnable(m_methods_push_head->next_runnable());
240 if ( m_methods_push_tail == m_methods_push_head ) // Empty queue.
241 {
242 m_methods_push_tail->set_next_runnable(method_h);
243 m_methods_push_tail = method_h;
244 }
245 else // Non-empty queue.
246 {
247 m_methods_push_head->set_next_runnable(method_h);
248 }
249}
250
251
252//------------------------------------------------------------------------------
253//"sc_runnable::push_front_thread"
254//
255// This method pushes the supplied thread process onto the front of the queue of
256// runnable thread processes. If the queue is empty the process is the tail
257// also.
258// thread_h -> thread process to add to the queue.
259//------------------------------------------------------------------------------
261{
262 // sc_assert( thread_h->next_runnable() == 0 ); // Can't queue twice.
263 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing front thread");
264 thread_h->set_next_runnable(m_threads_push_head->next_runnable());
265 if ( m_threads_push_tail == m_threads_push_head ) // Empty queue.
266 {
267 m_threads_push_tail->set_next_runnable(thread_h);
268 m_threads_push_tail = thread_h;
269 }
270 else // Non-empty queue.
271 {
272 m_threads_push_head->set_next_runnable(thread_h);
273 }
274}
275
276//------------------------------------------------------------------------------
277//"sc_runnable::pop_method"
278//
279// This method pops the next method process to be executed, or returns a null
280// if no method processes are available for execution.
281//------------------------------------------------------------------------------
283{
284 sc_method_handle result_p;
285
286 result_p = m_methods_pop;
287 if ( result_p != SC_NO_METHODS )
288 {
289 m_methods_pop = result_p->next_runnable();
290 result_p->set_next_runnable(0);
291 }
292 else
293 {
294 result_p = 0;
295 }
296 DEBUG_MSG(DEBUG_NAME,result_p,"popping method");
297 return result_p;
298
299}
300
301//------------------------------------------------------------------------------
302//"sc_runnable::pop_thread"
303//
304// This method pops the next thread process to be executed, or returns a null
305// if no thread processes are available for execution.
306//------------------------------------------------------------------------------
308{
309 sc_thread_handle result_p;
310
311 result_p = m_threads_pop;
312 if ( result_p != SC_NO_THREADS )
313 {
314 m_threads_pop = result_p->next_runnable();
315 result_p->set_next_runnable(0);
316 }
317 else
318 {
319 result_p = 0;
320 }
321 DEBUG_MSG(DEBUG_NAME,result_p,"popping thread for execution");
322 return result_p;
323}
324
325
326//------------------------------------------------------------------------------
327//"sc_runnable::remove_method"
328//
329// This method removes the supplied method process from the push queue if it is
330// present. Note we clear the method's next pointer so that it may be queued
331// again.
332// remove_p -> method process to remove from the run queue.
333//------------------------------------------------------------------------------
335{
336 sc_method_handle now_p; // Method now checking.
337 sc_method_handle prior_p; // Method prior to now_p.
338
339 // Don't try to remove things if we have not been initialized.
340
341 if ( !is_initialized() ) return;
342
343 // Search the push queue:
344
345 prior_p = m_methods_push_head;
346 for ( now_p = m_methods_push_head->next_runnable(); now_p!= SC_NO_METHODS;
347 now_p = now_p->next_runnable() )
348 {
349 if ( remove_p == now_p )
350 {
351 prior_p->set_next_runnable( now_p->next_runnable() );
352 if (now_p == m_methods_push_tail) {
353 m_methods_push_tail = prior_p;
354 }
355 now_p->set_next_runnable(0);
356 DEBUG_MSG(DEBUG_NAME,now_p,"removing method from push queue");
357 return;
358 }
359 prior_p = now_p;
360 }
361
362 // Search the pop queue:
363
364 prior_p = NULL;
365 for ( now_p = m_methods_pop; now_p != SC_NO_METHODS;
366 now_p = now_p->next_runnable() )
367 {
368 if ( remove_p == now_p )
369 {
370 if ( prior_p )
371 prior_p->set_next_runnable( now_p->next_runnable() );
372 else
373 m_methods_pop = now_p->next_runnable();
374 now_p->set_next_runnable(0);
375 DEBUG_MSG(DEBUG_NAME,now_p,"removing method from pop queue");
376 return;
377 }
378 prior_p = now_p;
379 }
380}
381
382
383//------------------------------------------------------------------------------
384//"sc_runnable::remove_thread"
385//
386// This method removes the supplied thread process from the push or pop
387// queue if it is present. Note we clear the thread's next pointer so that it
388// may be queued again.
389// remove_p -> thread process to remove from the run queue.
390//------------------------------------------------------------------------------
392{
393 sc_thread_handle now_p; // Thread now checking.
394 sc_thread_handle prior_p; // Thread prior to now_p.
395
396 // Don't try to remove things if we have not been initialized.
397
398 if ( !is_initialized() ) return;
399
400 // Search the push queue:
401
402 prior_p = m_threads_push_head;
403 for ( now_p = m_threads_push_head->next_runnable(); now_p != SC_NO_THREADS;
404 now_p = now_p->next_runnable() )
405 {
406 if ( remove_p == now_p )
407 {
408 prior_p->set_next_runnable( now_p->next_runnable() );
409 if (now_p == m_threads_push_tail) {
410 m_threads_push_tail = prior_p;
411 }
412 now_p->set_next_runnable(0);
413 DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from push queue");
414 return;
415 }
416 prior_p = now_p;
417 }
418
419 // Search the pop queue:
420
421 prior_p = NULL;
422 for ( now_p = m_threads_pop; now_p != SC_NO_THREADS;
423 now_p = now_p->next_runnable() )
424 {
425 if ( remove_p == now_p )
426 {
427 if ( prior_p )
428 prior_p->set_next_runnable( now_p->next_runnable() );
429 else
430 m_threads_pop = now_p->next_runnable();
431 now_p->set_next_runnable(0);
432 DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from pop queue");
433 return;
434 }
435 prior_p = now_p;
436 }
437}
438
439//------------------------------------------------------------------------------
440//"sc_runnable::sc_runnable"
441//
442// This is the object instance constructor for this class.
443//------------------------------------------------------------------------------
445 m_methods_push_head(0), m_methods_push_tail(0), m_methods_pop(SC_NO_METHODS),
446 m_threads_push_head(0), m_threads_push_tail(0), m_threads_pop(SC_NO_THREADS)
447{}
448
449//------------------------------------------------------------------------------
450//"sc_runnable::~sc_runnable"
451//
452// This is the object instance destructor for this class.
453//------------------------------------------------------------------------------
455{
456 delete m_methods_push_head;
457 delete m_threads_push_head;
458}
459
460
461//------------------------------------------------------------------------------
462//"sc_runnable::toggle_methods"
463//
464// This method moves the methods push queue to the pop queue and zeros the push
465// queue. This will only be done if the pop queue is presently empty.
466//------------------------------------------------------------------------------
468{
469 if ( m_methods_pop == SC_NO_METHODS )
470 {
471 m_methods_pop = m_methods_push_head->next_runnable();
472 m_methods_push_head->set_next_runnable(SC_NO_METHODS);
473 m_methods_push_tail = m_methods_push_head;
474 }
475}
476
477
478//------------------------------------------------------------------------------
479//"sc_runnable::toggle_threads"
480//
481// This method moves the threads push queue to the pop queue and zeros the push
482// queue. This will only be done if the pop queue is presently empty.
483//------------------------------------------------------------------------------
485{
486 if ( m_threads_pop == SC_NO_THREADS )
487 {
488 m_threads_pop = m_threads_push_head->next_runnable();
489 m_threads_push_head->set_next_runnable(SC_NO_THREADS);
490 m_threads_push_tail = m_threads_push_head;
491 }
492}
493
494#undef SC_NO_METHODS
495#undef SC_NO_THREADS
496#undef DEBUG_MSG
497
498} // namespace sc_core
499
500
501/*******************************************************************************
502
503 MODIFICATION LOG - modifiers, enter your name, affiliation, date and
504 changes you are making here.
505 Andy Goodrich, Forte Design Systems, 2 September 2003
506 Changed queue heads to instances to eliminate the checks for null heads.
507
508 ******************************************************************************/
509
510// $Log: sc_runnable_int.h,v $
511// Revision 1.19 2011/08/24 22:05:51 acg
512// Torsten Maehne: initialization changes to remove warnings.
513//
514// Revision 1.18 2011/08/07 19:08:04 acg
515// Andy Goodrich: moved logs to end of file so line number synching works
516// better between versions.
517//
518// Revision 1.17 2011/04/13 02:45:11 acg
519// Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG
520// macro was used.
521//
522// Revision 1.16 2011/04/10 22:18:23 acg
523// Andy Goodrich: debugging message clean up.
524//
525// Revision 1.15 2011/04/08 18:26:07 acg
526// Andy Goodrich: added execute_method_next() to handle method dispatch
527// for asynchronous notifications that occur outside the evaluation phase.
528//
529// Revision 1.14 2011/04/01 21:31:10 acg
530// Andy Goodrich: turn off diagnostic messages by default.
531//
532// Revision 1.13 2011/04/01 21:30:02 acg
533// Andy Goodrich: inserted conditional displays for queue manipulations.
534//
535// Revision 1.12 2011/03/30 00:01:34 acg
536// Philip A. Hartmann: change break to return in remove_method() to short
537// circuit the search the way remove_thread() works.
538//
539// Revision 1.11 2011/03/28 13:02:52 acg
540// Andy Goodrich: Changes for disable() interactions.
541//
542// Revision 1.10 2011/03/06 15:58:17 acg
543// Andy Goodrich: formatting changes.
544//
545// Revision 1.9 2011/02/18 20:27:14 acg
546// Andy Goodrich: Updated Copyrights.
547//
548// Revision 1.8 2011/02/13 21:47:38 acg
549// Andy Goodrich: update copyright notice.
550//
551// Revision 1.7 2011/02/02 06:37:03 acg
552// Andy Goodrich: removed toggle() method since it is no longer used.
553//
554// Revision 1.6 2011/02/01 21:09:13 acg
555// Andy Goodrich: addition of toggle_methods() and toggle_threads() calls.
556//
557// Revision 1.5 2011/01/25 20:50:37 acg
558// Andy Goodrich: changes for IEEE 1666 2011.
559//
560// Revision 1.4 2010/07/22 20:02:33 acg
561// Andy Goodrich: bug fixes.
562//
563// Revision 1.3 2009/02/28 00:26:58 acg
564// Andy Goodrich: changed boost name space to sc_boost to allow use with
565// full boost library applications.
566//
567// Revision 1.2 2008/05/22 17:06:26 acg
568// Andy Goodrich: updated copyright notice to include 2008.
569//
570// Revision 1.1.1.1 2006/12/15 20:20:05 acg
571// SystemC 2.3
572//
573// Revision 1.4 2006/04/20 17:08:17 acg
574// Andy Goodrich: 3.0 style process changes.
575//
576// Revision 1.3 2006/01/13 18:44:30 acg
577// Added $Log to record CVS changes into the source.
578//
579
580#endif // SC_RUNNABLE_INT_H
581
582// Taf!
#define DEBUG_MSG(NAME, P, MSG)
#define SC_NO_THREADS
#define SC_NO_METHODS
class sc_method_process * sc_method_handle
Definition: sc_process.h:61
class sc_thread_process * sc_thread_handle
Definition: sc_process.h:62
void(sc_process_host::* sc_entry_func)()
Definition: sc_process.h:132
void push_front_thread(sc_thread_handle)
void execute_thread_next(sc_thread_handle)
void remove_method(sc_method_handle)
void push_back_thread(sc_thread_handle)
void execute_method_next(sc_method_handle)
void remove_thread(sc_thread_handle)
bool is_initialized() const
void push_back_method(sc_method_handle)
void push_front_method(sc_method_handle)
sc_method_handle pop_method()
sc_thread_handle pop_thread()