Jump to content

David Long

Members
  • Content Count

    37
  • Joined

  • Last visited

  • Days Won

    8

Reputation Activity

  1. Like
    David Long got a reaction from maehne in static and dynamic sensitivity   
    Hi Amit,
     
    A process has static sensitivity if it contains one or more calls to wait(). The sensitivity is set before the simulation starts running, usually be using "sensitive" in its parent module's constructor.
     
    Dynamic sensitivity is where a process contains one or more calls to wait(a_time_value) or wait(a_named_event). It is dynamic because the conditions that cause a thread process to wake up change as each wait statement is executed when the simulation runs.
     
    Here is a very brief example (not tested):
     
    SC_MODULE(mod) { sc_in<bool> clk; sc_event e; void proc1() { wait(); //static sensitivity e.notify(); } void proc2() { while(1) { wait(e); //wait for event (dynamic) //do something wait(1,SC_NS); //wait for time (dynamic) //do something } SC_CTOR(mod) { SC_METHOD(proc1); sensitive << clk.pos(); //static sensitivity SC_THREAD(proc2); //no static sensitivity, runs during initialization until 1st wait reached } };  
    You can find further details in section 4.2 of the SystemC LRM (1066.2011).
     
    Regards,
    Dave
  2. Like
    David Long got a reaction from maehne in static and dynamic sensitivity   
    Hi Amit,
     
    I would not say that next_trigger is "like a delay element" since it does not hold up execution of an SC_METHOD (which would be illegal). It overrides the static sensititivity of an SC_METHOD and so changes the conditions which next cause the method to execute. There is an example on page 51 of the LRM.
     
    Regards,
    Dave
  3. Like
    David Long got a reaction from amitk3553 in static and dynamic sensitivity   
    wait() with no arguments is only used for static sensitivity
     
    next_trigger() has similiar functionality to wait() but is only used within sc_method processes, while wait() is only used within sc_thread processes. The main difference is that sc_methods cannot consume time (wait is illegal) so next_trigger (with an argument) overrides any static sensitivity to control when the sc_method will next be called (after it has completed). There might be multiple calls to next_trigger in the same sc_method - the last one to be executed before the function returns is the one that sets the sensitivity for the next call.
     
    Regards,
    Dave
  4. Like
    David Long got a reaction from maehne in static and dynamic sensitivity   
    Hi Amit,
     
    A process has static sensitivity if it contains one or more calls to wait(). The sensitivity is set before the simulation starts running, usually be using "sensitive" in its parent module's constructor.
     
    Dynamic sensitivity is where a process contains one or more calls to wait(a_time_value) or wait(a_named_event). It is dynamic because the conditions that cause a thread process to wake up change as each wait statement is executed when the simulation runs.
     
    Here is a very brief example (not tested):
     
    SC_MODULE(mod) { sc_in<bool> clk; sc_event e; void proc1() { wait(); //static sensitivity e.notify(); } void proc2() { while(1) { wait(e); //wait for event (dynamic) //do something wait(1,SC_NS); //wait for time (dynamic) //do something } SC_CTOR(mod) { SC_METHOD(proc1); sensitive << clk.pos(); //static sensitivity SC_THREAD(proc2); //no static sensitivity, runs during initialization until 1st wait reached } };  
    You can find further details in section 4.2 of the SystemC LRM (1066.2011).
     
    Regards,
    Dave
  5. Like
    David Long got a reaction from karandeep963 in SystemC simulation Kernel scheduling   
    Hi,
     
    Because process 2 has to suspend and wait for event x, and because event x is only notified by process 1, the state of the instructions seen by process 2 when it wakes up will alway depend on what has happened in process 1 or process 3. Once a process is active, it will remain active until either it reaches the end of the function or it reaches a wait statement. Only one process can be active at the same time. The SystemC scheduler does not currently allow one process to pre-empt another (this feature might be added to a future version).
     
    This confirms your assumption above  "So the answer to question, that in process P2 does the instruction 3 will get the updated value of instruction 1-2 of the same process P2.?
    is NO."
     
    Regards,
    Dave
  6. Like
    David Long reacted to apfitch in Timing Annotation   
    See the glossary of the SystemC standard paragraph B.183 p580.
     
    regards
    Alan
     
    P.S. At the risk of sounding like a broken record, it is always best to look things up in the standard first.
     
    P.P.S. If you're young and don't know what a broken record is, imagine I said "scratched CD"
     
    P.P.P.S If you're really young and don't know what a scratched CD is, imagine I said "sample with corrupted loop points"
  7. Like
    David Long got a reaction from karandeep963 in spawned and unspawned process   
    Hi KS,
     
    If you are just starting out with SystemC, you can probably safely ignore dynamic (spawned) processes - just use SC_METHOD or SC_THREAD in the module's constructor. Dynamic processes can be useful for advanced cases (e.g. responding to some condition that is not known at compile time).
     
    Regards,
    Dave
  8. Like
    David Long got a reaction from amitk3553 in Mutex and semaphore   
    Hi Amit,
     
    The scheduling mechanism for sc_mutex and sc_semaphore is very simple and does not have fifo characteristics (i.e. if several processes are waiting for the mutex/semaphore, they are not granted it based on the order in which they requested it - although there is nothing to stop an implementation of SystemC from executing processes in the same order as they are added to the list of runnable processes, the LRM says that the order is implementation defined).
     
    The basic operation of a set of processes using a mutex/semaphore could be like this:
     
    1) a process runs and grabs the free mutex/semaphore, it then hits a wait before releasing it
    2) other processes run and attempt to grab the mutex/semaphore. If it is not free, the processes wait (for an event that is within the mutex/semaphore object)
    3) the process with that has grabbed the mutex/semaphore wakes up and frees the mutex/semaphore - this issues an immediate notification on the mutex/semaphore's internal event
    4) the processes waiting for the mutex/semaphore get added to the list of runnable processes. One of them starts executing and grabs the mutex/semaphore but hits a wait statement before releasing it
    5) the remaining processes in the list of runnable processes will each start executing in the same evaluation phase, but now the mutex/semaphore is locked by the process that started in step 4 so they will block again until the next notifcation of the mutex/semaphore event (as in step 3)
    Steps 3 to 4 are repeated until the end of the simulation or until every process has completed its access to the shared resource
     
    Hope that is enough to give you the idea!
     
    Regards,
    Dave
  9. Like
    David Long got a reaction from apfitch in spawned and unspawned process   
    Hi Amit,
     
     
    Pretty much - static processes are created using the SC_METHOD and SC_THREAD macros. Dynamic processes are created by calling sc_spawn. There is one slight complication, calling sc_spawn from a module's constructor will actually create a static process since the LRM defines a dynamic process as one created from "the end_of_elaboration callback or during simulation" (see Glossary B.51). The LRM uses the term "spawned" and "unspawned" to try to avoid this confusion!
     
    Regards,
    Dave
  10. Like
    David Long got a reaction from apfitch in spawned and unspawned process   
    Hi Amit,
     
     
    Pretty much - static processes are created using the SC_METHOD and SC_THREAD macros. Dynamic processes are created by calling sc_spawn. There is one slight complication, calling sc_spawn from a module's constructor will actually create a static process since the LRM defines a dynamic process as one created from "the end_of_elaboration callback or during simulation" (see Glossary B.51). The LRM uses the term "spawned" and "unspawned" to try to avoid this confusion!
     
    Regards,
    Dave
  11. Like
    David Long got a reaction from amitk3553 in static and dynamic sensitivity   
    Hi KS,
     
    By default, proc1 runs once during the initialization phase (unless dont_initialize() is called immediately after SC_METHOD(proc1) in the module constructor).
    Once proc1 has executed, the next_trigger statement changes its sensitivity so that from then on it will be called whenever event x is notified, not when clk has an event.
     
    Regards,
    Dave
  12. Like
    David Long got a reaction from amitk3553 in Mutex and semaphore   
    Hi Amit,
     
    A mutex is used to ensure mutual-exclusive access to a shared resource. Think of it as being like having a single key to unlock access to the resource that you pass between processes that request it. Only one process can have it at a time - any other process that wants it will have to wait until the key becomes available.
     
    A semaphore is similar but is more like a bucket containing multiple keys. You can set the number of keys in the bucket when it is created, processes request keys just like the mutex and will have to wait ("block") when no key is available. However, unlike the mutex, you can have multiple processes accessing the resource in the same time interval.
     
    Regards,
    Dave
  13. Like
    David Long got a reaction from amitk3553 in static and dynamic sensitivity   
    wait() with no arguments is only used for static sensitivity
     
    next_trigger() has similiar functionality to wait() but is only used within sc_method processes, while wait() is only used within sc_thread processes. The main difference is that sc_methods cannot consume time (wait is illegal) so next_trigger (with an argument) overrides any static sensitivity to control when the sc_method will next be called (after it has completed). There might be multiple calls to next_trigger in the same sc_method - the last one to be executed before the function returns is the one that sets the sensitivity for the next call.
     
    Regards,
    Dave
  14. Like
    David Long got a reaction from amitk3553 in SystemC simulation Kernel scheduling   
    You have waits in each process so I am assuming they are all sc_threads (otherwise you will get a run-time error).
    Also, I should point out that by defualt, all processes are executed once, during initialization and will run until either they hit a wait or the end of the function is reached.
    You have not shown any loops in your processes. This means that each process will die (and cannot be resurected) when it gets to the end.
     
    So ...
     
    During initialization (at time 0), each process will run, in some unknown order (you must not make any assumptions about which order the processes will be executed in).
    P1 will run until it hits the wait statement, generating an immediate notification (i.e. in the current sim cycle) on event x.
    If P2 happens to run before P1, it will stop at the wait(x) statement. Once P1 has run, it will immediately wake up, continue to the end and then die. If P2 runs after P1, it will stop at the wait(x) statement and never wake up - a process must be waiting BEFORE an event is notified in order to respond to it and P1 does not contain a loop so it will not notify x again!
    P3 runs up until the wait statement.
     
    When the event in the static sensitivity list occurs, P1 and P3 will wake up (again we do not know in what order), run to the end and then die.
     
    I suggest you take another look at the LRM if this is not the behaviour you were expecting!
     
    Regards,
    Dave
  15. Like
    David Long got a reaction from karandeep963 in SystemC simulation Kernel scheduling   
    Hi KS,
     
    Before answering your question, it is worth pointing out the way the SystemC scheduler works. After inititialization, it advances time to the earliest time step where there is a scheduled event notification. It adds all processes that are sensitive to that event (or other events at the same time step) into a list of "runnable" processes. It then resumes execution of every process in the list of runnable processes (one at a time) in some non-deterministic order. This is known as the evaluation phase. An immediate event notification can add processes to the list of runnable processes within the current time step, provided such processes are currently waiting for that event.  Once the list of runnable processes is empty, the scheduler proceedes to the update phase where primitive channels (such as sc_signal) that have been written to, get updated. These primitive channels may be in the sensitivity list of other processes, in which case there is another iteration of the evaluate and update phases known as a delta cycle. This continues until there are no more events to process at the current time step, when the scheduler advances to the next time step.
     
    Now, sssuming all of your processes above are within infinite loops, then after the end of the initialization phase, P1 and P3 will be suspended at their wait() statements and P2 will be waiting for an event on x.
     
    When the event in P1 and P3's static sensitivity list happens, both processes get added into the list of runnable processes in the current time step. P1 or P3 will then run. If P1 runs first, it will notify event x immediately, this will add P2 to the list of runnable processes. The next process to run could be either P2 or P3.
     
    Since P2 always waits for the event notified by P1, it will always run after P1 in any simulation cycle.
     
    It's not clear to me what instruction1,etc are doing. If they are just variables that are being read and written, then P2 could see the values written by P1. However, P3 could be executed after P1 but before P3. In which case P2 would see the values written by P3. We cannot predict what will happen (although the order will always be the same every time the simulation is run). Instruction3 in P2 would see the values of instruction1/2 set by P1 or P3, depending on the order that the scheduler executes the process.
     
    Hope that makes it a bit clearer for you.
     
    Regards,
    Dave
  16. Like
    David Long got a reaction from maehne in How to change the word length of "sc_fix" dynamically? Any examples?   
    The integer bit length is set when the sc_fix object is created and cannot subsequently be varied. If you want to find the optimum representation, I would suggest an iterative approach where you copy the original number to a new object with a different word length on iteration until you find the best fit. If you want to affect the representation of multiple object from one place, have a look at the sc_context_switch (see sections 7.2.3 and 7.11 in the LRM).
     
    You might also want to look at the sc_fxcast_switch. This can be used to turn fixed-point represention on and off (sc_fix reverts to floating point when off). This is good to see how your fixed-point representation compares against ideal floating point behaviour.
     
    Regards,
    Dave
  17. Like
    David Long got a reaction from maehne in sc_module_name used for ???   
    sc_module_name is required as an argument of the constructor to any class derived from sc_module (if there are multiple constructor arguments, sc_module_name is usually the first). It is passed a string argument which is used to create a temporary sc_module_name object that is then passed to the sc_module constructor, and used to create a hiearachical name for every component in a SystemC model (sc_module_name is itself a class and its constructor takes a string).
     
    If that still seems a bit confusing, I suggest you read through section 5.3 of the SystemC Language Reference Manual (available from http://standards.ieee.org/getieee/1666/download/1666-2011.pdf)
     
    Regards,
    Dave
  18. Like
    David Long got a reaction from amitk3553 in static and dynamic processes   
    Hi Amit,
     
    Static processes are created before the start of simulation, by calling e.g. SC_THREAD macro or sc_spawn in the constructor or end_elaboration callback.
     
    Dynamic processes are created by calling sc_spawn within another process (which will not be executed until the simulation is running).
     
    Regards,
    Dave
  19. Like
    David Long got a reaction from amitk3553 in SystemC simulation Kernel scheduling   
    You have waits in each process so I am assuming they are all sc_threads (otherwise you will get a run-time error).
    Also, I should point out that by defualt, all processes are executed once, during initialization and will run until either they hit a wait or the end of the function is reached.
    You have not shown any loops in your processes. This means that each process will die (and cannot be resurected) when it gets to the end.
     
    So ...
     
    During initialization (at time 0), each process will run, in some unknown order (you must not make any assumptions about which order the processes will be executed in).
    P1 will run until it hits the wait statement, generating an immediate notification (i.e. in the current sim cycle) on event x.
    If P2 happens to run before P1, it will stop at the wait(x) statement. Once P1 has run, it will immediately wake up, continue to the end and then die. If P2 runs after P1, it will stop at the wait(x) statement and never wake up - a process must be waiting BEFORE an event is notified in order to respond to it and P1 does not contain a loop so it will not notify x again!
    P3 runs up until the wait statement.
     
    When the event in the static sensitivity list occurs, P1 and P3 will wake up (again we do not know in what order), run to the end and then die.
     
    I suggest you take another look at the LRM if this is not the behaviour you were expecting!
     
    Regards,
    Dave
  20. Like
    David Long reacted to apfitch in SystemC Guides for Beginners   
    On our website there's a tutorial and a number of videos and examples of TLM2 and SystemC (see www.doulos.com/knowhow/systemc and www.doulos.com/knowhow/systemc/tlm2), though I must admit the tutorial is quite hardware orientated.
    There used to be a tutorial on the Forte Design Systems website, but I can't find it any more.
    I would recommend downloading the latest standard (IEEE 1666-2011) via
    http://www.accellera.org/downloads/ieee/
    I certainly would *not* recommend either the 2.0 user guide or the 2.0.1 reference manual, they are very out-of-date. To paraphrase someone, every time I see sc_bit I reach for my revolver :-)
    Probably the best general book is "SystemC from the Ground Up" by David C Black, Jack Donovan, Bill Bunton and Anna Keist.
    regards
    Alan
  21. Like
    David Long got a reaction from farhad01 in How to pass variable sized packed arguments to a task/function?   
    If you want to add "missing" features into a SV testbench, it can be very easy using DPI, provided you know basic C/C++ syntax.
     
    For example, here is a version of your double task that takes an open array (assumed here to be a packed bit vector of any length). I haven't included any checking/error handling but even so, this should still be OK for up to 32-bit vectors.
    #include "svdpi.h" extern "C" { int double_vec (svOpenArrayHandle h) {   svBitVecVal *ptr;   int size;   int value;   size = svSize(h,0);   //get bit vector ptr from handle   ptr = (svBitVecVal*)svGetArrayPtr(h);   //convert to int   value = bv_to_int(ptr,size);   value *= 2;   //write int back to bv   int_to_bv(value,ptr,size);   return 0; } }  
    The functions to convert to/from int/bit vector could be something like:
     
    int bv_to_int(const svBitVecVal* bv, int size) {   int val = 0;   int mask = 1;   for (int i=0; i<size; i++){       if (svGetBitselBit(bv,i) == sv_1)           val |= mask;       mask <<= 1;   }   return val; } void int_to_bv (int val, svBitVecVal* bv, int size) {   int mask = 1;   svBit b;   for (int i=0; i<size; i++){       b = (val & mask) ? sv_1 : sv_0;       svPutBitselBit(bv,i,;       mask <<= 1;   } }  
    You could declare and use the DPI function in SV as follows:
     
    module top();   import "DPI-C" task double_vec(inout bit[] vec);     bit [7:0] vec8 = 8'd15;   bit [15:0] vec16 = 16'd1234;     initial begin     $display ("vec8 = %0d, vec16 = %0d", vec8, vec16);       double_vec(vec8);     double_vec(vec16);     $display ("vec8 = %0d, vec16 = %0d", vec8, vec16);     end endmodule: top   With simple uses of DPI such as this, most current SV simulators will automatically compile and link the SV and C/C++ code for you, e.g.
    qverilog top.sv double.cpp  
    Hope that gives you some ideas, even if it is a somewhat more complicated solution than you were hoping for!
     
    Regards,
    Dave
     
     

     

     
  22. Like
    David Long got a reaction from ggupta in OVM RGM Porting to UVM   
    Hi,
     
    The iregGen tool supports both uvm_rgm and the standard uvm_reg classes. I would recommend using the uvm_reg if possible since RGM is not part of the ASI standard.
     
    Regards,
    Dave
×