Jump to content

ANKUR SAINI

Members
  • Content Count

    20
  • Joined

  • Last visited


Reputation Activity

  1. Like
    ANKUR SAINI reacted to Philipp A Hartmann in SystemC Simulation Semantics and Scheduler Steps   
    Hi Ivan,
    instead of referring to the very old 2.01. LRM, I suggest to check the IEEE Std. 1666-2011 for SystemC, which could can download at no cost (sponsored by Accellera) via https://standards.ieee.org/findstds/standard/1666-2011.html.  This document includes the normative answers to all of your questions.
     
    Yes, see section 5.10.8 of the aforementioned standard.
     
    Kind of, yes.  This is called "time out", see section 4.2(.1) of the standard.
     
    The order to execution of processes in the runnable queue is entirely implementation-defined. See section 4.2.1.2.
    Hope that helps,
      Philipp
    Disclaimer: I haven't checked all of your post for correctness and focused on the questions instead.
    .
     
  2. Like
    ANKUR SAINI reacted to Ivan in SystemC Simulation Semantics and Scheduler Steps   
    Hello everyone, 
    first of all I apologize if the post is too big and I know sometimes people get discouraged to read big posts. On the other hand I spent quite some time trying to make the post as clear as possible for the reader. So please do not get discouraged :).
    My SystemC version: SystemC 2.3.1
    My operating System: Ubuntu 16.04
    I am trying to understand how SystemC simulator works, and for that I ran the following code:
    SC_MODULE(EventNotifications) { sc_event evt1; void p1() { evt1.notify(10, SC_NS); evt1.notify(5, SC_NS); evt1.notify(); evt1.notify(0, SC_NS); wait(10, SC_NS); evt1.notify(5, SC_NS); wait(10, SC_NS); } void p2() { wait(10, SC_NS); evt1.cancel(); evt1.notify(); wait(10,SC_NS); } void p3() { cout << "evt1 is activated at " << sc_time_stamp() << endl; } SC_CTOR(EventNotifications){ SC_THREAD(p1); SC_THREAD(p2); SC_METHOD(p3); sensitive << evt1; dont_initialize(); } }; I referred to the SystemC Language Reference Manual 2.0.1: http://homes.di.unimi.it/~pedersini/AD/SystemC_v201_LRM.pdf
    and in my explanation down below, I used the following abbreviations: 
    R = {} - list of runnable processes, 
    D = {} - list of processes that have been notified using delta notifications, 
    T = {} - list of processes where timed notification has been used e.g. event.notify( >0, SC_NS) 
    2.4.1 Scheduler Steps at page 6 from the SystemC Language Reference Manual 2.0.1 was used for the following reasoning of how this code works:
    Initialize phase:
        We initialize all the processes that are ready to run. Process p3 at the beginning will not be runnable due to dont_initialize command. So only p1 and p2 processes runnable, as a result  R = {p1, p2} at  the end of initialize phase. Now we go to the evaluation phase. We start with simulation time equal to 0ns.
    Simulation time = 0 ns
        Evaluation phase (delta cycle = 0):
            We have at the beginning R = {p1, p2}, D = {} (empty list) and  T = {}. Let's say scheduler decides to execute p1 first, so p1 gets removed from R, effectively R = {p2}.
            Then we execute 1st timed notifications evt1.notify(10, SC_NS), after that we have evt1.notify(5, SC_NS), since 5ns is earlier than 10ns, only 5ns will be remembered so we have T = {p3}.
            Next statement is evt1.notify() which is immediate notification, and will overwrite the previous notification evt1.notify(5, SC_NS). Immediate notification is put into the list p3, R ={p3}, and T = {}. Next statement is evt1.notify(0, SC_NS), so p3 will be put in the list D. So now we have R = {p3}, D = {p3}, T ={}. 
        
            Question 1: if I swapped two statements evt1.notify(0, SC_NS) and evt1.notify() here, will the delta notification will be removed? In my opinion only evt1.nofity() will be remembered:
            From page 128 of the manual: "A given sc_event object can have at most one pending notification at any point. If multiple notifications are made to an event that would violate this rule, the “earliest notification wins” rule is applied to determine which notification is discarded."
            As a result I would have R = {p3, p2}, D = {}, T = {}. Now we encounter the wait(10, SC_NS) and p1 is put to wait. 
            Question 2: Since I we have wait(10, SC_NS), does that mean that the process p3 will be put in separate list/queue of sleep processes? Let's call it list S, so we would have S = {p1} effectively? 
     
            Next let's say scheduler decides to run p2, so we remove p2 from the R list and we have R = {p3}. There we encounter wait(10, SC_NS), and p2 gets into S list, S = {p1, p2}.
            Now we have R = {p3} and p3 gets executed, so immediate notification gets executed at simulation time 0 ns as 1st console output indicates. Now method p3 exits, and list R is empty, R = {}, so we go to update phase.
        
        Update phase (delta cycle = 0):
            Nothing to be updated. We just go to the next delta cycle phase.
            
        Next delta cycle phase(delta cycle = 0):
            We increment delta cycle, and check all the contents of list D and put them in the list R. In our case D = {p3}, thus R = {p3}. Now we go back to evaluation phase.
            
        Evaluation phase(delta cycle = 1):
            We run only p3, here so the delta notification happens at simulation time 0 ns + 1 delta cycle. R = {}, we go to the update phase.
            
        Update phase (delta cycle = 1):
            Nothing to be updated. Go to next delta cycle phase.
            
        Next delta cycle phase(delta cycle = 1):
            We increment delta cycle, but since D = {}, we go to the increase simulation time phase.
            
        Increase simulation time phase (delta cycle = 2):
            From the page 6: "If there are no more timed event notifications, the simulation is finished. Else, advance the current simulation time to the time of the earliest (next) pending timed event notification."
            Now back to my Question 2, since we T = {}, that would mean that we have no timed event notifications, and based on reference manual simulation should be finished, which is not the case here if you run the code. 
            So from my understanding, the processes that were called with wait operation, will not be put in the "list of sleep processes" but instead they will be put to either list T or D.
            I think in case wait(>0, SC_NS), process gets put into the T list, and if wait(0, SC_NS) is called process should be put into the D list. So in our case T = {p1, p2}?
            We increase simulation time to the earliest 10 ns, and contents of list T = {p1, p2} are put into the list R = {p1, p2}. and we go to the next evaluation phase.
            
    Simulation time = 10 ns:
        Evaluation phase (delta cycle = 0):
            Here we can either run p1 or p2. Let's say p2 is run first, and we encounter evt1.cancel(), since there are no pending events nothing will happen. Then we execute evt1.notify(), and p3 gets into the list R, so R = {p1, p3}. Then wait encountered, so T = {p2}.
            
            Now let's say scheduler decides to execute p3, and then immediate notification happens at simulation time of 10 ns.
            Now R = {p1}, so p1 gets executed and there we have evt1.notify(5, SC_NS), so p3 gets into the list T = {p2, p3}. Then we execute wait(10, SC_NS), and p1 sleeps again. So T = {p2, p3, p1}. Since R = {0}, we go to update phase.
            
        Update phase (delta cycle = 0):
            Nothing to be updated, so we go to the next phase.
            
        Next delta cycle phase (delta cycle = 0):
            We increment delta cycle. Nothing in list D, so we go to the next phase.
            
        Increase simulation time phase (delta cycle = 1):
            We put contents of T into R, thus R = {p2, p3, p1}, and we increment time to the earliest pending notification, since we had evt1.notify(5, SC_NS) and threads slept for 10 ns, we chose 5 ns. So simulated time is increased to 15 ns. We again go to the evaluation phase.
    Simulation time = 15 ns:
        
        Evaluation phase (delta cycle = 0):
            Here R = {p2, p3, p1}, so let's say we execute p3 first, as result timed notification evt1.notify(5, SC_NS), happens at simulated time 15 ns. Now R = {p2, p1}, and p1 executes, since nothing after last wait statement thread terminates. Same situation for p2, so p2 terminates. R ={} go to next phase.
            
        Update phase (delta cycle = 0):
            Go to next phase.
            
        Next delta cycle phase (delta cycle = 0):
            Delta cycle updates, since D = {}, we go to the next phase
            
        Increase simulation time phase (delta cycle = 1):
            Since T = {}, nothing to be simulated and simulation ends. 
    So this would explain the following result I got outputted on the console:

    evt1 is activated at 0 s
    evt1 is activated at 0 s
    evt1 is activated at 5 ns
    evt1 is activated at 10 ns
     
    I tried to check my assumption that when wait(0, SC_NS) gets called in some process, the process will be put in the D list. So I ran this code:
    SC_MODULE(DeltaTimeWait) { void p1(void) { while (true) { cout << "p1: " << sc_time_stamp() << endl; wait(0, SC_NS); } } void p2(void) { while (true) { cout << "p2: " << sc_time_stamp() << endl; wait(0, SC_NS); } } SC_CTOR(DeltaTimeWait) { SC_THREAD(p1); SC_THREAD(p2); } }; There is also one thing I noticed. For example if I change the order of the thread registration in the constructor of the 1st code, and having SC_THREAD(p2) before the SC_THREAD(p1), I get different result.
    SC_CTOR(Task5_d){ SC_THREAD(p2); SC_THREAD(p1); SC_METHOD(p3); sensitive << evt1; dont_initialize(); } I get the following result:
    evt1 is activated at 0 s
    evt1 is activated at 0 s
    evt1 is activated at 10 ns
    I am not sure if my reasoning for this result is correct. So I think that we get his output due to reason that at the point where simulation time was 10 ns, we had two choices, we could either schedule p1 or p2 first.
    Simulation time = 10 ns:
        Evaluation phase (delta cycle = 0):
           At this point as I have mentioned earlier, we can either run p1 or p2 first. And in the first case we assumed p2 was run first. But if we assume now p1 will be run 1st instead of p2. So now p1 gets executed and statement evt1.notfiy(5, SC_NS) is encountered. As a result, process p1 gets into the list T and then we sleep the process. Now the process p2 gets scheduled, and the 1st line we encounter is evt1.cancel(), which as result would cancel pending notification evt1.notfiy(5, SC_NS) from process p1. After that evt1.notify() is executed which results p3 getting into R list. So p3 being only in the list R, we execute process p3, and evt1 is notified at simulation of time 10 ns.  
    Question 3: How come that order of thread registration actually affects the order of the process being scheduled?
    I am not sure if my reasoning is correct, so I would appreciate your feedback, as I am only a beginner in SystemC.
     
    Looking forward to your feedback.
    Ivan.
  3. Like
    ANKUR SAINI reacted to Roman Popov in Debugging Multi threaded program in SystemC   
    SystemC does not execute your threads in parallel, they are executed sequentially. But this is true that inter-thread communtication is hard to debug. Best known debugging method is waveform analysis. Usually it is much faster to identify source of problem on waveform, rather than with text logs. With opensource kernel you can use sc_trace to trace variables. Commerical SystemC debuggers offer GUI with drag-and-drop support.
  4. Like
    ANKUR SAINI reacted to AmeyaVS in Debugging Multi threaded program in SystemC   
    Hello @ANKUR SAINI,
    If you are on Linux/UNIX with the Accellera release of SystemC library with the GNU toolchain, you can use the following tutorials for reference:
    https://sourceware.org/gdb/onlinedocs/gdb/Threads.html https://stackoverflow.com/questions/1695268/multi-threaded-debugging-tutorial-for-gdb-and-c Due to the co-operative multi-tasking implementation of the SystemC library available from Accellera as @Roman Popov has mentioned, much of the debugging tasks are easier since all threads synchronize with the main library thread.
    Let me know if it helps.
    Regards,
    Ameya Vikram Singh
     
  5. Like
    ANKUR SAINI reacted to David Black in Tracing internal signals declared in sc_module using sc_trace   
    Manikanta's solution assumes temp is public. If not public, you can take the opposite approach and simply call sc_trace from within the module itself. You could even do it conditionally based on run-time command-line arguments:
      
    sc_core::sc_trace_file trace_file = 0; //< initialize to indicate not open top::before_end_of_elaboration() {    for (int i=1; i<sc_argc(); ++i) {       if ( trace_file == 0 && std::string(sc_core::sc_argv()[i]) == "-trace" ) trace_file = sc_core::sc_create_vcd_trace_file("your.vcd"); }//endfor } top::end_of_simulation() {   if ( trace_file != 0 ) sc_core::sc_close_trace_file(trace_file); } ... extern sc_core::sc_trace_file trace_file; void dut::end_of_elaboration() {   if (trace_file != 0) { sc_core::sc_trace(trace_file, temp,"temp");   } }  
    Of course I am assuming fp is made public as shown, and that you have opened it before end of elaboration:
  6. Thanks
    ANKUR SAINI reacted to David Black in How exactly sc_main works !!   
    Just to add a bit to Philipp's excellent reply:
    In part this was done to support EDA tools that support co-simulation of SystemC with other languages (e.g. SystemVerilog and VHDL). The EDA tools themselves implement main and then they can dynamically link in your sc_main as needed.
    Of course if you really know how to control the linker, there are other means as well, but we don't need to go there.
  7. Thanks
    ANKUR SAINI reacted to Philipp A Hartmann in How exactly sc_main works !!   
    This question in mostly about how the linker works on your platform, and not really specific to SystemC.  Let me try to give a short summary:
    Yes, the "main" symbol is needed by the final application For every needed symbol, the linker looks in your object files first If the symbol is present there, the linker picks it up If not, the linker looks in the libraries given by the user (order/lookup is platform-specific) Repeat this for all required symbols (including "sc_main") So, if you define your own "main" in your application, SystemC's "main" will not be picked. This is actually a feature, as you can call "sc_elab_and_sim" manually from your "main" as well, if you want.
    Hope that helps,
      Philipp
     
  8. Like
    ANKUR SAINI reacted to Philipp A Hartmann in before_end_of_elaboration callback   
    Because your "analyzer" instance is a local variable in the before_end_of_elaboration function, which gets destructed immediately, when the function returns.  So there is no analyzer left to call the callback on later (same holds for the local signal sig2, btw.).  You would need to allocate the module dynamically instead.
     
    You cannot alter/modify/redefine any existing port binding at any time.  You can only add new bindings, including during before_end_of_elaboration.
    Hope that helps,
      Philipp
×
×
  • Create New...