Jump to content

Method execution order


betabandido

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).

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.

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...