scc  2024.06
SystemC components library
chi_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 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
20 #define SC_INCLUDE_DYNAMIC_PROCESSES
21 #endif
22 
23 #include <array>
24 #include <chi/chi_tlm.h>
25 #include <regex>
26 #include <string>
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 
34 namespace chi {
35 namespace scv {
36 
37 bool register_extensions();
38 
39 namespace impl {
42 template <typename TYPES = chi::chi_protocol_types> class chi_recording_payload : public TYPES::tlm_payload_type {
43 public:
44  SCVNS scv_tr_handle parent;
45  uint64_t id{0};
46  bool is_snoop{false};
47  bool is_data{false};
48  bool is_credit{false};
49  chi_recording_payload& operator=(const typename TYPES::tlm_payload_type& x) {
50  id = (uint64_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(0);
55  this->set_response_status(x.get_response_status());
56  this->set_byte_enable_ptr(nullptr);
57  this->set_byte_enable_length(0);
58  this->set_streaming_width(x.get_streaming_width());
59  return (*this);
60  }
61  explicit chi_recording_payload(tlm::tlm_mm_interface* mm)
62  : TYPES::tlm_payload_type(mm)
63  , parent() {}
64 };
65 
66 template <typename TYPES = chi::chi_protocol_types> struct chi_recording_types {
68  using tlm_phase_type = typename TYPES::tlm_phase_type;
69 };
70 
71 } // namespace impl
80 template <typename TYPES = chi::chi_protocol_types>
81 class chi_trx_recorder : public virtual chi::chi_fw_transport_if<TYPES>,
82  public virtual chi::chi_bw_transport_if<TYPES> {
83 public:
84  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
86 
87  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
89 
93 
94  SC_HAS_PROCESS(chi_trx_recorder<TYPES>); // NOLINT
95 
97  sc_core::sc_attribute<bool> enableBlTracing;
98 
100  sc_core::sc_attribute<bool> enableNbTracing;
101 
103  sc_core::sc_attribute<bool> enableTimedTracing{"enableTimedTracing", true};
104 
106  sc_core::sc_attribute<bool> enableDmiTracing{"enableDmiTracing", false};
107 
109  sc_core::sc_attribute<bool> enableTrDbgTracing{"enableTrDbgTracing", false};
110 
112  virtual tlm::tlm_fw_transport_if<TYPES>* get_fw_if() = 0;
113 
115  virtual tlm::tlm_bw_transport_if<TYPES>* get_bw_if() = 0;
116 
125  chi_trx_recorder(const char* name, bool recording_enabled = true,
126  SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
127  : enableBlTracing("enableBlTracing", recording_enabled)
128  , enableNbTracing("enableNbTracing", recording_enabled)
129  , b_timed_peq(this, &chi_trx_recorder::btx_cb)
130  , nb_timed_peq(this, &chi_trx_recorder::nbtx_cb)
131  , m_db(tr_db)
132  , fixed_basename(name) {
133  register_extensions();
134  }
135 
136  virtual ~chi_trx_recorder() override {
137  btx_handle_map.clear();
138  nbtx_req_handle_map.clear();
139  nbtx_last_req_handle_map.clear();
140  nbtx_resp_handle_map.clear();
141  nbtx_last_resp_handle_map.clear();
142  nbtx_data_handle_map.clear();
143  nbtx_last_data_handle_map.clear();
144  nbtx_ack_handle_map.clear();
145 
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 
240 private:
242  tlm_utils::peq_with_cb_and_phase<chi_trx_recorder, recording_types> b_timed_peq;
244  tlm_utils::peq_with_cb_and_phase<chi_trx_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, DATA, ACK, CREDIT, REQ = FW, RESP = BW };
269  enum TYPE {
270  READ = tlm::TLM_READ_COMMAND,
271  WRITE = tlm::TLM_WRITE_COMMAND,
272  OTHER = tlm::TLM_IGNORE_COMMAND,
273  SNOOP,
274  NO_OF_TYPES
275  };
277  SCVNS scv_tr_stream* nb_streamHandle{nullptr};
279  SCVNS scv_tr_stream* nb_streamHandleTimed{nullptr};
281  std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{nullptr, nullptr}};
283  std::array<SCVNS scv_tr_generator<>*, 5> nb_trTimedHandle{{nullptr, nullptr, nullptr, nullptr, nullptr}};
284  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
285  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
286  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_resp_handle_map;
287  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_resp_handle_map;
288  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_data_handle_map;
289  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_data_handle_map;
290  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_ack_handle_map;
292  SCVNS scv_tr_stream* dmi_streamHandle{nullptr};
294  SCVNS scv_tr_generator<>* dmi_trGetHandle{nullptr};
295  SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{nullptr};
296 
297 protected:
298  void initialize_streams() {
300  b_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_bl").c_str(), "[TLM][chi][b]", m_db);
301  b_trHandle[tlm::TLM_READ_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
302  "read", *b_streamHandle, "start_delay", "end_delay");
303  b_trHandle[tlm::TLM_WRITE_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
304  "write", *b_streamHandle, "start_delay", "end_delay");
305  b_trHandle[tlm::TLM_IGNORE_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
306  "ignore", *b_streamHandle, "start_delay", "end_delay");
307  if(enableTimedTracing.value) {
308  b_streamHandleTimed =
309  new SCVNS scv_tr_stream((fixed_basename + "_bl_timed").c_str(), "[TLM][chi][b][timed]", m_db);
310  b_trTimedHandle[tlm::TLM_READ_COMMAND] = new SCVNS scv_tr_generator<>("read", *b_streamHandleTimed);
311  b_trTimedHandle[tlm::TLM_WRITE_COMMAND] = new SCVNS scv_tr_generator<>("write", *b_streamHandleTimed);
312  b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] = new SCVNS scv_tr_generator<>("ignore", *b_streamHandleTimed);
313  }
314  }
315  if(isRecordingNonBlockingTxEnabled() && !nb_streamHandle) {
316  nb_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_nb").c_str(), "[TLM][chi][nb]", m_db);
317  nb_trHandle[FW] = new SCVNS scv_tr_generator<std::string, std::string>("fw", *nb_streamHandle, "tlm_phase",
318  "tlm_phase[return_path]");
319  nb_trHandle[BW] = new SCVNS scv_tr_generator<std::string, std::string>("bw", *nb_streamHandle, "tlm_phase",
320  "tlm_phase[return_path]");
321  if(enableTimedTracing.value) {
322  nb_streamHandleTimed =
323  new SCVNS scv_tr_stream((fixed_basename + "_nb_timed").c_str(), "[TLM][chi][nb][timed]", m_db);
324  nb_trTimedHandle[REQ] = new SCVNS scv_tr_generator<>("request", *nb_streamHandleTimed);
325  nb_trTimedHandle[RESP] = new SCVNS scv_tr_generator<>("response", *nb_streamHandleTimed);
326  nb_trTimedHandle[DATA] = new SCVNS scv_tr_generator<>("data", *nb_streamHandleTimed);
327  nb_trTimedHandle[ACK] = new SCVNS scv_tr_generator<>("ack", *nb_streamHandleTimed);
328  nb_trTimedHandle[CREDIT] = new SCVNS scv_tr_generator<>("link", *nb_streamHandleTimed);
329  }
330  }
331  if(m_db && enableDmiTracing.value && !dmi_streamHandle) {
332  dmi_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_dmi").c_str(), "[TLM][ace][dmi]", m_db);
333  dmi_trGetHandle = new SCVNS scv_tr_generator<>("get", *dmi_streamHandle, "trans", "dmi_data");
334  dmi_trInvalidateHandle = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
335  "invalidate", *dmi_streamHandle, "start_addr", "end_addr");
336  }
337  }
338 
339 private:
340  const std::string fixed_basename;
341 
342  inline std::string phase2string(const tlm::tlm_phase& p) {
343  std::stringstream ss;
344  ss << p;
345  return ss.str();
346  }
347 };
348 
350 // implementations of functions
352 
353 template <typename TYPES>
354 void chi_trx_recorder<TYPES>::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
355  tlm_recording_payload* req{nullptr};
356  if(!isRecordingBlockingTxEnabled()) {
357  get_fw_if()->b_transport(trans, delay);
358  return;
359  }
360  // Get a handle for the new transaction
361  SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
362 
363  /*************************************************************************
364  * do the timed notification
365  *************************************************************************/
366  if(b_streamHandleTimed) {
367  req = mm::get().allocate();
368  req->acquire();
369  (*req) = trans;
370  req->parent = h;
371  req->id = h.get_id();
372  b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
373  }
374 
376  if(ext)
377  ext->recordBeginTx(h, trans);
378  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
379 
380  trans.get_extension(preExt);
381  if(preExt == nullptr) { // we are the first recording this transaction
382  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
383  trans.set_extension(preExt);
384  } else {
386  }
387  SCVNS scv_tr_handle preTx(preExt->txHandle);
388  preExt->txHandle = h;
389  get_fw_if()->b_transport(trans, delay);
390  trans.get_extension(preExt);
391  if(preExt->get_creator() == this) {
392  // clean-up the extension if this is the original creator
393  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
394  } else {
395  preExt->txHandle = preTx;
396  }
397  tlm::scc::scv::record(h, trans);
399  if(ext)
400  ext->recordEndTx(h, trans);
401  // End the transaction
402  b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
403  // and now the stuff for the timed tx
404  if(b_streamHandleTimed) {
405  b_timed_peq.notify(*req, tlm::END_RESP, delay);
406  }
407 }
408 
409 template <typename TYPES>
410 void chi_trx_recorder<TYPES>::b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
411  tlm_recording_payload* req{nullptr};
412  if(!b_streamHandleTimed) {
413  get_fw_if()->b_transport(trans, delay);
414  return;
415  }
416  // Get a handle for the new transaction
417  SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
418  /*************************************************************************
419  * do the timed notification
420  *************************************************************************/
421  if(b_streamHandleTimed) {
422  req = mm::get().allocate();
423  req->acquire();
424  (*req) = trans;
425  req->parent = h;
426  req->id = h.get_id();
427  b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
428  }
429 
431  if(ext)
432  ext->recordBeginTx(h, trans);
434 
435  trans.get_extension(preExt);
436  if(preExt == NULL) { // we are the first recording this transaction
437  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
438  trans.set_extension(preExt);
439  } else {
441  }
442  SCVNS scv_tr_handle preTx(preExt->txHandle);
443  preExt->txHandle = h;
444  get_fw_if()->b_transport(trans, delay);
445  trans.get_extension(preExt);
446  if(preExt->get_creator() == this) {
447  // clean-up the extension if this is the original creator
448  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
449  } else {
450  preExt->txHandle = preTx;
451  }
452 
453  tlm::scc::scv::record(h, trans);
455  if(ext)
456  ext->recordEndTx(h, trans);
457  // End the transaction
458  b_trHandle[trans.get_command()]->end_transaction(h, delay.value());
459  // and now the stuff for the timed tx
460  if(b_streamHandleTimed) {
461  b_timed_peq.notify(*req, tlm::END_RESP, delay);
462  }
463 }
464 
465 template <typename TYPES>
466 void chi_trx_recorder<TYPES>::btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
467  SCVNS scv_tr_handle h;
468  // Now process outstanding recordings
469  switch(phase) {
470  case tlm::BEGIN_REQ: {
471  h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
472  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
473  btx_handle_map[rec_parts.id] = h;
474  } break;
475  case tlm::END_RESP: {
476  auto it = btx_handle_map.find(rec_parts.id);
477  sc_assert(it != btx_handle_map.end());
478  h = it->second;
479  btx_handle_map.erase(it);
480  tlm::scc::scv::record(h, rec_parts);
481  h.end_transaction();
482  rec_parts.release();
483  } break;
484  default:
485  sc_assert(!"phase not supported!");
486  }
487  return;
488 }
489 
490 template <typename TYPES>
491 tlm::tlm_sync_enum chi_trx_recorder<TYPES>::nb_transport_fw(typename TYPES::tlm_payload_type& trans,
492  typename TYPES::tlm_phase_type& phase,
493  sc_core::sc_time& delay) {
494  if(!nb_trHandle[FW])
495  return get_fw_if()->nb_transport_fw(trans, phase, delay);
496  /*************************************************************************
497  * prepare recording
498  *************************************************************************/
499  // Get a handle for the new transaction
500  bool is_snoop = (trans.template get_extension<chi::chi_snp_extension>() != nullptr);
501  SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase2string(phase));
502  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
503  trans.get_extension(preExt);
504  if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
505  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
506  trans.set_extension(preExt);
507  } else if(preExt != nullptr) {
508  // link handle if we have a predecessor
510  } else {
511  sc_assert(preExt != nullptr && "ERROR on forward path in phase other than tlm::BEGIN_REQ");
512  }
513  // update the extension
514  preExt->txHandle = h;
515  h.record_attribute("delay", delay.to_string());
517  if(ext)
518  ext->recordBeginTx(h, trans);
519  /*************************************************************************
520  * do the timed notification
521  *************************************************************************/
522  if(nb_streamHandleTimed) {
523  tlm_recording_payload* req = mm::get().allocate();
524  req->acquire();
525  (*req) = trans;
526  req->parent = h;
527  req->is_snoop = is_snoop;
528  req->is_data = (phase == chi::BEGIN_DATA || chi::BEGIN_PARTIAL_DATA);
530  trans.get_extension(ext);
531  req->is_credit = (phase == tlm::BEGIN_REQ && ext != nullptr);
532  nb_timed_peq.notify(*req, phase, delay);
533  }
534  /*************************************************************************
535  * do the access
536  *************************************************************************/
537  tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
538  /*************************************************************************
539  * handle recording
540  *************************************************************************/
541  tlm::scc::scv::record(h, status);
542  h.record_attribute("delay[return_path]", delay.to_string());
543  tlm::scc::scv::record(h, trans);
545  if(ext)
546  ext->recordEndTx(h, trans);
547  // get the extension and free the memory if it was mine
548  if(status == tlm::TLM_COMPLETED) {
549  // the transaction is finished
550  trans.get_extension(preExt);
551  if(preExt && preExt->get_creator() == this) {
552  // clean-up the extension if this is the original creator
553  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
554  }
555  /*************************************************************************
556  * do the timed notification if req. finished here
557  *************************************************************************/
558  if(nb_streamHandleTimed) {
559  tlm_recording_payload* req = mm::get().allocate();
560  req->acquire();
561  (*req) = trans;
562  req->parent = h;
563  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
564  delay);
565  }
566  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
567  tlm_recording_payload* req = mm::get().allocate();
568  req->acquire();
569  (*req) = trans;
570  req->parent = h;
571  nb_timed_peq.notify(*req, phase, delay);
572  }
573  // End the transaction
574  nb_trHandle[FW]->end_transaction(h, phase2string(phase));
575  return status;
576 }
577 
578 template <typename TYPES>
579 tlm::tlm_sync_enum chi_trx_recorder<TYPES>::nb_transport_bw(typename TYPES::tlm_payload_type& trans,
580  typename TYPES::tlm_phase_type& phase,
581  sc_core::sc_time& delay) {
582  if(!nb_trHandle[BW])
583  return get_bw_if()->nb_transport_bw(trans, phase, delay);
584  /*************************************************************************
585  * prepare recording
586  *************************************************************************/
587  // Get a handle for the new transaction
588  bool is_snoop = (trans.template get_extension<chi::chi_snp_extension>() != nullptr);
589  SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase2string(phase));
590  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
591  trans.get_extension(preExt);
592  if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
593  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
594  trans.set_extension(preExt);
595  } else if(preExt != nullptr) {
596  // link handle if we have a predecessor
598  } else {
599  sc_assert(preExt != nullptr && "ERROR on backward path in phase other than tlm::BEGIN_REQ");
600  }
601  // and set the extension handle to this transaction
602  preExt->txHandle = h;
603  h.record_attribute("delay", delay.to_string());
605  if(ext)
606  ext->recordBeginTx(h, trans);
607  /*************************************************************************
608  * do the timed notification
609  *************************************************************************/
610  if(nb_streamHandleTimed) {
611  tlm_recording_payload* req = mm::get().allocate();
612  req->acquire();
613  (*req) = trans;
614  req->parent = h;
615  req->is_snoop = is_snoop;
616  req->is_data = (phase == chi::BEGIN_DATA || chi::BEGIN_PARTIAL_DATA);
618  trans.get_extension(ext);
619  req->is_credit = (phase == tlm::BEGIN_REQ && ext != nullptr);
620  nb_timed_peq.notify(*req, phase, delay);
621  }
622  /*************************************************************************
623  * do the access
624  *************************************************************************/
625  tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
626  /*************************************************************************
627  * handle recording
628  *************************************************************************/
629  tlm::scc::scv::record(h, status);
630  h.record_attribute("delay[return_path]", delay.to_string());
631  tlm::scc::scv::record(h, trans);
633  if(ext)
634  ext->recordEndTx(h, trans);
635  // get the extension and free the memory if it was mine
636  if(status == tlm::TLM_COMPLETED) {
637  // the transaction is finished
638  trans.get_extension(preExt);
639  if(preExt->get_creator() == this) {
640  // clean-up the extension if this is the original creator
641  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
642  }
643  /*************************************************************************
644  * do the timed notification if req. finished here
645  *************************************************************************/
646  if(nb_streamHandleTimed) {
647  tlm_recording_payload* req = mm::get().allocate();
648  req->acquire();
649  (*req) = trans;
650  req->parent = h;
651  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
652  delay);
653  }
654  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
655  tlm_recording_payload* req = mm::get().allocate();
656  req->acquire();
657  (*req) = trans;
658  req->parent = h;
659  nb_timed_peq.notify(*req, phase, delay);
660  }
661  // End the transaction
662  nb_trHandle[BW]->end_transaction(h, phase2string(phase));
663  return status;
664 }
665 
666 template <typename TYPES>
667 void chi_trx_recorder<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
668  SCVNS scv_tr_handle h;
669  std::unordered_map<uint64_t, SCVNS scv_tr_handle>::iterator it;
670  // Now process outstanding recordings
671  if(rec_parts.is_credit) {
672  nb_trTimedHandle[CREDIT]->begin_transaction().end_transaction();
673  } else if(phase == tlm::BEGIN_REQ) {
674  h = nb_trTimedHandle[REQ]->begin_transaction();
675  tlm::scc::scv::record(h, rec_parts);
676  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
677  nbtx_req_handle_map[rec_parts.id] = h;
678  nbtx_last_req_handle_map[rec_parts.id] = h;
679  } else if(phase == tlm::END_REQ) {
680  it = nbtx_req_handle_map.find(rec_parts.id);
681  if(it != nbtx_req_handle_map.end()) {
682  it->second.end_transaction();
683  nbtx_req_handle_map.erase(it);
684  }
685  } else if(phase == tlm::BEGIN_RESP) {
686  it = nbtx_req_handle_map.find(rec_parts.id);
687  if(it != nbtx_req_handle_map.end()) {
688  it->second.end_transaction();
689  nbtx_req_handle_map.erase(it);
690  }
691  h = nb_trTimedHandle[RESP]->begin_transaction();
692  tlm::scc::scv::record(h, rec_parts);
693  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
694  nbtx_resp_handle_map[rec_parts.id] = h;
695  it = nbtx_last_req_handle_map.find(rec_parts.id);
696  if(it != nbtx_last_req_handle_map.end()) {
697  SCVNS scv_tr_handle pred = it->second;
698  nbtx_last_req_handle_map.erase(it);
700  } else {
701  it = nbtx_last_resp_handle_map.find(rec_parts.id);
702  if(it != nbtx_last_resp_handle_map.end()) {
703  SCVNS scv_tr_handle pred = it->second;
704  nbtx_last_resp_handle_map.erase(it);
706  }
707  }
708  } else if(phase == tlm::END_RESP) {
709  it = nbtx_resp_handle_map.find(rec_parts.id);
710  if(it != nbtx_resp_handle_map.end()) {
711  h = it->second;
712  nbtx_resp_handle_map.erase(it);
713  h.end_transaction();
714  } else {
715  it = nbtx_req_handle_map.find(rec_parts.id);
716  if(it != nbtx_req_handle_map.end()) {
717  h = it->second;
718  nbtx_req_handle_map.erase(it);
719  h.end_transaction();
720  }
721  }
722  } else if(phase == chi::BEGIN_DATA || phase == chi::BEGIN_PARTIAL_DATA) {
723  it = nbtx_req_handle_map.find(rec_parts.id);
724  if(it != nbtx_req_handle_map.end()) {
725  h = it->second;
726  h.end_transaction();
727  nbtx_last_req_handle_map[rec_parts.id] = h;
728  }
729  h = nb_trTimedHandle[DATA]->begin_transaction();
730  tlm::scc::scv::record(h, rec_parts);
731  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
732  nbtx_data_handle_map[rec_parts.id] = h;
733  it = nbtx_last_data_handle_map.find(rec_parts.id);
734  if(it != nbtx_last_data_handle_map.end()) {
735  SCVNS scv_tr_handle pred = it->second;
736  nbtx_last_data_handle_map.erase(it);
738  }
739  } else if(phase == chi::END_DATA || phase == chi::END_PARTIAL_DATA) {
740  it = nbtx_data_handle_map.find(rec_parts.id);
741  if(it != nbtx_data_handle_map.end()) {
742  h = it->second;
743  nbtx_data_handle_map.erase(it);
744  h.end_transaction();
745  }
746  } else if(phase == chi::ACK) {
747  it = nbtx_ack_handle_map.find(rec_parts.id);
748  if(it == nbtx_ack_handle_map.end()) {
749  auto h = nb_trTimedHandle[ACK]->begin_transaction();
750  nbtx_ack_handle_map[rec_parts.id] = h;
751  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
752  } else {
753  nb_trTimedHandle[ACK]->end_transaction(it->second);
754  nbtx_ack_handle_map.erase(it);
755  }
756  } else
757  sc_assert(!"phase not supported!");
758  rec_parts.release();
759  return;
760 }
761 
762 template <typename TYPES>
763 bool chi_trx_recorder<TYPES>::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) {
764  if(!(m_db && enableDmiTracing.value))
765  return get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
766  else if(!dmi_streamHandle)
767  initialize_streams();
768  SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
769  bool status = get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
770  tlm::scc::scv::record(h, trans);
771  tlm::scc::scv::record(h, dmi_data);
772  h.end_transaction();
773  return status;
774 }
781 template <typename TYPES>
782 void chi_trx_recorder<TYPES>::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) {
783  if(!(m_db && enableDmiTracing.value)) {
784  get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
785  return;
786  } else if(!dmi_streamHandle)
787  initialize_streams();
788  SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
789  get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
790  dmi_trInvalidateHandle->end_transaction(h, end_addr);
791  return;
792 }
799 template <typename TYPES> unsigned int chi_trx_recorder<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) {
800  unsigned int count = get_fw_if()->transport_dbg(trans);
801  return count;
802 }
803 } // namespace scv
804 } // namespace chi
The TLM2 transaction recorder.
Definition: chi_recorder.h:82
void b_snoop(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking snoop function.
Definition: chi_recorder.h:410
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.
Definition: chi_recorder.h:579
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
Definition: chi_recorder.h:763
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
Definition: chi_recorder.h:354
virtual tlm::tlm_fw_transport_if< TYPES > * get_fw_if()=0
the port where fw 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.
Definition: chi_recorder.h:782
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
Definition: chi_recorder.h:103
sc_core::sc_attribute< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
Definition: chi_recorder.h:100
virtual tlm::tlm_bw_transport_if< TYPES > * get_bw_if()=0
the port where bw accesses are forwarded to
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
Definition: chi_recorder.h:799
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.
Definition: chi_recorder.h:491
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
Definition: chi_recorder.h:97
sc_core::sc_attribute< bool > enableTrDbgTracing
the attribute to selectively enable/disable transport dbg recording
Definition: chi_recorder.h:109
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
Definition: chi_recorder.h:232
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
Definition: chi_recorder.h:238
chi_trx_recorder(const char *name, bool recording_enabled=true, SCVNS scv_tr_db *tr_db=SCVNS scv_tr_db::get_default_db())
The constructor of the component.
Definition: chi_recorder.h:125
sc_core::sc_attribute< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
Definition: chi_recorder.h:106
the class to hold the information to be recorded on the timed streams
Definition: chi_recorder.h:42
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 CHI.
Definition: chi_tlm.cpp:21
tlm::tlm_fw_transport_if< TYPES > chi_fw_transport_if
alias declaration for the forward interface
Definition: chi_tlm.h:912
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string
a tlm memory manager
Definition: tlm_mm.h:285