122struct cxs_transmitter :
public sc_core::sc_module,
125 using flit_tx_type = cxs_flit_types::tlm_payload_type;
126 using flit_phase_type = cxs_flit_types::tlm_phase_type;
128 using pkt_tx_type = cxs_packet_types::tlm_payload_type;
129 using pkt_phase_type = cxs_packet_types::tlm_phase_type;
131 static constexpr unsigned PHIT_BYTE_WIDTH = PHITWIDTH / 8;
132 static constexpr unsigned BUCKET_SIZE = PHITWIDTH / 8 / CXSMAXPKTPERFLIT;
134 sc_core::sc_in<bool> clk_i{
"clk_i"};
136 sc_core::sc_in<bool> rst_i{
"rst_i"};
138 cxs_pkt_target_socket<> tsck{
"tsck"};
140 cxs_flit_initiator_socket<PHITWIDTH> isck{
"isck"};
142 cci::cci_param<sc_core::sc_time> clock_period{
"clock_period", sc_core::SC_ZERO_TIME,
"clock period of the CXS transmitter"};
145 "minimum amount of credits to start transmitting flits, shall be larger than 0"};
147 cxs_transmitter(sc_core::sc_module_name
const& nm)
148 : sc_core::sc_module(nm) {
149 register_extensions();
152 SC_HAS_PROCESS(cxs_transmitter);
154 sensitive << clk_i.pos();
155 SC_METHOD(handle_received_credits);
156 sensitive << received_credits.event();
161 void start_of_simulation()
override {
162 if(clock_period.get_value() == sc_core::SC_ZERO_TIME)
163 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()))
164 clock_period.set_value(clk_if->period());
167 void b_transport(pkt_tx_type& trans, sc_core::sc_time& t)
override {
170 tx.set_extension(ext);
171 ext->orig_ext.emplace_back(&trans);
172 isck->b_transport(tx, t);
175 tlm::tlm_sync_enum nb_transport_fw(pkt_tx_type& trans, pkt_phase_type& phase, sc_core::sc_time& t)
override {
176 SCCTRACEALL(SCMOD) <<
"Forwarding CXS packet with size " << trans.
get_data().size() <<
"bytes";
177 if(phase == tlm::nw::REQUEST) {
178 pkt_peq.notify(cxs_pkt_shared_ptr(&trans), t);
179 if(clock_period.get_value() != sc_core::SC_ZERO_TIME)
180 t += clock_period.get_value() - 1_ps;
181 phase = tlm::nw::CONFIRM;
182 return tlm::TLM_UPDATED;
184 throw std::runtime_error(
"illegal request in forward path");
187 unsigned int transport_dbg(pkt_tx_type& trans)
override {
return 0; }
189 tlm::tlm_sync_enum nb_transport_bw(flit_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
190 SCCTRACEALL(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name() <<
" and command "
192 if(phase == tlm::nw::REQUEST && trans.
get_command() == cxs::CXS_CMD::CREDIT) {
193 received_credits.notify(trans.
get_data()[0], sc_core::SC_ZERO_TIME);
194 SCCTRACE(SCMOD) <<
"Received " <<
static_cast<unsigned>(trans.
get_data()[0]) <<
" credit(s), " << available_credits.get()
195 <<
" credit(s) in total";
196 if(clock_period.get_value() > sc_core::SC_ZERO_TIME)
197 t += clock_period - 1_ps;
198 phase = tlm::nw::CONFIRM;
199 return tlm::TLM_UPDATED;
201 throw std::runtime_error(
"illegal request in backward path");
204 void handle_received_credits() {
205 while(received_credits.has_next()) {
206 auto crd = received_credits.get();
207 available_credits += crd;
213 available_credits = 0u;
215 pending_pkt =
nullptr;
218 if((!pending_pkt && !pkt_peq.has_next()) ||
219 (!burst_credits && (available_credits < burst_len.get_value())))
225 ptr->set_auto_extension(ext);
227 auto next_bucket = 0U;
228 auto start_ptr_idx = 0U;
229 auto end_ptr_idx = 0U;
230 while(pkt_peq.has_next() || pending_pkt) {
231 auto trans = pending_pkt ? pending_pkt : pkt_peq.get();
232 pending_pkt =
nullptr;
233 if(!transfered_pkt_bytes) {
234 ptr->start |= 1u << start_ptr_idx;
235 ptr->start_ptr[start_ptr_idx++] = next_bucket;
237 const auto remaining_bytes = trans->
get_data().size() - transfered_pkt_bytes;
238 const auto remaining_buckets = (CXSMAXPKTPERFLIT - next_bucket);
239 const auto bucketed_size = (remaining_bytes + BUCKET_SIZE - 1) / BUCKET_SIZE;
240 if(bucketed_size > remaining_buckets) {
242 transfered_pkt_bytes += remaining_buckets * BUCKET_SIZE;
247 ptr->end |= 1u << end_ptr_idx;
248 ptr->end_ptr[end_ptr_idx++] = (next_bucket * BUCKET_SIZE + remaining_bytes + 1) / 4 - 1;
250 next_bucket += bucketed_size;
251 ext->orig_ext.push_back(trans);
252 transfered_pkt_bytes = 0;
256 auto phase = tlm::nw::REQUEST;
257 isck->nb_transport_fw(*ptr, phase, t);
259 burst_credits = burst_len.get_value();
260 available_credits -= burst_credits;
263 SCCTRACE(SCMOD) <<
"Transmitted one flit, " << available_credits.get() <<
" credit(s) in total";
267 cxs_pkt_shared_ptr pending_pkt;
268 unsigned transfered_pkt_bytes{0};
272 unsigned burst_credits{0};
276struct cxs_receiver :
public sc_core::sc_module,
279 using flit_tx_type = cxs_flit_types::tlm_payload_type;
280 using flit_phase_type = cxs_flit_types::tlm_phase_type;
282 using pkt_tx_type = cxs_packet_types::tlm_payload_type;
283 using pkt_phase_type = cxs_packet_types::tlm_phase_type;
285 static constexpr unsigned PHIT_BYTE_WIDTH = PHITWIDTH / 8;
286 static constexpr unsigned BUCKET_SIZE = PHITWIDTH / 8 / CXSMAXPKTPERFLIT;
288 sc_core::sc_in<bool> clk_i{
"clk_i"};
290 sc_core::sc_in<bool> rst_i{
"rst_i"};
292 cxs_flit_target_socket<PHITWIDTH> tsck{
"tsck"};
294 cxs_pkt_initiator_socket<> isck{
"isck"};
296 cci::cci_param<sc_core::sc_time> clock_period{
"clock_period", sc_core::SC_ZERO_TIME,
"clock period of the CXS receiver"};
299 "CXS_MAX_CREDIT property, shall be larger than 0"};
301 cxs_receiver(sc_core::sc_module_name
const& nm)
302 : sc_core::sc_module(nm) {
303 register_extensions();
306 SC_HAS_PROCESS(cxs_receiver);
308 sensitive << clk_i.pos();
310 SC_METHOD(handle_received_credits);
311 sensitive << returned_credits.event();
316 void start_of_simulation()
override {
317 if(clock_period.get_value() == sc_core::SC_ZERO_TIME)
318 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()))
319 clock_period.set_value(clk_if->period());
322 void b_transport(flit_tx_type& trans, sc_core::sc_time& t)
override {
325 auto tx = ext->orig_ext.front();
326 isck->b_transport(*tx, t);
329 tlm::tlm_sync_enum nb_transport_fw(flit_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
330 SCCTRACEALL(SCMOD) <<
"Received non-blocking transaction in fw path with phase " << phase.get_name();
331 returned_credits.notify(1, sc_core::SC_ZERO_TIME);
334 for(
auto& orig_ptr : ext->orig_ext) {
335 auto ph = tlm::nw::REQUEST;
336 auto d = sc_core::SC_ZERO_TIME;
337 SCCDEBUG(SCMOD) <<
"Forwarding CXS pkt with size " << orig_ptr->get_data().size() <<
"bytes";
338 auto status = isck->nb_transport_fw(*orig_ptr, ph, t);
339 sc_assert(status == tlm::TLM_UPDATED);
342 if(clock_period.get_value() != sc_core::SC_ZERO_TIME)
343 t += clock_period.get_value() - 1_ps;
344 phase = tlm::nw::RESPONSE;
345 return tlm::TLM_UPDATED;
348 unsigned int transport_dbg(flit_tx_type& trans)
override {
return 0; }
350 tlm::tlm_sync_enum nb_transport_bw(pkt_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
351 SCCTRACEALL(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name();
352 if(phase == tlm::nw::CONFIRM)
353 return tlm::TLM_ACCEPTED;
354 throw std::runtime_error(
"illegal request in backward path");
357 void handle_received_credits() {
358 while(returned_credits.has_next()) {
359 auto crd = returned_credits.get();
360 available_credits += crd;
366 available_credits = max_credit.get_value();
367 }
else if(available_credits > 0u) {
369 ptr->set_command(cxs::CXS_CMD::CREDIT);
371 auto ph = tlm::nw::REQUEST;
372 auto t = sc_core::SC_ZERO_TIME;
373 auto status = tsck->nb_transport_bw(*ptr, ph, t);
374 sc_assert(status == tlm::TLM_UPDATED);
375 available_credits -= 1u;
383struct cxs_channel :
public sc_core::sc_module,
387 using transaction_type = cxs_flit_types::tlm_payload_type;
388 using phase_type = cxs_flit_types::tlm_phase_type;
390 sc_core::sc_in<bool> rx_clk_i{
"rx_clk_i"};
392 cxs_flit_target_socket<PHITWIDTH> tsck{
"tsck"};
394 sc_core::sc_in<bool> tx_clk_i{
"tx_clk_i"};
396 cxs_flit_initiator_socket<PHITWIDTH> isck{
"isck"};
398 cci::cci_param<sc_core::sc_time> channel_delay{
"channel_delay", sc_core::SC_ZERO_TIME,
"delay of the CXS channel"};
400 cci::cci_param<sc_core::sc_time> tx_clock_period{
"tx_clock_period", sc_core::SC_ZERO_TIME,
401 "transmitter side clock period of the CXS channel"};
403 cci::cci_param<sc_core::sc_time> rx_clock_period{
"rx_clock_period", sc_core::SC_ZERO_TIME,
404 "receiver side clock period of the CXS channel"};
406 cxs_channel(sc_core::sc_module_name
const& nm)
407 : sc_core::sc_module(nm) {
410 SC_HAS_PROCESS(cxs_channel);
415 void b_transport(transaction_type& trans, sc_core::sc_time& t)
override {
417 isck->b_transport(trans, t);
420 tlm::tlm_sync_enum nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
override {
421 SCCTRACEALL(SCMOD) <<
"Received non-blocking transaction in fw path with phase " << phase.get_name();
422 if(phase == tlm::nw::REQUEST) {
423 if(trans.
get_data().size() > PHITWIDTH / 8) {
424 SCCERR(SCMOD) <<
"A CXS flit can be maximal " << PHITWIDTH / 8 <<
" bytes long, current data length is "
425 << trans.
get_data().size() <<
" bytes";
427 if(tx_clock_period.get_value().value()) {
429 (sc_core::sc_time_stamp().value() + channel_delay.get_value().value()) / tx_clock_period.get_value().value() + 1;
430 fw_peq.notify(cxs_flit_shared_ptr(&trans), tx_clock_period.get_value() * exit_cycle - sc_core::sc_time_stamp());
432 fw_peq.notify(cxs_flit_shared_ptr(&trans), channel_delay.get_value());
433 if(rx_clock_period.get_value() > sc_core::SC_ZERO_TIME)
434 t += rx_clock_period - 1_ps;
435 phase = tlm::nw::CONFIRM;
436 return tlm::TLM_UPDATED;
437 }
else if(phase == tlm::nw::RESPONSE) {
438 bw_resp.notify(sc_core::SC_ZERO_TIME);
439 return tlm::TLM_ACCEPTED;
441 throw std::runtime_error(
"illegal request in forward path");
444 tlm::tlm_sync_enum nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
override {
445 SCCTRACEALL(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name();
446 if(phase == tlm::nw::REQUEST) {
447 SCCTRACE(SCMOD) <<
"Forwarding " <<
static_cast<unsigned>(trans.
get_data()[0]) <<
" credit(s)";
448 if(rx_clock_period.get_value().value()) {
450 (sc_core::sc_time_stamp().value() + channel_delay.get_value().value()) / rx_clock_period.get_value().value() + 1;
451 bw_peq.notify(cxs_flit_shared_ptr(&trans), rx_clock_period.get_value() * exit_cycle - sc_core::sc_time_stamp());
453 bw_peq.notify(cxs_flit_shared_ptr(&trans), channel_delay.get_value());
454 if(tx_clock_period.get_value() > sc_core::SC_ZERO_TIME)
455 t += tx_clock_period - 1_ps;
456 phase = tlm::nw::CONFIRM;
457 return tlm::TLM_UPDATED;
458 }
else if(phase == tlm::nw::RESPONSE) {
459 fw_resp.notify(sc_core::SC_ZERO_TIME);
460 return tlm::TLM_ACCEPTED;
462 throw std::runtime_error(
"illegal response in backward path");
465 unsigned int transport_dbg(transaction_type& trans)
override {
return isck->transport_dbg(trans); }
468 void start_of_simulation()
override {
469 if(tx_clock_period.get_value() == sc_core::SC_ZERO_TIME)
470 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(tx_clk_i.get_interface()))
471 tx_clock_period.set_value(clk_if->period());
472 if(rx_clock_period.get_value() == sc_core::SC_ZERO_TIME)
473 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(rx_clk_i.get_interface()))
474 rx_clock_period.set_value(clk_if->period());
478 auto cur_cycle = sc_core::sc_time_stamp() / tx_clock_period.get_value();
479 if(fw_resp.triggered() && tx_clock_period.get_value().value()) {
480 auto next_cycle = sc_core::sc_time_stamp().value() / tx_clock_period.get_value().value() + 1;
481 next_trigger(tx_clock_period.get_value() * next_cycle - sc_core::sc_time_stamp());
484 while(fw_peq.has_next()) {
485 auto ptr = fw_peq.get();
486 auto phase = tlm::nw::INDICATION;
487 auto t = sc_core::SC_ZERO_TIME;
488 auto sync = isck->nb_transport_fw(*ptr, phase, t);
489 if(sync == tlm::TLM_ACCEPTED) {
490 next_trigger(fw_resp);
493 sc_assert(sync == tlm::TLM_UPDATED || sync == tlm::TLM_COMPLETED);
494 next_trigger(tx_clock_period.get_value());
498 next_trigger(fw_peq.event());
502 if(bw_resp.triggered() && rx_clock_period.get_value().value()) {
503 auto next_cycle = sc_core::sc_time_stamp().value() / rx_clock_period.get_value().value() + 1;
504 next_trigger(rx_clock_period.get_value() * next_cycle - sc_core::sc_time_stamp());
507 while(bw_peq.has_next()) {
508 auto ptr = bw_peq.get();
509 auto ph{tlm::nw::REQUEST};
511 auto sync = tsck->nb_transport_bw(*ptr, ph, d);
512 if(sync == tlm::TLM_ACCEPTED) {
513 next_trigger(bw_resp);
516 sc_assert(sync == tlm::TLM_UPDATED || sync == tlm::TLM_COMPLETED);
517 next_trigger(rx_clock_period.get_value());
521 next_trigger(bw_peq.event());
526 sc_core::sc_event fw_resp, bw_resp;