19 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
20 #define SC_INCLUDE_DYNAMIC_PROCESSES
23 #include <axi/checker/axi_protocol.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();
48 template <
typename TYPES = axi::axi_protocol_types>
51 template <
unsigned int BUSWIDTH = 32,
int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
54 template <
unsigned int BUSWIDTH = 32,
int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
81 sc_core::sc_attribute<unsigned> rd_response_timeout{
"rd_response_timeout", 0};
83 sc_core::sc_attribute<unsigned> wr_response_timeout{
"wr_response_timeout", 0};
86 virtual tlm::tlm_fw_transport_if<TYPES>*
get_fw_if() = 0;
89 virtual tlm::tlm_bw_transport_if<TYPES>*
get_bw_if() = 0;
99 axi_recorder(
const char* name,
unsigned bus_width,
bool recording_enabled =
true,
100 SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
105 , bus_width(bus_width)
107 , fixed_basename(name) {
108 register_extensions();
112 btx_handle_map.clear();
113 nbtx_req_handle_map.clear();
114 nbtx_last_req_handle_map.clear();
115 nbtx_resp_handle_map.clear();
116 nbtx_last_resp_handle_map.clear();
117 delete b_streamHandle;
118 for(
auto* p : b_trHandle)
120 delete b_streamHandleTimed;
121 for(
auto* p : b_trTimedHandle)
123 delete nb_streamHandle;
124 for(
auto* p : nb_trHandle)
126 delete nb_streamHandleTimed;
127 for(
auto* p : nb_trTimedHandle)
129 delete dmi_streamHandle;
130 delete dmi_trGetHandle;
131 delete dmi_trInvalidateHandle;
146 tlm::tlm_sync_enum
nb_transport_fw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
147 sc_core::sc_time& delay)
override;
157 tlm::tlm_sync_enum
nb_transport_bw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
158 sc_core::sc_time& delay)
override;
167 void b_transport(
typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay)
override;
189 unsigned int transport_dbg(
typename TYPES::tlm_payload_type& trans)
override;
205 tlm_utils::peq_with_cb_and_phase<axi_recorder, recording_types> b_timed_peq;
207 tlm_utils::peq_with_cb_and_phase<axi_recorder, recording_types> nb_timed_peq;
212 void btx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
217 void nbtx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
218 const unsigned bus_width{0};
220 SCVNS scv_tr_db* m_db{
nullptr};
222 SCVNS scv_tr_stream* b_streamHandle{
nullptr};
224 std::array<SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>*, 3> b_trHandle{{
nullptr,
nullptr,
nullptr}};
226 SCVNS scv_tr_stream* b_streamHandleTimed{
nullptr};
229 std::array<SCVNS scv_tr_generator<>*, 3> b_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
230 std::unordered_map<uint64_t, SCVNS scv_tr_handle> btx_handle_map;
232 enum DIR { FW, BW, REQ = FW, RESP = BW };
234 SCVNS scv_tr_stream* nb_streamHandle{
nullptr};
236 SCVNS scv_tr_stream* nb_streamHandleTimed{
nullptr};
238 std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{
nullptr,
nullptr}};
240 std::array<SCVNS scv_tr_generator<>*, 2> nb_trTimedHandle{{
nullptr,
nullptr}};
241 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
242 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
243 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_resp_handle_map;
244 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_resp_handle_map;
246 SCVNS scv_tr_stream* dmi_streamHandle{
nullptr};
248 SCVNS scv_tr_generator<>* dmi_trGetHandle{
nullptr};
249 SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{
nullptr};
252 void initialize_streams() {
254 b_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_bl").c_str(),
"[TLM][axi][b]", m_db);
255 b_trHandle[tlm::TLM_READ_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
256 "read", *b_streamHandle,
"start_delay",
"end_delay");
257 b_trHandle[tlm::TLM_WRITE_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
258 "write", *b_streamHandle,
"start_delay",
"end_delay");
259 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
260 "ignore", *b_streamHandle,
"start_delay",
"end_delay");
262 b_streamHandleTimed =
263 new SCVNS scv_tr_stream((fixed_basename +
"_bl_timed").c_str(),
"[TLM][axi][b][timed]", m_db);
264 b_trTimedHandle[tlm::TLM_READ_COMMAND] =
new SCVNS scv_tr_generator<>(
"read", *b_streamHandleTimed);
265 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] =
new SCVNS scv_tr_generator<>(
"write", *b_streamHandleTimed);
266 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] =
new SCVNS scv_tr_generator<>(
"ignore", *b_streamHandleTimed);
270 nb_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_nb").c_str(),
"[TLM][axi][nb]", m_db);
271 nb_trHandle[FW] =
new SCVNS scv_tr_generator<std::string, std::string>(
"fw", *nb_streamHandle,
"tlm_phase",
272 "tlm_phase[return_path]");
273 nb_trHandle[BW] =
new SCVNS scv_tr_generator<std::string, std::string>(
"bw", *nb_streamHandle,
"tlm_phase",
274 "tlm_phase[return_path]");
276 nb_streamHandleTimed =
277 new SCVNS scv_tr_stream((fixed_basename +
"_nb_timed").c_str(),
"[TLM][axi][nb][timed]", m_db);
278 nb_trTimedHandle[FW] =
new SCVNS scv_tr_generator<>(
"request", *nb_streamHandleTimed);
279 nb_trTimedHandle[BW] =
new SCVNS scv_tr_generator<>(
"response", *nb_streamHandleTimed);
283 dmi_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_dmi").c_str(),
"[TLM][axi][dmi]", m_db);
284 dmi_trGetHandle =
new SCVNS scv_tr_generator<>(
"get", *dmi_streamHandle);
285 dmi_trInvalidateHandle =
new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
286 "invalidate", *dmi_streamHandle,
"start_addr",
"end_addr");
294 const std::string fixed_basename;
296 inline std::string phase2string(
const tlm::tlm_phase& p) {
297 std::stringstream ss;
307 template <
typename TYPES>
310 if(!isRecordingBlockingTxEnabled()) {
311 get_fw_if()->b_transport(trans, delay);
315 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
319 if(b_streamHandleTimed) {
320 req = mm::get().allocate();
324 req->id = h.get_id();
325 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
330 ext->recordBeginTx(h, trans);
333 trans.get_extension(preExt);
334 if(preExt ==
nullptr) {
336 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
340 SCVNS scv_tr_handle preTx(preExt->
txHandle);
342 get_fw_if()->b_transport(trans, delay);
343 trans.get_extension(preExt);
354 tlm::scc::scv::record(h, trans);
357 ext->recordEndTx(h, trans);
359 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
361 if(b_streamHandleTimed) {
362 b_timed_peq.notify(*req, tlm::END_RESP, delay);
366 template <
typename TYPES>
368 SCVNS scv_tr_handle h;
371 case tlm::BEGIN_REQ: {
372 h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
374 btx_handle_map[rec_parts.id] = h;
376 case tlm::END_RESP: {
377 auto it = btx_handle_map.find(rec_parts.id);
378 sc_assert(it != btx_handle_map.end());
380 btx_handle_map.erase(it);
381 tlm::scc::scv::record(h, rec_parts);
386 sc_assert(!
"phase not supported!");
391 template <
typename TYPES>
393 typename TYPES::tlm_phase_type& phase,
394 sc_core::sc_time& delay) {
395 if(!isRecordingNonBlockingTxEnabled()){
397 checker->fw_pre(trans, phase);
398 tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
399 checker->fw_post(trans, phase, status);
402 return get_fw_if()->nb_transport_fw(trans, phase, delay);
408 SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase2string(phase));
410 trans.get_extension(preExt);
411 if((phase == axi::BEGIN_PARTIAL_REQ || phase == tlm::BEGIN_REQ) &&
414 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
415 }
else if(preExt !=
nullptr) {
419 sc_assert(preExt !=
nullptr &&
"ERROR on forward path in phase other than tlm::BEGIN_REQ");
423 h.record_attribute(
"delay", delay.to_string());
426 ext->recordBeginTx(h, trans);
430 if(nb_streamHandleTimed) {
435 nb_timed_peq.notify(*req, phase, delay);
440 if(checker) checker->fw_pre(trans, phase);
441 tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
442 if(checker) checker->fw_post(trans, phase, status);
446 tlm::scc::scv::record(h, status);
447 h.record_attribute(
"delay[return_path]", delay.to_string());
448 tlm::scc::scv::record(h, trans);
451 ext->recordEndTx(h, trans);
453 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) {
455 trans.get_extension(preExt);
466 if(nb_streamHandleTimed) {
471 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
474 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
479 nb_timed_peq.notify(*req, phase, delay);
482 nb_trHandle[FW]->end_transaction(h, phase2string(phase));
486 template <
typename TYPES>
488 typename TYPES::tlm_phase_type& phase,
489 sc_core::sc_time& delay) {
490 if(!isRecordingNonBlockingTxEnabled()){
492 checker->bw_pre(trans, phase);
493 tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
494 checker->bw_post(trans, phase, status);
497 return get_bw_if()->nb_transport_bw(trans, phase, delay);
503 SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase2string(phase));
505 trans.get_extension(preExt);
506 if(phase == tlm::BEGIN_REQ && preExt ==
nullptr) {
508 if(trans.has_mm()) trans.set_auto_extension(preExt);
else trans.set_extension(preExt);
509 }
else if(preExt !=
nullptr) {
513 sc_assert(preExt !=
nullptr &&
"ERROR on backward path in phase other than tlm::BEGIN_REQ");
517 h.record_attribute(
"delay", delay.to_string());
520 ext->recordBeginTx(h, trans);
524 if(nb_streamHandleTimed) {
529 nb_timed_peq.notify(*req, phase, delay);
534 if(checker) checker->bw_pre(trans, phase);
535 tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
536 if(checker) checker->bw_post(trans, phase, status);
540 tlm::scc::scv::record(h, status);
541 h.record_attribute(
"delay[return_path]", delay.to_string());
542 tlm::scc::scv::record(h, trans);
545 ext->recordEndTx(h, trans);
547 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
549 trans.get_extension(preExt);
560 if(nb_streamHandleTimed) {
565 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
568 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
573 nb_timed_peq.notify(*req, phase, delay);
576 nb_trHandle[BW]->end_transaction(h, phase2string(phase));
580 template <
typename TYPES>
582 SCVNS scv_tr_handle h;
584 if(phase == tlm::BEGIN_REQ || phase == axi::BEGIN_PARTIAL_REQ) {
585 h = nb_trTimedHandle[REQ]->begin_transaction();
586 tlm::scc::scv::record(h, rec_parts);
588 nbtx_req_handle_map[rec_parts.id] = h;
589 }
else if(phase == tlm::END_REQ || phase == axi::END_PARTIAL_REQ) {
590 auto it = nbtx_req_handle_map.find(rec_parts.id);
591 if(it != nbtx_req_handle_map.end()) {
593 nbtx_req_handle_map.erase(it);
595 nbtx_last_req_handle_map[rec_parts.id] = h;
597 }
else if(phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP) {
598 auto it = nbtx_req_handle_map.find(rec_parts.id);
599 if(it != nbtx_req_handle_map.end()) {
601 nbtx_req_handle_map.erase(it);
603 nbtx_last_req_handle_map[rec_parts.id] = h;
605 h = nb_trTimedHandle[RESP]->begin_transaction();
606 tlm::scc::scv::record(h, rec_parts);
608 nbtx_resp_handle_map[rec_parts.id] = h;
609 it = nbtx_last_req_handle_map.find(rec_parts.id);
610 if(it != nbtx_last_req_handle_map.end()) {
611 SCVNS scv_tr_handle& pred = it->second;
613 nbtx_last_req_handle_map.erase(it);
615 it = nbtx_last_resp_handle_map.find(rec_parts.id);
616 if(it != nbtx_last_resp_handle_map.end()) {
617 SCVNS scv_tr_handle& pred = it->second;
619 nbtx_last_resp_handle_map.erase(it);
622 }
else if(phase == tlm::END_RESP || phase == axi::END_PARTIAL_RESP) {
623 auto it = nbtx_resp_handle_map.find(rec_parts.id);
624 if(it != nbtx_resp_handle_map.end()) {
626 nbtx_resp_handle_map.erase(it);
628 if(phase == axi::END_PARTIAL_RESP) {
629 nbtx_last_resp_handle_map[rec_parts.id] = h;
633 sc_assert(!
"phase not supported!");
638 template <
typename TYPES>
640 if(!(m_db && enableDmiTracing.value))
641 return get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
642 else if(!dmi_streamHandle)
643 initialize_streams();
644 SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
645 bool status = get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
646 tlm::scc::scv::record(h, trans);
647 tlm::scc::scv::record(h, dmi_data);
657 template <
typename TYPES>
659 if(!(m_db && enableDmiTracing.value)) {
660 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
662 }
else if(!dmi_streamHandle)
663 initialize_streams();
664 SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
665 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
666 dmi_trInvalidateHandle->end_transaction(h, end_addr);
676 unsigned int count = get_fw_if()->transport_dbg(trans);
The TLM2 transaction recorder.
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
virtual tlm::tlm_fw_transport_if< TYPES > * get_fw_if()=0
the port where fw accesses are forwarded to
virtual tlm::tlm_bw_transport_if< TYPES > * get_bw_if()=0
the port where bw accesses are forwarded to
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
sc_core::sc_attribute< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport 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 > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
sc_core::sc_attribute< bool > enableProtocolChecker
the attribute to enable/disable protocol checking
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
sc_core::sc_attribute< bool > enableTrDbgTracing
the attribute to selectively enable/disable transport dbg recording
axi_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.
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
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.
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_bw_transport_if< TYPES > axi_bw_transport_if
alias declaration for the backward interface:
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string