17 #ifndef TLM2_RECORDER_H_
18 #define TLM2_RECORDER_H_
20 #include "tlm_extension_recording_registry.h"
21 #include "tlm_recording_extension.h"
26 #include <sysc/kernel/sc_dynamic_processes.h>
27 #include <tlm/scc/tlm_mm.h>
29 #include <tlm_utils/peq_with_cb_and_phase.h>
30 #include <unordered_map>
39 void record(SCVNS scv_tr_handle&, tlm::tlm_generic_payload&);
40 void record(SCVNS scv_tr_handle&, tlm::tlm_phase&);
41 void record(SCVNS scv_tr_handle&, tlm::tlm_sync_enum);
42 void record(SCVNS scv_tr_handle&, tlm::tlm_dmi&);
45 template <
typename TYPES = tlm::tlm_base_protocol_types>
class tlm_recording_payload :
public TYPES::tlm_payload_type {
47 SCVNS scv_tr_handle parent;
50 id =
reinterpret_cast<uintptr_t
>(&x);
51 this->set_command(x.get_command());
52 this->set_address(x.get_address());
53 this->set_data_ptr(
nullptr);
54 this->set_data_length(x.get_data_length());
55 this->set_response_status(x.get_response_status());
56 this->set_byte_enable_ptr(
nullptr);
57 this->set_byte_enable_length(x.get_byte_enable_length());
58 this->set_streaming_width(x.get_streaming_width());
62 : TYPES::tlm_payload_type(mm)
68 using tlm_phase_type =
typename TYPES::tlm_phase_type;
80 template <
typename TYPES = tlm::tlm_base_protocol_types>
81 class tlm_recorder :
public virtual tlm::tlm_fw_transport_if<TYPES>,
public virtual tlm::tlm_bw_transport_if<TYPES> {
82 std::string get_parent(
char const* hier_name) {
83 std::string ret(hier_name);
84 auto pos = ret.rfind(
'.');
85 return pos == std::string::npos ? ret : ret.substr(0, pos);
106 sc_core::sc_port_b<tlm::tlm_fw_transport_if<TYPES>>&
fw_port;
109 sc_core::sc_port_b<tlm::tlm_bw_transport_if<TYPES>>&
bw_port;
124 tlm_recorder(sc_core::sc_port_b<tlm::tlm_fw_transport_if<TYPES>>&
fw_port, sc_core::sc_port_b<tlm::tlm_bw_transport_if<TYPES>>&
bw_port,
125 bool recording_enabled =
true, SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
141 tlm_recorder(
const char* name, sc_core::sc_port_b<tlm::tlm_fw_transport_if<TYPES>>&
fw_port,
142 sc_core::sc_port_b<tlm::tlm_bw_transport_if<TYPES>>&
bw_port,
bool recording_enabled =
true,
143 SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
151 , fixed_basename(name) {}
153 virtual ~tlm_recorder()
override {
154 btx_handle_map.clear();
155 nbtx_req_handle_map.clear();
156 nbtx_last_req_handle_map.clear();
157 delete b_streamHandle;
158 for(
auto* p : b_trHandle)
160 delete b_streamHandleTimed;
161 for(
auto* p : b_trTimedHandle)
163 delete nb_streamHandle;
164 for(
auto* p : nb_trHandle)
166 delete nb_streamHandleTimed;
167 for(
auto* p : nb_trTimedHandle)
169 delete dmi_streamHandle;
170 delete dmi_trGetHandle;
171 delete dmi_trInvalidateHandle;
185 tlm::tlm_sync_enum
nb_transport_fw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
186 sc_core::sc_time& delay)
override;
197 tlm::tlm_sync_enum
nb_transport_bw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
198 sc_core::sc_time& delay)
override;
208 void b_transport(
typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay)
override;
230 unsigned int transport_dbg(
typename TYPES::tlm_payload_type& trans)
override;
246 tlm_utils::peq_with_cb_and_phase<tlm_recorder, recording_types> b_timed_peq;
248 tlm_utils::peq_with_cb_and_phase<tlm_recorder, recording_types> nb_timed_peq;
253 void btx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
258 void nbtx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase);
260 SCVNS scv_tr_db* m_db{
nullptr};
262 SCVNS scv_tr_stream* b_streamHandle{
nullptr};
264 std::array<SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>*, 3> b_trHandle{{
nullptr,
nullptr,
nullptr}};
266 SCVNS scv_tr_stream* b_streamHandleTimed{
nullptr};
269 std::array<SCVNS scv_tr_generator<>*, 3> b_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
270 std::unordered_map<uint64_t, SCVNS scv_tr_handle> btx_handle_map;
272 enum DIR { FW, BW, REQ = FW, RESP = BW };
274 SCVNS scv_tr_stream* nb_streamHandle{
nullptr};
276 SCVNS scv_tr_stream* nb_streamHandleTimed{
nullptr};
278 std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{
nullptr,
nullptr}};
280 std::array<SCVNS scv_tr_generator<>*, 2> nb_trTimedHandle{{
nullptr,
nullptr}};
281 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
282 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
285 SCVNS scv_tr_stream* dmi_streamHandle{
nullptr};
287 SCVNS scv_tr_generator<>* dmi_trGetHandle{
nullptr};
288 SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{
nullptr};
291 void initialize_streams() {
293 b_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_bl").c_str(),
"[TLM][base-protocol][b]", m_db);
294 b_trHandle[tlm::TLM_READ_COMMAND] =
295 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
"read", *b_streamHandle,
"start_delay",
"end_delay");
296 b_trHandle[tlm::TLM_WRITE_COMMAND] =
297 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
"write", *b_streamHandle,
"start_delay",
"end_delay");
298 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
299 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
"ignore", *b_streamHandle,
"start_delay",
"end_delay");
301 b_streamHandleTimed =
302 new SCVNS scv_tr_stream((fixed_basename +
"_bl_timed").c_str(),
"[TLM][base-protocol][b][timed]", m_db);
303 b_trTimedHandle[tlm::TLM_READ_COMMAND] =
new SCVNS scv_tr_generator<>(
"read", *b_streamHandleTimed);
304 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] =
new SCVNS scv_tr_generator<>(
"write", *b_streamHandleTimed);
305 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] =
new SCVNS scv_tr_generator<>(
"ignore", *b_streamHandleTimed);
309 nb_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_nb").c_str(),
"[TLM][base-protocol][nb]", m_db);
311 new SCVNS scv_tr_generator<std::string, std::string>(
"fw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
313 new SCVNS scv_tr_generator<std::string, std::string>(
"bw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
315 nb_streamHandleTimed =
316 new SCVNS scv_tr_stream((fixed_basename +
"_nb_timed").c_str(),
"[TLM][base-protocol][nb][timed]", m_db);
317 nb_trTimedHandle[FW] =
new SCVNS scv_tr_generator<>(
"request", *nb_streamHandleTimed);
318 nb_trTimedHandle[BW] =
new SCVNS scv_tr_generator<>(
"response", *nb_streamHandleTimed);
322 dmi_streamHandle =
new SCVNS scv_tr_stream((fixed_basename +
"_dmi").c_str(),
"[TLM][base-protocol][dmi]", m_db);
323 dmi_trGetHandle =
new SCVNS scv_tr_generator<>(
"get", *dmi_streamHandle);
324 dmi_trInvalidateHandle =
325 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
"invalidate", *dmi_streamHandle,
"start_addr",
"end_addr");
330 const std::string fixed_basename;
331 inline std::string phase2string(
const tlm::tlm_phase& p) {
332 std::stringstream ss;
344 if(!isRecordingBlockingTxEnabled()) {
345 fw_port->b_transport(trans, delay);
347 }
else if(!b_streamHandle)
348 initialize_streams();
350 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
354 if(b_streamHandleTimed) {
355 req = mm::get().allocate();
359 req->id = h.get_id();
360 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
364 if(extensionRecording)
365 extensionRecording->recordBeginTx(h, trans);
368 trans.get_extension(preExt);
369 if(preExt ==
nullptr) {
372 trans.set_auto_extension(preExt);
374 trans.set_extension(preExt);
378 SCVNS scv_tr_handle preTx{preExt->
txHandle};
380 fw_port->b_transport(trans, delay);
384 if(!trans.has_mm()) {
392 if(extensionRecording)
393 extensionRecording->recordEndTx(h, trans);
395 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
397 if(b_streamHandleTimed) {
398 b_timed_peq.notify(*req, tlm::END_RESP, delay);
402 template <
typename TYPES>
void tlm_recorder<TYPES>::btx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase) {
403 SCVNS scv_tr_handle h;
406 case tlm::BEGIN_REQ: {
407 h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
409 btx_handle_map[rec_parts.id] = h;
411 case tlm::END_RESP: {
412 auto it = btx_handle_map.find(rec_parts.id);
413 sc_assert(it != btx_handle_map.end());
415 btx_handle_map.erase(it);
416 record(h, rec_parts);
421 sc_assert(!
"phase not supported!");
426 template <
typename TYPES>
428 sc_core::sc_time& delay) {
429 if(!isRecordingNonBlockingTxEnabled())
430 return fw_port->nb_transport_fw(trans, phase, delay);
431 else if(!nb_streamHandle)
432 initialize_streams();
437 SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase2string(phase));
439 trans.get_extension(preExt);
440 if(preExt ==
nullptr) {
443 trans.set_auto_extension(preExt);
445 trans.set_extension(preExt);
453 h.record_attribute(
"delay", delay.to_string());
455 if(extensionRecording)
456 extensionRecording->recordBeginTx(h, trans);
460 if(nb_streamHandleTimed) {
461 auto* req = mm::get().allocate();
465 nb_timed_peq.notify(*req, phase, delay);
470 tlm::tlm_sync_enum status = fw_port->nb_transport_fw(trans, phase, delay);
475 h.record_attribute(
"delay[return_path]", delay.to_string());
478 if(extensionRecording)
479 extensionRecording->recordEndTx(h, trans);
481 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) {
482 trans.get_extension(preExt);
485 if(!trans.has_mm()) {
492 if(nb_streamHandleTimed) {
497 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase, delay);
499 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
504 nb_timed_peq.notify(*req, phase, delay);
507 nb_trHandle[FW]->end_transaction(h, phase2string(phase));
511 template <
typename TYPES>
513 sc_core::sc_time& delay) {
514 if(!isRecordingNonBlockingTxEnabled())
515 return bw_port->nb_transport_bw(trans, phase, delay);
516 else if(!nb_streamHandle)
517 initialize_streams();
522 trans.get_extension(preExt);
525 SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase2string(phase));
532 h.record_attribute(
"delay", delay.to_string());
534 if(extensionRecording)
535 extensionRecording->recordBeginTx(h, trans);
539 if(nb_streamHandleTimed) {
544 nb_timed_peq.notify(*req, phase, delay);
549 tlm::tlm_sync_enum status = bw_port->nb_transport_bw(trans, phase, delay);
554 h.record_attribute(
"delay[return_path]", delay.to_string());
557 if(extensionRecording)
558 extensionRecording->recordEndTx(h, trans);
560 nb_trHandle[BW]->end_transaction(h, phase2string(phase));
561 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
566 if(!trans.has_mm()) {
573 if(nb_streamHandleTimed) {
578 nb_timed_peq.notify(*req, phase, delay);
584 template <
typename TYPES>
void tlm_recorder<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts,
const typename TYPES::tlm_phase_type& phase) {
585 SCVNS scv_tr_handle h;
586 std::unordered_map<uint64_t, SCVNS scv_tr_handle>::iterator it;
590 record(h, rec_parts);
591 nbtx_req_handle_map[rec_parts.id] = h;
594 it = nbtx_req_handle_map.find(rec_parts.id);
595 sc_assert(it != nbtx_req_handle_map.end());
597 nbtx_req_handle_map.erase(it);
599 nbtx_last_req_handle_map[rec_parts.id] = h;
601 case tlm::BEGIN_RESP:
602 it = nbtx_req_handle_map.find(rec_parts.id);
603 if(it != nbtx_req_handle_map.end()) {
605 nbtx_req_handle_map.erase(it);
607 nbtx_last_req_handle_map[rec_parts.id] = h;
610 record(h, rec_parts);
611 nbtx_req_handle_map[rec_parts.id] = h;
612 it = nbtx_last_req_handle_map.find(rec_parts.id);
613 if(it != nbtx_last_req_handle_map.end()) {
614 SCVNS scv_tr_handle pred = it->second;
615 nbtx_last_req_handle_map.erase(it);
620 it = nbtx_req_handle_map.find(rec_parts.id);
621 if(it != nbtx_req_handle_map.end()) {
623 nbtx_req_handle_map.erase(it);
636 if(!(m_db && enableDmiTracing.value))
637 return fw_port->get_direct_mem_ptr(trans, dmi_data);
638 else if(!dmi_streamHandle)
639 initialize_streams();
640 SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
641 bool status = fw_port->get_direct_mem_ptr(trans, dmi_data);
654 if(!(m_db && enableDmiTracing.value)) {
655 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
657 }
else if(!dmi_streamHandle)
658 initialize_streams();
659 SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
660 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
661 dmi_trInvalidateHandle->end_transaction(h, end_addr);
671 unsigned int count = fw_port->transport_dbg(trans);
The TLM transaction extensions recorder registry.
The TLM2 transaction recorder.
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
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
bool isRecordingNonBlockingTxEnabled() 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.
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 > enableDmiTracing
the attribute to selectively enable/disable DMI recording
sc_core::sc_attribute< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
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.
sc_core::sc_port_b< tlm::tlm_fw_transport_if< TYPES > > & fw_port
the port where fw accesses are forwarded to
sc_core::sc_port_b< tlm::tlm_bw_transport_if< TYPES > > & bw_port
the port where bw accesses are forwarded to
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
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.
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string