scc 2025.09
SystemC components library
tlc_recorder.h
1/*
2 * Copyright 2020, 2021 Arteris IP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h>
20#ifndef SC_INCLUDE_DYNAMIC_PROCESSES
21#define SC_INCLUDE_DYNAMIC_PROCESSES
22#endif
23
24#include <array>
25#include <string>
26#include <tilelink/tl_tlm.h>
27#include <tlm/scc/scv/tlm_recorder.h>
28#include <tlm/scc/scv/tlm_recording_extension.h>
29#include <tlm_utils/peq_with_cb_and_phase.h>
30#include <unordered_map>
31#include <vector>
32
34namespace tilelink {
35namespace scv {
36
37bool register_extensions();
38
39namespace impl {
42template <typename TYPES = tilelink::tl_protocol_types> class tlc_recording_payload : public TYPES::tlm_payload_type {
43public:
44 SCVNS scv_tr_handle parent;
45 uint64_t id{0};
46 bool is_snoop{false};
47 tlc_recording_payload& operator=(const typename TYPES::tlm_payload_type& x) {
48 id = (uint64_t)&x;
49 this->set_command(x.get_command());
50 this->set_address(x.get_address());
51 this->set_data_ptr(nullptr);
52 this->set_data_length(x.get_data_length());
53 this->set_response_status(x.get_response_status());
54 this->set_byte_enable_ptr(nullptr);
55 this->set_byte_enable_length(x.get_byte_enable_length());
56 this->set_streaming_width(x.get_streaming_width());
57 return (*this);
58 }
59 explicit tlc_recording_payload(tlm::tlm_mm_interface* mm)
60 : TYPES::tlm_payload_type(mm)
61 , parent() {}
62};
63
64template <typename TYPES = tilelink::tl_protocol_types> struct tlc_recording_types {
65 using tlm_payload_type = tlc_recording_payload<TYPES>;
66 using tlm_phase_type = typename TYPES::tlm_phase_type;
67};
68
69} // namespace impl
78template <typename TYPES = tilelink::tl_protocol_types>
79class tlc_recorder : public virtual tilelink::tlc_fw_transport_if<TYPES>, public virtual tilelink::tlc_bw_transport_if<TYPES> {
80public:
81 template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
83
84 template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
86
87 using recording_types = impl::tlc_recording_types<TYPES>;
89 using tlm_recording_payload = impl::tlc_recording_payload<TYPES>;
90
91 SC_HAS_PROCESS(tlc_recorder<TYPES>); // NOLINT
92
94 sc_core::sc_attribute<bool> enableBlTracing;
95
97 sc_core::sc_attribute<bool> enableNbTracing;
98
100 sc_core::sc_attribute<bool> enableTimedTracing{"enableTimedTracing", true};
101
103 sc_core::sc_attribute<bool> enableDmiTracing{"enableDmiTracing", false};
104
106 sc_core::sc_attribute<bool> enableTrDbgTracing{"enableTrDbgTracing", false};
107
109 sc_core::sc_attribute<bool> enableProtocolChecker{"enableProtocolChecker", false};
110
111 sc_core::sc_attribute<unsigned> rd_response_timeout{"rd_response_timeout", 0};
112
113 sc_core::sc_attribute<unsigned> wr_response_timeout{"wr_response_timeout", 0};
114
117
120
129 tlc_recorder(const char* name, unsigned bus_width, bool recording_enabled = true,
130 SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
131 : enableBlTracing("enableBlTracing", recording_enabled)
132 , enableNbTracing("enableNbTracing", recording_enabled)
133 , b_timed_peq(this, &tlc_recorder::btx_cb)
134 , nb_timed_peq(this, &tlc_recorder::nbtx_cb)
135 , m_db(tr_db)
136 , fixed_basename(name) {
137 register_extensions();
138 }
139
140 virtual ~tlc_recorder() override {
141 btx_handle_map.clear();
142 nbtx_req_handle_map.clear();
143 nbtx_last_req_handle_map.clear();
144 nbtx_resp_handle_map.clear();
145 nbtx_last_resp_handle_map.clear();
146 delete b_streamHandle;
147 for(auto* p : b_trHandle)
148 delete p; // NOLINT
149 delete b_streamHandleTimed;
150 for(auto* p : b_trTimedHandle)
151 delete p; // NOLINT
152 delete nb_streamHandle;
153 for(auto* p : nb_trHandle)
154 delete p; // NOLINT
155 delete nb_streamHandleTimed;
156 for(auto* p : nb_trTimedHandle)
157 delete p; // NOLINT
158 delete dmi_streamHandle;
159 delete dmi_trGetHandle;
160 delete dmi_trInvalidateHandle;
161 }
162
163 // TLM-2.0 interface methods for initiator and target sockets, surrounded with
164 // Tx Recording
174 tlm::tlm_sync_enum nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
175 sc_core::sc_time& delay) override;
185 tlm::tlm_sync_enum nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
186 sc_core::sc_time& delay) override;
195 void b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
204 void b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
212 bool get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) override;
219 void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override;
226 unsigned int transport_dbg(typename TYPES::tlm_payload_type& trans) override;
232 inline bool isRecordingBlockingTxEnabled() const { return m_db && enableBlTracing.value; }
238 inline bool isRecordingNonBlockingTxEnabled() const { return m_db && enableNbTracing.value; }
239
240private:
242 tlm_utils::peq_with_cb_and_phase<tlc_recorder, recording_types> b_timed_peq;
244 tlm_utils::peq_with_cb_and_phase<tlc_recorder, recording_types> nb_timed_peq;
249 void btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase);
254 void nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase);
256 SCVNS scv_tr_db* m_db{nullptr};
258 SCVNS scv_tr_stream* b_streamHandle{nullptr};
260 std::array<SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>*, 3> b_trHandle{{nullptr, nullptr, nullptr}};
262 SCVNS scv_tr_stream* b_streamHandleTimed{nullptr};
265 std::array<SCVNS scv_tr_generator<>*, 3> b_trTimedHandle{{nullptr, nullptr, nullptr}};
266 std::unordered_map<uint64_t, SCVNS scv_tr_handle> btx_handle_map;
267
268 enum DIR { FW, BW, REQ = FW, RESP = BW, ACK };
270 SCVNS scv_tr_stream* nb_streamHandle{nullptr};
272 SCVNS scv_tr_stream* nb_streamHandleTimed{nullptr};
274 std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{nullptr, nullptr}};
276 std::array<SCVNS scv_tr_generator<>*, 3> nb_trTimedHandle{{nullptr, nullptr, nullptr}};
277 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
278 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
279 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_resp_handle_map;
280 std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_resp_handle_map;
282 SCVNS scv_tr_stream* dmi_streamHandle{nullptr};
284 SCVNS scv_tr_generator<>* dmi_trGetHandle{nullptr};
285 SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{nullptr};
286
287protected:
288 void initialize_streams() {
290 b_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_bl").c_str(), "[TLM][ace][b]", m_db);
291 b_trHandle[tlm::TLM_READ_COMMAND] =
292 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("read", *b_streamHandle, "start_delay", "end_delay");
293 b_trHandle[tlm::TLM_WRITE_COMMAND] =
294 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("write", *b_streamHandle, "start_delay", "end_delay");
295 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
296 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("ignore", *b_streamHandle, "start_delay", "end_delay");
297 if(enableTimedTracing.value) {
298 b_streamHandleTimed = new SCVNS scv_tr_stream((fixed_basename + "_bl_timed").c_str(), "[TLM][ace][b][timed]", m_db);
299 b_trTimedHandle[tlm::TLM_READ_COMMAND] = new SCVNS scv_tr_generator<>("read", *b_streamHandleTimed);
300 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] = new SCVNS scv_tr_generator<>("write", *b_streamHandleTimed);
301 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] = new SCVNS scv_tr_generator<>("ignore", *b_streamHandleTimed);
302 }
303 }
304 if(isRecordingNonBlockingTxEnabled() && !nb_streamHandle) {
305 nb_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_nb").c_str(), "[TLM][ace][nb]", m_db);
306 nb_trHandle[FW] =
307 new SCVNS scv_tr_generator<std::string, std::string>("fw", *nb_streamHandle, "tlm_phase", "tlm_phase[return_path]");
308 nb_trHandle[BW] =
309 new SCVNS scv_tr_generator<std::string, std::string>("bw", *nb_streamHandle, "tlm_phase", "tlm_phase[return_path]");
310 if(enableTimedTracing.value) {
311 nb_streamHandleTimed = new SCVNS scv_tr_stream((fixed_basename + "_nb_timed").c_str(), "[TLM][ace][nb][timed]", m_db);
312 nb_trTimedHandle[FW] = new SCVNS scv_tr_generator<>("request", *nb_streamHandleTimed);
313 nb_trTimedHandle[BW] = new SCVNS scv_tr_generator<>("response", *nb_streamHandleTimed);
314 nb_trTimedHandle[ACK] = new SCVNS scv_tr_generator<>("ack", *nb_streamHandleTimed);
315 }
316 }
317 if(m_db && enableDmiTracing.value && !dmi_streamHandle) {
318 dmi_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_dmi").c_str(), "[TLM][ace][dmi]", m_db);
319 dmi_trGetHandle = new SCVNS scv_tr_generator<>("get", *dmi_streamHandle);
320 dmi_trInvalidateHandle =
321 new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("invalidate", *dmi_streamHandle, "start_addr", "end_addr");
322 }
323 // if(enableProtocolChecker.value) {
324 // checker=new tilelink::checker::tlc_protocol(fixed_basename, bus_width/8, rd_response_timeout.value,
325 // wr_response_timeout.value);
326 // }
327 }
328
329private:
330 const std::string fixed_basename;
331};
332
343template <unsigned int BUSWIDTH, typename TYPES = tilelink::tl_protocol_types>
344class tlc_recorder_module : public sc_core::sc_module, public tlc_recorder<TYPES> {
345public:
346 using BASE = tlc_recorder<TYPES>;
347 SC_HAS_PROCESS(axitlm_recorder_module); // NOLINT
349 typename BASE::template target_socket_type<BUSWIDTH> ts{"ts"};
351 typename BASE::template initiator_socket_type<BUSWIDTH> is{"is"};
352
361 tlc_recorder_module(sc_core::sc_module_name name, bool recording_enabled = true,
362 SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
363 : sc_module(name)
364 , BASE(this->name(), BUSWIDTH, recording_enabled, tr_db) {
365 // bind the sockets to the module
366 ts.bind(*this);
367 is.bind(*this);
368 add_attribute(BASE::enableBlTracing);
369 add_attribute(BASE::enableNbTracing);
370 add_attribute(BASE::enableTimedTracing);
371 add_attribute(BASE::enableDmiTracing);
372 add_attribute(BASE::enableTrDbgTracing);
373 add_attribute(BASE::enableProtocolChecker);
374 add_attribute(BASE::rd_response_timeout);
375 add_attribute(BASE::wr_response_timeout);
376 }
377
379
380 typename BASE::template target_socket_type<BUSWIDTH>::base_type::fw_interface_type* get_fw_if() override {
381 return is.get_base_port().operator->();
382 }
383
384 typename BASE::template target_socket_type<BUSWIDTH>::base_type::bw_interface_type* get_bw_if() override {
385 return ts.get_base_port().operator->();
386 }
387
388private:
389 void start_of_simulation() override { BASE::initialize_streams(); }
390};
391
393// implementations of functions
395
396template <typename TYPES> void tlc_recorder<TYPES>::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
397 tlm_recording_payload* req{nullptr};
399 get_fw_if()->b_transport(trans, delay);
400 return;
401 }
402 // Get a handle for the new transaction
403 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
404 /*************************************************************************
405 * do the timed notification
406 *************************************************************************/
407 if(b_streamHandleTimed) {
408 req = mm::get().allocate();
409 req->acquire();
410 (*req) = trans;
411 req->parent = h;
412 req->id = h.get_id();
413 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
414 }
415
416 auto addr = trans.get_address();
417 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
418 if(ext)
419 ext->recordBeginTx(h, trans);
421
422 trans.get_extension(preExt);
423 if(preExt == nullptr) { // we are the first recording this transaction
424 preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
425 if(trans.has_mm())
426 trans.set_auto_extension(preExt);
427 else
428 trans.set_extension(preExt);
429 } else {
431 }
432 SCVNS scv_tr_handle preTx(preExt->txHandle);
433 preExt->txHandle = h;
434 get_fw_if()->b_transport(trans, delay);
435 trans.get_extension(preExt);
436 if(preExt->get_creator() == this) {
437 // clean-up the extension if this is the original creator
438 if(trans.has_mm())
439 trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
440 else
441 delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
442 } else {
443 preExt->txHandle = preTx;
444 }
445
446 trans.set_address(addr);
447 tlm::scc::scv::record(h, trans);
448 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
449 if(ext)
450 ext->recordEndTx(h, trans);
451 // End the transaction
452 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
453 // and now the stuff for the timed tx
454 if(b_streamHandleTimed) {
455 b_timed_peq.notify(*req, tlm::END_RESP, delay);
456 }
457}
458
459template <typename TYPES> void tlc_recorder<TYPES>::b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
460 tlm_recording_payload* req{nullptr};
461 if(!b_streamHandleTimed) {
462 get_bw_if()->b_snoop(trans, delay);
463 return;
464 }
465 // Get a handle for the new transaction
466 SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
467 /*************************************************************************
468 * do the timed notification
469 *************************************************************************/
470 if(b_streamHandleTimed) {
471 req = mm::get().allocate();
472 req->acquire();
473 (*req) = trans;
474 req->parent = h;
475 req->id = h.get_id();
476 b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
477 }
478
479 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
480 if(ext)
481 ext->recordBeginTx(h, trans);
483
484 trans.get_extension(preExt);
485 if(preExt == NULL) { // we are the first recording this transaction
486 preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
487 if(trans.has_mm())
488 trans.set_auto_extension(preExt);
489 else
490 trans.set_extension(preExt);
491 } else {
493 }
494 SCVNS scv_tr_handle preTx(preExt->txHandle);
495 preExt->txHandle = h;
496 get_bw_if()->b_snoop(trans, delay);
497 trans.get_extension(preExt);
498 if(preExt->get_creator() == this) {
499 // clean-up the extension if this is the original creator
500 if(trans.has_mm())
501 trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
502 else
503 delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
504 } else {
505 preExt->txHandle = preTx;
506 }
507
508 tlm::scc::scv::record(h, trans);
509 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
510 if(ext)
511 ext->recordEndTx(h, trans);
512 // End the transaction
513 b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
514 // and now the stuff for the timed tx
515 if(b_streamHandleTimed) {
516 b_timed_peq.notify(*req, tlm::END_RESP, delay);
517 }
518}
519
520template <typename TYPES> void tlc_recorder<TYPES>::btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
521 SCVNS scv_tr_handle h;
522 // Now process outstanding recordings
523 switch(phase) {
524 case tlm::BEGIN_REQ: {
525 h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
526 h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
527 btx_handle_map[rec_parts.id] = h;
528 } break;
529 case tlm::END_RESP: {
530 auto it = btx_handle_map.find(rec_parts.id);
531 sc_assert(it != btx_handle_map.end());
532 h = it->second;
533 btx_handle_map.erase(it);
534 tlm::scc::scv::record(h, rec_parts);
535 h.end_transaction();
536 rec_parts.release();
537 } break;
538 default:
539 sc_assert(!"phase not supported!");
540 }
541 return;
542}
543
544template <typename TYPES>
545tlm::tlm_sync_enum tlc_recorder<TYPES>::nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
546 sc_core::sc_time& delay) {
548 return get_fw_if()->nb_transport_fw(trans, phase, delay);
549 }
550 /*************************************************************************
551 * prepare recording
552 *************************************************************************/
553 // Get a handle for the new transaction
554 SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase.get_name());
556 trans.get_extension(preExt);
557 if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
558 preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
559 if(trans.has_mm())
560 trans.set_auto_extension(preExt);
561 else
562 trans.set_extension(preExt);
563 } else if(preExt != nullptr) {
564 // link handle if we have a predecessor
566 } else {
567 sc_assert(preExt != nullptr && "ERROR on forward path in phase other than tlm::BEGIN_REQ");
568 }
569 // update the extension
570 preExt->txHandle = h;
571 h.record_attribute("delay", delay.to_string());
572 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
573 if(ext)
574 ext->recordBeginTx(h, trans);
575 /*************************************************************************
576 * do the timed notification
577 *************************************************************************/
578 if(nb_streamHandleTimed) {
579 tlm_recording_payload* req = mm::get().allocate();
580 req->acquire();
581 (*req) = trans;
582 req->parent = h;
583 req->is_snoop = phase == tlm::BEGIN_RESP;
584 nb_timed_peq.notify(*req, phase, delay);
585 }
586 /*************************************************************************
587 * do the access
588 *************************************************************************/
589 tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
590 /*************************************************************************
591 * handle recording
592 *************************************************************************/
593 tlm::scc::scv::record(h, status);
594 h.record_attribute("delay[return_path]", delay.to_string());
595 tlm::scc::scv::record(h, trans);
596 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
597 if(ext)
598 ext->recordEndTx(h, trans);
599 // get the extension and free the memory if it was mine
600 if(status == tlm::TLM_COMPLETED || (phase == tilelink::ACK)) {
601 // the transaction is finished
602 trans.get_extension(preExt);
603 if(preExt && preExt->get_creator() == this) {
604 // clean-up the extension if this is the original creator
605 if(trans.has_mm())
606 trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
607 else
608 delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
609 }
610 /*************************************************************************
611 * do the timed notification if req. finished here
612 *************************************************************************/
613 if(nb_streamHandleTimed) {
614 tlm_recording_payload* req = mm::get().allocate();
615 req->acquire();
616 (*req) = trans;
617 req->parent = h;
618 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase, delay);
619 }
620 } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
621 tlm_recording_payload* req = mm::get().allocate();
622 req->acquire();
623 (*req) = trans;
624 req->parent = h;
625 nb_timed_peq.notify(*req, phase, delay);
626 }
627 // End the transaction
628 nb_trHandle[FW]->end_transaction(h, phase.get_name());
629 return status;
630}
631
632template <typename TYPES>
633tlm::tlm_sync_enum tlc_recorder<TYPES>::nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
634 sc_core::sc_time& delay) {
636 return get_bw_if()->nb_transport_bw(trans, phase, delay);
637 }
638 /*************************************************************************
639 * prepare recording
640 *************************************************************************/
641 // Get a handle for the new transaction
642 SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase.get_name());
644 trans.get_extension(preExt);
645 if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
646 preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
647 if(trans.has_mm())
648 trans.set_auto_extension(preExt);
649 else
650 trans.set_extension(preExt);
651 } else if(preExt != nullptr) {
652 // link handle if we have a predecessor
654 } else {
655 sc_assert(preExt != nullptr && "ERROR on backward path in phase other than tlm::BEGIN_REQ");
656 }
657 // and set the extension handle to this transaction
658 preExt->txHandle = h;
659 h.record_attribute("delay", delay.to_string());
660 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
661 if(ext)
662 ext->recordBeginTx(h, trans);
663 /*************************************************************************
664 * do the timed notification
665 *************************************************************************/
666 if(nb_streamHandleTimed) {
667 tlm_recording_payload* req = mm::get().allocate();
668 req->acquire();
669 (*req) = trans;
670 req->parent = h;
671 req->is_snoop = phase == tlm::BEGIN_REQ;
672 nb_timed_peq.notify(*req, phase, delay);
673 }
674 /*************************************************************************
675 * do the access
676 *************************************************************************/
677 tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
678 /*************************************************************************
679 * handle recording
680 *************************************************************************/
681 tlm::scc::scv::record(h, status);
682 h.record_attribute("delay[return_path]", delay.to_string());
683 tlm::scc::scv::record(h, trans);
684 for(auto& ext : tlm::scc::scv::tlm_extension_recording_registry<TYPES>::inst().get())
685 if(ext)
686 ext->recordEndTx(h, trans);
687 // get the extension and free the memory if it was mine
688 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tilelink::ACK)) {
689 // the transaction is finished
690 trans.get_extension(preExt);
691 if(preExt->get_creator() == this) {
692 // clean-up the extension if this is the original creator
693 if(trans.has_mm())
694 trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
695 else
696 delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
697 }
698 /*************************************************************************
699 * do the timed notification if req. finished here
700 *************************************************************************/
701 if(nb_streamHandleTimed) {
702 tlm_recording_payload* req = mm::get().allocate();
703 req->acquire();
704 (*req) = trans;
705 req->parent = h;
706 nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase, delay);
707 }
708 } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
709 tlm_recording_payload* req = mm::get().allocate();
710 req->acquire();
711 (*req) = trans;
712 req->parent = h;
713 nb_timed_peq.notify(*req, phase, delay);
714 }
715 // End the transaction
716 nb_trHandle[BW]->end_transaction(h, phase.get_name());
717 return status;
718}
719
720template <typename TYPES> void tlc_recorder<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
721 SCVNS scv_tr_handle h;
722 // Now process outstanding recordings
723 if(phase == tlm::BEGIN_REQ) {
724 h = nb_trTimedHandle[REQ]->begin_transaction();
725 tlm::scc::scv::record(h, rec_parts);
726 h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
727 nbtx_req_handle_map[rec_parts.id] = h;
728 } else if(phase == tlm::END_REQ) {
729 auto it = nbtx_req_handle_map.find(rec_parts.id);
730 sc_assert(it != nbtx_req_handle_map.end());
731 h = it->second;
732 nbtx_req_handle_map.erase(it);
733 h.end_transaction();
734 nbtx_last_req_handle_map[rec_parts.id] = h;
735 } else if(phase == tlm::BEGIN_RESP) {
736 auto it = nbtx_req_handle_map.find(rec_parts.id);
737 if(it != nbtx_req_handle_map.end()) {
738 h = it->second;
739 nbtx_req_handle_map.erase(it);
740 h.end_transaction();
741 nbtx_last_req_handle_map[rec_parts.id] = h;
742 }
743 h = nb_trTimedHandle[RESP]->begin_transaction();
744 tlm::scc::scv::record(h, rec_parts);
745 h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
746 nbtx_resp_handle_map[rec_parts.id] = h;
747 it = nbtx_last_req_handle_map.find(rec_parts.id);
748 if(it != nbtx_last_req_handle_map.end()) {
749 SCVNS scv_tr_handle& pred = it->second;
751 nbtx_last_req_handle_map.erase(it);
752 } else {
753 it = nbtx_last_resp_handle_map.find(rec_parts.id);
754 if(it != nbtx_last_resp_handle_map.end()) {
755 SCVNS scv_tr_handle& pred = it->second;
757 nbtx_last_resp_handle_map.erase(it);
758 }
759 }
760 } else if(phase == tlm::END_RESP) {
761 auto it = nbtx_resp_handle_map.find(rec_parts.id);
762 if(it != nbtx_resp_handle_map.end()) {
763 h = it->second;
764 nbtx_resp_handle_map.erase(it);
765 h.end_transaction();
766 }
767 } else if(phase == tilelink::ACK) {
768 h = nb_trTimedHandle[ACK]->begin_transaction();
769 tlm::scc::scv::record(h, rec_parts);
770 h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
771 h.end_transaction();
772 } else
773 sc_assert(!"phase not supported!");
774 rec_parts.release();
775 return;
776}
777
778template <typename TYPES> bool tlc_recorder<TYPES>::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) {
779 if(!(m_db && enableDmiTracing.value))
780 return get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
781 else if(!dmi_streamHandle)
782 initialize_streams();
783 SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
784 bool status = get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
785 tlm::scc::scv::record(h, trans);
786 tlm::scc::scv::record(h, dmi_data);
787 h.end_transaction();
788 return status;
789}
790
796template <typename TYPES> void tlc_recorder<TYPES>::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) {
797 if(!(m_db && enableDmiTracing.value)) {
798 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
799 return;
800 } else if(!dmi_streamHandle)
801 initialize_streams();
802 SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
803 get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
804 dmi_trInvalidateHandle->end_transaction(h, end_addr);
805 return;
806}
807
813template <typename TYPES> unsigned int tlc_recorder<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) {
814 unsigned int count = get_fw_if()->transport_dbg(trans);
815 return count;
816}
817} // namespace scv
818} // namespace tilelink
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
a tlm memory manager
Definition tlm_mm.h:330