sc_reset.cpp revision 12027
13914Ssaidi@eecs.umich.edu/*****************************************************************************
23914Ssaidi@eecs.umich.edu
33914Ssaidi@eecs.umich.edu  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
43914Ssaidi@eecs.umich.edu  more contributor license agreements.  See the NOTICE file distributed
53914Ssaidi@eecs.umich.edu  with this work for additional information regarding copyright ownership.
63914Ssaidi@eecs.umich.edu  Accellera licenses this file to you under the Apache License, Version 2.0
73914Ssaidi@eecs.umich.edu  (the "License"); you may not use this file except in compliance with the
83914Ssaidi@eecs.umich.edu  License.  You may obtain a copy of the License at
93914Ssaidi@eecs.umich.edu
103914Ssaidi@eecs.umich.edu    http://www.apache.org/licenses/LICENSE-2.0
113914Ssaidi@eecs.umich.edu
123914Ssaidi@eecs.umich.edu  Unless required by applicable law or agreed to in writing, software
133914Ssaidi@eecs.umich.edu  distributed under the License is distributed on an "AS IS" BASIS,
143914Ssaidi@eecs.umich.edu  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
153914Ssaidi@eecs.umich.edu  implied.  See the License for the specific language governing
163914Ssaidi@eecs.umich.edu  permissions and limitations under the License.
173914Ssaidi@eecs.umich.edu
183914Ssaidi@eecs.umich.edu *****************************************************************************/
193914Ssaidi@eecs.umich.edu
203914Ssaidi@eecs.umich.edu/*****************************************************************************
213914Ssaidi@eecs.umich.edu
223914Ssaidi@eecs.umich.edu  sc_reset.cpp -- Support for reset.
233914Ssaidi@eecs.umich.edu
243914Ssaidi@eecs.umich.edu  Original Author: Andy Goodrich, Forte Design Systems
253914Ssaidi@eecs.umich.edu
263914Ssaidi@eecs.umich.edu  CHANGE LOG AT THE END OF THE FILE
273914Ssaidi@eecs.umich.edu *****************************************************************************/
283914Ssaidi@eecs.umich.edu
293914Ssaidi@eecs.umich.edu
303914Ssaidi@eecs.umich.edu#include "sysc/kernel/sc_simcontext.h"
313914Ssaidi@eecs.umich.edu#include "sysc/kernel/sc_reset.h"
323914Ssaidi@eecs.umich.edu#include "sysc/kernel/sc_process_handle.h"
333914Ssaidi@eecs.umich.edu#include "sysc/communication/sc_signal.h"
343914Ssaidi@eecs.umich.edu#include "sysc/communication/sc_signal_ports.h"
353914Ssaidi@eecs.umich.edu
363914Ssaidi@eecs.umich.edu
373914Ssaidi@eecs.umich.edu// THE SYSTEMC PROOF OF CONCEPT SIMULATOR RESET SIGNAL IMPLEMENTATION:
383914Ssaidi@eecs.umich.edu//
393914Ssaidi@eecs.umich.edu// (1) An instance of the sc_reset class is attached to each sc_signal<bool>
404762Snate@binkert.org//     that is used as a reset signal.
413914Ssaidi@eecs.umich.edu//
426658Snate@binkert.org// (2) Each process that is senstive to a reset signal will be registered in the
433914Ssaidi@eecs.umich.edu//     sc_reset class attached to that reset signal.
443914Ssaidi@eecs.umich.edu//
453914Ssaidi@eecs.umich.edu// (3) When a change in the value of a reset signal occurs it invokes the
463914Ssaidi@eecs.umich.edu//     notify_processes() method of its sc_reset object instance. The
473914Ssaidi@eecs.umich.edu//     notify_processes() method will call the reset_changed() method of each
483914Ssaidi@eecs.umich.edu//     process that is registered with it to inform the process that
493914Ssaidi@eecs.umich.edu//     state of the reset signal has changed.
503914Ssaidi@eecs.umich.edu//
513914Ssaidi@eecs.umich.edu// (4) A process may have multiple reset signals, so counters are kept for the
524762Snate@binkert.org//     number of active asynchronous, and synchronous, reset signals that are
539808Sstever@gmail.com//     active. Those counters are incremented and decremented in the process'
543914Ssaidi@eecs.umich.edu//     reset_changed() method.
554762Snate@binkert.org//
5610531Sandreas.hansson@arm.com// (5) When a process' semantics() method is called the current reset state is
573943Sbinkertn@umich.edu//     checked, and a reset sequence is initiated if the process is in reset.
583914Ssaidi@eecs.umich.edu//     This will occur every time an SC_METHOD is dispatched. SC_CTHREAD and
593914Ssaidi@eecs.umich.edu//     and SC_THREAD instances, only go through the semantics() method they
603914Ssaidi@eecs.umich.edu//     initially start up. So the reset check  is duplicated in the suspend_me()
613914Ssaidi@eecs.umich.edu//     method, the tail of which will execute each time the thread is
623914Ssaidi@eecs.umich.edu//     dispatched.
633914Ssaidi@eecs.umich.edu
643914Ssaidi@eecs.umich.edunamespace sc_core {
653914Ssaidi@eecs.umich.edu
663914Ssaidi@eecs.umich.educlass sc_reset_finder;
673914Ssaidi@eecs.umich.edustatic sc_reset_finder* reset_finder_q=0;  // Q of reset finders to reconcile.
683914Ssaidi@eecs.umich.edu
693914Ssaidi@eecs.umich.edu//==============================================================================
703914Ssaidi@eecs.umich.edu// sc_reset_finder - place holder class for a port reset signal until it is
714870Sstever@eecs.umich.edu//                   bound and an interface class is available. When the port
723914Ssaidi@eecs.umich.edu//                   has been bound the information in this class will be used
733914Ssaidi@eecs.umich.edu//                   to initialize its sc_reset object instance.
743914Ssaidi@eecs.umich.edu//==============================================================================
753914Ssaidi@eecs.umich.educlass sc_reset_finder {
763914Ssaidi@eecs.umich.edu    friend class sc_reset;
773914Ssaidi@eecs.umich.edu  public:
783914Ssaidi@eecs.umich.edu    sc_reset_finder( bool async, const sc_in<bool>* port_p, bool level,
793914Ssaidi@eecs.umich.edu        sc_process_b* target_p);
803914Ssaidi@eecs.umich.edu    sc_reset_finder( bool async, const sc_inout<bool>* port_p, bool level,
813990Ssaidi@eecs.umich.edu        sc_process_b* target_p);
8210905Sandreas.sandberg@arm.com    sc_reset_finder( bool async, const sc_out<bool>* port_p, bool level,
833990Ssaidi@eecs.umich.edu        sc_process_b* target_p);
843990Ssaidi@eecs.umich.edu
853990Ssaidi@eecs.umich.edu  protected:
863990Ssaidi@eecs.umich.edu    bool                   m_async;     // True if asynchronous reset.
873990Ssaidi@eecs.umich.edu    bool                   m_level;     // Level for reset.
8810905Sandreas.sandberg@arm.com    sc_reset_finder*       m_next_p;    // Next reset finder in list.
893990Ssaidi@eecs.umich.edu    const sc_in<bool>*     m_in_p;      // Port for which reset is needed.
903990Ssaidi@eecs.umich.edu    const sc_inout<bool>*  m_inout_p;   // Port for which reset is needed.
913990Ssaidi@eecs.umich.edu    const sc_out<bool>*    m_out_p;     // Port for which reset is needed.
923990Ssaidi@eecs.umich.edu    sc_process_b*          m_target_p;  // Process to reset.
934762Snate@binkert.org
944762Snate@binkert.org  private: // disabled
953914Ssaidi@eecs.umich.edu    sc_reset_finder( const sc_reset_finder& );
964762Snate@binkert.org    const sc_reset_finder& operator = ( const sc_reset_finder& );
973914Ssaidi@eecs.umich.edu};
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