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_reset.cpp -- Support for reset.
23
24  Original Author: Andy Goodrich, Forte Design Systems
25
26  CHANGE LOG AT THE END OF THE FILE
27 *****************************************************************************/
28
29
30#include "sysc/kernel/sc_simcontext.h"
31#include "sysc/kernel/sc_reset.h"
32#include "sysc/kernel/sc_process_handle.h"
33#include "sysc/communication/sc_signal.h"
34#include "sysc/communication/sc_signal_ports.h"
35
36
37// THE SYSTEMC PROOF OF CONCEPT SIMULATOR RESET SIGNAL IMPLEMENTATION:
38//
39// (1) An instance of the sc_reset class is attached to each sc_signal<bool>
40//     that is used as a reset signal.
41//
42// (2) Each process that is senstive to a reset signal will be registered in the
43//     sc_reset class attached to that reset signal.
44//
45// (3) When a change in the value of a reset signal occurs it invokes the
46//     notify_processes() method of its sc_reset object instance. The
47//     notify_processes() method will call the reset_changed() method of each
48//     process that is registered with it to inform the process that
49//     state of the reset signal has changed.
50//
51// (4) A process may have multiple reset signals, so counters are kept for the
52//     number of active asynchronous, and synchronous, reset signals that are
53//     active. Those counters are incremented and decremented in the process'
54//     reset_changed() method.
55//
56// (5) When a process' semantics() method is called the current reset state is
57//     checked, and a reset sequence is initiated if the process is in reset.
58//     This will occur every time an SC_METHOD is dispatched. SC_CTHREAD and
59//     and SC_THREAD instances, only go through the semantics() method they
60//     initially start up. So the reset check  is duplicated in the suspend_me()
61//     method, the tail of which will execute each time the thread is
62//     dispatched.
63
64namespace sc_core {
65
66class sc_reset_finder;
67static sc_reset_finder* reset_finder_q=0;  // Q of reset finders to reconcile.
68
69//==============================================================================
70// sc_reset_finder - place holder class for a port reset signal until it is
71//                   bound and an interface class is available. When the port
72//                   has been bound the information in this class will be used
73//                   to initialize its sc_reset object instance.
74//==============================================================================
75class sc_reset_finder {
76    friend class sc_reset;
77  public:
78    sc_reset_finder( bool async, const sc_in<bool>* port_p, bool level,
79        sc_process_b* target_p);
80    sc_reset_finder( bool async, const sc_inout<bool>* port_p, bool level,
81        sc_process_b* target_p);
82    sc_reset_finder( bool async, const sc_out<bool>* port_p, bool level,
83        sc_process_b* target_p);
84
85  protected:
86    bool                   m_async;     // True if asynchronous reset.
87    bool                   m_level;     // Level for reset.
88    sc_reset_finder*       m_next_p;    // Next reset finder in list.
89    const sc_in<bool>*     m_in_p;      // Port for which reset is needed.
90    const sc_inout<bool>*  m_inout_p;   // Port for which reset is needed.
91    const sc_out<bool>*    m_out_p;     // Port for which reset is needed.
92    sc_process_b*          m_target_p;  // Process to reset.
93
94  private: // disabled
95    sc_reset_finder( const sc_reset_finder& );
96    const sc_reset_finder& operator = ( const sc_reset_finder& );
97};
98
99inline sc_reset_finder::sc_reset_finder(
100    bool async, const sc_in<bool>* port_p, bool level, sc_process_b* target_p) :
101    m_async(async), m_level(level), m_next_p(0), m_in_p(port_p), m_inout_p(0),
102    m_out_p(0), m_target_p(target_p)
103{
104    m_next_p = reset_finder_q;
105    reset_finder_q = this;
106}
107
108inline sc_reset_finder::sc_reset_finder(
109    bool async, const sc_inout<bool>* port_p, bool level, sc_process_b* target_p
110) :
111    m_async(async), m_level(level), m_next_p(0), m_in_p(0), m_inout_p(port_p),
112    m_out_p(0), m_target_p(target_p)
113{
114    m_next_p = reset_finder_q;
115    reset_finder_q = this;
116}
117
118inline sc_reset_finder::sc_reset_finder(
119    bool async, const sc_out<bool>* port_p, bool level, sc_process_b* target_p
120) :
121    m_async(async), m_level(level), m_next_p(0), m_in_p(0), m_inout_p(0),
122    m_out_p(port_p), m_target_p(target_p)
123{
124    m_next_p = reset_finder_q;
125    reset_finder_q = this;
126}
127
128
129//------------------------------------------------------------------------------
130//"sc_reset::notify_processes"
131//
132// Notify processes that there is a change in the reset signal value.
133//------------------------------------------------------------------------------
134void sc_reset::notify_processes()
135{
136    bool                                    active;       // true if reset is active.
137    sc_reset_target*                        entry_p;      // reset entry processing.
138    std::vector<sc_reset_target>::size_type process_i;    // index of process resetting.
139    std::vector<sc_reset_target>::size_type process_n;    // # of processes to reset.
140    bool                                    value;        // value of our signal.
141
142    value = m_iface_p->read();
143    process_n = m_targets.size();
144    for ( process_i = 0; process_i < process_n; process_i++ )
145    {
146        entry_p = &m_targets[process_i];
147	active = ( entry_p->m_level == value );
148	entry_p->m_process_p->reset_changed( entry_p->m_async, active );
149    }
150}
151
152
153//------------------------------------------------------------------------------
154//"sc_reset::reconcile_resets"
155//
156// This static method processes the sc_reset_finders to establish the actual
157// reset connections.
158//
159// Notes:
160//   (1) If reset is asserted we tell the process that it is in reset.
161//------------------------------------------------------------------------------
162void sc_reset::reconcile_resets()
163{
164    const sc_signal_in_if<bool>*  iface_p;      // Interface to reset signal.
165    sc_reset_finder*              next_p;       // Next finder to process.
166    sc_reset_finder*              now_p;        // Finder currently processing.
167    sc_reset_target               reset_target; // Target's reset entry.
168    sc_reset*                     reset_p;      // Reset object to use.
169
170    for ( now_p = reset_finder_q; now_p; now_p = next_p )
171    {
172        next_p = now_p->m_next_p;
173        if ( now_p->m_in_p )
174        {
175            iface_p = DCAST<const sc_signal_in_if<bool>*>(
176                now_p->m_in_p->get_interface());
177        }
178        else if ( now_p->m_inout_p )
179        {
180            iface_p = DCAST<const sc_signal_in_if<bool>*>(
181                now_p->m_inout_p->get_interface());
182        }
183        else
184        {
185            iface_p = DCAST<const sc_signal_in_if<bool>*>(
186                now_p->m_out_p->get_interface());
187        }
188        assert( iface_p != 0 );
189        reset_p = iface_p->is_reset();
190	now_p->m_target_p->m_resets.push_back(reset_p);
191	reset_target.m_async = now_p->m_async;
192	reset_target.m_level = now_p->m_level;
193	reset_target.m_process_p = now_p->m_target_p;
194	reset_p->m_targets.push_back(reset_target);
195	if ( iface_p->read() == now_p->m_level ) // see note 1 above
196	    now_p->m_target_p->initially_in_reset( now_p->m_async );
197        delete now_p;
198    }
199}
200
201
202//------------------------------------------------------------------------------
203//"sc_reset::remove_process"
204//
205// This method removes the supplied process from the list of processes that
206// should be notified when there is a change in the value of the reset signal.
207//
208// Arguments:
209//     process_p -> process to be removed.
210//------------------------------------------------------------------------------
211void sc_reset::remove_process( sc_process_b* process_p )
212{
213    int process_i; // Index of process resetting.
214    int process_n; // # of processes to reset.
215
216    process_n = m_targets.size();
217    for ( process_i = 0; process_i < process_n; )
218    {
219        if ( m_targets[process_i].m_process_p == process_p )
220        {
221            m_targets[process_i] = m_targets[process_n-1];
222	    process_n--;
223            m_targets.resize(process_n);
224        }
225	else
226	{
227	    process_i++;
228	}
229    }
230}
231
232//------------------------------------------------------------------------------
233//"sc_reset::reset_signal_is - ports"
234//
235// These overloads of the reset_signal_is() method will register the active
236// process with the sc_reset object instance associated with the supplied port.
237// If the port does not yet have a pointer to its sc_signal<bool> instance it
238// will create an sc_reset_finder class object instance that will be used
239// to set the process' reset information when the port has been bound.
240//
241// Arguments:
242//     async = true if the reset signal is asynchronous, false if not.
243//     port  = port for sc_signal<bool> that will provide the reset signal.
244//     level = level at which reset is active, either true or false.
245//------------------------------------------------------------------------------
246void sc_reset::reset_signal_is( bool async, const sc_in<bool>& port, bool level)
247{
248    const sc_signal_in_if<bool>* iface_p;
249    sc_process_b*                process_p;
250
251    process_p = (sc_process_b*)sc_get_current_process_handle();
252    assert( process_p );
253    process_p->m_has_reset_signal = true;
254    switch ( process_p->proc_kind() )
255    {
256      case SC_THREAD_PROC_:
257      case SC_METHOD_PROC_:
258      case SC_CTHREAD_PROC_:
259        iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface());
260        if ( iface_p )
261            reset_signal_is( async, *iface_p, level );
262        else
263            new sc_reset_finder( async, &port, level, process_p );
264        break;
265      default:
266        SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name());
267        break;
268    }
269}
270
271void sc_reset::reset_signal_is(
272    bool async, const sc_inout<bool>& port, bool level )
273{
274    const sc_signal_in_if<bool>* iface_p;
275    sc_process_b*                process_p;
276
277    process_p = (sc_process_b*)sc_get_current_process_handle();
278    assert( process_p );
279    process_p->m_has_reset_signal = true;
280    switch ( process_p->proc_kind() )
281    {
282      case SC_THREAD_PROC_:
283      case SC_METHOD_PROC_:
284      case SC_CTHREAD_PROC_:
285        iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface());
286        if ( iface_p )
287            reset_signal_is( async, *iface_p, level );
288        else
289            new sc_reset_finder( async, &port, level, process_p );
290        break;
291      default:
292        SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name());
293        break;
294    }
295}
296
297void sc_reset::reset_signal_is(
298    bool async, const sc_out<bool>& port, bool level )
299{
300    const sc_signal_in_if<bool>* iface_p;
301    sc_process_b*                process_p;
302
303    process_p = (sc_process_b*)sc_get_current_process_handle();
304    assert( process_p );
305    process_p->m_has_reset_signal = true;
306    switch ( process_p->proc_kind() )
307    {
308      case SC_THREAD_PROC_:
309      case SC_METHOD_PROC_:
310      case SC_CTHREAD_PROC_:
311        iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface());
312        if ( iface_p )
313            reset_signal_is( async, *iface_p, level );
314        else
315            new sc_reset_finder( async, &port, level, process_p );
316        break;
317      default:
318        SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name());
319        break;
320    }
321}
322
323//------------------------------------------------------------------------------
324//"sc_reset::reset_signal_is"
325//
326// This static method will register the active process instance as being
327// reset by the sc_signal<bool> whose interface has been supplied. If no
328// sc_reset object instance has been attached to the sc_signal<bool> yet, it
329// will be created and attached. The active process instance is pushed into
330// the list of processes that the sc_reset object instance should notify if
331// the value of the reset signal changes.
332//
333// Arguments:
334//     async = true if the reset signal is asynchronous, false if not.
335//     iface = interface for the reset signal.
336//     level = is the level at which reset is active, either true or false.
337// Notes:
338//   (1) If reset is asserted we tell the process that it is in reset
339//       initially.
340//------------------------------------------------------------------------------
341void sc_reset::reset_signal_is(
342    bool async, const sc_signal_in_if<bool>& iface, bool level )
343{
344    sc_process_b*   process_p;    // process adding reset for.
345    sc_reset_target reset_target; // entry to build for the process.
346    sc_reset*       reset_p;      // reset object.
347
348    process_p = sc_process_b::last_created_process_base();
349    assert( process_p );
350    process_p->m_has_reset_signal = true;
351    switch ( process_p->proc_kind() )
352    {
353      case SC_METHOD_PROC_:
354      case SC_CTHREAD_PROC_:
355      case SC_THREAD_PROC_:
356	reset_p = iface.is_reset();
357	process_p->m_resets.push_back(reset_p);
358        reset_target.m_async = async;
359	reset_target.m_level = level;
360	reset_target.m_process_p = process_p;
361	reset_p->m_targets.push_back(reset_target);
362	if ( iface.read() == level ) process_p->initially_in_reset( async );
363        break;
364      default:
365        SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name());
366        break;
367    }
368}
369
370} // namespace sc_core
371
372// $Log: sc_reset.cpp,v $
373// Revision 1.16  2011/08/26 20:46:10  acg
374//  Andy Goodrich: moved the modification log to the end of the file to
375//  eliminate source line number skew when check-ins are done.
376//
377// Revision 1.15  2011/08/24 22:05:51  acg
378//  Torsten Maehne: initialization changes to remove warnings.
379//
380// Revision 1.14  2011/04/08 22:37:34  acg
381//  Andy Goodrich: documentation of the reset mechanism and additional
382//  documentation of methods. Removal of check for SC_METHODs in
383//  sc_reset_signal_is() that should not have been there.
384//
385// Revision 1.13  2011/03/20 15:13:01  acg
386//  Andy Goodrich: set the reset flag for async_reset_signal_is to catch
387//  the suspend() corner case.
388//
389// Revision 1.12  2011/03/20 13:43:23  acg
390//  Andy Goodrich: added async_signal_is() plus suspend() as a corner case.
391//
392// Revision 1.11  2011/03/06 19:57:11  acg
393//  Andy Goodrich: refinements for the illegal suspend - synchronous reset
394//  interaction.
395//
396// Revision 1.10  2011/02/18 20:27:14  acg
397//  Andy Goodrich: Updated Copyrights.
398//
399// Revision 1.9  2011/02/13 21:47:37  acg
400//  Andy Goodrich: update copyright notice.
401//
402// Revision 1.8  2011/02/01 21:08:26  acg
403//  Andy Goodrich: new multiple reset support.
404//
405// Revision 1.7  2011/01/06 18:04:38  acg
406//  Andy Goodrich: removed commented out code.
407//
408// Revision 1.6  2010/12/07 20:09:13  acg
409// Andy Goodrich: removed sc_signal overloads since already have sc_signal_in_if overloads.
410//
411// Revision 1.5  2010/11/20 17:10:56  acg
412//  Andy Goodrich: reset processing changes for new IEEE 1666 standard.
413//
414// Revision 1.4  2009/05/22 16:06:29  acg
415//  Andy Goodrich: process control updates.
416//
417// Revision 1.3  2009/03/12 22:59:58  acg
418//  Andy Goodrich: updates for 2.4 stuff.
419//
420// Revision 1.2  2008/05/22 17:06:26  acg
421//  Andy Goodrich: updated copyright notice to include 2008.
422//
423// Revision 1.1.1.1  2006/12/15 20:20:05  acg
424// SystemC 2.3
425//
426// Revision 1.7  2006/12/02 20:58:19  acg
427//  Andy Goodrich: updates from 2.2 for IEEE 1666 support.
428//
429// Revision 1.5  2006/04/11 23:13:21  acg
430//   Andy Goodrich: Changes for reduced reset support that only includes
431//   sc_cthread, but has preliminary hooks for expanding to method and thread
432//   processes also.
433//
434// Revision 1.4  2006/01/24 20:49:05  acg
435// Andy Goodrich: changes to remove the use of deprecated features within the
436// simulator, and to issue warning messages when deprecated features are used.
437//
438// Revision 1.3  2006/01/13 18:44:30  acg
439// Added $Log to record CVS changes into the source.
440//
441