19 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
20 #define SC_INCLUDE_DYNAMIC_PROCESSES
23 #include <axi/checker/checker_if.h>
25 #include <axi/axi_tlm.h>
28 #include <tlm/scc/scv/tlm_recorder.h>
29 #include <tlm/scc/scv/tlm_recording_extension.h>
30 #include <tlm_utils/peq_with_cb_and_phase.h>
31 #include <unordered_map>
38 bool register_extensions();
43 template <
typename TYPES = axi::axi_protocol_types>
class ace_recording_payload :
public TYPES::tlm_payload_type {
45 SCVNS scv_tr_handle parent;
50 this->set_command(x.get_command());
51 this->set_address(x.get_address());
52 this->set_data_ptr(
nullptr);
53 this->set_data_length(x.get_data_length());
54 this->set_response_status(x.get_response_status());
55 this->set_byte_enable_ptr(
nullptr);
56 this->set_byte_enable_length(x.get_byte_enable_length());
57 this->set_streaming_width(x.get_streaming_width());
61 : TYPES::tlm_payload_type(mm)
67 using tlm_phase_type =
typename TYPES::tlm_phase_type;
79 template <
typename TYPES = axi::axi_protocol_types>
82 template <
unsigned int BUSWIDTH = 32,
int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
85 template <
unsigned int BUSWIDTH = 32,
int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
112 sc_core::sc_attribute<unsigned> rd_response_timeout{
"rd_response_timeout", 0};
114 sc_core::sc_attribute<unsigned> wr_response_timeout{
"wr_response_timeout", 0};
130 ace_recorder(
const char* name,
unsigned bus_width,
bool recording_enabled =
true,
131 SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
137 , fixed_basename(name) {
138 register_extensions();
142 btx_handle_map.clear();
143 nbtx_req_handle_map.clear();
144 nbtx_last_req_handle_map.clear();
145 nbtx_resp_handle_map.clear();
146 nbtx_last_resp_handle_map.clear();
147 delete b_streamHandle;
148 for(
auto* p : b_trHandle)
150 delete b_streamHandleTimed;
151 for(
auto* p : b_trTimedHandle)
153 delete nb_streamHandle;
154 for(
auto* p : nb_trHandle)
156 delete nb_streamHandleTimed;
157 for(
auto* p : nb_trTimedHandle)
159 delete dmi_streamHandle;
160 delete dmi_trGetHandle;
161 delete dmi_trInvalidateHandle;
175 tlm::tlm_sync_enum
nb_transport_fw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
176 sc_core::sc_time& delay)
override;
186 tlm::tlm_sync_enum
nb_transport_bw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
187 sc_core::sc_time& delay)
override;
196 void b_transport(
typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay)
override;
205 void b_snoop(
typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay)
override;
227 unsigned int transport_dbg(
typename TYPES::tlm_payload_type& trans)
override;
243 tlm_utils::peq_with_cb_and_phase<ace_recorder, recording_types> b_timed_peq;
245 tlm_utils::peq_with_cb_and_phase<ace_recorder, recording_types> nb_timed_peq;
250 void btx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
255 void nbtx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
257 SCVNS scv_tr_db* m_db{
nullptr};
259 SCVNS scv_tr_stream* b_streamHandle{
nullptr};
261 std::array<SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>*, 3> b_trHandle{{
nullptr,
nullptr,
nullptr}};
263 SCVNS scv_tr_stream* b_streamHandleTimed{
nullptr};
266 std::array<SCVNS scv_tr_generator<>*, 3> b_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
267 std::unordered_map<uint64_t, SCVNS scv_tr_handle> btx_handle_map;
269 enum DIR { FW, BW, REQ = FW, RESP = BW, ACK };
271 SCVNS scv_tr_stream* nb_streamHandle{
nullptr};
273 SCVNS scv_tr_stream* nb_streamHandleTimed{
nullptr};
275 std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{
nullptr,
nullptr}};
277 std::array<SCVNS scv_tr_generator<>*, 3> nb_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
278 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
279 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
280 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_resp_handle_map;
281 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_resp_handle_map;
283 SCVNS scv_tr_stream* dmi_streamHandle{
nullptr};
285 SCVNS scv_tr_generator<>* dmi_trGetHandle{
nullptr};
286 SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{
nullptr};
289 void initialize_streams() {
291 b_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_bl").c_str(),
"[TLM][ace][b]", m_db);
292 b_trHandle[tlm::TLM_READ_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
293 "read", *b_streamHandle,
"start_delay",
"end_delay");
294 b_trHandle[tlm::TLM_WRITE_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
295 "write", *b_streamHandle,
"start_delay",
"end_delay");
296 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
297 "ignore", *b_streamHandle,
"start_delay",
"end_delay");
299 b_streamHandleTimed =
300 new SCVNS scv_tr_stream((fixed_basename +
"_bl_timed").c_str(),
"[TLM][ace][b][timed]", m_db);
301 b_trTimedHandle[tlm::TLM_READ_COMMAND] =
new SCVNS scv_tr_generator<>(
"read", *b_streamHandleTimed);
302 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] =
new SCVNS scv_tr_generator<>(
"write", *b_streamHandleTimed);
303 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] =
new SCVNS scv_tr_generator<>(
"ignore", *b_streamHandleTimed);
307 nb_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_nb").c_str(),
"[TLM][ace][nb]", m_db);
308 nb_trHandle[FW] =
new SCVNS scv_tr_generator<std::string, std::string>(
"fw", *nb_streamHandle,
"tlm_phase",
309 "tlm_phase[return_path]");
310 nb_trHandle[BW] =
new SCVNS scv_tr_generator<std::string, std::string>(
"bw", *nb_streamHandle,
"tlm_phase",
311 "tlm_phase[return_path]");
313 nb_streamHandleTimed =
314 new SCVNS scv_tr_stream((fixed_basename +
"_nb_timed").c_str(),
"[TLM][ace][nb][timed]", m_db);
315 nb_trTimedHandle[FW] =
new SCVNS scv_tr_generator<>(
"request", *nb_streamHandleTimed);
316 nb_trTimedHandle[BW] =
new SCVNS scv_tr_generator<>(
"response", *nb_streamHandleTimed);
317 nb_trTimedHandle[ACK] =
new SCVNS scv_tr_generator<>(
"ack", *nb_streamHandleTimed);
321 dmi_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_dmi").c_str(),
"[TLM][ace][dmi]", m_db);
322 dmi_trGetHandle =
new SCVNS scv_tr_generator<>(
"get", *dmi_streamHandle);
323 dmi_trInvalidateHandle =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
324 "invalidate", *dmi_streamHandle,
"start_addr",
"end_addr");
332 const std::string fixed_basename;
340 template <
typename TYPES>
343 if(!isRecordingBlockingTxEnabled()) {
344 get_fw_if()->b_transport(trans, delay);
348 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
352 if(b_streamHandleTimed) {
353 req = mm::get().allocate();
357 req->id = h.get_id();
358 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
363 ext->recordBeginTx(h, trans);
366 trans.get_extension(preExt);
367 if(preExt ==
nullptr) {
369 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
373 SCVNS scv_tr_handle preTx(preExt->
txHandle);
375 get_fw_if()->b_transport(trans, delay);
376 trans.get_extension(preExt);
387 tlm::scc::scv::record(h, trans);
390 ext->recordEndTx(h, trans);
392 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
394 if(b_streamHandleTimed) {
395 b_timed_peq.notify(*req, tlm::END_RESP, delay);
399 template <
typename TYPES>
402 if(!b_streamHandleTimed) {
403 get_fw_if()->b_transport(trans, delay);
407 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
411 if(b_streamHandleTimed) {
412 req = mm::get().allocate();
416 req->id = h.get_id();
417 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
422 ext->recordBeginTx(h, trans);
425 trans.get_extension(preExt);
428 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
432 SCVNS scv_tr_handle preTx(preExt->
txHandle);
434 get_bw_if()->b_snoop(trans, delay);
435 trans.get_extension(preExt);
446 tlm::scc::scv::record(h, trans);
449 ext->recordEndTx(h, trans);
451 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
453 if(b_streamHandleTimed) {
454 b_timed_peq.notify(*req, tlm::END_RESP, delay);
458 template <
typename TYPES>
460 SCVNS scv_tr_handle h;
463 case tlm::BEGIN_REQ: {
464 h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
466 btx_handle_map[rec_parts.id] = h;
468 case tlm::END_RESP: {
469 auto it = btx_handle_map.find(rec_parts.id);
470 sc_assert(it != btx_handle_map.end());
472 btx_handle_map.erase(it);
473 tlm::scc::scv::record(h, rec_parts);
478 sc_assert(!
"phase not supported!");
483 template <
typename TYPES>
485 typename TYPES::tlm_phase_type& phase,
486 sc_core::sc_time& delay) {
487 if(!isRecordingNonBlockingTxEnabled()){
489 checker->fw_pre(trans, phase);
490 tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
491 checker->fw_post(trans, phase, status);
494 return get_fw_if()->nb_transport_fw(trans, phase, delay);
500 SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase.get_name());
502 trans.get_extension(preExt);
503 if((phase == axi::BEGIN_PARTIAL_REQ || phase == tlm::BEGIN_REQ) &&
506 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
507 }
else if(preExt !=
nullptr) {
511 sc_assert(preExt !=
nullptr &&
"ERROR on forward path in phase other than tlm::BEGIN_REQ");
515 h.record_attribute(
"delay", delay.to_string());
518 ext->recordBeginTx(h, trans);
522 if(nb_streamHandleTimed) {
527 req->is_snoop = (phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP);
528 nb_timed_peq.notify(*req, phase, delay);
533 if(checker) checker->fw_pre(trans, phase);
534 tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
535 if(checker) checker->fw_post(trans, phase, status);
539 tlm::scc::scv::record(h, status);
540 h.record_attribute(
"delay[return_path]", delay.to_string());
541 tlm::scc::scv::record(h, trans);
544 ext->recordEndTx(h, trans);
546 if(status == tlm::TLM_COMPLETED || (phase == axi::ACK)) {
548 trans.get_extension(preExt);
559 if(nb_streamHandleTimed) {
564 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
567 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
572 nb_timed_peq.notify(*req, phase, delay);
575 nb_trHandle[FW]->end_transaction(h, phase.get_name());
579 template <
typename TYPES>
581 typename TYPES::tlm_phase_type& phase,
582 sc_core::sc_time& delay) {
583 if(!isRecordingNonBlockingTxEnabled()){
585 checker->bw_pre(trans, phase);
586 tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
587 checker->bw_post(trans, phase, status);
590 return get_bw_if()->nb_transport_bw(trans, phase, delay);
596 SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase.get_name());
598 trans.get_extension(preExt);
599 if(phase == tlm::BEGIN_REQ && preExt ==
nullptr) {
601 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
602 }
else if(preExt !=
nullptr) {
606 sc_assert(preExt !=
nullptr &&
"ERROR on backward path in phase other than tlm::BEGIN_REQ");
610 h.record_attribute(
"delay", delay.to_string());
613 ext->recordBeginTx(h, trans);
617 if(nb_streamHandleTimed) {
622 req->is_snoop = phase == tlm::BEGIN_REQ;
623 nb_timed_peq.notify(*req, phase, delay);
628 if(checker) checker->bw_pre(trans, phase);
629 tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
630 if(checker) checker->bw_post(trans, phase, status);
634 tlm::scc::scv::record(h, status);
635 h.record_attribute(
"delay[return_path]", delay.to_string());
636 tlm::scc::scv::record(h, trans);
639 ext->recordEndTx(h, trans);
641 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == axi::ACK)) {
643 trans.get_extension(preExt);
654 if(nb_streamHandleTimed) {
659 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
662 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
667 nb_timed_peq.notify(*req, phase, delay);
670 nb_trHandle[BW]->end_transaction(h, phase.get_name());
674 template <
typename TYPES>
676 SCVNS scv_tr_handle h;
678 if(phase == tlm::BEGIN_REQ || phase == axi::BEGIN_PARTIAL_REQ) {
679 h = nb_trTimedHandle[REQ]->begin_transaction();
680 tlm::scc::scv::record(h, rec_parts);
682 nbtx_req_handle_map[rec_parts.id] = h;
683 }
else if(phase == tlm::END_REQ || phase == axi::END_PARTIAL_REQ) {
684 auto it = nbtx_req_handle_map.find(rec_parts.id);
685 sc_assert(it != nbtx_req_handle_map.end());
687 nbtx_req_handle_map.erase(it);
689 nbtx_last_req_handle_map[rec_parts.id] = h;
690 }
else if(phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP) {
691 auto it = nbtx_req_handle_map.find(rec_parts.id);
692 if(it != nbtx_req_handle_map.end()) {
694 nbtx_req_handle_map.erase(it);
696 nbtx_last_req_handle_map[rec_parts.id] = h;
698 h = nb_trTimedHandle[RESP]->begin_transaction();
699 tlm::scc::scv::record(h, rec_parts);
701 nbtx_resp_handle_map[rec_parts.id] = h;
702 it = nbtx_last_req_handle_map.find(rec_parts.id);
703 if(it != nbtx_last_req_handle_map.end()) {
704 SCVNS scv_tr_handle& pred = it->second;
706 nbtx_last_req_handle_map.erase(it);
708 it = nbtx_last_resp_handle_map.find(rec_parts.id);
709 if(it != nbtx_last_resp_handle_map.end()) {
710 SCVNS scv_tr_handle& pred = it->second;
712 nbtx_last_resp_handle_map.erase(it);
715 }
else if(phase == tlm::END_RESP || phase == axi::END_PARTIAL_RESP) {
716 auto it = nbtx_resp_handle_map.find(rec_parts.id);
717 if(it != nbtx_resp_handle_map.end()) {
719 nbtx_resp_handle_map.erase(it);
721 if(phase == axi::END_PARTIAL_RESP) {
722 nbtx_last_resp_handle_map[rec_parts.id] = h;
725 }
else if(phase == axi::ACK) {
726 h = nb_trTimedHandle[ACK]->begin_transaction();
727 tlm::scc::scv::record(h, rec_parts);
731 sc_assert(!
"phase not supported!");
736 template <
typename TYPES>
738 if(!(m_db && enableDmiTracing.value))
739 return get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
740 else if(!dmi_streamHandle)
741 initialize_streams();
742 SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
743 bool status = get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
744 tlm::scc::scv::record(h, trans);
745 tlm::scc::scv::record(h, dmi_data);
755 template <
typename TYPES>
757 if(!(m_db && enableDmiTracing.value)) {
758 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
760 }
else if(!dmi_streamHandle)
761 initialize_streams();
762 SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
763 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
764 dmi_trInvalidateHandle->end_transaction(h, end_addr);
774 unsigned int count = get_fw_if()->transport_dbg(trans);
The TLM2 transaction recorder.
sc_core::sc_attribute< bool > enableTrDbgTracing
the attribute to selectively enable/disable transport dbg recording
tlm::tlm_sync_enum nb_transport_bw(typename TYPES::tlm_payload_type &trans, typename TYPES::tlm_phase_type &phase, sc_core::sc_time &delay) override
The non-blocking backward transport function.
ace_recorder(const char *name, unsigned bus_width, bool recording_enabled=true, SCVNS scv_tr_db *tr_db=SCVNS scv_tr_db::get_default_db())
The constructor of the component.
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
tlm::tlm_sync_enum nb_transport_fw(typename TYPES::tlm_payload_type &trans, typename TYPES::tlm_phase_type &phase, sc_core::sc_time &delay) override
The non-blocking forward transport function.
sc_core::sc_attribute< bool > enableProtocolChecker
the attribute to enable/disable protocol checking
void b_snoop(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking snoop function.
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
virtual axi::ace_bw_transport_if< TYPES > * get_bw_if()=0
the port where bw accesses are forwarded to
sc_core::sc_attribute< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
virtual axi::ace_fw_transport_if< TYPES > * get_fw_if()=0
the port where fw accesses are forwarded to
sc_core::sc_attribute< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
the class to hold the information to be recorded on the timed streams
The TLM transaction extensions recorder registry.
generic payload extension class holding the handle of the last recorded SCV transaction
SCVNS scv_tr_handle txHandle
accessor to the SCV transaction handle.
void * get_creator()
accessor to the owner, the property is read only.
TLM2.0 components modeling AHB.
tlm::tlm_fw_transport_if< TYPES > ace_fw_transport_if
alias declaration for the ACE forward interface
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string