betabandido Posted December 10, 2015 Report Posted December 10, 2015 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). Quote
Roman Popov Posted December 10, 2015 Report Posted December 10, 2015 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. Quote
dakupoto Posted December 14, 2015 Report Posted December 14, 2015 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. Quote
Recommended Posts
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.