Jump to content
NickIlieskou

Delta Cycle and concurrency

Recommended Posts

Hey to everybody, 

 

I would like to ask a very simple question just to clarify how the concurrency concept work in SystemC. Let's say that we have two modules. Both modules are sensitive to the positive edge of the simulation clock. module1 is changing the value of a signal (or of a global variable). At the same time module2 has to read the signal ( or the global variable ).

 

So my main question is if in one cycle during which both modules are invoked at the same time module 2 will read the latest value that module1 will output. I think that SystemC has the notion of delta cycle by which before going to the next simulation step ( or clock cycle ) it will make sure that all processes read the latest values of signal/variables independently from which or how many modules have changed their value.  

 

Thank you in advance!!! 

Share this post


Link to post
Share on other sites

There's a difference between a signal and a variable. A signal does have delta cycle behaviour - so when the clock changes, module 2 will read the current (before the change) value.

 

With a plain C++ variable the result is undefined as you don't know which process will run first (the process in module 1 or the process in module 2)

 

regards

Alan

Share this post


Link to post
Share on other sites

Thank you for your answer. It's nice that you specify the difference between the signal and the variable. So if I want to be sure that module2 will read the latest value of something I should make sure that this will be a signal and not a global variable. Thank you again Alan. 

Share this post


Link to post
Share on other sites

Sorry for asking again, but I would like to know if there is any way for module 2 to read the latest value of the signal that module1 has written at the same time ( let's say at the same positive edge).

Share this post


Link to post
Share on other sites

The danger with that approach is that you have to manually make sure you have no race hazards in your design or indeterminacy in your design.

 

My first answer would be "don't use a signal", use a shared variable instead.

 

Another answer would be to have a shared event between the modules. You could do something like

module1
   sc_event sig_written;

 // in  a process
     my_sig.write(true);
     sig_written.notify(); // immediate notify!

///////////////////////////
module2

   sc_in<int> sig;
   // in an sc_thread
   sc_event * ev;

    module2(sc_module_name name_, sc_event * ev_) : sc_module(name_),  ev(ev_) {
   }

    void thread()  {
        while (true) {
         wait(sig_written); 
         cout << my_sig << endl;
       }

There must be a better way of doing that, but the idea is to share an event between the modules then use immediate notify to trigger the read. Of course there's no real point using an sc_signal then, as the ordering is given by the event, so you might as well just use a shared variable.

 

A third answer is to put the code in a single module, so you then have direct access to the value you are writing to the signal.

 

regards

Alan

Share this post


Link to post
Share on other sites

Thank you again for your answer Alan. Your idea about using events is nice. I hope it will work in my case. I can't put the whole code in a single module. I am trying to develop a simulation framework for different software applications. So in my application I have several dlls which have to execute at the same time depending on the scheduler, which I am trying to implement with SystemC. The problem is that I might need to execute dll n.1 first and then dll n.2 etc because these dlls they will change values of variables in the SystemC framework that will be read from other dlls at the same simulation time. However the order is not fixed. Thank you again!!!

 

regards

Nick 

Share this post


Link to post
Share on other sites

Hi,

Sorry for resurrecting this post but it addresses an issue i'm currently facing.

Does this mean that it is not possible  to implement instantaneous broadcast (as used in StateCharts or synchronous reactive models of computation for ex.) in SystemC ? With the latters, the undeterminacy is resolved by iterating  until a fix-point is reached so that the final values of shared variables do not depend on the order of (micro)-steps ? 


Jocelyn

Share this post


Link to post
Share on other sites
30 minutes ago, jserot said:

Does this mean that it is not possible  to implement instantaneous broadcast (as used in StateCharts or synchronous reactive models of computation for ex.) in SystemC ?

Can you please elaborate what do you mean by instantaneous broadcast for those who are not familiar with named formalisms?

Some small example will be the best. 

Share this post


Link to post
Share on other sites

Hi Roman, thanks for your feedback.

Instantaneous broadcast - also called "perfect synchrony" - means that any update performed to a shared value by a component (a module in our case) will be viewed immediately by other components (and not after n delta cycles, as for sc_signals). 


Here's a typical example, with two modules :

- module A waits for (global) event H (a clock typically) and, when received, set shared variable v  to 1

- module B also waits for H but when received only performs action xxx if v=1 (in StateChart, this is called a guarded transition)

void A::my_thread()
{
  ...
  while ( 1 ) {
    ...
    wait(h.posedge_event());
    v = 1;
    ...
    }
};

void B::my_thread()
{
  while ( 1 ) {
    wait(h.posedge_event());
    if ( v == 1 ) xxx;
    ...
    }
};

As explained by Alan, the above implementation does not correspond to the behavior suggested above :

- if v is implemented by using a sc_signal, then v only takes value 1 at time t+delta (if H occurs at time t), and hence "too late" for B

- if v is implemented as a "regular" shared variable, then  the behavior becomes non-deterministic (whether B "sees" v=1 depends on the order at which the scheduler runs the corresponding threads, which is un-predictable).

Currently, I don't see a solution other than enforcing execution order using sc_events (as suggested by Alan). But this seriously complicates the translation from formalisms supporting the SB hypothesis to SystemC. I was just wondering if i was missing sth about SystemC semantics or whether this  was simply not possible..

Jocelyn

 

Share this post


Link to post
Share on other sites

Ok, understood.

Yes, the only way to execute this in a single delta cycle is to enforce execution order using events with immediate notification. It is impossible to implement it in other way in C++.

What you want is a “SystemC-language-aware” compiler. Such a compiler will need to understand a semantics of processes and create a static schedule: such as a producer processes are always executed before consumer processes. Static scheduling is not always possible, because some processes can have cyclic data dependencies. So as you’ve said, sometimes it will need to resolve <<undeterminacy by iterating  until a fix-point is reached>>

But since SystemC is just a library, it can't guess what your processes code is doing (because C++ has no code reflection capabilities). 

Share this post


Link to post
Share on other sites

If your issue is that you don't like to have two variables: data and event, you can create a convenient class like sc_signal, that will pack data end event together. 

Essentially it will be sc_fifo with immediate notification and capacity  == 1.  If consumer reads from empty fifo it will be blocked until producer writes into fifo. With immediate notification it will be resumed in the same delta cycle as producer writes into fifo. 

Share this post


Link to post
Share on other sites
11 hours ago, Roman Popov said:
Quote

 

Ok, understood.

Yes, the only way to execute this in a single delta cycle is to enforce execution order using events with immediate notification. It is impossible to implement it in other way in C++.


 

Ok, thanks. This is indeed what i suspected.

Quote

 

What you want is a “SystemC-language-aware” compiler. Such a compiler will need to understand a semantics of processes and create a static schedule: such as a producer processes are always executed before consumer processes.


 

Exactly. In fact, this is the kind of  solution i'm investigating. I'm starting from a compiler internal representation of the application as a graph of FSMs connected via shared variables. Each FSM is implemented as a SystemC module. The idea is to extract from the graph the chain of dependencies - i.e. which module(s) read (resp. write) each variable - and to insert delta wait(s) at the right place(s). In the example above, this would involve rewriting B as 


void B::my_thread()
{
  while ( 1 ) {
    wait(h.posedge_event());
    wait(SC_ZERO_CYCLE);
    if ( v == 1 ) xxx;
    ...
    }
};
Quote

Static scheduling is not always possible, because some processes can have cyclic data dependencies. So as you’ve said, sometimes it will need to resolve <<undeterminacy by iterating  until a fix-point is reached>>

Cyclic dependencies can be detected statically (as loops in the graph) and the corresponding programs rejected i guess.

 

Share this post


Link to post
Share on other sites
11 hours ago, Roman Popov said:
Quote

Essentially it will be sc_fifo with immediate notification and capacity  == 1.  If consumer reads from empty fifo it will be blocked until producer writes into fifo. With immediate notification it will be resumed in the same delta cycle as producer writes into fifo. 

The consumer should never block in my case. Reading twice a shared variable which has only been written once should not block the reader...

 

 

Share this post


Link to post
Share on other sites

Hi.

Maybe you should have a look at SystemC AMS. It offers the TDF (timed data flow) model of computation. It follows the data flow concept, i.e. you have a cluster of blocks; the solver defines an order of evaluation of each block; and in every time step, the blocks (or modules) are evaluated in that order. The output of one block is immediately visible at the input of the following block.

Greetings

Ralph

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×