Jump to content
Sign in to follow this  
betabandido

Method execution order

Recommended Posts

I'm implementing a network simulator where modules send flits (packets of information) to other modules. They can only do so if there is available space in a buffer to hold a flit. Credits are used to control when a module can send a flit to another module. Basically credits in a given module correspond to the number of available positions in the input buffer of the next module.

 

I am having some issues related to the order of method execution. I know SystemC does not specify a predefined order in which methods are executed. But, I somehow need to enforce a given order (even if it is in an indirect way). Therefore, I would really appreciate if I could get some directions on how to actually accomplish it with SystemC.

 

An example intermediate module receives flits in the request input port:

void receive() {
  auto& flit = req_in.read();
  LOG_M(boost::format("Received %1%") % flit.to_str());
  buffer_.push_back(flit);
  process_buffer_event_.notify(clk);
}

One cycle after receiving a flit, it is necessary to process the flit buffer:

void process_buffer() {
  if (buffer_.empty())
    return;

  if (credits_ == 0) {
    LOG_M("No credits!!!");
    return;
  }

  auto& flit = buffer_.front();
  LOG_M(boost::format("Sending %1%") % flit.to_str());
  req_out.write(flit);
  credits_--; // consumes a credit
  buffer_.erase(begin(buffer_));
  if (!buffer_.empty())
    process_buffer_event_.notify(clk);
}

Finally, the method receiving credits back from the next module is defined as:

void receive_credits() {
  auto credits = cr_rcv.read();
  credits_ += credits;
  LOG_M(boost::format("%1% credits received (total=%2%)") % credits % credits_);
  process_buffer_event_.notify(SC_ZERO_TIME);
}

The problem with this approach is that at a given time the previous module in the network might send a flit while the next module returns a credit. This would happen at delta cycle 0. Then at delta cycle 1, both receive() and receive_credits() would execute. That would trigger an execution of process_buffer() at delta cycle 2. If the buffer was originally empty, process_buffer() would proceed to send the flit that arrived at delta cycle 1. But, that flit just arrived in this very same cycle, so it should not be eligible for sending it until next cycle.

 

If I could guarantee that receive_credits() always executes before receive(), I could rewrite that function like this:

void receive_credits() {
  auto credits = cr_rcv.read();
  credits_ += credits;
  LOG_M(boost::format("%1% credits received (total=%2%)") % credits % credits_);
  if (!buffer_.empty())
    process_buffer_event_.notify(SC_ZERO_TIME);
}

That would guarantee that a flit is not sent too early. But as far as I know, there is no way to specify the order of methods' execution.

 

What would be the most SystemC-like approach to solve this issue?

 

A fully functional example can be found here (http://pastebin.com/Ma6Hxq31).

Share this post


Link to post
Share on other sites

Have not checked you example, but as you've said, you can't force method exectution order in same delta cycle.

So you will have to put execution in different delta cycles, by implementing some sort of syncrhonization between methods, using sc_event or sc_channel.

Share this post


Link to post
Share on other sites

I'm implementing a network simulator where modules send flits (packets of information) to other modules. They can only do so if there is available space in a buffer to hold a flit. Credits are used to control when a module can send a flit to another module. Basically credits in a given module correspond to the number of available positions in the input buffer of the next module.

 

I am having some issues related to the order of method execution. I know SystemC does not specify a predefined order in which methods are executed. But, I somehow need to enforce a given order (even if it is in an indirect way). Therefore, I would really appreciate if I could get some directions on how to actually accomplish it with SystemC.

 

An example intermediate module receives flits in the request input port:

void receive() {
  auto& flit = req_in.read();
  LOG_M(boost::format("Received %1%") % flit.to_str());
  buffer_.push_back(flit);
  process_buffer_event_.notify(clk);
}

One cycle after receiving a flit, it is necessary to process the flit buffer:

void process_buffer() {
  if (buffer_.empty())
    return;

  if (credits_ == 0) {
    LOG_M("No credits!!!");
    return;
  }

  auto& flit = buffer_.front();
  LOG_M(boost::format("Sending %1%") % flit.to_str());
  req_out.write(flit);
  credits_--; // consumes a credit
  buffer_.erase(begin(buffer_));
  if (!buffer_.empty())
    process_buffer_event_.notify(clk);
}

Finally, the method receiving credits back from the next module is defined as:

void receive_credits() {
  auto credits = cr_rcv.read();
  credits_ += credits;
  LOG_M(boost::format("%1% credits received (total=%2%)") % credits % credits_);
  process_buffer_event_.notify(SC_ZERO_TIME);
}

The problem with this approach is that at a given time the previous module in the network might send a flit while the next module returns a credit. This would happen at delta cycle 0. Then at delta cycle 1, both receive() and receive_credits() would execute. That would trigger an execution of process_buffer() at delta cycle 2. If the buffer was originally empty, process_buffer() would proceed to send the flit that arrived at delta cycle 1. But, that flit just arrived in this very same cycle, so it should not be eligible for sending it until next cycle.

 

If I could guarantee that receive_credits() always executes before receive(), I could rewrite that function like this:

void receive_credits() {
  auto credits = cr_rcv.read();
  credits_ += credits;
  LOG_M(boost::format("%1% credits received (total=%2%)") % credits % credits_);
  if (!buffer_.empty())
    process_buffer_event_.notify(SC_ZERO_TIME);
}

That would guarantee that a flit is not sent too early. But as far as I know, there is no way to specify the order of methods' execution.

 

What would be the most SystemC-like approach to solve this issue?

 

A fully functional example can be found here (http://pastebin.com/Ma6Hxq31).

 

Hello Sir,

It appears that you are trying to synchronize read/write to buffers

(core operation in any network protocol). Please check SystemC's

built-in synchronization features as sc_mutex, sc_semaphore etc.,

Also please check the classical consumer-producer model. This

has been implemented in recent books on SystemC. Please do

not try to re-invent the wheel and implement your algorithm in

one go, but rather build it up incrementally from available parts.

Hope you might find this useful.

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.

Sign in to follow this  

×
×
  • Create New...