Jump to content
sdressler

Best Practice to Synchronize Modules

Recommended Posts

Hi,

 

I created a pair of modules in SystemC. The purpose is to model a data transfer with one side being the source and the other side being the sink. It currently uses SC_THREAD for processing, e.g. (not showing all details):

class Source : sc_module
{
    sc_in<bool> clk;
    sc_in<bool> ready;
    sc_out<bool> valid;
    sc_out<sc_bv<8>> data;

    // This is a SC_THREAD
    void process()
    {
        while(true)
        {
            wait(clk.posedge_event());

            valid.write(data_available());
            wait(SC_ZERO_TIME);

            if (data_available())
            {
                auto datum = get_datum_to_transfer();
                data.write(datum);
                if (ready.read())
                {
                    erase_transferred_datum();
                }
            }
        }
    }

}

class Sink : sc_module
{
    sc_in<bool> clk;
    sc_out<bool> ready;
    sc_in<bool> valid;
    sc_in<sc_bv<8>> data;

    // This is a SC_THREAD
    void process()
    {
        while(true)
        {
            wait(clk.posedge_event());
            
            const bool is_ready = get_ready_state();
            ready.write(is_ready);
            wait(SC_ZERO_TIME);

            if (is_ready && valid.read())
            {
                store_datum(data.read());
            }
        }
    }
}

For testing, the two modules are connected via sc_signal.

 

Now, the problem that arose was, that it could happen, that ready and valid where assigned at the exact same simulation time respectively on the same rising edge of the clock. Then, the sink could not properly receive the data. I circumvented this by using wait(SC_ZERO_TIME); to issue delta-cycles which fully solved this particular problems.

 

However, this particular design brings me to the following questions:

 

  1. Assuming, that there are many of these modules in the complete simulation, is the overhead of SC_THREAD negligible? I am aware, that internally pthreads are used and thus the OS has to deal with it (context switches). But I'm wondering, whether this approach will eventually slow the simulation.
  2. When implementing the exact same modules with SC_METHOD, is there a possibility to issue delta cycles in order to update the signals, whenever they are written? I found out, that triggering sc_start(SC_ZERO_TIME); results in the same effect. However, I don't think it is appropriate.
  3. Is this already the cleanest approach to the given problem of synchronizing two usually independent modules?

 

Cheers,

Sebastian

Share this post


Link to post
Share on other sites

Hi,

 

I created a pair of modules in SystemC. The purpose is to model a data transfer with one side being the source and the other side being the sink. It currently uses SC_THREAD for processing, e.g. (not showing all details):

class Source : sc_module
{
    sc_in<bool> clk;
    sc_in<bool> ready;
    sc_out<bool> valid;
    sc_out<sc_bv<8>> data;

    // This is a SC_THREAD
    void process()
    {
        while(true)
        {
            wait(clk.posedge_event());

            valid.write(data_available());
            wait(SC_ZERO_TIME);

            if (data_available())
            {
                auto datum = get_datum_to_transfer();
                data.write(datum);
                if (ready.read())
                {
                    erase_transferred_datum();
                }
            }
        }
    }

}

class Sink : sc_module
{
    sc_in<bool> clk;
    sc_out<bool> ready;
    sc_in<bool> valid;
    sc_in<sc_bv<8>> data;

    // This is a SC_THREAD
    void process()
    {
        while(true)
        {
            wait(clk.posedge_event());
            
            const bool is_ready = get_ready_state();
            ready.write(is_ready);
            wait(SC_ZERO_TIME);

            if (is_ready && valid.read())
            {
                store_datum(data.read());
            }
        }
    }
}

For testing, the two modules are connected via sc_signal.

 

Now, the problem that arose was, that it could happen, that ready and valid where assigned at the exact same simulation time respectively on the same rising edge of the clock. Then, the sink could not properly receive the data. I circumvented this by using wait(SC_ZERO_TIME); to issue delta-cycles which fully solved this particular problems.

 

However, this particular design brings me to the following questions:

 

  1. Assuming, that there are many of these modules in the complete simulation, is the overhead of SC_THREAD negligible? I am aware, that internally pthreads are used and thus the OS has to deal with it (context switches). But I'm wondering, whether this approach will eventually slow the simulation.
  2. When implementing the exact same modules with SC_METHOD, is there a possibility to issue delta cycles in order to update the signals, whenever they are written? I found out, that triggering sc_start(SC_ZERO_TIME); results in the same effect. However, I don't think it is appropriate.
  3. Is this already the cleanest approach to the given problem of synchronizing two usually independent modules?

 

Cheers,

Sebastian

Hello Sir,

Please examine the SystemC built-in synchronization primitives as 'sc_mutex', 'sc_semaphore'

etc., and find out which of these could be used most effectively for your own needs. Also, some

recent books on SystemC have fully worked out examples of the 'consumer-producer' model.

This model is designed for synchronized module operation. Hope that helps.

Share this post


Link to post
Share on other sites

Several topics here...

 

EFFICIENCY/PERFORMANCE

I hear so often the comment that SC_THREAD is less efficient than SC_METHOD, but the claim is incorrect. It is true that in the Accellera implementation there is a small difference favoring SC_METHOD. I am aware of SystemC implementations where exactly the opposite is true. In general, there are much better things to worry about:

  • Coding efficiency (how fast can you get a correctly working model written)?
  • Does your code work?
  • Is this the most natural way to write the code?
  • Is your code easy to understand?
  • Are you writing at the correct level of abstraction (RTL is typically inappropriate)?

If you are concerned about execution performance, you should be more concerned about the amount of context switching. In other words, how frequently are your SC_METHOD's called and how frequently do your SC_THREAD's call wait(). If you really want to focus on this, remove those clocks. Clocks have two context switches per clock period (rising and falling). You can synchronize to clock timing by treating time as modulus a clock_period variable.

 

The intent of SystemC is to write models and verify (you do hopefully write unit tests) quickly. You should be able to write loosely timed models of your SoC in hours or days - not weeks or months. Approximately timed models may take a bit more time (perhaps a few days to a couple of weeks).

 

SYNCHRONIZATION

As regards synchronization, you need to completely understand the event-driven simulator mechanisms, and use proper handshaking of events or channels to accomplish your tasks. Mutex or semaphore may be appropriate, but not always. Sometimes you need to write your own custom channels. FIFO's are an excellent synchronization method, and make many modeling tasks trivial.

Share this post


Link to post
Share on other sites

David, thank you for that thorough answer. I'd like to discuss different aspects a bit more.

If you really want to focus on this, remove those clocks. Clocks have two context switches per clock period (rising and falling). You can synchronize to clock timing by treating time as modulus a clock_period variable.

 

Could you explain me a bit more, how this is supposed to work? E.g. for this particular models, the goal was to also have cycle-accuracy, i.e. to me it seems unable to remove the clocks. This results from the following problem: usually the valid is raised only once. That is, with every new rising clock, new data is transferred. If I now remove the clock, then I won't know when there is new data. The next thing is, that these models are supposed to be connected to a complete system which would expect the clock port, because it would also transfer data synchronized to the clock. But maybe my approach is wrong.

 

The intent of SystemC is to write models and verify (you do hopefully write unit tests) quickly.

 

Yes, I do write unit tests, in fact the approach I'm currently using is test-driven to ensure that the models are working properly. For instance, I figured out by using a test, that my model would work when ready is true all the time but that data is lost, when it switches to false from time to time (e.g. because the internal memory is full).

 

SYNCHRONIZATION

As regards synchronization, you need to completely understand the event-driven simulator mechanisms, and use proper handshaking of events or channels to accomplish your tasks. Mutex or semaphore may be appropriate, but not always. Sometimes you need to write your own custom channels. FIFO's are an excellent synchronization method, and make many modeling tasks trivial.

 

If I understand this correctly, then, in turn, the model might expose a different interface than for instance an implementation in Verilog or VHDL does? Also here I have had the problem, that I was unable to do synchronization between both modules. For example, I implemented them with SC_METHOD only and used next_trigger in order to maintain dynamic sensitivity on e.g. valid and ready. However, I had the requirement, that ready must be true before valid. I'm unsure how to model this correctly. So, for instance to avoid syncing to the clock again, I would use events. But to me this seems not being a good idea, since I would have to make this event visible across the modules in their interfaces. And I also think, this is what channels are for. Maybe you could give me a hint on this. To me, it seems that it is absolutely necessary and also absolutely ok to add additional signals to help with synchronization, even if they are not in the implementation afterwards.

 

Thanks & Cheers,

Sebastian

Share this post


Link to post
Share on other sites

Well, after doing some more research on this topic, I think I can answers parts on my own:

 

1. Regarding the clock, I now understand, that this is not necessary. Instead, I can pre-calculate specific times and use events or other mechanisms to get notified once the particular time is reached.

2. Regarding synchronization, I used a sc_fifo now for transferring data. When it comes to signals on the ports, I simply set them wrt timing, so that CA is still maintained.

 

I think that nails it pretty much...

 

Cheers,

Sebastian

Share this post


Link to post
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...