Jump to content

wait() is not allowed inside run_phase


Recommended Posts

I am trying to implement SC_JOIN any in a uvm component run phase analogous to SystemVerilog UVM, but the wait statements inside the threads are not executing in the run phase. It will work fine if I use SC_THREAD instead.

 

Here is my code:

The code is fine for SC_JOIN all and SC_JOIN NONE implementation. And apparently this issue is there for every uvm_component I instantiate.

#include<systemc.h>
#include<uvm>

template <int TOP_DEPTH=10>
class top: public uvm::uvm_component{
public:


       void fun1() {
         cout<<"Current time is "<< sc_time_stamp() << endl;
     cout<< " =========== fun1========" << endl;
         wait(30,SC_NS);
         cout<<"Current time is "<< sc_time_stamp() << endl;
       }

       void fun2() {
         cout<<"Current time is "<< sc_time_stamp() << endl;
        cout<< " =========== fun2========" << endl;
       wait(20,SC_NS);
         cout<<"Current time is "<< sc_time_stamp() << endl;
       }

   void run_phase(uvm::uvm_phase& phase) {
     
             cout<< " run: before fork/join" << endl;

         /*SC_FORK
                         sc_spawn(sc_bind(&top::fun1, this)),
                         sc_spawn(sc_bind(&top::fun2, this))
             SC_JOIN*/

         /*void(sc_spawn(sc_bind(&top::fun1, this)));
           void(sc_spawn(sc_bind(&top::fun2, this)));*/


 

    
     std::vector<sc_process_handle> process_handles;
     process_handles.push_back(sc_spawn(sc_bind(&top::fun1, this)) );
     process_handles.push_back(sc_spawn(sc_bind(&top::fun2, this)) );
     sc_event_or_list terminated_events;
     for(std::vector<sc_process_handle>::iterator it = process_handles.begin(); it != process_handles.end(); ++it) {
       terminated_events |= (*it).terminated_event();
     }
     wait( terminated_events ); //< wait for any process to exit
     for(std::vector<sc_process_handle>::iterator it = process_handles.begin(); it != process_handles.end(); ++it) {
       (*it).kill();
       }


                 cout << "run: after fork/join" << endl;
                wait(40,SC_NS);
                cout<<"Current time is "<< sc_time_stamp() << endl;
        }


 top (uvm::uvm_component_name name="top") : uvm::uvm_component( name ) {

     }

};

 

int sc_main(int argc, char **argv) {

       top<15>* top_1;

       top_1 = new top<15>("top_1");


       uvm::run_test("");

      return 0;

}

Link to comment
Share on other sites

Can you show the output of your simulation?  And maybe add sc_get_current_process_handle().name() to the log statements to include the process name in the output.  I would expect to at last see the output after the wait() in fun2. Secondly, you should check for (*it).terminated() and only kill() running processes in the termination loop.

Link to comment
Share on other sites

Hi Philip, Here is the output of the simulation. I have observed that it works fine when you include phase.raise() and phase.drop() objection inside the run_phase. Well there are instances where you cannot afford to have these objections in every run_phase. 

 

      SystemC 2.3.2-Accellera --- Dec 18 2018 15:43:13
        Copyright (c) 1996-2017 by all Contributors,
        ALL RIGHTS RESERVED


   Universal Verification Methodology for SystemC (UVM-SystemC)
              Version: 1.0-beta2  Date: 2018-10-24
          Copyright (c) 2006 - 2018 by all Contributors
            See NOTICE file for all Contributors
                    ALL RIGHTS RESERVED
         Licensed under the Apache License, Version 2.0


UVM_INFO @ 0 s: reporter [RNTST] Running test ...
 run: before fork/join
top_1.thread_p_0
Current time is 0 s
 =========== fun1========
top_1.thread_p_1
Current time is 0 s
 =========== fun2========

Fatal: (F565) invalid use of sc_(and|or)_event_list: list prematurely destroyed
In file: ../../../src/sysc/kernel/sc_event.cpp:679
In process: uvm_top.uvm_phase_run_process.thread_p_1.thread_p_0.exec_proc_run_top_1_0 @ 0 s

Info: (I99) simulation aborted
run_c++: line 9:  5962 Aborted                 (core dumped) ./sc_main.o
 

Link to comment
Share on other sites

The error looks strange to me, as terminated_events is not destroyed before exiting run_phase, i.e. after the wait() has returned.  However, I don't know how the objections are implemented in UVM SystemC and whether or how wait() is supported without raising an objection.  Can you check with a debugger, if an exception is thrown while your run_phase function is inside the wait()?

Hope that helps,
  Philipp

Link to comment
Share on other sites

Hi Kevin,

you are missing the raising and dropping of an objection in the run_phase method (which would be required in SystemVerilog too) to prevent the early finish of the test sequence:

void run_phase(uvm::uvm_phase& phase) {

  phase.raise_objection(this);

  [...]

  phase.drop_objection(this);
}

By adding this I get the desired result:

UVM_INFO @ 0 s: reporter [RNTST] Running test ...
 run: before fork/join
Current time is 0 s
 =========== fun1========
Current time is 0 s
 =========== fun2========
Current time is 20 ns
run: after fork/join
Current time is 60 ns
UVM_INFO ../../../../uvm-systemc-1.0-beta2/src/uvmsc/report/uvm_default_report_server.cpp(666) @ 60 ns: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---

** Report counts by severity
UVM_INFO      :   1
UVM_WARNING   :   0
UVM_ERROR     :   0
UVM_FATAL     :   0
** Report counts by id
[RNTST]                 1

UVM_INFO @ 60 ns: reporter [FINISH] UVM-SystemC phasing completed; simulation finished

 

Link to comment
Share on other sites

Hi ,

Yes by adding the raise and drop phase objection the problem is solvable, but not all run phase can afford having these objections. 

For eg:

    top_uvm2 is a uvm component that has a run phase which has a thread that has to be run forever; like a driver component. It cannot have phaise raise or drop objections because of this reason. top_uvm2 is instantiated inside top_uvm1 component. top_uvm1 component has a phase raise and drop objections to  make sure the phase is persistent and does not get over. 

    If the threads in top_uvm2 are in a SC_JOIN or SC_JOIN_None implementation(both commented in code) the whole system works fine without any errors but the issue is with the SC_JOIN_ANY implementation. 

   

class top_uvm2: public uvm::uvm_component{
public:
  sc_event e1,e2;

       void fun1() { 
          for(;;){       
//Could be the main reason for different results   between SC_JOIN and SC_JOIN_ANY                                   
            cout<<"Current time is "<< sc_time_stamp() << endl;
            cout<< " =========== Main_fun1========" << endl;

            wait(e1);
            cout<<"Current time is "<< sc_time_stamp() << endl;
         }
       }

       void fun2() {

            cout<<"Current time is "<< sc_time_stamp() << endl;
            cout<< " =========== Main_fun2========" << endl;

           wait(e2);
           cout<<"Current time is "<< sc_time_stamp() << endl;
       }

   void run_phase(uvm::uvm_phase& phase) {
          uvm::uvm_component::run_phase(phase);
          cout<< " run: before fork/join main" << endl;

        

            /* SC_FORK
                 sc_spawn(sc_bind(&top_uvm2::fun1, this)),
                 sc_spawn(sc_bind(&top_uvm2::fun2, this))
             SC_JOIN*/

             /* void(sc_spawn(sc_bind(&top_uvm1::fun1, this)));
                 void(sc_spawn(sc_bind(&top_uvm1::fun2, this)));*/

            

     std::vector<sc_process_handle> process_handles;
     process_handles.push_back(sc_spawn(sc_bind(&top_uvm2::fun1, this)) );
     process_handles.push_back(sc_spawn(sc_bind(&top_uvm2::fun2, this)) );
     sc_event_or_list terminated_events;
     for(std::vector<sc_process_handle>::iterator it = process_handles.begin(); it != process_handles.end(); ++it) {
       terminated_events |= (*it).terminated_event();
     }
     sc_core::wait( terminated_events ); //< wait for any process to exit
     for(std::vector<sc_process_handle>::iterator it = process_handles.begin(); it != process_handles.end(); ++it) {
    
       (*it).kill();
       }
     

      cout << "run: after fork/join main" << endl;
      wait(50,SC_NS);
      cout<<"Current time is "<< sc_time_stamp() << endl;

 }


  top_uvm2 (uvm::uvm_component_name name="uvm_top2") : uvm::uvm_component( name ) {  }

};
 

class top_uvm1: public uvm::uvm_component{
   public:

   top_uvm2* top_uvm_2;

       void fun1() {
         cout<<"Current time is "<< sc_time_stamp() << endl;
         cout<< " =========== fun1========" << endl;
         wait(10,SC_NS);

         top_uvm_2->e1.notify();
         cout<<"Current time is "<< sc_time_stamp() << endl;
       }

       void fun2() {
         cout<<"Current time is "<< sc_time_stamp() << endl;
        cout<< " =========== fun2========" << endl;
        wait(40,SC_NS);
         cout<<"Current time is "<< sc_time_stamp() << endl;
       }
  

  void build_phase(uvm::uvm_phase& phase){

                top_uvm_2 = new top_uvm2("top_2"); 

  }

 void run_phase(uvm::uvm_phase& phase) {
     uvm::uvm_component::run_phase(phase);
     cout<< " run: before fork/join" << endl;

      phase.raise_objection(this);

           SC_FORK
                     sc_spawn(sc_bind(&top_uvm1::fun1, this)),
                     sc_spawn(sc_bind(&top_uvm1::fun2, this))
           SC_JOIN

      cout << "run: after fork/join" << endl;
      wait(100,SC_NS);
      cout<<"Current time is "<< sc_time_stamp() << endl;

       phase.drop_objection(this);

        }


  top_uvm1 (uvm::uvm_component_name name="uvm_top1") : uvm::uvm_component( name ) { }

};

 

int sc_main(int argc, char **argv) {
       
       top_uvm1* top_uvm_1;
       
       top_uvm_1 = new top_uvm1("top_1");

       uvm::run_test("");

      return 0;

}
 

Link to comment
Share on other sites

22 hours ago, KEVIN CHACKO said:

If the threads in top_uvm2 are in a SC_JOIN or SC_JOIN_None implementation(both commented in code) the whole system works fine without any errors but the issue is with the SC_JOIN_ANY implementation. 

If you use SC_JOIN or your SC_JOIN_ANY, you want to keep the run_phase active until all (or at least one) of the threads terminate(s).  Why can't you raise an objection here?  You will drop the objection after the join, so the phase can successfully complete. (Without joining, it's fine not to raise an objection).

Link to comment
Share on other sites

Interesting observation:

The error is reproducible if you just add one process to the "terminated_events". But if I replace the list (which has only one event now) within the wait statement with the concrete terminated_event() of that process it works as expected (kind of, as we have now only one process):

Replacing

sc_core::wait(terminated_events);

with

sc_core::wait(sc_spawn(sc_bind(&top_uvm2::fun1, this),"fun1").terminated_event());

 

Link to comment
Share on other sites

Further investigation seems to indicate that, when the process for the non-objected run_phase is destroyed its get_child_objects() list is empty. Thus, the spawned processes get not killed before the sc_event_or_list is destructed. Which in turn, raise the "prematurely destroyed" message. I could not reproduce this with plain SystemC, so a bug in UVM-SystemC is not ruled out, yet.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...