174 unsigned int transport_dbg(
typename TYPES::tlm_payload_type& trans)
override;
190 sc_core::sc_port<axi::axi_fw_transport_if<TYPES>>
fw_port{
"fw_port"};
193 sc_core::sc_port<axi::axi_bw_transport_if<TYPES>>
bw_port{
"bw_port"};
196 std::string
const full_name;
204 const unsigned bus_width{0};
206 tx_db* m_db{
nullptr};
208 ::lwtr::tx_relation_handle pred_succ_hndl{0}, par_chld_hndl{0};
210 tx_fiber* b_streamHandle{
nullptr};
212 std::array<tx_generator<sc_core::sc_time, sc_core::sc_time>*, 3> b_trHandle{{
nullptr,
nullptr,
nullptr}};
214 tx_fiber* b_streamHandleTimed{
nullptr};
217 std::array<tx_generator<>*, 3> b_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
219 enum DIR { FW, BW, REQ = FW, RESP = BW };
221 tx_fiber* nb_streamHandle{
nullptr};
223 tx_fiber* nb_streamHandleTimed{
nullptr};
225 std::array<tx_generator<std::string, std::string>*, 2> nb_trHandle{{
nullptr,
nullptr}};
227 std::array<tx_generator<>*, 2> nb_trTimedHandle{{
nullptr,
nullptr}};
228 std::unordered_map<uint64_t, tx_handle> nbtx_req_handle_map;
229 std::unordered_map<uint64_t, tx_handle> nbtx_last_req_handle_map;
230 std::unordered_map<uint64_t, tx_handle> nbtx_resp_handle_map;
231 std::unordered_map<uint64_t, tx_handle> nbtx_last_resp_handle_map;
233 tx_fiber* dmi_streamHandle{
nullptr};
235 tx_generator<>* dmi_trGetHandle{
nullptr};
236 tx_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{
nullptr};
239 void initialize_streams() {
241 pred_succ_hndl = m_db->create_relation(
"PREDECESSOR_SUCCESSOR");
242 par_chld_hndl = m_db->create_relation(
"PARENT_CHILD");
245 b_streamHandle =
new tx_fiber((full_name +
"_bl").c_str(),
"[TLM][axi][b]", m_db);
246 b_trHandle[tlm::TLM_READ_COMMAND] =
247 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"read", *b_streamHandle,
"start_delay",
"end_delay");
248 b_trHandle[tlm::TLM_WRITE_COMMAND] =
249 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"write", *b_streamHandle,
"start_delay",
"end_delay");
250 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
251 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"ignore", *b_streamHandle,
"start_delay",
"end_delay");
253 b_streamHandleTimed =
new tx_fiber((full_name +
"_bl_timed").c_str(),
"[TLM][axi][b][timed]", m_db);
254 b_trTimedHandle[tlm::TLM_READ_COMMAND] =
new tx_generator<>(
"read", *b_streamHandleTimed);
255 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] =
new tx_generator<>(
"write", *b_streamHandleTimed);
256 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] =
new tx_generator<>(
"ignore", *b_streamHandleTimed);
260 nb_streamHandle =
new tx_fiber((full_name +
"_nb").c_str(),
"[TLM][axi][nb]", m_db);
261 nb_trHandle[FW] =
new tx_generator<std::string, std::string>(
"fw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
262 nb_trHandle[BW] =
new tx_generator<std::string, std::string>(
"bw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
264 nb_streamHandleTimed =
new tx_fiber((full_name +
"_nb_timed").c_str(),
"[TLM][axi][nb][timed]", m_db);
265 nb_trTimedHandle[FW] =
new tx_generator<>(
"request", *nb_streamHandleTimed);
266 nb_trTimedHandle[BW] =
new tx_generator<>(
"response", *nb_streamHandleTimed);
270 dmi_streamHandle =
new tx_fiber((full_name +
"_dmi").c_str(),
"[TLM][axi][dmi]", m_db);
271 dmi_trGetHandle =
new tx_generator<>(
"get", *dmi_streamHandle);
272 dmi_trInvalidateHandle =
273 new tx_generator<sc_dt::uint64, sc_dt::uint64>(
"invalidate", *dmi_streamHandle,
"start_addr",
"end_addr");
277 new axi::checker::axi_protocol(full_name, bus_width / 8, rd_response_timeout.get_value(), wr_response_timeout.get_value());
282 axi::checker::checker_if<TYPES>* checker{
nullptr};
285template <
unsigned BUSWIDTH = 32,
typename TYPES = axi::axi_protocol_types,
int N = 1,
286 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
287class axi_lwtr_recorder :
public sc_core::sc_module,
public axi_lwtr<TYPES> {
292 axi_lwtr_recorder(sc_core::sc_module_name nm,
bool recording_enabled =
true, tx_db* tr_db = tx_db::get_default_db())
293 : sc_core::sc_module(nm)
297 this->
bw_port(ts.get_base_port());
298 this->
fw_port(is.get_base_port());
307 fw_port->b_transport(trans, delay);
311 tx_handle h = b_trHandle[trans.get_command()]->begin_tx(delay);
316 if(b_streamHandleTimed)
317 htim = b_trTimedHandle[trans.get_command()]->begin_tx_delayed(sc_core::sc_time_stamp() + delay, par_chld_hndl, h);
320 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
321 if(extensionRecording) {
322 extensionRecording->recordBeginTx(h, trans);
324 extensionRecording->recordBeginTx(htim, trans);
328 trans.get_extension(preExt);
329 if(preExt ==
nullptr) {
332 trans.set_auto_extension(preExt);
334 trans.set_extension(preExt);
336 h.add_relation(pred_succ_hndl, preExt->txHandle);
338 tx_handle preTx{preExt->txHandle};
339 preExt->txHandle = h;
340 fw_port->b_transport(trans, delay);
341 trans.get_extension(preExt);
342 if(preExt->creator ==
this) {
345 if(!trans.has_mm()) {
349 preExt->txHandle = preTx;
352 h.record_attribute(
"trans", trans);
354 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
355 if(extensionRecording) {
356 extensionRecording->recordEndTx(h, trans);
358 extensionRecording->recordEndTx(htim, trans);
363 if(htim.is_valid()) {
364 htim.record_attribute(
"trans", trans);
365 htim.end_tx_delayed(sc_core::sc_time_stamp() + delay);
369template <
typename TYPES>
371 sc_core::sc_time& delay) {
374 checker->fw_pre(trans, phase);
375 tlm::tlm_sync_enum status =
fw_port->nb_transport_fw(trans, phase, delay);
376 checker->fw_post(trans, phase, status);
379 return fw_port->nb_transport_fw(trans, phase, delay);
385 tx_handle h = nb_trHandle[FW]->begin_tx(phase.get_name());
387 trans.get_extension(preExt);
388 if((phase == axi::BEGIN_PARTIAL_REQ || phase == tlm::BEGIN_REQ) && preExt ==
nullptr) {
391 trans.set_auto_extension(preExt);
393 trans.set_extension(preExt);
394 }
else if(preExt !=
nullptr) {
396 h.add_relation(pred_succ_hndl, preExt->txHandle);
398 sc_assert(preExt !=
nullptr &&
"ERROR on forward path in phase other than tlm::BEGIN_REQ");
401 preExt->txHandle = h;
402 h.record_attribute(
"delay", delay);
404 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
405 if(extensionRecording)
406 extensionRecording->recordBeginTx(h, trans);
410 if(nb_streamHandleTimed) {
412 rec.tr->deep_copy_from(trans);
413 nb_timed_peq.notify(rec, delay);
419 checker->fw_pre(trans, phase);
420 tlm::tlm_sync_enum status =
fw_port->nb_transport_fw(trans, phase, delay);
422 checker->fw_post(trans, phase, status);
426 h.record_attribute(
"tlm_sync", status);
427 h.record_attribute(
"delay[return_path]", delay);
428 h.record_attribute(
"trans", trans);
430 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
431 if(extensionRecording)
432 extensionRecording->recordEndTx(h, trans);
434 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) {
435 trans.get_extension(preExt);
436 if(preExt && preExt->creator ==
this) {
438 if(!trans.has_mm()) {
445 if(nb_streamHandleTimed) {
447 rec.tr->deep_copy_from(trans);
448 nb_timed_peq.notify(rec, delay);
450 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
452 rec.tr->deep_copy_from(trans);
453 nb_timed_peq.notify(rec, delay);
456 nb_trHandle[FW]->end_tx(h, phase.get_name());
460template <
typename TYPES>
462 sc_core::sc_time& delay) {
465 checker->bw_pre(trans, phase);
466 tlm::tlm_sync_enum status =
bw_port->nb_transport_bw(trans, phase, delay);
467 checker->bw_post(trans, phase, status);
470 return bw_port->nb_transport_bw(trans, phase, delay);
476 trans.get_extension(preExt);
478 tx_handle h = nb_trHandle[BW]->begin_tx(phase.get_name());
480 if(phase == tlm::BEGIN_REQ && preExt ==
nullptr) {
482 trans.set_extension(preExt);
483 preExt->txHandle = h;
486 h.add_relation(pred_succ_hndl, preExt->txHandle);
488 preExt->txHandle = h;
490 sc_assert(preExt !=
nullptr &&
"ERROR on backward path in phase other than tlm::BEGIN_REQ");
493 h.record_attribute(
"delay", delay);
494 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
495 if(extensionRecording)
496 extensionRecording->recordBeginTx(h, trans);
500 if(nb_streamHandleTimed) {
502 rec.tr->deep_copy_from(trans);
503 nb_timed_peq.notify(rec, delay);
509 checker->bw_pre(trans, phase);
510 tlm::tlm_sync_enum status =
bw_port->nb_transport_bw(trans, phase, delay);
512 checker->bw_post(trans, phase, status);
516 h.record_attribute(
"tlm_sync", status);
517 h.record_attribute(
"delay[return_path]", delay);
518 h.record_attribute(
"trans", trans);
520 for(
auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
521 if(extensionRecording)
522 extensionRecording->recordEndTx(h, trans);
524 nb_trHandle[BW]->end_tx(h, phase.get_name());
526 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
528 if(preExt && preExt->creator ==
this) {
531 if(!trans.has_mm()) {
538 if(nb_streamHandleTimed) {
540 rec.tr->deep_copy_from(trans);
541 nb_timed_peq.notify(rec, delay);
543 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
545 rec.tr->deep_copy_from(trans);
546 nb_timed_peq.notify(rec, delay);
551template <
typename TYPES>
void axi_lwtr<TYPES>::nbtx_cb() {
557 if(e.ph == tlm::BEGIN_REQ || e.ph == axi::BEGIN_PARTIAL_REQ) {
558 h = nb_trTimedHandle[REQ]->begin_tx(par_chld_hndl, e.parent);
559 nbtx_req_handle_map[e.id] = h;
560 }
else if(e.ph == tlm::END_REQ || e.ph == axi::END_PARTIAL_REQ) {
561 auto it = nbtx_req_handle_map.find(e.id);
562 if(it != nbtx_req_handle_map.end()) {
564 nbtx_req_handle_map.erase(it);
565 h.record_attribute(
"trans", *e.tr);
567 nbtx_last_req_handle_map[e.id] = h;
569 }
else if(e.ph == tlm::BEGIN_RESP || e.ph == axi::BEGIN_PARTIAL_RESP) {
570 auto it = nbtx_req_handle_map.find(e.id);
571 if(it != nbtx_req_handle_map.end()) {
573 nbtx_req_handle_map.erase(it);
574 h.record_attribute(
"trans", *e.tr);
576 nbtx_last_req_handle_map[e.id] = h;
578 h = nb_trTimedHandle[RESP]->begin_tx(par_chld_hndl, e.parent);
579 nbtx_resp_handle_map[e.id] = h;
580 it = nbtx_last_req_handle_map.find(e.id);
581 if(it != nbtx_last_req_handle_map.end()) {
582 tx_handle& pred = it->second;
583 h.add_relation(pred_succ_hndl, pred);
584 nbtx_last_req_handle_map.erase(it);
586 it = nbtx_last_resp_handle_map.find(e.id);
587 if(it != nbtx_last_resp_handle_map.end()) {
588 tx_handle& pred = it->second;
589 h.add_relation(pred_succ_hndl, pred);
590 nbtx_last_resp_handle_map.erase(it);
593 }
else if(e.ph == tlm::END_RESP || e.ph == axi::END_PARTIAL_RESP) {
594 auto it = nbtx_resp_handle_map.find(e.id);
595 if(it != nbtx_resp_handle_map.end()) {
597 h.record_attribute(
"trans", *e.tr);
598 nbtx_resp_handle_map.erase(it);
600 if(e.ph == axi::END_PARTIAL_RESP) {
601 nbtx_last_resp_handle_map[e.id] = h;
605 sc_assert(!
"phase not supported!");
612 return fw_port->get_direct_mem_ptr(trans, dmi_data);
613 tx_handle h = dmi_trGetHandle->begin_tx();
614 bool status =
fw_port->get_direct_mem_ptr(trans, dmi_data);
615 h.record_attribute(
"trans", trans);
616 h.record_attribute(
"dmi_data", dmi_data);
628 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
631 tx_handle h = dmi_trInvalidateHandle->begin_tx(start_addr);
632 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
633 dmi_trInvalidateHandle->end_tx(h, end_addr);
643 return fw_port->transport_dbg(trans);