KEVIN CHACKO Posted January 17, 2019 Report Share Posted January 17, 2019 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; } Quote Link to comment Share on other sites More sharing options...
KEVIN CHACKO Posted January 17, 2019 Author Report Share Posted January 17, 2019 The wait statements inside the dynamically spawned threads are the cause of the problem. The waits cause the threads to terminate without completing. Quote Link to comment Share on other sites More sharing options...
Philipp A Hartmann Posted January 21, 2019 Report Share Posted January 21, 2019 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. Quote Link to comment Share on other sites More sharing options...
KEVIN CHACKO Posted January 22, 2019 Author Report Share Posted January 22, 2019 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 Quote Link to comment Share on other sites More sharing options...
Philipp A Hartmann Posted January 22, 2019 Report Share Posted January 22, 2019 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 Quote Link to comment Share on other sites More sharing options...
Stephan Gerth Posted January 23, 2019 Report Share Posted January 23, 2019 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 maehne 1 Quote Link to comment Share on other sites More sharing options...
KEVIN CHACKO Posted January 23, 2019 Author Report Share Posted January 23, 2019 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; } Quote Link to comment Share on other sites More sharing options...
Philipp A Hartmann Posted January 24, 2019 Report Share Posted January 24, 2019 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). Quote Link to comment Share on other sites More sharing options...
Stephan Gerth Posted January 25, 2019 Report Share Posted January 25, 2019 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()); Quote Link to comment Share on other sites More sharing options...
Stephan Gerth Posted January 25, 2019 Report Share Posted January 25, 2019 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. Quote Link to comment Share on other sites More sharing options...
Stephan Gerth Posted January 31, 2019 Report Share Posted January 31, 2019 As a temporary workaround you could make "sc_event_or_list terminated_events" a member of top_uvm2. Quote Link to comment Share on other sites More sharing options...
Stephan Gerth Posted January 31, 2019 Report Share Posted January 31, 2019 Minimal example of the actual underlying issues posted here: http://forums.accellera.org/topic/6232-killing-a-process-with-an-included-sc_event_andor_list/ maehne 1 Quote Link to comment Share on other sites More sharing options...
KEVIN CHACKO Posted February 1, 2019 Author Report Share Posted February 1, 2019 Thanks Stephan, for the temporary workaround. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.