scc  2022.4.0
SystemC components library
ace_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/checker_if.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 
40 namespace impl {
43 template <typename TYPES = axi::axi_protocol_types> class ace_recording_payload : public TYPES::tlm_payload_type {
44 public:
45  SCVNS scv_tr_handle parent;
46  uint64_t id{0};
47  bool is_snoop{false};
48  ace_recording_payload& operator=(const typename TYPES::tlm_payload_type& x) {
49  id = (uint64_t)&x;
50  this->set_command(x.get_command());
51  this->set_address(x.get_address());
52  this->set_data_ptr(nullptr);
53  this->set_data_length(x.get_data_length());
54  this->set_response_status(x.get_response_status());
55  this->set_byte_enable_ptr(nullptr);
56  this->set_byte_enable_length(x.get_byte_enable_length());
57  this->set_streaming_width(x.get_streaming_width());
58  return (*this);
59  }
60  explicit ace_recording_payload(tlm::tlm_mm_interface* mm)
61  : TYPES::tlm_payload_type(mm)
62  , parent() {}
63 };
64 
65 template <typename TYPES = axi::axi_protocol_types> struct ace_recording_types {
67  using tlm_phase_type = typename TYPES::tlm_phase_type;
68 };
69 
70 } // namespace impl
79 template <typename TYPES = axi::axi_protocol_types>
80 class ace_recorder : public virtual axi::ace_fw_transport_if<TYPES>, public virtual axi::ace_bw_transport_if<TYPES> {
81 public:
82  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
84 
85  template <unsigned int BUSWIDTH = 32, int N = 1, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
87 
91 
92  SC_HAS_PROCESS(ace_recorder<TYPES>); // NOLINT
93 
95  sc_core::sc_attribute<bool> enableBlTracing;
96 
98  sc_core::sc_attribute<bool> enableNbTracing;
99 
101  sc_core::sc_attribute<bool> enableTimedTracing{"enableTimedTracing", true};
102 
104  sc_core::sc_attribute<bool> enableDmiTracing{"enableDmiTracing", false};
105 
107  sc_core::sc_attribute<bool> enableTrDbgTracing{"enableTrDbgTracing", false};
108 
110  sc_core::sc_attribute<bool> enableProtocolChecker{"enableProtocolChecker", false};
111 
112  sc_core::sc_attribute<unsigned> rd_response_timeout{"rd_response_timeout", 0};
113 
114  sc_core::sc_attribute<unsigned> wr_response_timeout{"wr_response_timeout", 0};
115 
118 
121 
130  ace_recorder(const char* name, unsigned bus_width, bool recording_enabled = true,
131  SCVNS scv_tr_db* tr_db = SCVNS scv_tr_db::get_default_db())
132  : enableBlTracing("enableBlTracing", recording_enabled)
133  , enableNbTracing("enableNbTracing", recording_enabled)
134  , b_timed_peq(this, &ace_recorder::btx_cb)
135  , nb_timed_peq(this, &ace_recorder::nbtx_cb)
136  , m_db(tr_db)
137  , fixed_basename(name) {
138  register_extensions();
139  }
140 
141  virtual ~ace_recorder() override {
142  btx_handle_map.clear();
143  nbtx_req_handle_map.clear();
144  nbtx_last_req_handle_map.clear();
145  nbtx_resp_handle_map.clear();
146  nbtx_last_resp_handle_map.clear();
147  delete b_streamHandle;
148  for(auto* p : b_trHandle)
149  delete p; // NOLINT
150  delete b_streamHandleTimed;
151  for(auto* p : b_trTimedHandle)
152  delete p; // NOLINT
153  delete nb_streamHandle;
154  for(auto* p : nb_trHandle)
155  delete p; // NOLINT
156  delete nb_streamHandleTimed;
157  for(auto* p : nb_trTimedHandle)
158  delete p; // NOLINT
159  delete dmi_streamHandle;
160  delete dmi_trGetHandle;
161  delete dmi_trInvalidateHandle;
162  }
163 
164  // TLM-2.0 interface methods for initiator and target sockets, surrounded with
165  // Tx Recording
175  tlm::tlm_sync_enum nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
176  sc_core::sc_time& delay) override;
186  tlm::tlm_sync_enum nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
187  sc_core::sc_time& delay) override;
196  void b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
205  void b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
213  bool get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) override;
220  void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override;
227  unsigned int transport_dbg(typename TYPES::tlm_payload_type& trans) override;
233  inline bool isRecordingBlockingTxEnabled() const { return m_db && enableBlTracing.value; }
239  inline bool isRecordingNonBlockingTxEnabled() const { return m_db && enableNbTracing.value; }
240 
241 private:
243  tlm_utils::peq_with_cb_and_phase<ace_recorder, recording_types> b_timed_peq;
245  tlm_utils::peq_with_cb_and_phase<ace_recorder, recording_types> nb_timed_peq;
250  void btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase);
255  void nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase);
257  SCVNS scv_tr_db* m_db{nullptr};
259  SCVNS scv_tr_stream* b_streamHandle{nullptr};
261  std::array<SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>*, 3> b_trHandle{{nullptr, nullptr, nullptr}};
263  SCVNS scv_tr_stream* b_streamHandleTimed{nullptr};
266  std::array<SCVNS scv_tr_generator<>*, 3> b_trTimedHandle{{nullptr, nullptr, nullptr}};
267  std::unordered_map<uint64_t, SCVNS scv_tr_handle> btx_handle_map;
268 
269  enum DIR { FW, BW, REQ = FW, RESP = BW, ACK };
271  SCVNS scv_tr_stream* nb_streamHandle{nullptr};
273  SCVNS scv_tr_stream* nb_streamHandleTimed{nullptr};
275  std::array<SCVNS scv_tr_generator<std::string, std::string>*, 2> nb_trHandle{{nullptr, nullptr}};
277  std::array<SCVNS scv_tr_generator<>*, 3> nb_trTimedHandle{{nullptr, nullptr, nullptr}};
278  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_req_handle_map;
279  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_req_handle_map;
280  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_resp_handle_map;
281  std::unordered_map<uint64_t, SCVNS scv_tr_handle> nbtx_last_resp_handle_map;
283  SCVNS scv_tr_stream* dmi_streamHandle{nullptr};
285  SCVNS scv_tr_generator<>* dmi_trGetHandle{nullptr};
286  SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{nullptr};
287 
288 protected:
289  void initialize_streams() {
291  b_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_bl").c_str(), "[TLM][ace][b]", m_db);
292  b_trHandle[tlm::TLM_READ_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
293  "read", *b_streamHandle, "start_delay", "end_delay");
294  b_trHandle[tlm::TLM_WRITE_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
295  "write", *b_streamHandle, "start_delay", "end_delay");
296  b_trHandle[tlm::TLM_IGNORE_COMMAND] = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
297  "ignore", *b_streamHandle, "start_delay", "end_delay");
298  if(enableTimedTracing.value) {
299  b_streamHandleTimed =
300  new SCVNS scv_tr_stream((fixed_basename + "_bl_timed").c_str(), "[TLM][ace][b][timed]", m_db);
301  b_trTimedHandle[tlm::TLM_READ_COMMAND] = new SCVNS scv_tr_generator<>("read", *b_streamHandleTimed);
302  b_trTimedHandle[tlm::TLM_WRITE_COMMAND] = new SCVNS scv_tr_generator<>("write", *b_streamHandleTimed);
303  b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] = new SCVNS scv_tr_generator<>("ignore", *b_streamHandleTimed);
304  }
305  }
306  if(isRecordingNonBlockingTxEnabled() && !nb_streamHandle) {
307  nb_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_nb").c_str(), "[TLM][ace][nb]", m_db);
308  nb_trHandle[FW] = new SCVNS scv_tr_generator<std::string, std::string>("fw", *nb_streamHandle, "tlm_phase",
309  "tlm_phase[return_path]");
310  nb_trHandle[BW] = new SCVNS scv_tr_generator<std::string, std::string>("bw", *nb_streamHandle, "tlm_phase",
311  "tlm_phase[return_path]");
312  if(enableTimedTracing.value) {
313  nb_streamHandleTimed =
314  new SCVNS scv_tr_stream((fixed_basename + "_nb_timed").c_str(), "[TLM][ace][nb][timed]", m_db);
315  nb_trTimedHandle[FW] = new SCVNS scv_tr_generator<>("request", *nb_streamHandleTimed);
316  nb_trTimedHandle[BW] = new SCVNS scv_tr_generator<>("response", *nb_streamHandleTimed);
317  nb_trTimedHandle[ACK] = new SCVNS scv_tr_generator<>("ack", *nb_streamHandleTimed);
318  }
319  }
320  if(m_db && enableDmiTracing.value && !dmi_streamHandle) {
321  dmi_streamHandle = new SCVNS scv_tr_stream((fixed_basename + "_dmi").c_str(), "[TLM][ace][dmi]", m_db);
322  dmi_trGetHandle = new SCVNS scv_tr_generator<>("get", *dmi_streamHandle);
323  dmi_trInvalidateHandle = new SCVNS scv_tr_generator<sc_dt::uint64, sc_dt::uint64>(
324  "invalidate", *dmi_streamHandle, "start_addr", "end_addr");
325  }
326 // if(enableProtocolChecker.value) {
327 // checker=new axi::checker::ace_protocol(fixed_basename, bus_width/8, rd_response_timeout.value, wr_response_timeout.value);
328 // }
329  }
330 
331 private:
332  const std::string fixed_basename;
333  axi::checker::checker_if<TYPES>* checker{nullptr};
334 };
335 
337 // implementations of functions
339 
340 template <typename TYPES>
341 void ace_recorder<TYPES>::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
342  tlm_recording_payload* req{nullptr};
343  if(!isRecordingBlockingTxEnabled()) {
344  get_fw_if()->b_transport(trans, delay);
345  return;
346  }
347  // Get a handle for the new transaction
348  SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
349  /*************************************************************************
350  * do the timed notification
351  *************************************************************************/
352  if(b_streamHandleTimed) {
353  req = mm::get().allocate();
354  req->acquire();
355  (*req) = trans;
356  req->parent = h;
357  req->id = h.get_id();
358  b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
359  }
360 
362  if(ext)
363  ext->recordBeginTx(h, trans);
364  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
365 
366  trans.get_extension(preExt);
367  if(preExt == nullptr) { // we are the first recording this transaction
368  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
369  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
370  } else {
372  }
373  SCVNS scv_tr_handle preTx(preExt->txHandle);
374  preExt->txHandle = h;
375  get_fw_if()->b_transport(trans, delay);
376  trans.get_extension(preExt);
377  if(preExt->get_creator() == this) {
378  // clean-up the extension if this is the original creator
379  if(trans.has_mm())
380  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
381  else
382  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
383  } else {
384  preExt->txHandle = preTx;
385  }
386 
387  tlm::scc::scv::record(h, trans);
389  if(ext)
390  ext->recordEndTx(h, trans);
391  // End the transaction
392  b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
393  // and now the stuff for the timed tx
394  if(b_streamHandleTimed) {
395  b_timed_peq.notify(*req, tlm::END_RESP, delay);
396  }
397 }
398 
399 template <typename TYPES>
400 void ace_recorder<TYPES>::b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
401  tlm_recording_payload* req{nullptr};
402  if(!b_streamHandleTimed) {
403  get_fw_if()->b_transport(trans, delay);
404  return;
405  }
406  // Get a handle for the new transaction
407  SCVNS scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_core::sc_time_stamp());
408  /*************************************************************************
409  * do the timed notification
410  *************************************************************************/
411  if(b_streamHandleTimed) {
412  req = mm::get().allocate();
413  req->acquire();
414  (*req) = trans;
415  req->parent = h;
416  req->id = h.get_id();
417  b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay);
418  }
419 
421  if(ext)
422  ext->recordBeginTx(h, trans);
424 
425  trans.get_extension(preExt);
426  if(preExt == NULL) { // we are the first recording this transaction
427  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
428  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
429  } else {
431  }
432  SCVNS scv_tr_handle preTx(preExt->txHandle);
433  preExt->txHandle = h;
434  get_bw_if()->b_snoop(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  tlm::scc::scv::record(h, trans);
448  if(ext)
449  ext->recordEndTx(h, trans);
450  // End the transaction
451  b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_core::sc_time_stamp());
452  // and now the stuff for the timed tx
453  if(b_streamHandleTimed) {
454  b_timed_peq.notify(*req, tlm::END_RESP, delay);
455  }
456 }
457 
458 template <typename TYPES>
459 void ace_recorder<TYPES>::btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
460  SCVNS scv_tr_handle h;
461  // Now process outstanding recordings
462  switch(phase) {
463  case tlm::BEGIN_REQ: {
464  h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction();
465  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
466  btx_handle_map[rec_parts.id] = h;
467  } break;
468  case tlm::END_RESP: {
469  auto it = btx_handle_map.find(rec_parts.id);
470  sc_assert(it != btx_handle_map.end());
471  h = it->second;
472  btx_handle_map.erase(it);
473  tlm::scc::scv::record(h, rec_parts);
474  h.end_transaction();
475  rec_parts.release();
476  } break;
477  default:
478  sc_assert(!"phase not supported!");
479  }
480  return;
481 }
482 
483 template <typename TYPES>
484 tlm::tlm_sync_enum ace_recorder<TYPES>::nb_transport_fw(typename TYPES::tlm_payload_type& trans,
485  typename TYPES::tlm_phase_type& phase,
486  sc_core::sc_time& delay) {
487  if(!isRecordingNonBlockingTxEnabled()){
488  if(checker){
489  checker->fw_pre(trans, phase);
490  tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
491  checker->fw_post(trans, phase, status);
492  return status;
493  } else
494  return get_fw_if()->nb_transport_fw(trans, phase, delay);
495  }
496  /*************************************************************************
497  * prepare recording
498  *************************************************************************/
499  // Get a handle for the new transaction
500  SCVNS scv_tr_handle h = nb_trHandle[FW]->begin_transaction(phase.get_name());
501  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
502  trans.get_extension(preExt);
503  if((phase == axi::BEGIN_PARTIAL_REQ || phase == tlm::BEGIN_REQ) &&
504  preExt == nullptr) { // we are the first recording this transaction
505  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
506  if(trans.has_mm()) trans.set_auto_extension(preExt); else 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 = (phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP);
528  nb_timed_peq.notify(*req, phase, delay);
529  }
530  /*************************************************************************
531  * do the access
532  *************************************************************************/
533  if(checker) checker->fw_pre(trans, phase);
534  tlm::tlm_sync_enum status = get_fw_if()->nb_transport_fw(trans, phase, delay);
535  if(checker) checker->fw_post(trans, phase, status);
536  /*************************************************************************
537  * handle recording
538  *************************************************************************/
539  tlm::scc::scv::record(h, status);
540  h.record_attribute("delay[return_path]", delay.to_string());
541  tlm::scc::scv::record(h, trans);
543  if(ext)
544  ext->recordEndTx(h, trans);
545  // get the extension and free the memory if it was mine
546  if(status == tlm::TLM_COMPLETED || (phase == axi::ACK)) {
547  // the transaction is finished
548  trans.get_extension(preExt);
549  if(preExt && preExt->get_creator() == this) {
550  // clean-up the extension if this is the original creator
551  if(trans.has_mm())
552  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
553  else
554  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
555  }
556  /*************************************************************************
557  * do the timed notification if req. finished here
558  *************************************************************************/
559  if(nb_streamHandleTimed) {
560  tlm_recording_payload* req = mm::get().allocate();
561  req->acquire();
562  (*req) = trans;
563  req->parent = h;
564  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
565  delay);
566  }
567  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
568  tlm_recording_payload* req = mm::get().allocate();
569  req->acquire();
570  (*req) = trans;
571  req->parent = h;
572  nb_timed_peq.notify(*req, phase, delay);
573  }
574  // End the transaction
575  nb_trHandle[FW]->end_transaction(h, phase.get_name());
576  return status;
577 }
578 
579 template <typename TYPES>
580 tlm::tlm_sync_enum ace_recorder<TYPES>::nb_transport_bw(typename TYPES::tlm_payload_type& trans,
581  typename TYPES::tlm_phase_type& phase,
582  sc_core::sc_time& delay) {
583  if(!isRecordingNonBlockingTxEnabled()){
584  if(checker) {
585  checker->bw_pre(trans, phase);
586  tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
587  checker->bw_post(trans, phase, status);
588  return status;
589  } else
590  return get_bw_if()->nb_transport_bw(trans, phase, delay);
591  }
592  /*************************************************************************
593  * prepare recording
594  *************************************************************************/
595  // Get a handle for the new transaction
596  SCVNS scv_tr_handle h = nb_trHandle[BW]->begin_transaction(phase.get_name());
597  tlm::scc::scv::tlm_recording_extension* preExt = nullptr;
598  trans.get_extension(preExt);
599  if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
600  preExt = new tlm::scc::scv::tlm_recording_extension(h, this);
601  if(trans.has_mm()) trans.set_auto_extension(preExt); else trans.set_extension(preExt);
602  } else if(preExt != nullptr) {
603  // link handle if we have a predecessor
605  } else {
606  sc_assert(preExt != nullptr && "ERROR on backward path in phase other than tlm::BEGIN_REQ");
607  }
608  // and set the extension handle to this transaction
609  preExt->txHandle = h;
610  h.record_attribute("delay", delay.to_string());
612  if(ext)
613  ext->recordBeginTx(h, trans);
614  /*************************************************************************
615  * do the timed notification
616  *************************************************************************/
617  if(nb_streamHandleTimed) {
618  tlm_recording_payload* req = mm::get().allocate();
619  req->acquire();
620  (*req) = trans;
621  req->parent = h;
622  req->is_snoop = phase == tlm::BEGIN_REQ;
623  nb_timed_peq.notify(*req, phase, delay);
624  }
625  /*************************************************************************
626  * do the access
627  *************************************************************************/
628  if(checker) checker->bw_pre(trans, phase);
629  tlm::tlm_sync_enum status = get_bw_if()->nb_transport_bw(trans, phase, delay);
630  if(checker) checker->bw_post(trans, phase, status);
631  /*************************************************************************
632  * handle recording
633  *************************************************************************/
634  tlm::scc::scv::record(h, status);
635  h.record_attribute("delay[return_path]", delay.to_string());
636  tlm::scc::scv::record(h, trans);
638  if(ext)
639  ext->recordEndTx(h, trans);
640  // get the extension and free the memory if it was mine
641  if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == axi::ACK)) {
642  // the transaction is finished
643  trans.get_extension(preExt);
644  if(preExt->get_creator() == this) {
645  // clean-up the extension if this is the original creator
646  if(trans.has_mm())
647  trans.set_auto_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
648  else
649  delete trans.set_extension(static_cast<tlm::scc::scv::tlm_recording_extension*>(nullptr));
650  }
651  /*************************************************************************
652  * do the timed notification if req. finished here
653  *************************************************************************/
654  if(nb_streamHandleTimed) {
655  tlm_recording_payload* req = mm::get().allocate();
656  req->acquire();
657  (*req) = trans;
658  req->parent = h;
659  nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
660  delay);
661  }
662  } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
663  tlm_recording_payload* req = mm::get().allocate();
664  req->acquire();
665  (*req) = trans;
666  req->parent = h;
667  nb_timed_peq.notify(*req, phase, delay);
668  }
669  // End the transaction
670  nb_trHandle[BW]->end_transaction(h, phase.get_name());
671  return status;
672 }
673 
674 template <typename TYPES>
675 void ace_recorder<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) {
676  SCVNS scv_tr_handle h;
677  // Now process outstanding recordings
678  if(phase == tlm::BEGIN_REQ || phase == axi::BEGIN_PARTIAL_REQ) {
679  h = nb_trTimedHandle[REQ]->begin_transaction();
680  tlm::scc::scv::record(h, rec_parts);
681  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
682  nbtx_req_handle_map[rec_parts.id] = h;
683  } else if(phase == tlm::END_REQ || phase == axi::END_PARTIAL_REQ) {
684  auto it = nbtx_req_handle_map.find(rec_parts.id);
685  sc_assert(it != nbtx_req_handle_map.end());
686  h = it->second;
687  nbtx_req_handle_map.erase(it);
688  h.end_transaction();
689  nbtx_last_req_handle_map[rec_parts.id] = h;
690  } else if(phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP) {
691  auto it = nbtx_req_handle_map.find(rec_parts.id);
692  if(it != nbtx_req_handle_map.end()) {
693  h = it->second;
694  nbtx_req_handle_map.erase(it);
695  h.end_transaction();
696  nbtx_last_req_handle_map[rec_parts.id] = h;
697  }
698  h = nb_trTimedHandle[RESP]->begin_transaction();
699  tlm::scc::scv::record(h, rec_parts);
700  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
701  nbtx_resp_handle_map[rec_parts.id] = h;
702  it = nbtx_last_req_handle_map.find(rec_parts.id);
703  if(it != nbtx_last_req_handle_map.end()) {
704  SCVNS scv_tr_handle& pred = it->second;
706  nbtx_last_req_handle_map.erase(it);
707  } else {
708  it = nbtx_last_resp_handle_map.find(rec_parts.id);
709  if(it != nbtx_last_resp_handle_map.end()) {
710  SCVNS scv_tr_handle& pred = it->second;
712  nbtx_last_resp_handle_map.erase(it);
713  }
714  }
715  } else if(phase == tlm::END_RESP || phase == axi::END_PARTIAL_RESP) {
716  auto it = nbtx_resp_handle_map.find(rec_parts.id);
717  if(it != nbtx_resp_handle_map.end()) {
718  h = it->second;
719  nbtx_resp_handle_map.erase(it);
720  h.end_transaction();
721  if(phase == axi::END_PARTIAL_RESP) {
722  nbtx_last_resp_handle_map[rec_parts.id] = h;
723  }
724  }
725  } else if(phase == axi::ACK) {
726  h = nb_trTimedHandle[ACK]->begin_transaction();
727  tlm::scc::scv::record(h, rec_parts);
728  h.add_relation(tlm::scc::scv::rel_str(tlm::scc::scv::PARENT_CHILD), rec_parts.parent);
729  h.end_transaction();
730  } else
731  sc_assert(!"phase not supported!");
732  rec_parts.release();
733  return;
734 }
735 
736 template <typename TYPES>
737 bool ace_recorder<TYPES>::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) {
738  if(!(m_db && enableDmiTracing.value))
739  return get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
740  else if(!dmi_streamHandle)
741  initialize_streams();
742  SCVNS scv_tr_handle h = dmi_trGetHandle->begin_transaction();
743  bool status = get_fw_if()->get_direct_mem_ptr(trans, dmi_data);
744  tlm::scc::scv::record(h, trans);
745  tlm::scc::scv::record(h, dmi_data);
746  h.end_transaction();
747  return status;
748 }
755 template <typename TYPES>
756 void ace_recorder<TYPES>::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) {
757  if(!(m_db && enableDmiTracing.value)) {
758  get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
759  return;
760  } else if(!dmi_streamHandle)
761  initialize_streams();
762  SCVNS scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr);
763  get_bw_if()->invalidate_direct_mem_ptr(start_addr, end_addr);
764  dmi_trInvalidateHandle->end_transaction(h, end_addr);
765  return;
766 }
773 template <typename TYPES> unsigned int ace_recorder<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) {
774  unsigned int count = get_fw_if()->transport_dbg(trans);
775  return count;
776 }
777 } // namespace scv
778 } // namespace axi
The TLM2 transaction recorder.
Definition: ace_recorder.h:80
sc_core::sc_attribute< bool > enableTrDbgTracing
the attribute to selectively enable/disable transport dbg recording
Definition: ace_recorder.h:107
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: ace_recorder.h:580
ace_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: ace_recorder.h:130
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
Definition: ace_recorder.h:756
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: ace_recorder.h:484
sc_core::sc_attribute< bool > enableProtocolChecker
the attribute to enable/disable protocol checking
Definition: ace_recorder.h:110
void b_snoop(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking snoop function.
Definition: ace_recorder.h:400
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
Definition: ace_recorder.h:341
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
Definition: ace_recorder.h:233
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
Definition: ace_recorder.h:737
virtual axi::ace_bw_transport_if< TYPES > * get_bw_if()=0
the port where bw accesses are forwarded to
sc_core::sc_attribute< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
Definition: ace_recorder.h:98
sc_core::sc_attribute< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
Definition: ace_recorder.h:101
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
Definition: ace_recorder.h:773
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
Definition: ace_recorder.h:239
virtual axi::ace_fw_transport_if< TYPES > * get_fw_if()=0
the port where fw accesses are forwarded to
sc_core::sc_attribute< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
Definition: ace_recorder.h:104
sc_core::sc_attribute< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
Definition: ace_recorder.h:95
the class to hold the information to be recorded on the timed streams
Definition: ace_recorder.h:43
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.
a tlm memory manager
Definition: tlm_mm.h:161
TLM2.0 components modeling AHB.
Definition: axi_initiator.h:30
tlm::tlm_fw_transport_if< TYPES > ace_fw_transport_if
alias declaration for the ACE forward interface
Definition: axi_tlm.h:920
const char * rel_str(tx_rel rel)
cast the tx_rel enum to a string