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// kill_reset.cpp -- test for
21//
22//  Original Author: John Aynsley, Doulos, Inc.
23//
24// MODIFICATION LOG - modifiers, enter your name, affiliation, date and
25//
26// $Log: kill_reset.cpp,v $
27// Revision 1.2  2011/05/08 19:18:46  acg
28//  Andy Goodrich: remove extraneous + prefixes from git diff.
29//
30
31// Reset and kill a thread process, including nested kills and resets
32
33#include <systemc>
34
35using namespace sc_core;
36using std::cout;
37using std::endl;
38
39struct M3: sc_module
40{
41  M3(sc_module_name _name)
42  {
43    SC_THREAD(ticker);
44      k = sc_get_current_process_handle();
45
46    SC_THREAD(calling);
47
48    SC_THREAD(target);
49      t = sc_get_current_process_handle();
50
51    SC_THREAD(victim);
52      v = sc_get_current_process_handle();
53
54    SC_THREAD(bystander);
55      b = sc_get_current_process_handle();
56
57    SC_THREAD(second_bystander);
58      b2 = sc_get_current_process_handle();
59
60    SC_THREAD(third_bystander);
61      b3 = sc_get_current_process_handle();
62
63    killing_over = false;
64    third_bystander_knocked_over = false;
65  }
66
67  sc_process_handle t, k, v, b, b2, b3;
68  sc_event ev;
69  int count;
70  bool killing_over;
71  bool third_bystander_knocked_over;
72
73  void ticker()
74  {
75    for (;;)
76    {
77      try {
78        wait(10, SC_NS);
79        ev.notify();
80        sc_assert( !sc_is_unwinding() );
81      }
82      catch (const sc_unwind_exception& ex)
83      {
84        // ticker process killed by target
85        cout << "sc_unwind_exception caught by ticker" << endl;
86        sc_assert( !ex.is_reset() );
87        sc_assert( count == 1 );
88        sc_assert( !killing_over );
89        sc_assert( t.is_unwinding() );
90        sc_assert( sc_is_unwinding() );
91
92        v.kill();
93        throw ex;
94      }
95    }
96  }
97
98  void calling()
99  {
100    wait(15, SC_NS);
101    // Target runs at time 10 NS due to notification
102    sc_assert( count == 1 );
103    // The victim awakes every 1ns
104    sc_assert( sc_time_to_pending_activity() <= sc_time(1, SC_NS) );
105
106    wait(10, SC_NS);
107    // Target runs again at time 20 NS due to notification
108    sc_assert( count == 2 );
109
110    t.reset();
111    // Target reset immediately at time 25 NS
112    sc_assert( count == 0 );
113
114    wait(10, SC_NS);
115    // Target runs again at time 30 NS due to notification
116    sc_assert( count == 1 );
117
118    t.kill();
119    sc_assert( !killing_over );
120    killing_over = true;
121
122    // Target killed immediately at time 35 NS
123    if (t.valid())
124      sc_assert( t.terminated() );
125    if (k.valid())
126      sc_assert( k.terminated() );
127    if (v.valid())
128      sc_assert( v.terminated() );
129    sc_assert( b.valid() && !b.terminated() );
130    sc_assert( b2.valid() && !b2.terminated() );
131    if (b3.valid())
132      sc_assert( b3.terminated() );
133
134    sc_stop();
135  }
136
137  void target()
138  {
139    cout << "Target called/reset at " << sc_time_stamp() << endl;
140    count = 0;
141    for (;;)
142    {
143      try {
144        wait(ev);
145        cout << "Target awoke at " << sc_time_stamp() << endl;
146        ++count;
147      }
148      catch (const sc_unwind_exception& ex)
149      {
150        cout << "sc_unwind_exception caught by target" << endl;
151        if (count == 2)
152          sc_assert( ex.is_reset() );
153        else if (count == 1)
154        {
155          sc_assert( !ex.is_reset() );
156          sc_assert( !killing_over );
157          k.kill();
158        }
159        else
160          sc_assert( false );
161        throw ex;
162      }
163    }
164  }
165
166  void victim()
167  {
168    try {
169      while (true)
170      {
171        wait(1, SC_NS);
172        sc_assert( !sc_is_unwinding() );
173      }
174    }
175    catch (const sc_unwind_exception& ex)
176    {
177      cout << "sc_unwind_exception caught by victim" << endl;
178      sc_assert( sc_time_stamp() == sc_time(35, SC_NS) );
179      sc_assert( ex.is_reset() == false );
180      sc_assert( !killing_over );
181      sc_assert( v.is_unwinding() );
182      sc_assert( sc_is_unwinding() );
183
184      b.reset();
185      throw ex;
186    }
187  }
188
189  void bystander() // Gets reset by victim
190  {
191    for (;;)
192    {
193      try {
194        wait(ev);
195      }
196      catch (const sc_unwind_exception& ex) {
197        cout << "sc_unwind_exception caught by bystander" << endl;
198        sc_assert( sc_time_stamp() == sc_time(35, SC_NS) );
199        sc_assert( ex.is_reset() == true );
200        sc_assert( !killing_over );
201        sc_assert( v.is_unwinding() ); // sic
202        sc_assert( sc_is_unwinding() );
203
204        b2.reset();
205        throw ex;
206      }
207    }
208  }
209
210  void second_bystander() // Gets reset by bystander
211  {
212    for (;;)
213    {
214      try {
215        wait(ev);
216      }
217      catch (const sc_unwind_exception& ex) {
218        cout << "sc_unwind_exception caught by second_bystander" << endl;
219        sc_assert( sc_time_stamp() == sc_time(35, SC_NS) );
220        sc_assert( ex.is_reset() == true );
221        sc_assert( !killing_over );
222        sc_assert( v.is_unwinding() ); // sic
223        sc_assert( b.is_unwinding() ); // sic
224        sc_assert( sc_is_unwinding() );
225
226        b3.kill();
227        throw ex;
228      }
229    }
230  }
231
232  void third_bystander() // Gets killed by second bystander
233  {
234    for (;;)
235    {
236      try {
237        wait(ev);
238      }
239      catch (const sc_unwind_exception& ex) {
240        cout << "sc_unwind_exception caught by third_bystander" << endl;
241        sc_assert( sc_time_stamp() == sc_time(35, SC_NS) );
242        sc_assert( !ex.is_reset() == true );
243        sc_assert( !killing_over );
244        sc_assert( v.is_unwinding() ); // sic
245        sc_assert( b.is_unwinding() ); // sic
246        sc_assert( b2.is_unwinding() ); // sic
247        sc_assert( sc_is_unwinding() );
248
249        third_bystander_knocked_over = true;
250        throw ex;
251      }
252    }
253  }
254
255  SC_HAS_PROCESS(M3);
256};
257
258int sc_main(int argc, char* argv[])
259{
260  M3 m("m");
261  sc_assert( sc_pending_activity() == false );
262  sc_assert( sc_time_to_pending_activity() == sc_max_time() );
263
264  sc_start();
265  sc_assert( m.third_bystander_knocked_over );
266
267  cout << endl << "Success" << endl;
268  return 0;
269}
270
271