Jump to content

Using SC_CTHREAD in end_of_elaboration()


DavidC

Recommended Posts

 

Hi,

For reasons beyond the scope of this message, I want to declare a clocked thread in the end_of_elaboration() callback of a SystemC module.

(one simple situation where that might be useful is for example when a module needs to wait till port binding is complete, so it can safely determine the period of its input clocks using clock.get_interface(). At this point, depending on these clock frequencies, the module can determine in a list of possible threads which one is appropriate to use, and it simply wants to register it).

Here is a trivial example:

#include "systemc.h"

SC_MODULE(tb) {
  sc_in_clk clk;

  SC_CTOR(tb)
  {
#ifdef REGISTER_IN_CONSTRUCTOR
    SC_CTHREAD(scenario, clk.pos());
#endif
  }

  void end_of_elaboration(void)
  {
#ifndef REGISTER_IN_CONSTRUCTOR
    SC_CTHREAD(scenario, clk.pos());
#endif
  }

  void scenario(void)
  {
    while (sc_time_stamp() < sc_time(10, SC_NS))
    {
      cout << "Clocked thread event - Time is " << sc_time_stamp() << endl;
      wait(1);
    }

    sc_stop();
  }
};

int sc_main (int argc, char* argv[])
{
  tb       u_tb("u_tb");
  sc_clock u_clk("u_clk", 1, SC_NS, 0.5);

  u_tb.clk(u_clk);
  sc_start();

  return 0;
}


What I find is that if CTHREAD is used in the module constructor (REGISTER_IN_CONSTRUCTOR is defined) then I get the expected behavior, and the thread receives events on every positive clock edge:

Clocked thread event - Time is 0 s
Clocked thread event - Time is 1 ns
Clocked thread event - Time is 2 ns
Clocked thread event - Time is 3 ns

But if if CTHREAD is used in the end_of_elaboration() callback (REGISTER_IN_CONSTRUCTOR is not defined) then thread receives events on both positive and negative clock edges:

Clocked thread event - Time is 0 s
Clocked thread event - Time is 500 ps
Clocked thread event - Time is 1 ns
Clocked thread event - Time is 1500 ps
Clocked thread event - Time is 2 ns
Clocked thread event - Time is 2500 ps
Clocked thread event - Time is 3 ns

Is this expected ? Is there an implementation detail that I'm not aware of which would explain this ? or is there a bug perhaps somewhere ?

Thanks !

Link to comment
Share on other sites

13 minutes ago, DavidC said:

Is this expected ? Is there an implementation detail that I'm not aware of which would explain this ? or is there a bug perhaps somewhere ?

The standard says (5.2.9 SC_METHOD, SC_THREAD, SC_CTHREAD), "Macro SC_CTHREAD shall not be invoked from the end_of_elaboration callback". But I don't know the reason behind this - perhaps others here can pitch in. I personally stick to SC_THREAD and SC_METHOD, don't use clock threads.

Link to comment
Share on other sites

2 hours ago, karthickg said:

The standard says (5.2.9 SC_METHOD, SC_THREAD, SC_CTHREAD), "Macro SC_CTHREAD shall not be invoked from the end_of_elaboration callback

Well I guess the standard is the definitive source of information but I found conflicting information here:

Quote

The process macros SC_METHOD, SC_THREAD and SC_CTHREAD can be invoked during elaboration. These process macros have always been permitted in end_of_elaboration() , and the new standard clarifies that this is a deliberate feature rather than an accident of the implementation.

The same link also mentions:

Quote

An alternative is to bypass the event finder mechanism by only adding events to the static sensitivity of processes after the end of elaboration, in the end_of_elaboration() callbacks. At this stage, event finders are not necessary (indeed, they cannot be called) because port binding has been completed

I have to admit my understanding of SystemC is too limited to fully make sense of the above. Can anyone explain why event finders (pos() and neg()) cannot be called in the end_of_elaboration() callbacks ?

However it would indeed confirm that SC_CTHREAD cannot be used in the end_of_elaboration() callbacks. It would be really nice if the SystemC library could detect this invalid situation and generate at least a warning message (either at compile-time or run-time).

At the end of the day it almost seems like a pure point of syntax - The wanted effect can be achieved with SC_THREAD instead and the variant below:

 void end_of_elaboration(void)
  {
#ifndef REGISTER_IN_CONSTRUCTOR
    SC_THREAD(scenario);
    sensitive << clk.posedge_event();
#endif
  }
Link to comment
Share on other sites

13 hours ago, DavidC said:

It would be really nice if the SystemC library could detect this invalid situation and generate at least a warning message (either at compile-time or run-time).

You can file an issue here: https://github.com/accellera-official/systemc/issues

 

13 hours ago, DavidC said:

Can anyone explain why event finders (pos() and neg()) cannot be called in the end_of_elaboration() callbacks ?

I think it is a choice to simplify the SystemC implementation - while not taking away any flexibility from the user's code. Consider the following code in a module constructor:

// Case 1: The event that process is sensitive to is known at the
//         time when process handle is declared
SC_METHOD(a_process);
sensitive << some_event;                   // sc_event some_event;
sensitive << some_channel.posedge_event(); // sc_signal<bool> some_channel;

// Case 2: The event that process is sensitive to is NOT known at the
//         time when process handle is declared, as the port binding
//         is not complete yet
sensitive << some_port.pos();              // sc_in<bool> some_port;

Here, the implementation (by that I mean the SystemC simulator), has to do the following:

  • For "case 1", it can directly populate the sensitivity list of the process, as it has the event reference
  • For "case 2", it has to store the event finder reference - and, after elaboration is done and before calling end_of_elaboration, it has to populate the sensitivity list of the process. It does that by fetching the reference of the event object inside the channel that the port is connected to. The "event finder" only serves as a stand-in, to let the implementation figure out which event reference is finally needed (posedge event or negedge event or default).

Due to this difference in handling, it probably is simpler to disallow event handlers from being used after elaboration is complete.

Link to comment
Share on other sites

On 3/8/2022 at 8:08 PM, DavidC said:

I have to admit my understanding of SystemC is too limited to fully make sense of the above. Can anyone explain why event finders (pos() and neg()) cannot be called in the end_of_elaboration() callbacks ?

I would assume, it's an oversight as it is currently not supported by the IEEE 1666-2011 standard.
You can likely "fix" it by changing line 248 in src/sysc/kernel/sc_sensitivity.cpp:

void
sc_sensitive::make_static_sensitivity(
    sc_process_b* handle_, sc_event_finder& event_finder_)
{
    if (sc_is_running() || event_finder_.port().get_interface()) { // line 248, check for already bound port
      handle_->add_static_event( event_finder_.find_event() );
    } else {


Greetings from Linz,
 Philipp

Link to comment
Share on other sites

On 3/12/2022 at 1:52 AM, Philipp A Hartmann said:

You can likely "fix" it by changing line 248 in src/sysc/kernel/sc_sensitivity.cpp

Thanks for digging into the details, I appreciate the effort 😉

While I can certainly build my own modified SystemC libraries (which I do occasionally for experimentation purposes), this is not a viable long-term solution for me as I need to deliver code that will run with pre-generated third-party libraries.

However, just like me, many SystemC developers might be unaware of the all the details in the IEEE 1666-2011 standard (e.g. that SC_CTHREAD cannot be used in the end_of_elaboration() callbacks). Is there a simple way to catch these situations where code can be compiled and even executed without any trouble, but where the behavior is actually undefined / non guaranteed ? (see my initial example)

Link to comment
Share on other sites

56 minutes ago, DavidC said:

Is there a simple way to catch these situations where code can be compiled and even executed without any trouble, but where the behavior is actually undefined / non guaranteed ?

I don't think there's such a way without changing the SystemC library? You can certainly change the aforementioned part to raise a warning/error instead, when calling sc_sensitive for SC_CTHREAD with an event finder during sc_get_status() == SC_END_OF_ELABORATION.

Link to comment
Share on other sites

Thanks a lot Philipp for the detailed suggestion !

I guess my question was : would it make sense to include these changes in the official SystemC library release ? Functionally it doesn't bring anything new, and it doesn't fix any issue either. But it can occasionally save a lot of time when someone is trying to do something that they shouldn't be doing....

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...