scc  2024.06
SystemC components library
axi_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 <axi/checker/axi_protocol.h>
24 #include <array>
25 #include <axi/axi_tlm.h>
26 #include <regex>
27 #include <string>
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>
32 #include <vector>
33 
35 namespace axi {
36 namespace scv {
37 
38 bool register_extensions();
39 
48 template <typename TYPES = axi::axi_protocol_types>
49 class axi_recorder : public virtual axi::axi_fw_transport_if<TYPES>, public virtual axi::axi_bw_transport_if<TYPES> {
50 public:
51  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
53 
54  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
56 
60 
61  SC_HAS_PROCESS(axi_recorder<TYPES>); // NOLINT
62 
64  sc_core::sc_attribute<bool> enableBlTracing;
65 
67  sc_core::sc_attribute<bool> enableNbTracing;
68 
70  sc_core::sc_attribute<bool> enableTimedTracing{"enableTimedTracing", true};
71 
73  sc_core::sc_attribute<bool> enableDmiTracing{"enableDmiTracing", false};
74 
76  sc_core::sc_attribute<bool> enableTrDbgTracing{"enableTrDbgTracing", false};
77 
79  sc_core::sc_attribute<bool> enableProtocolChecker{"enableProtocolChecker", false};
80 
81  sc_core::sc_attribute<unsigned> rd_response_timeout{"rd_response_timeout", 0};
82 
83  sc_core::sc_attribute<unsigned> wr_response_timeout{"wr_response_timeout", 0};
84 
86  virtual tlm::tlm_fw_transport_if<TYPES>* get_fw_if() = 0;
87 
89  virtual tlm::tlm_bw_transport_if<TYPES>* get_bw_if() = 0;
90 
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())
101  : enableBlTracing("enableBlTracing", recording_enabled)
102  , enableNbTracing("enableNbTracing", recording_enabled)
103  , b_timed_peq(this, &axi_recorder::btx_cb)
104  , nb_timed_peq(this, &axi_recorder::nbtx_cb)
105  , bus_width(bus_width)
106  , m_db(tr_db)
107  , fixed_basename(name) {
108  register_extensions();
109  }
110 
111  virtual ~axi_recorder() override {
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)
119  delete p; // NOLINT
120  delete b_streamHandleTimed;
121  for(auto* p : b_trTimedHandle)
122  delete p; // NOLINT
123  delete nb_streamHandle;
124  for(auto* p : nb_trHandle)
125  delete p; // NOLINT
126  delete nb_streamHandleTimed;
127  for(auto* p : nb_trTimedHandle)
128  delete p; // NOLINT
129  delete dmi_streamHandle;
130  delete dmi_trGetHandle;
131  delete dmi_trInvalidateHandle;
132  delete checker;
133  }
134 
135  // TLM-2.0 interface methods for initiator and target sockets, surrounded with
136  // Tx Recording
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;
175  bool get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) override;
182  void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override;
189  unsigned int transport_dbg(typename TYPES::tlm_payload_type& trans) override;
195  inline bool isRecordingBlockingTxEnabled() const { return m_db && enableBlTracing.value; }
201  inline bool isRecordingNonBlockingTxEnabled() const { return m_db && enableNbTracing.value; }
202 
203 private:
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;
231 
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};
250 
251 protected:
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");
261  if(enableTimedTracing.value) {
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);
267  }
268  }
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]");
275  if(enableTimedTracing.value) {
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);
280  }
281  }
282  if(m_db && enableDmiTracing.value && !dmi_streamHandle) {
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");
287  }
288  if(enableProtocolChecker.value) {
289  checker=new axi::checker::axi_protocol(fixed_basename, bus_width/8, rd_response_timeout.value, wr_response_timeout.value);
290  }
291  }
292 
293 private:
294  const std::string fixed_basename;
295  axi::checker::checker_if<TYPES>* checker{nullptr};
296  inline std::string phase2string(const tlm::tlm_phase& p) {
297  std::stringstream ss;
298  ss << p;
299  return ss.str();
300  }
301 };
302 
304 // implementations of functions
306 
307 template <typename TYPES>
308 void axi_recorder<TYPES>::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
309  tlm_recording_payload* req{nullptr};
310  if(!isRecordingBlockingTxEnabled()) {
311  get_fw_if()->b_transport(trans, delay);
312  return;
313  }
314  // Get a handle for the new transaction
315  SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
316  /*************************************************************************
317  * do the timed notification
318  *************************************************************************/
319  if(b_streamHandleTimed) {
320  req = mm::get().allocate();
321  req->acquire();
322  (*req) = trans;
323  req->parent = h;
324  req->id = h.get_id();
325  b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
326  }
327 
329  if(ext)
330  ext->recordBeginTx(h, trans);
331  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
332 
333  trans.get_extension(preExt);
334  if(preExt == nullptr) { // we are the first recording this transaction
335  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
336  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
337  } else {
339  }
340  SCVNS scv_tr_handle preTx(preExt->txHandle);
341  preExt->txHandle = h;
342  get_fw_if()->b_transport(trans, delay);
343  trans.get_extension(preExt);
344  if(preExt->get_creator() == this) {
345  // clean-up the extension if this is the original creator
346  if(trans.has_mm())
347  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
348  else
349  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
350  } else {
351  preExt->txHandle = preTx;
352  }
353 
354  tlm::scc::scv::record(h, trans);
356  if(ext)
357  ext->recordEndTx(h, trans);
358  // End the transaction
359  b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
360  // and now the stuff for the timed tx
361  if(b_streamHandleTimed) {
362  b_timed_peq.notify(*req, tlm::END_RESP, delay);
363  }
364 }
365 
366 template <typename TYPES>
367 void axi_recorder<TYPES>::btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
368  SCVNS scv_tr_handle h;
369  // Now process outstanding recordings
370  switch(phase) {
371  case tlm::BEGIN_REQ: {
372  h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
373  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
374  btx_handle_map[rec_parts.id] = h;
375  } break;
376  case tlm::END_RESP: {
377  auto it = btx_handle_map.find(rec_parts.id);
378  sc_assert(it != btx_handle_map.end());
379  h = it->second;
380  btx_handle_map.erase(it);
381  tlm::scc::scv::record(h, rec_parts);
382  h.end_transaction();
383  rec_parts.release();
384  } break;
385  default:
386  sc_assert(!"phase not supported!");
387  }
388  return;
389 }
390 
391 template <typename TYPES>
392 tlm::tlm_sync_enum axi_recorder<TYPES>::nb_transport_fw(typename TYPES::tlm_payload_type& trans,
393  typename TYPES::tlm_phase_type& phase,
394  sc_core::sc_time& delay) {
395  if(!isRecordingNonBlockingTxEnabled()){
396  if(checker){
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);
400  return status;
401  } else
402  return get_fw_if()->nb_transport_fw(trans, phase, delay);
403  }
404  /*************************************************************************
405  * prepare recording
406  *************************************************************************/
407  // Get a handle for the new transaction
408  SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase2string(phase));
409  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
410  trans.get_extension(preExt);
411  if((phase == axi::BEGIN_PARTIAL_REQ || phase == tlm::BEGIN_REQ) &&
412  preExt == nullptr) { // we are the first recording this transaction
413  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
414  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
415  } else if(preExt != nullptr) {
416  // link handle if we have a predecessor
418  } else {
419  sc_assert(preExt != nullptr && "ERROR on forward path in phase other than tlm::BEGIN_REQ");
420  }
421  // update the extension
422  preExt->txHandle = h;
423  h.record_attribute("delay", delay.to_string());
425  if(ext)
426  ext->recordBeginTx(h, trans);
427  /*************************************************************************
428  * do the timed notification
429  *************************************************************************/
430  if(nb_streamHandleTimed) {
431  tlm_recording_payload* req = mm::get().allocate();
432  req->acquire();
433  (*req) = trans;
434  req->parent = h;
435  nb_timed_peq.notify(*req, phase, delay);
436  }
437  /*************************************************************************
438  * do the access
439  *************************************************************************/
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);
443  /*************************************************************************
444  * handle recording
445  *************************************************************************/
446  tlm::scc::scv::record(h, status);
447  h.record_attribute("delay[return_path]", delay.to_string());
448  tlm::scc::scv::record(h, trans);
450  if(ext)
451  ext->recordEndTx(h, trans);
452  // get the extension and free the memory if it was mine
453  if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) {
454  // the transaction is finished
455  trans.get_extension(preExt);
456  if(preExt && preExt->get_creator() == this) {
457  // clean-up the extension if this is the original creator
458  if(trans.has_mm())
459  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
460  else
461  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
462  }
463  /*************************************************************************
464  * do the timed notification if req. finished here
465  *************************************************************************/
466  if(nb_streamHandleTimed) {
467  tlm_recording_payload* req = mm::get().allocate();
468  req->acquire();
469  (*req) = trans;
470  req->parent = h;
471  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
472  delay);
473  }
474  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
475  tlm_recording_payload* req = mm::get().allocate();
476  req->acquire();
477  (*req) = trans;
478  req->parent = h;
479  nb_timed_peq.notify(*req, phase, delay);
480  }
481  // End the transaction
482  nb_trHandle[FW]->end_transaction(h, phase2string(phase));
483  return status;
484 }
485 
486 template <typename TYPES>
487 tlm::tlm_sync_enum axi_recorder<TYPES>::nb_transport_bw(typename TYPES::tlm_payload_type& trans,
488  typename TYPES::tlm_phase_type& phase,
489  sc_core::sc_time& delay) {
490  if(!isRecordingNonBlockingTxEnabled()){
491  if(checker) {
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);
495  return status;
496  } else
497  return get_bw_if()->nb_transport_bw(trans, phase, delay);
498  }
499  /*************************************************************************
500  * prepare recording
501  *************************************************************************/
502  // Get a handle for the new transaction
503  SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase2string(phase));
504  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
505  trans.get_extension(preExt);
506  if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
507  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
508  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
509  } else if(preExt != nullptr) {
510  // link handle if we have a predecessor
512  } else {
513  sc_assert(preExt != nullptr && "ERROR on backward path in phase other than tlm::BEGIN_REQ");
514  }
515  // and set the extension handle to this transaction
516  preExt->txHandle = h;
517  h.record_attribute("delay", delay.to_string());
519  if(ext)
520  ext->recordBeginTx(h, trans);
521  /*************************************************************************
522  * do the timed notification
523  *************************************************************************/
524  if(nb_streamHandleTimed) {
525  tlm_recording_payload* req = mm::get().allocate();
526  req->acquire();
527  (*req) = trans;
528  req->parent = h;
529  nb_timed_peq.notify(*req, phase, delay);
530  }
531  /*************************************************************************
532  * do the access
533  *************************************************************************/
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);
537  /*************************************************************************
538  * handle recording
539  *************************************************************************/
540  tlm::scc::scv::record(h, status);
541  h.record_attribute("delay[return_path]", delay.to_string());
542  tlm::scc::scv::record(h, trans);
544  if(ext)
545  ext->recordEndTx(h, trans);
546  // get the extension and free the memory if it was mine
547  if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
548  // the transaction is finished
549  trans.get_extension(preExt);
550  if(preExt->get_creator() == this) {
551  // clean-up the extension if this is the original creator
552  if(trans.has_mm())
553  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
554  else
555  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
556  }
557  /*************************************************************************
558  * do the timed notification if req. finished here
559  *************************************************************************/
560  if(nb_streamHandleTimed) {
561  tlm_recording_payload* req = mm::get().allocate();
562  req->acquire();
563  (*req) = trans;
564  req->parent = h;
565  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
566  delay);
567  }
568  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
569  tlm_recording_payload* req = mm::get().allocate();
570  req->acquire();
571  (*req) = trans;
572  req->parent = h;
573  nb_timed_peq.notify(*req, phase, delay);
574  }
575  // End the transaction
576  nb_trHandle[BW]->end_transaction(h, phase2string(phase));
577  return status;
578 }
579 
580 template <typename TYPES>
581 void axi_recorder<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
582  SCVNS scv_tr_handle h;
583  // Now process outstanding recordings
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);
587  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
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()) {
592  h = it->second;
593  nbtx_req_handle_map.erase(it);
594  h.end_transaction();
595  nbtx_last_req_handle_map[rec_parts.id] = h;
596  }
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()) {
600  h = it->second;
601  nbtx_req_handle_map.erase(it);
602  h.end_transaction();
603  nbtx_last_req_handle_map[rec_parts.id] = h;
604  }
605  h = nb_trTimedHandle[RESP]->begin_transaction();
606  tlm::scc::scv::record(h, rec_parts);
607  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
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);
614  } else {
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);
620  }
621  }
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()) {
625  h = it->second;
626  nbtx_resp_handle_map.erase(it);
627  h.end_transaction();
628  if(phase == axi::END_PARTIAL_RESP) {
629  nbtx_last_resp_handle_map[rec_parts.id] = h;
630  }
631  }
632  } else
633  sc_assert(!"phase not supported!");
634  rec_parts.release();
635  return;
636 }
637 
638 template <typename TYPES>
639 bool axi_recorder<TYPES>::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) {
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);
648  h.end_transaction();
649  return status;
650 }
657 template <typename TYPES>
658 void axi_recorder<TYPES>::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) {
659  if(!(m_db && enableDmiTracing.value)) {
660  get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
661  return;
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);
667  return;
668 }
675 template <typename TYPES> unsigned int axi_recorder<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) {
676  unsigned int count = get_fw_if()->transport_dbg(trans);
677  return count;
678 }
679 } // namespace scv
680 } // namespace axi
The TLM2 transaction recorder.
Definition: axi_recorder.h:49
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
Definition: axi_recorder.h:64
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
Definition: axi_recorder.h:201
sc_core::sc_attribute< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
Definition: axi_recorder.h:73
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
Definition: axi_recorder.h:308
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: axi_recorder.h:392
sc_core::sc_attribute< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
Definition: axi_recorder.h:67
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
Definition: axi_recorder.h:658
sc_core::sc_attribute< bool > enableProtocolChecker
the attribute to enable/disable protocol checking
Definition: axi_recorder.h:79
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
Definition: axi_recorder.h:639
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
Definition: axi_recorder.h:195
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
Definition: axi_recorder.h:70
sc_core::sc_attribute< bool > enableTrDbgTracing
the attribute to selectively enable/disable transport dbg recording
Definition: axi_recorder.h:76
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.
Definition: axi_recorder.h:99
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
Definition: axi_recorder.h:675
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: axi_recorder.h:487
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.
Definition: axi_initiator.h:30
tlm::tlm_bw_transport_if< TYPES > axi_bw_transport_if
alias declaration for the backward interface:
Definition: axi_tlm.h:956
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
Definition: axi_tlm.h:954
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string
a tlm memory manager
Definition: tlm_mm.h:285