Jump to content
ivan.bodrov

sc_signal<T>.event() behavior does not match the one described in LRM

Recommended Posts

SystemC LRM says:
6.4 sc_signal
6.4.9 Member functions for events
Member function event shall return the value true if and only if the value of the signal changed in
the update phase of the immediately preceding delta cycle and at the current simulation time

 

Then what about following code:

#include <systemc.h>

#include <cassert>

int sc_main(int, char *[])
{
    sc_signal<int> sig;

    sig.write(1);

    sc_start();
    assert(sig.event());
    sc_start(1, SC_NS);
    assert(sig.event());

    return 0;
}

In this example signal was changed at 0 ns, but event() function still returns true 1 ns after.

 

Considering the fact that LRM also says

 

4.5.5 Function sc_delta_count

The function sc_delta_count shall return an integer value that is incremented exactly once in each delta
cycle in which at least one process is triggered or resumed and, thus, returns a count of the absolute number
of delta cycles that have occurred during simulation, starting from zero, ignoring any delta cycles in which
there were no runnable processes
 

 

and describes delta cycle as

4.2.2 Initialization, cycles, and pauses in the scheduling algorithm
A delta cycle is a sequence of steps in the scheduling algorithm consisting of the following steps in the order given:
a) An evaluation phase
b ) An update phase
c) A delta notification phase

 

Looks like the only way to make mq_signal<T>::event() work is to compare both time and delta count of the last change with current values, but current implementation only compares delta count.

 

So my question is: is this a bug or was it made on purpose for performance reasons?

Share this post


Link to post
Share on other sites

Hi Ivan,

 

thanks for your report and your detailed analysis.

 

From my understanding of your quotes of the IEEE 1666-2011 standard, I would say that this is a bug in the Accellera proof-of-concept simulator.

 

IIRC, the wording (and implementation) around the delta count has been refined during the IEEE update to 1666-2011, which was required to ensure determinism under presence of new features like sc_pause.

 

I'll take your report to the SystemC LWG to resolve this issue in the next release.

 

Thanks again and Greetings from Duisburg,
  Philipp

Share this post


Link to post
Share on other sites

Hi Ivan,

 

I have some follow-up questions on this issue:

Have you been able to reproduce it during a "real" simulation?

Do you see a warning about an empty evaluation phase during the simulation?

 

In your special case, you check for 'event()' from within 'sc_main' again and you don't really simulate at all (no processes are running).  In this case, the delta count is expected not to advance. 

 

Thanks,

  Philipp

Share this post


Link to post
Share on other sites

I haven't seen this in real simulation, that is why I asked if this was made on purpose. Just not what I would expect and it doesn't match LRM (or at least that is how it looks to me).

 

Original example doesn't trigger any warnings since signal is updated from first sc_start() call when elaboration gets completed (per my undestanding).

 

Actually at first I though that delta count is used to check whether event has occured on a signal, now I see that there is a separate counter which is called m_change_stamp that is incremented every time delta count is incremented plus every time simulation time advances - this should solve issue of spurious events for processes.

 

Also please check my next example:

#include <iostream>
#include <systemc.h>

class module : public sc_module
{
    SC_HAS_PROCESS(module);
public:
    explicit module(const sc_module_name &name)
        : sc_module(name)
    {
        SC_METHOD(process);
        sensitive << ev;
        dont_initialize();
    }

public:
    sc_in<int> input;
    sc_event ev;

private:
    void process()
    {
        if (input->event())
        {
            std::cout << "event at " << sc_time_stamp() << std::endl;
        }
        else
        {
            std::cout << "no event at " << sc_time_stamp() << std::endl;
        }
    }
};

int sc_main(int, char *[])
{
    sc_signal<int> sig;
    module mod("mod");

    mod.input.bind(sig);
    sc_start(); // complete elaboration

    sig.write(1);
    std::cout << "change signal at " << sc_time_stamp() << std::endl;

    sc_start(1, SC_NS); // doesn't give ant warnings because it advances simulation time
    mod.ev.notify(SC_ZERO_TIME);
    sc_start();

    return 0;
}

My output is:

change signal at 0 s

event at 1 ns

 

This is the only case I come up with when process sees signal change made in the past. Again, this is not a "real world" code. Just now what I would expect. I noticed this when writing and testing my custom primitive channel.

 

PS: Correction: m_change_stamp is not incremented when time gets advanced due to sc_start SC_RUN_TO_TIME policy. If it would do so, I think this would solve this issue.

 

An by the way, I have checked again and it seems that SystemC 2.2 indeed used delta count comparison in event() implementation. This could create spurious events for processes, so I assume version 2.3 tried to fix this by introducing m_change_count.

Edited by ivan.bodrov

Share this post


Link to post
Share on other sites

I don't see this "m_change_count" anywhere in LRM, so I assume it is non-standard.

If so, how custom primitive channels should implement event() function similar to one from sc_signal?

Looks like the only "official" way to do so is to save both delta count and time stamp.

Pros:

- Yields expected results for all cases

- Eliminates need for "m_change_count"

Cons:

- requires more memory (+8 bytes per channel)

- event() function requries additional 64-bit comparison, so it will work slower

Share this post


Link to post
Share on other sites

Hi Ivan,

 

thanks for your follow-up and for the updated example.  I also do not see a way to trigger this corner-case from within a process, i.e. without jumping to sc_main in-between (and then using event() in sc_main itself).  Therefore, I'm not sure if it's necessary to change the current implementation of the sc_signal::event function.  An alternative could be to add a way to explicitly check for "empty evaluation phases", i.e. whether sc_delta_count() yields the same value before and after the sc_start call.

 

That said, you can add this check to your sc_main logic manually already today.  This way, only users doing such step-wise simulations require to pay the cost of the additional checks. For the next version of the SystemC standard, we should still clarify this behavior in more detail.

 

And yes, there is no standardized API to simplify the implementation of an event()-like functionality in a custom channel.  With the corner case you describe, maybe there is now an interest to define such a function, also taking care of the "same simulation time" guarantee.  But as I said above, another option might be to relax an implementation's requirements for this check to allow for the corner cases of empty evaluation phases via sc_main between time steps.

 

Greetings from Duisburg,
  Philipp

Share this post


Link to post
Share on other sites

Thanks for explanation Philipp!

 

But if so, I don't think I understand why sc_delta_count() was introduced. Initially I thought about it as m_change_stamp from current implementation (used to implement event() function). What is its use cases? What does it solves, aside of statistical infomation on how simulation was performing?

Share this post


Link to post
Share on other sites

You're right: sc_delta_count is in fact intended (and used) for exactly such use cases.

 

Historically (i.e. pre 1666-2011), the delta count semantics were a bit different, as we didn't have sc_pause and the starvation policy for sc_start, yet.  So by nature of an event-driven simulator, there simply was no "empty time advance" before. With the extensions added to 1666-2011, we tightened the semantics when the delta count is increased in order to maintain deterministic results of the same simulation, regardless of the "activation sequence" in terms of sc_start calls.  Therefore, the delta count is no longer incremented in such "empty evaluation phases", which you can introduce manually by calling sc_start without anything happening in the model (except for the time advance, maybe).

 

Thanks again for bringing this up,
  Philipp

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

×