17 #ifndef _CXS_CXS_TLM_H_
18 #define _CXS_CXS_TLM_H_
20 #include <cci_configuration>
22 #include <scc/fifo_w_cb.h>
24 #include <scc/report.h>
25 #include <scc/sc_variable.h>
26 #include <tlm/nw/tlm_network_gp.h>
27 #include <tlm/nw/tlm_network_sockets.h>
28 #include <tlm/scc/tlm_gp_shared.h>
29 #include <tlm/scc/tlm_mm.h>
33 enum class CXS_CMD { FLIT, CREDIT, CRDRTN };
41 std::array<uint8_t, 8> start_ptr;
42 std::array<uint8_t, 8> end_ptr;
51 using tlm_phase_type = ::tlm::tlm_phase;
54 enum class CXS_PKT { DATA };
64 using tlm_phase_type = ::tlm::tlm_phase;
84 template <
unsigned PHITWIDTH = 256,
int N = 1>
86 template <
unsigned PHITWIDTH = 256,
int N = 1>
97 virtual tlm_extension_base* clone()
const override {
102 void copy_from(tlm_extension_base
const& ext)
override { *
this =
dynamic_cast<orig_pkt_extension const&
>(ext); }
105 std::vector<cxs_pkt_shared_ptr> orig_ext;
108 template <
unsigned PHITWIDTH = 256,
unsigned CXSMAXPKTPERFLIT = 2>
113 using flit_phase_type = cxs_flit_types::tlm_phase_type;
116 using pkt_phase_type = cxs_packet_types::tlm_phase_type;
118 static constexpr
unsigned PHIT_BYTE_WIDTH = PHITWIDTH / 8;
119 static constexpr
unsigned BUCKET_SIZE = PHITWIDTH / 8 / CXSMAXPKTPERFLIT;
121 sc_core::sc_in<bool> clk_i{
"clk_i"};
123 sc_core::sc_in<bool> rst_i{
"rst_i"};
129 cci::cci_param<sc_core::sc_time> clock_period{
"clock_period", sc_core::SC_ZERO_TIME,
"clock period of the CXS transmitter"};
131 cci::cci_param<unsigned> burst_len{
"burst_len", 1,
"minimum amount of credits to start transmitting flits"};
134 : sc_core::sc_module(nm) {
139 sensitive << clk_i.pos();
146 void start_of_simulation()
override {
147 if(clock_period.get_value() == sc_core::SC_ZERO_TIME)
148 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()))
149 clock_period.set_value(clk_if->period());
152 void b_transport(
pkt_tx_type& trans, sc_core::sc_time& t)
override {
155 tx.set_extension(ext);
156 ext->orig_ext.emplace_back(&trans);
157 isck->b_transport(tx, t);
160 tlm::tlm_sync_enum nb_transport_fw(
pkt_tx_type& trans, pkt_phase_type& phase, sc_core::sc_time& t)
override {
161 SCCTRACE(SCMOD) <<
"Forwarding CXS packet with size " << trans.get_data().size() <<
"bytes";
162 if(phase == tlm::nw::REQUEST) {
164 phase = tlm::nw::CONFIRM;
165 return tlm::TLM_UPDATED;
167 throw std::runtime_error(
"illegal request in forward path");
170 unsigned int transport_dbg(
pkt_tx_type& trans)
override {
return 0; }
172 tlm::tlm_sync_enum nb_transport_bw(
flit_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
173 SCCTRACE(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name();
174 if(phase == tlm::nw::REQUEST) {
175 received_credits += trans.get_data()[0];
176 SCCDEBUG(SCMOD) <<
"Received " <<
static_cast<unsigned>(trans.get_data()[0]) <<
" credit(s), " << received_credits.
get()
177 <<
" credit(s) in total";
178 phase = tlm::nw::CONFIRM;
179 return tlm::TLM_UPDATED;
181 throw std::runtime_error(
"illegal request in backward path");
185 if((!pending_pkt && !pkt_peq.has_next()) ||
186 (received_credits < burst_len.get_value() && !burst_credits) ||
193 ptr->set_auto_extension(ext);
195 auto next_bucket = 0U;
196 auto start_ptr_idx = 0U;
197 auto end_ptr_idx = 0U;
198 while(pkt_peq.has_next() || pending_pkt) {
199 auto trans = pending_pkt ? pending_pkt : pkt_peq.get();
200 pending_pkt =
nullptr;
201 if(!transfered_pkt_bytes) {
202 ptr->start |= 1u << start_ptr_idx;
203 ptr->start_ptr[start_ptr_idx++] = next_bucket;
205 const auto remaining_bytes = trans->get_data().size() - transfered_pkt_bytes;
206 const auto remaining_buckets = (CXSMAXPKTPERFLIT - next_bucket);
207 const auto bucketed_size = (remaining_bytes + BUCKET_SIZE - 1) / BUCKET_SIZE;
208 if(bucketed_size > remaining_buckets) {
210 transfered_pkt_bytes += remaining_buckets * BUCKET_SIZE;
215 ptr->end |= 1u << end_ptr_idx;
216 ptr->end_ptr[end_ptr_idx++] = (next_bucket * BUCKET_SIZE + remaining_bytes + 1) / 4 - 1;
218 next_bucket += bucketed_size;
219 ext->orig_ext.push_back(trans);
220 transfered_pkt_bytes = 0;
224 auto phase = tlm::nw::REQUEST;
225 isck->nb_transport_fw(*ptr, phase, t);
227 burst_credits = burst_len.get_value();
228 received_credits -= burst_credits;
235 received_credits = 0;
237 pending_pkt =
nullptr;
243 unsigned transfered_pkt_bytes{0};
246 unsigned burst_credits{0};
249 template <
unsigned PHITWIDTH = 64,
unsigned CXSMAXPKTPERFLIT = 2>
254 using flit_phase_type = cxs_flit_types::tlm_phase_type;
257 using pkt_phase_type = cxs_packet_types::tlm_phase_type;
259 static constexpr
unsigned PHIT_BYTE_WIDTH = PHITWIDTH / 8;
260 static constexpr
unsigned BUCKET_SIZE = PHITWIDTH / 8 / CXSMAXPKTPERFLIT;
262 sc_core::sc_in<bool> clk_i{
"clk_i"};
264 sc_core::sc_in<bool> rst_i{
"rst_i"};
270 cci::cci_param<sc_core::sc_time> clock_period{
"clock_period", sc_core::SC_ZERO_TIME,
"clock period of the CXS receiver"};
272 cci::cci_param<unsigned> max_credit{
"max_credits", 1,
"CXS_MAX_CREDIT property"};
275 : sc_core::sc_module(nm) {
280 sensitive << clk_i.pos();
285 SC_METHOD(send_credit);
286 sensitive << credit_returned.data_written_event();
291 void start_of_simulation()
override {
292 if(clock_period.get_value() == sc_core::SC_ZERO_TIME)
293 if(
auto clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()))
294 clock_period.set_value(clk_if->period());
297 void b_transport(
flit_tx_type& trans, sc_core::sc_time& t)
override {
300 auto tx = ext->orig_ext.front();
301 isck->b_transport(*tx, t);
304 tlm::tlm_sync_enum nb_transport_fw(
flit_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
305 SCCTRACE(SCMOD) <<
"Received non-blocking transaction in fw path with phase " << phase.get_name();
306 credit_returned.push_back(1);
309 for(
auto& orig_ptr : ext->orig_ext) {
310 auto ph = tlm::nw::REQUEST;
311 auto d = sc_core::SC_ZERO_TIME;
312 SCCTRACE(SCMOD) <<
"Forwarding CXS pkt with size " << orig_ptr->get_data().size() <<
"bytes";
313 auto status = isck->nb_transport_fw(*orig_ptr, ph, t);
314 sc_assert(status == tlm::TLM_UPDATED);
317 phase = tlm::nw::RESPONSE;
318 if(clock_period.get_value() != sc_core::SC_ZERO_TIME)
319 t += clock_period.get_value() - 1_ps;
320 return tlm::TLM_UPDATED;
323 unsigned int transport_dbg(
flit_tx_type& trans)
override {
return 0; }
325 tlm::tlm_sync_enum nb_transport_bw(
pkt_tx_type& trans, flit_phase_type& phase, sc_core::sc_time& t)
override {
326 SCCTRACE(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name();
327 if(phase == tlm::nw::CONFIRM)
328 return tlm::TLM_ACCEPTED;
329 throw std::runtime_error(
"illegal request in backward path");
334 credit_returned.push_back(max_credit.get_value());
339 auto amount = credit_returned.front();
340 credit_returned.pop_front();
341 available_credits += amount;
347 if(available_credits > 0) {
349 ptr->set_command(cxs::CXS_CMD::CREDIT);
351 auto ph = tlm::nw::REQUEST;
352 auto t = sc_core::SC_ZERO_TIME;
353 auto status = tsck->nb_transport_bw(*ptr, ph, t);
354 sc_assert(status == tlm::TLM_UPDATED);
355 available_credits -= 1;
362 template <
unsigned PHITWIDTH = 64>
368 using phase_type = cxs_flit_types::tlm_phase_type;
374 cci::cci_param<sc_core::sc_time> channel_delay{
"channel_delay", sc_core::SC_ZERO_TIME,
"delay of the CXS channel"};
376 cci::cci_param<sc_core::sc_time> tx_clock_period{
"tx_clock_period", sc_core::SC_ZERO_TIME,
377 "receiver side clock period of the CXS channel"};
379 cci::cci_param<sc_core::sc_time> rx_clock_period{
"rx_clock_period", sc_core::SC_ZERO_TIME,
380 "receiver side clock period of the CXS channel"};
383 : sc_core::sc_module(nm) {
393 isck->b_transport(trans, t);
396 tlm::tlm_sync_enum nb_transport_fw(
transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
override {
397 SCCTRACE(SCMOD) <<
"Received non-blocking transaction in fw path with phase " << phase.get_name();
398 if(phase == tlm::nw::REQUEST) {
399 if(trans.get_data().size() > PHITWIDTH / 8) {
400 SCCERR(SCMOD) <<
"A CXS flit can be maximal " << PHITWIDTH / 8 <<
" bytes long, current data length is "
401 << trans.get_data().size() <<
" bytes";
404 if(rx_clock_period.get_value() > sc_core::SC_ZERO_TIME)
405 t += rx_clock_period - 1_ps;
406 phase = tlm::nw::CONFIRM;
407 return tlm::TLM_UPDATED;
408 }
else if(phase == tlm::nw::RESPONSE) {
409 bw_resp.notify(sc_core::SC_ZERO_TIME);
410 return tlm::TLM_ACCEPTED;
412 throw std::runtime_error(
"illegal request in forward path");
415 tlm::tlm_sync_enum nb_transport_bw(
transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
override {
416 SCCTRACE(SCMOD) <<
"Received non-blocking transaction in bw path with phase " << phase.get_name();
417 if(phase == tlm::nw::REQUEST) {
418 SCCDEBUG(SCMOD) <<
"Forwarding " <<
static_cast<unsigned>(trans.get_data()[0]) <<
" credit(s)";
420 if(tx_clock_period.get_value() > sc_core::SC_ZERO_TIME)
421 t += tx_clock_period - 1_ps;
422 phase = tlm::nw::CONFIRM;
423 return tlm::TLM_UPDATED;
424 }
else if(phase == tlm::nw::RESPONSE) {
425 fw_resp.notify(sc_core::SC_ZERO_TIME);
426 return tlm::TLM_ACCEPTED;
428 throw std::runtime_error(
"illegal response in backward path");
431 unsigned int transport_dbg(
transaction_type& trans)
override {
return isck->transport_dbg(trans); }
435 while(fw_peq.has_next()) {
436 auto ptr = fw_peq.get();
437 auto phase = tlm::nw::INDICATION;
438 auto t = sc_core::SC_ZERO_TIME;
439 auto sync = isck->nb_transport_fw(*ptr, phase, t);
440 if(sync == tlm::TLM_ACCEPTED) {
441 next_trigger(fw_resp);
444 sc_assert(sync == tlm::TLM_UPDATED || sync == tlm::TLM_COMPLETED);
447 next_trigger(fw_peq.event());
451 while(bw_peq.has_next()) {
452 auto ptr = bw_peq.get();
453 auto ph{tlm::nw::REQUEST};
455 auto sync = tsck->nb_transport_bw(*ptr, ph, d);
456 if(sync == tlm::TLM_ACCEPTED) {
457 next_trigger(bw_resp);
460 sc_assert(sync == tlm::TLM_UPDATED || sync == tlm::TLM_COMPLETED);
463 next_trigger(bw_peq.event());
468 sc_core::sc_event fw_resp, bw_resp;
payload_type * allocate()
get a plain tlm_payload_type without extensions
T get() const
value getter
static tlm_mm & get()
accessor function of the singleton