
//******************************************************************************
//
//  The following code is derived, directly or indirectly, from the SystemC
//  source code Copyright (c) 1996-2011 by all Contributors.
//  All Rights reserved.
//
//  The contents of this file are subject to the restrictions and limitations
//  set forth in the SystemC Open Source License Version 2.4 (the "License");
//  You may not use this file except in compliance with such restrictions and
//  limitations. You may obtain instructions on how to receive a copy of the
//  License at http://www.systemc.org/. Software distributed by Contributors
//  under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
//  ANY KIND, either express or implied. See the License for the specific
//  language governing rights and limitations under the License.
//******************************************************************************

// proc_ctrl_elab.cpp -- test for 
//
//  Original Author: John Aynsley, Doulos, Inc.
//
// MODIFICATION LOG - modifiers, enter your name, affiliation, date and
//
// $Log: proc_ctrl_elab.cpp,v $
// Revision 1.2  2011/05/08 19:18:46  acg
//  Andy Goodrich: remove extraneous + prefixes from git diff.
//

// Calling process control methods during elaboration

#define SC_INCLUDE_DYNAMIC_PROCESSES

#include "systemc.h"

SC_MODULE(Top)
{
  SC_CTOR(Top)
  : caught_throw_it(0)
  , caught_reset(0)
  , caught_kill(0)
  
  , target_suspend_1_called(false)
  , target_suspend_2_called(false)
  , target_suspend_3_called(false)
  , target_suspend_4_called(false)
  , target_suspend_5_called(false)

  , target_disable_1_called(false)
  , target_disable_2_called(false)
  , target_disable_2_called_again(false)
  , target_disable_3_called(false)
  , target_disable_4_called(false)
  , target_disable_5_called(false)

  , target_sync_reset_1_called(false)
  , target_sync_reset_2_called(false)
  , target_sync_reset_3_called(false)
  , target_sync_reset_4_called(false)

  , reset_1_count(0)
  , reset_2_count(0)
  , reset_3_count(0)
  , reset_4_count(0)
  {
    SC_THREAD(ctrl);

    SC_THREAD(target_suspend_1);
      sensitive << ev;
      ts1 = sc_get_current_process_handle();

    SC_THREAD(target_suspend_2);
      dont_initialize();
      sensitive << ev;
      ts2 = sc_get_current_process_handle();

    SC_THREAD(target_suspend_3);
      dont_initialize();
      sensitive << ev;
      ts3 = sc_get_current_process_handle();

    SC_THREAD(target_suspend_4);
      dont_initialize();
      sensitive << ev;
      ts4 = sc_get_current_process_handle();
      ts4.suspend();
      
    SC_THREAD(target_suspend_5);
      dont_initialize();
      sensitive << ev;
      ts5 = sc_get_current_process_handle();
      ts5.suspend();
      ts5.resume();
      
    SC_THREAD(target_disable_1);
      sensitive << dummy_ev;
      td1 = sc_get_current_process_handle();

    SC_THREAD(target_disable_2);
      sensitive << ev;
      td2 = sc_get_current_process_handle();

    SC_THREAD(target_disable_3);
      td3 = sc_get_current_process_handle();
      
    SC_THREAD(target_disable_4);
      dont_initialize();
      sensitive << ev;
      td4 = sc_get_current_process_handle();
      td4.disable();

    SC_THREAD(target_disable_5);
      dont_initialize();
      sensitive << ev;
      td5 = sc_get_current_process_handle();
      td5.disable();
      td5.enable();
      td5.sync_reset_on();
      td5.sync_reset_off();

    SC_THREAD(target_sync_reset_1);
      sensitive << ev;
      tr1 = sc_get_current_process_handle();

    SC_THREAD(target_sync_reset_2);
      sensitive << ev;
      tr2 = sc_get_current_process_handle();

    SC_THREAD(target_sync_reset_3);
      dont_initialize();
      sensitive << ev;
      tr3 = sc_get_current_process_handle();

    SC_THREAD(target_sync_reset_4);
      dont_initialize();
      sensitive << ev;
      tr4 = sc_get_current_process_handle();
      tr4.sync_reset_on();
      
    try {
      ts2.throw_it(ex);
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_throw_it;
    }
      
    try {
      ts2.reset();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_reset;
    }
      
    try {
      ts2.kill();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_kill;
    }
  }
  
  void before_end_of_elaboration()
  {
    ts1.suspend();
    ts2.suspend();
    ts3.suspend();

    td1.disable();
    td2.disable();
    td3.disable();
    
    tr1.sync_reset_on();
    tr2.sync_reset_on();
    tr3.sync_reset_on();
      
    try {
      ts2.throw_it(ex);
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_throw_it;
    }
      
    try {
      ts2.reset();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_reset;
    }
      
    try {
      ts2.kill();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_kill;
    }
  }

  void start_of_simulation()
  {
    td3.enable();
    tr3.sync_reset_off();
      
    try {
      ts2.throw_it(ex);
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_throw_it;
    }
      
    try {
      ts2.reset();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_reset;
    }
      
    try {
      ts2.kill();
      sc_assert( false );
    }
    catch (std::exception e) {
      ++caught_kill;
    }
  }
  
  sc_event ev, dummy_ev;
  
  std::exception ex;  

  sc_process_handle ts1;
  sc_process_handle ts2;  
  sc_process_handle ts3;
  sc_process_handle ts4;
  sc_process_handle ts5;

  sc_process_handle td1;
  sc_process_handle td2;
  sc_process_handle td3;
  sc_process_handle td4;
  sc_process_handle td5;

  sc_process_handle tr1;
  sc_process_handle tr2;
  sc_process_handle tr3;
  sc_process_handle tr4;

  int caught_throw_it;
  int caught_reset;
  int caught_kill;

  bool target_suspend_1_called;
  bool target_suspend_2_called;
  bool target_suspend_3_called;
  bool target_suspend_4_called;
  bool target_suspend_5_called;

  bool target_disable_1_called;
  bool target_disable_2_called;
  bool target_disable_2_called_again;
  bool target_disable_3_called;
  bool target_disable_4_called;
  bool target_disable_5_called;

  bool target_sync_reset_1_called;
  bool target_sync_reset_2_called;
  bool target_sync_reset_3_called;
  bool target_sync_reset_4_called;
  
  int reset_1_count;
  int reset_2_count;
  int reset_3_count;
  int reset_4_count;
  
  void ctrl()
  {
    ts3.resume();
    
    wait(10, SC_NS);
    ts1.resume();
    ev.notify();
    
    wait(10, SC_NS);
    ts2.resume();
    tr2.sync_reset_off();
    tr4.sync_reset_off();
    
    wait(10, SC_NS);
    td2.enable();
    
    wait(10, SC_NS);
    ev.notify();
    
    wait(10, SC_NS);
    ev.notify();
    td2.disable();
    
    wait(10, SC_NS);
    td4.enable();
    ts4.resume();
    ev.notify();
  }
   
  void target_suspend_1()
  {
    sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
    target_suspend_1_called = true;
  }
   
  void target_suspend_2()
  {
    sc_assert( sc_time_stamp() == sc_time(20, SC_NS) );
    target_suspend_2_called = true;
  }
   
  void target_suspend_3()
  {
    sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
    target_suspend_3_called = true;
  }
   
  void target_suspend_4()
  {
    sc_assert( sc_time_stamp() == sc_time(60, SC_NS) );
    target_suspend_4_called = true;
  }
   
  void target_suspend_5()
  {
    sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
    target_suspend_5_called = true;
    ts5.suspend();
  }
   
  void target_disable_1()
  {
    sc_assert( false );
    target_disable_1_called = true;
  }
   
  void target_disable_2()
  {
    sc_assert( sc_time_stamp() == sc_time(40, SC_NS) );
    target_disable_2_called = true;
    wait(); // on ev

    sc_assert( sc_time_stamp() == sc_time(50, SC_NS) );
    target_disable_2_called_again = true;
  }
   
  void target_disable_3()
  {
    sc_assert( sc_time_stamp() == sc_time(0, SC_NS) );
    sc_assert( sc_delta_count() == 0 );
    target_disable_3_called = true;
  }
   
  void target_disable_4()
  {
    sc_assert( sc_time_stamp() == sc_time(60, SC_NS) );
    target_disable_4_called = true;
  }
   
  void target_disable_5()
  {
    sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
    target_disable_5_called = true;
    td5.disable();
  }
   
  void target_sync_reset_1()
  {
    switch (reset_1_count)
    {
      case 0: sc_assert( sc_time_stamp() == sc_time(0, SC_NS) );
              sc_assert( sc_delta_count() == 0 );
              break;
      case 1: sc_assert( sc_time_stamp() == sc_time(10, SC_NS) ); 
              break;
      case 2: sc_assert( sc_time_stamp() == sc_time(40, SC_NS) ); 
              break;
      case 3: sc_assert( sc_time_stamp() == sc_time(50, SC_NS) ); 
              target_sync_reset_1_called = true;
              break;
    }
    ++reset_1_count;
    
    while (true)
    {
      wait();
      sc_assert( false );
    }
  }
   
  void target_sync_reset_2()
  {
    switch (reset_2_count)
    {
      case 0: sc_assert( sc_time_stamp() == sc_time(0, SC_NS) );
              sc_assert( sc_delta_count() == 0 );
              break;
      case 1: sc_assert( sc_time_stamp() == sc_time(10, SC_NS) ); 
              break;
      case 2: sc_assert( false ); 
              break;
      case 3: sc_assert( false ); 
              break;
    }
    ++reset_2_count;
    
    while (true)
    {
      wait();
      
    switch (reset_2_count)
    {
      case 0: sc_assert( false );
              break;
      case 1: sc_assert( false );
              break;
      case 2: sc_assert( sc_time_stamp() == sc_time(40, SC_NS) ); 
              break;
      case 3: sc_assert( sc_time_stamp() == sc_time(50, SC_NS) ); 
              target_sync_reset_2_called = true;
              break;
    }
    ++reset_2_count;
    
    }
  }
   
  void target_sync_reset_3()
  {
    switch (reset_3_count)
    {
      case 0: sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
              break;
      case 1: sc_assert( false ); 
              break;
      case 2: sc_assert( false ); 
              break;
    }
    ++reset_3_count;
    
    while (true)
    {
      wait();
      
    switch (reset_3_count)
    {
      case 0: sc_assert( false );
              break;
      case 1: sc_assert( sc_time_stamp() == sc_time(40, SC_NS) ); 
              break;
      case 2: sc_assert( sc_time_stamp() == sc_time(50, SC_NS) ); 
              target_sync_reset_3_called = true;
              break;
    }
    ++reset_3_count;
    
    }
  }
   
  void target_sync_reset_4()
  {
    switch (reset_4_count)
    {
      case 0: sc_assert( sc_time_stamp() == sc_time(10, SC_NS) );
              break;
      case 1: sc_assert( false );
              break;
      case 2: sc_assert( false ); 
              break;
    }
    ++reset_4_count;
    
    while (true)
    {
      wait();
      
    switch (reset_4_count)
    {
      case 0: sc_assert( false );
              break;
      case 1: sc_assert( sc_time_stamp() == sc_time(40, SC_NS) ); 
              break;
      case 2: sc_assert( sc_time_stamp() == sc_time(50, SC_NS) ); 
              target_sync_reset_4_called = true;
              break;
    }
    ++reset_4_count;
    
    }
  }
};

int sc_main(int argc, char* argv[])
{
  Top top("top");
  sc_start();

  sc_assert( top.caught_throw_it == 3 );
  sc_assert( top.caught_reset == 3 );
  sc_assert( top.caught_kill == 3 );
  
  sc_assert( top.target_suspend_1_called );
  sc_assert( top.target_suspend_2_called );
  sc_assert( top.target_suspend_3_called );
  sc_assert( top.target_suspend_4_called );
  sc_assert( top.target_suspend_5_called );

  sc_assert( !top.target_disable_1_called );
  sc_assert( top.target_disable_2_called );
  sc_assert( top.target_disable_2_called_again );
  sc_assert( top.target_disable_3_called );
  sc_assert( top.target_disable_4_called );
  sc_assert( top.target_disable_5_called );

  sc_assert( top.target_sync_reset_1_called );
  sc_assert( top.target_sync_reset_2_called );
  sc_assert( top.target_sync_reset_3_called );
  sc_assert( top.target_sync_reset_4_called );
  
  cout << endl << "Success" << endl;
  return 0;
}
