scc 2026.07
SystemC components library
chi_lwtr.h
1/*
2 * Copyright 2023 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 <cci_configuration>
25#include <chi/chi_tlm.h>
26#include <regex>
27#include <scc/peq.h>
28#include <string>
29#include <tlm/scc/lwtr/tlm2_lwtr.h>
30#include <tlm/scc/tlm_mm.h>
31#include <unordered_map>
32#include <vector>
33
35namespace chi {
36namespace lwtr {
37namespace {
38inline bool has_credit(chi::chi_protocol_types::tlm_payload_type& trans) {
39 return trans.get_extension<chi::chi_credit_extension<chi::credit_type_e::REQ>>() ||
40 trans.get_extension<chi::chi_credit_extension<chi::credit_type_e::RESP>>() ||
41 trans.get_extension<chi::chi_credit_extension<chi::credit_type_e::DATA>>();
42}
43} // namespace
44
45using tx_db = ::lwtr::tx_db;
46using tx_fiber = ::lwtr::tx_fiber;
47template <typename BEGIN = ::lwtr::no_data, typename END = ::lwtr::no_data> using tx_generator = ::lwtr::tx_generator<BEGIN, END>;
48using tx_handle = ::lwtr::tx_handle;
49using mm = tlm::scc::tlm_mm<>;
50using namespace tlm::scc::lwtr;
51
52struct nb_chi_rec_entry : public nb_rec_entry {
53 const bool snoop;
54 const bool credit;
55 nb_chi_rec_entry(tlm::scc::tlm_gp_shared_ptr tr, tlm::tlm_phase const ph, uintptr_t const id, tx_handle parent, bool snoop = false,
56 bool credit = false)
57 : nb_rec_entry{tr, ph, id, parent}
58 , snoop(snoop)
59 , credit(credit) {}
60};
61extern bool registered;
62
71template <typename TYPES = chi::chi_protocol_types>
72class chi_lwtr : public virtual chi::chi_fw_transport_if<TYPES>, public virtual chi::chi_bw_transport_if<TYPES> {
73public:
75 cci::cci_param<bool> enableBlTracing;
76
78 cci::cci_param<bool> enableNbTracing;
79
81 cci::cci_param<bool> enableTimedTracing{"enableTimedTracing", true};
82
84 cci::cci_param<bool> enableDmiTracing{"enableDmiTracing", false};
85
94 chi_lwtr(char const* full_name, unsigned bus_width, bool recording_enabled = true, tx_db* tr_db = tx_db::get_default_db())
95 : enableBlTracing("enableBlTracing", recording_enabled)
96 , enableNbTracing("enableNbTracing", recording_enabled)
97 , full_name(full_name)
98 , nb_timed_peq()
99 , bus_width(bus_width)
100 , m_db(tr_db) {
101 sc_core::sc_spawn_options opts;
102 opts.spawn_method();
103 opts.dont_initialize();
104 opts.set_sensitivity(&nb_timed_peq.event());
105 sc_core::sc_spawn([this]() { nbtx_cb(); }, nullptr, &opts);
106 initialize_streams();
107 }
108
109 virtual ~chi_lwtr() override {
110 nbtx_req_handle_map.clear();
111 nbtx_last_req_handle_map.clear();
112 nbtx_resp_handle_map.clear();
113 nbtx_last_resp_handle_map.clear();
114 nbtx_data_handle_map.clear();
115 nbtx_last_data_handle_map.clear();
116 nbtx_ack_handle_map.clear();
117 delete dmi_trInvalidateHandle;
118 delete dmi_trGetHandle;
119 delete dmi_streamHandle;
120 for(auto* p : nb_trTimedHandle)
121 delete p; // NOLINT
122 delete nb_streamHandleTimed;
123 for(auto* p : nb_trHandle)
124 delete p; // NOLINT
125 delete nb_streamHandle;
126 for(auto* p : b_trTimedHandle)
127 delete p; // NOLINT
128 delete b_streamHandleTimed;
129 for(auto* p : b_trHandle)
130 delete p; // NOLINT
131 delete b_streamHandle;
132 }
133
134 // TLM-2.0 interface methods for initiator and target sockets, surrounded with
135 // Tx Recording
145 tlm::tlm_sync_enum nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
146 sc_core::sc_time& delay) override;
156 tlm::tlm_sync_enum nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
157 sc_core::sc_time& delay) override;
166 void b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
175 void b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) override;
183 bool get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) override;
190 void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override;
197 unsigned int transport_dbg(typename TYPES::tlm_payload_type& trans) override;
203 inline bool isRecordingBlockingTxEnabled() const { return m_db && enableBlTracing.get_value(); }
209 inline bool isRecordingNonBlockingTxEnabled() const { return m_db && enableNbTracing.get_value(); }
210
211protected:
213 sc_core::sc_port<chi::chi_fw_transport_if<TYPES>> fw_port{"fw_port"};
214
216 sc_core::sc_port<chi::chi_bw_transport_if<TYPES>> bw_port{"bw_port"};
217
218private:
219 std::string const full_name;
221 ::scc::peq<nb_chi_rec_entry> nb_timed_peq;
226 void nbtx_cb();
227 const unsigned bus_width{0};
229 tx_db* m_db{nullptr};
231 ::lwtr::tx_relation_handle pred_succ_hndl{0}, par_chld_hndl{0};
233 tx_fiber* b_streamHandle{nullptr};
235 std::array<tx_generator<sc_core::sc_time, sc_core::sc_time>*, 3> b_trHandle{{nullptr, nullptr, nullptr}};
237 tx_fiber* b_streamHandleTimed{nullptr};
240 std::array<tx_generator<>*, 3> b_trTimedHandle{{nullptr, nullptr, nullptr}};
241
242 enum DIR { FW, BW, DATA, ACK, CREDIT, REQ = FW, RESP = BW };
243 enum TYPE { READ = tlm::TLM_READ_COMMAND, WRITE = tlm::TLM_WRITE_COMMAND, OTHER = tlm::TLM_IGNORE_COMMAND, SNOOP, NO_OF_TYPES };
245 tx_fiber* nb_streamHandle{nullptr};
247 tx_fiber* nb_streamHandleTimed{nullptr};
249 std::array<tx_generator<std::string, std::string>*, 5> nb_trHandle{{nullptr, nullptr, nullptr, nullptr, nullptr}};
251 std::array<tx_generator<>*, 5> nb_trTimedHandle{{nullptr, nullptr}};
252 std::unordered_map<uint64_t, tx_handle> nbtx_req_handle_map;
253 std::unordered_map<uint64_t, tx_handle> nbtx_last_req_handle_map;
254 std::unordered_map<uint64_t, tx_handle> nbtx_resp_handle_map;
255 std::unordered_map<uint64_t, tx_handle> nbtx_last_resp_handle_map;
256 std::unordered_map<uint64_t, tx_handle> nbtx_data_handle_map;
257 std::unordered_map<uint64_t, tx_handle> nbtx_last_data_handle_map;
258 std::unordered_map<uint64_t, tx_handle> nbtx_ack_handle_map;
260 tx_fiber* dmi_streamHandle{nullptr};
262 tx_generator<>* dmi_trGetHandle{nullptr};
263 tx_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{nullptr};
264
265protected:
266 void initialize_streams() {
267 if(m_db) {
268 pred_succ_hndl = m_db->create_relation("PREDECESSOR_SUCCESSOR");
269 par_chld_hndl = m_db->create_relation("PARENT_CHILD");
270 }
271 if(isRecordingBlockingTxEnabled() && !b_streamHandle) {
272 b_streamHandle = new tx_fiber((full_name + "_bl").c_str(), "[TLM][chi][b]", m_db);
273 b_trHandle[tlm::TLM_READ_COMMAND] =
274 new tx_generator<sc_core::sc_time, sc_core::sc_time>("read", *b_streamHandle, "start_delay", "end_delay");
275 b_trHandle[tlm::TLM_WRITE_COMMAND] =
276 new tx_generator<sc_core::sc_time, sc_core::sc_time>("write", *b_streamHandle, "start_delay", "end_delay");
277 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
278 new tx_generator<sc_core::sc_time, sc_core::sc_time>("ignore", *b_streamHandle, "start_delay", "end_delay");
279 if(enableTimedTracing.get_value()) {
280 b_streamHandleTimed = new tx_fiber((full_name + "_bl_timed").c_str(), "[TLM][chi][b][timed]", m_db);
281 b_trTimedHandle[tlm::TLM_READ_COMMAND] = new tx_generator<>("read", *b_streamHandleTimed);
282 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] = new tx_generator<>("write", *b_streamHandleTimed);
283 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] = new tx_generator<>("ignore", *b_streamHandleTimed);
284 }
285 }
286 if(isRecordingNonBlockingTxEnabled() && !nb_streamHandle) {
287 nb_streamHandle = new tx_fiber((full_name + "_nb").c_str(), "[TLM][chi][nb]", m_db);
288 nb_trHandle[FW] = new tx_generator<std::string, std::string>("fw", *nb_streamHandle, "tlm_phase", "tlm_phase[return_path]");
289 nb_trHandle[BW] = new tx_generator<std::string, std::string>("bw", *nb_streamHandle, "tlm_phase", "tlm_phase[return_path]");
290 if(enableTimedTracing.get_value()) {
291 nb_streamHandleTimed = new tx_fiber((full_name + "_nb_timed").c_str(), "[TLM][chi][nb][timed]", m_db);
292 nb_trTimedHandle[REQ] = new tx_generator<>("request", *nb_streamHandleTimed);
293 nb_trTimedHandle[RESP] = new tx_generator<>("response", *nb_streamHandleTimed);
294 nb_trTimedHandle[DATA] = new tx_generator<>("data", *nb_streamHandleTimed);
295 nb_trTimedHandle[ACK] = new tx_generator<>("ack", *nb_streamHandleTimed);
296 nb_trTimedHandle[CREDIT] = new tx_generator<>("link", *nb_streamHandleTimed);
297 }
298 }
299 if(m_db && enableDmiTracing.get_value() && !dmi_streamHandle) {
300 dmi_streamHandle = new tx_fiber((full_name + "_dmi").c_str(), "[TLM][chi][dmi]", m_db);
301 dmi_trGetHandle = new tx_generator<>("get", *dmi_streamHandle);
302 dmi_trInvalidateHandle =
303 new tx_generator<sc_dt::uint64, sc_dt::uint64>("invalidate", *dmi_streamHandle, "start_addr", "end_addr");
304 }
305 }
306
307private:
308 inline std::string phase2string(const tlm::tlm_phase& p) {
309 std::stringstream ss;
310 ss << p;
311 return ss.str();
312 }
313};
314
315template <unsigned BUSWIDTH = 32, typename TYPES = chi::chi_protocol_types, int N = 1,
316 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
317class chi_lwtr_recorder : public sc_core::sc_module, public chi_lwtr<TYPES> {
318public:
321
322 chi_lwtr_recorder(sc_core::sc_module_name nm, bool recording_enabled = true, tx_db* tr_db = tx_db::get_default_db())
323 : sc_core::sc_module(nm)
324 , chi_lwtr<TYPES>(name(), BUSWIDTH, recording_enabled, tr_db) {
325 is(*this);
326 ts(*this);
327 this->bw_port(ts.get_base_port());
328 this->fw_port(is.get_base_port());
329 }
330};
331
332// implementations of functions
334
335template <typename TYPES> void chi_lwtr<TYPES>::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
337 fw_port->b_transport(trans, delay);
338 return;
339 }
340 // Get a handle for the new transaction
341 tx_handle h = b_trHandle[trans.get_command()]->begin_tx(delay);
342 tx_handle htim;
343 /*************************************************************************
344 * do the timed notification
345 *************************************************************************/
346 if(b_streamHandleTimed)
347 htim = b_trTimedHandle[trans.get_command()]->begin_tx_delayed(sc_core::sc_time_stamp() + delay, par_chld_hndl, h);
348
349 if(registered)
350 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
351 if(extensionRecording) {
352 extensionRecording->recordBeginTx(h, trans);
353 if(htim.is_valid())
354 extensionRecording->recordBeginTx(htim, trans);
355 }
356 link_pred_ext* preExt = nullptr;
357
358 trans.get_extension(preExt);
359 if(preExt == nullptr) { // we are the first recording this transaction
360 preExt = new link_pred_ext(h, this);
361 if(trans.has_mm())
362 trans.set_auto_extension(preExt);
363 else
364 trans.set_extension(preExt);
365 } else {
366 h.add_relation(pred_succ_hndl, preExt->txHandle);
367 }
368 tx_handle preTx(preExt->txHandle);
369 preExt->txHandle = h;
370 fw_port->b_transport(trans, delay);
371 trans.get_extension(preExt);
372 if(preExt->creator == this) {
373 // clean-up the extension if this is the original creator
374 trans.set_extension(static_cast<link_pred_ext*>(nullptr));
375 if(!trans.has_mm()) {
376 delete preExt;
377 }
378 } else {
379 preExt->txHandle = preTx;
380 }
381
382 h.record_attribute("trans", trans);
383 if(registered)
384 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
385 if(extensionRecording) {
386 extensionRecording->recordEndTx(h, trans);
387 if(htim.is_active())
388 extensionRecording->recordEndTx(htim, trans);
389 }
390 // End the transaction
391 h.end_tx(delay);
392 // and now the stuff for the timed tx
393 if(htim.is_valid()) {
394 htim.record_attribute("trans", trans);
395 htim.end_tx_delayed(sc_core::sc_time_stamp() + delay);
396 }
397}
398
399template <typename TYPES> void chi_lwtr<TYPES>::b_snoop(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) {
400 if(!b_streamHandleTimed) {
401 bw_port->b_snoop(trans, delay);
402 return;
403 }
404 // Get a handle for the new transaction
405 tx_handle h = b_trHandle[trans.get_command()]->begin_tx(delay);
406 tx_handle htim;
407 /*************************************************************************
408 * do the timed notification
409 *************************************************************************/
410 if(b_streamHandleTimed)
411 htim = b_trTimedHandle[trans.get_command()]->begin_tx_delayed(sc_core::sc_time_stamp() + delay, par_chld_hndl, h);
412
413 if(registered)
414 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
415 if(extensionRecording) {
416 extensionRecording->recordBeginTx(h, trans);
417 if(htim.is_valid())
418 extensionRecording->recordBeginTx(htim, trans);
419 }
420 link_pred_ext* preExt = nullptr;
421
422 trans.get_extension(preExt);
423 if(preExt == nullptr) { // we are the first recording this transaction
424 preExt = new link_pred_ext(h, this);
425 trans.set_extension(preExt);
426 } else {
427 h.add_relation(pred_succ_hndl, preExt->txHandle);
428 }
429 tx_handle preTx(preExt->txHandle);
430 preExt->txHandle = h;
431 bw_port->b_snoop(trans, delay);
432 trans.get_extension(preExt);
433 if(preExt->creator == this) {
434 // clean-up the extension if this is the original creator
435 trans.set_extension(static_cast<link_pred_ext*>(nullptr));
436 if(!trans.has_mm())
437 delete preExt;
438 } else {
439 preExt->txHandle = preTx;
440 }
441
442 h.record_attribute("trans", trans);
443 if(registered)
444 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
445 if(extensionRecording) {
446 extensionRecording->recordEndTx(h, trans);
447 if(htim.is_active())
448 extensionRecording->recordEndTx(htim, trans);
449 }
450 // End the transaction
451 h.end_tx(delay);
452 // and now the stuff for the timed tx
453 if(htim.is_valid()) {
454 htim.record_attribute("trans", trans);
455 htim.end_tx_delayed(sc_core::sc_time_stamp() + delay);
456 }
457}
458
459template <typename TYPES>
460tlm::tlm_sync_enum chi_lwtr<TYPES>::nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
461 sc_core::sc_time& delay) {
463 return fw_port->nb_transport_fw(trans, phase, delay);
464 }
465 /*************************************************************************
466 * prepare recording
467 *************************************************************************/
468 // Get a handle for the new transaction
469 tx_handle h = nb_trHandle[FW]->begin_tx(phase2string(phase));
470 link_pred_ext* preExt = nullptr;
471 trans.get_extension(preExt);
472 if((phase == tlm::BEGIN_REQ) && preExt == nullptr) { // we are the first recording this transaction
473 preExt = new link_pred_ext(h, this);
474 if(trans.has_mm())
475 trans.set_auto_extension(preExt);
476 else
477 trans.set_extension(preExt);
478 } else if(preExt != nullptr) {
479 // link handle if we have a predecessor
480 h.add_relation(pred_succ_hndl, preExt->txHandle);
481 } else {
482 sc_assert(preExt != nullptr && "ERROR on forward path in phase other than tlm::BEGIN_REQ");
483 }
484 // update the extension
485 preExt->txHandle = h;
486 h.record_attribute("delay", delay);
487 if(registered)
488 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
489 if(extensionRecording)
490 extensionRecording->recordBeginTx(h, trans);
491 /*************************************************************************
492 * do the timed notification
493 *************************************************************************/
494 if(nb_streamHandleTimed) {
495 nb_chi_rec_entry rec(mm::get().allocate(), phase, reinterpret_cast<uint64_t>(&trans), h,
496 (trans.template get_extension<chi::chi_snp_extension>() != nullptr),
497 (phase == tlm::BEGIN_REQ) && has_credit(trans));
498 rec.tr->deep_copy_from(trans);
499 nb_timed_peq.notify(rec, delay);
500 }
501 /*************************************************************************
502 * do the access
503 *************************************************************************/
504 tlm::tlm_sync_enum status = fw_port->nb_transport_fw(trans, phase, delay);
505 /*************************************************************************
506 * handle recording
507 *************************************************************************/
508 h.record_attribute("status", status);
509 h.record_attribute("delay[return_path]", delay);
510 h.record_attribute("trans", trans);
511 if(registered)
512 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
513 if(extensionRecording)
514 extensionRecording->recordEndTx(h, trans);
515 // get the extension and free the memory if it was mine
516 if(status == tlm::TLM_COMPLETED) {
517 // the transaction is finished
518 trans.get_extension(preExt);
519 if(preExt && preExt->creator == this) {
520 trans.set_extension(static_cast<link_pred_ext*>(nullptr));
521 if(!trans.has_mm()) {
522 delete preExt;
523 }
524 }
525 /*************************************************************************
526 * do the timed notification if req. finished here
527 *************************************************************************/
528 if(nb_streamHandleTimed) {
529 nb_chi_rec_entry rec{mm::get().allocate(), (phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
530 reinterpret_cast<uint64_t>(&trans), h}; // TODO: check phase
531 rec.tr->deep_copy_from(trans);
532 nb_timed_peq.notify(rec, delay);
533 }
534 } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
535 nb_chi_rec_entry rec{mm::get().allocate(), phase, reinterpret_cast<uint64_t>(&trans), h};
536 rec.tr->deep_copy_from(trans);
537 nb_timed_peq.notify(rec, delay);
538 }
539 // End the transaction
540 nb_trHandle[FW]->end_tx(h, phase2string(phase));
541 return status;
542}
543
544template <typename TYPES>
545tlm::tlm_sync_enum chi_lwtr<TYPES>::nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase,
546 sc_core::sc_time& delay) {
548 return bw_port->nb_transport_bw(trans, phase, delay);
549 }
550 /*************************************************************************
551 * prepare recording
552 *************************************************************************/
553 link_pred_ext* preExt = nullptr;
554 trans.get_extension(preExt);
555 // Get a handle for the new transaction
556 tx_handle h = nb_trHandle[BW]->begin_tx(phase2string(phase));
557 // link handle if we have a predecessor and that's not ourself
558 if(phase == tlm::BEGIN_REQ && preExt == nullptr) { // we are the first recording this transaction
559 preExt = new link_pred_ext(h, this);
560 trans.set_extension(preExt);
561 preExt->txHandle = h;
562 } else if(preExt) {
563 // link handle if we have a predecessor
564 h.add_relation(pred_succ_hndl, preExt->txHandle);
565 // and set the extension handle to this transaction
566 preExt->txHandle = h;
567 } else {
568 sc_assert(preExt != nullptr && "ERROR on backward path in phase other than tlm::BEGIN_REQ");
569 }
570 // and set the extension handle to this transaction
571 h.record_attribute("delay", delay);
572 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
573 if(extensionRecording)
574 extensionRecording->recordBeginTx(h, trans);
575 /*************************************************************************
576 * do the timed notification
577 *************************************************************************/
578 if(nb_streamHandleTimed) {
579 nb_chi_rec_entry rec(mm::get().allocate(), phase, reinterpret_cast<uint64_t>(&trans), h,
580 (trans.template get_extension<chi::chi_snp_extension>() != nullptr),
581 (phase == tlm::BEGIN_REQ) && has_credit(trans));
582 rec.tr->deep_copy_from(trans);
583 nb_timed_peq.notify(rec, delay);
584 }
585 /*************************************************************************
586 * do the access
587 *************************************************************************/
588 tlm::tlm_sync_enum status = bw_port->nb_transport_bw(trans, phase, delay);
589 /*************************************************************************
590 * handle recording
591 *************************************************************************/
592 h.record_attribute("status", status);
593 h.record_attribute("delay[return_path]", delay);
594 h.record_attribute("trans", trans);
595 if(registered)
596 for(auto& extensionRecording : lwtr4tlm2_extension_registry<TYPES>::inst().get())
597 if(extensionRecording)
598 extensionRecording->recordEndTx(h, trans);
599 // End the transaction
600 nb_trHandle[BW]->end_tx(h, phase2string(phase));
601 // get the extension and free the memory if it was mine
602 if(status == tlm::TLM_COMPLETED) {
603 // the transaction is finished
604 if(preExt && preExt->creator == this) {
605 // clean-up the extension if this is the original creator
606 trans.set_extension(static_cast<link_pred_ext*>(nullptr));
607 if(!trans.has_mm()) {
608 delete preExt;
609 }
610 }
611 /*************************************************************************
612 * do the timed notification if req. finished here
613 *************************************************************************/
614 if(nb_streamHandleTimed) {
615 nb_chi_rec_entry rec{mm::get().allocate(), (phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase,
616 reinterpret_cast<uint64_t>(&trans), h, phase == tlm::BEGIN_REQ};
617 rec.tr->deep_copy_from(trans);
618 nb_timed_peq.notify(rec, delay);
619 }
620 } else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
621 nb_chi_rec_entry rec{mm::get().allocate(), phase, reinterpret_cast<uint64_t>(&trans), h, phase == tlm::BEGIN_REQ};
622 rec.tr->deep_copy_from(trans);
623 nb_timed_peq.notify(rec, delay);
624 }
625 return status;
626}
627
628template <typename TYPES> void chi_lwtr<TYPES>::nbtx_cb() {
629 auto opt = nb_timed_peq.get_next();
630 if(opt) {
631 auto& e = opt.get();
632 tx_handle h;
633 // Now process outstanding recordings
634 if(e.credit) {
635 nb_trTimedHandle[CREDIT]->begin_tx().end_tx();
636 } else if(e.ph == tlm::BEGIN_REQ) {
637 h = nb_trTimedHandle[REQ]->begin_tx(par_chld_hndl, e.parent);
638 nbtx_req_handle_map[e.id] = h;
639 } else if(e.ph == tlm::END_REQ) {
640 auto it = nbtx_req_handle_map.find(e.id);
641 if(it != nbtx_req_handle_map.end()) {
642 h = it->second;
643 nbtx_req_handle_map.erase(it);
644 h.record_attribute("trans", *e.tr);
645 h.end_tx();
646 nbtx_last_req_handle_map[e.id] = h;
647 }
648 } else if(e.ph == tlm::BEGIN_RESP) {
649 auto it = nbtx_req_handle_map.find(e.id);
650 if(it != nbtx_req_handle_map.end()) {
651 h = it->second;
652 nbtx_req_handle_map.erase(it);
653 h.record_attribute("trans", *e.tr);
654 h.end_tx();
655 nbtx_last_req_handle_map[e.id] = h;
656 }
657 h = nb_trTimedHandle[RESP]->begin_tx(par_chld_hndl, e.parent);
658 nbtx_resp_handle_map[e.id] = h;
659 it = nbtx_last_req_handle_map.find(e.id);
660 if(it != nbtx_last_req_handle_map.end()) {
661 tx_handle& pred = it->second;
662 h.add_relation(pred_succ_hndl, pred);
663 nbtx_last_req_handle_map.erase(it);
664 } else {
665 it = nbtx_last_resp_handle_map.find(e.id);
666 if(it != nbtx_last_resp_handle_map.end()) {
667 tx_handle& pred = it->second;
668 h.add_relation(pred_succ_hndl, pred);
669 nbtx_last_resp_handle_map.erase(it);
670 }
671 }
672 } else if(e.ph == tlm::END_RESP) {
673 auto it = nbtx_resp_handle_map.find(e.id);
674 if(it != nbtx_resp_handle_map.end()) {
675 h = it->second;
676 nbtx_resp_handle_map.erase(it);
677 h.record_attribute("trans", *e.tr);
678 h.end_tx();
679 }
680 } else if(e.ph == chi::BEGIN_DATA || e.ph == chi::BEGIN_PARTIAL_DATA) {
681 auto it = nbtx_req_handle_map.find(e.id);
682 if(it != nbtx_req_handle_map.end()) {
683 h = it->second;
684 h.end_tx();
685 nbtx_last_req_handle_map[e.id] = h;
686 }
687 h = nb_trTimedHandle[DATA]->begin_tx();
688 h.record_attribute("trans", *e.tr);
689 h.add_relation(par_chld_hndl, e.parent);
690 nbtx_data_handle_map[e.id] = h;
691 it = nbtx_last_data_handle_map.find(e.id);
692 if(it != nbtx_last_data_handle_map.end()) {
693 auto pred = it->second;
694 nbtx_last_data_handle_map.erase(it);
695 h.add_relation(pred_succ_hndl, pred);
696 }
697 } else if(e.ph == chi::END_DATA || e.ph == chi::END_PARTIAL_DATA) {
698 auto it = nbtx_data_handle_map.find(e.id);
699 if(it != nbtx_data_handle_map.end()) {
700 h = it->second;
701 nbtx_data_handle_map.erase(it);
702 h.end_tx();
703 }
704 } else if(e.ph == chi::ACK) {
705 auto it = nbtx_ack_handle_map.find(e.id);
706 if(it == nbtx_ack_handle_map.end()) {
707 auto h = nb_trTimedHandle[ACK]->begin_tx();
708 nbtx_ack_handle_map[e.id] = h;
709 h.add_relation(par_chld_hndl, e.parent);
710 } else {
711 nb_trTimedHandle[ACK]->end_tx(it->second);
712 nbtx_ack_handle_map.erase(it);
713 }
714 } else
715 sc_assert(!"phase not supported!");
716 }
717 return;
718}
719
720template <typename TYPES> bool chi_lwtr<TYPES>::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) {
721 if(!(m_db && enableDmiTracing.get_value()))
722 return fw_port->get_direct_mem_ptr(trans, dmi_data);
723 tx_handle h = dmi_trGetHandle->begin_tx();
724 bool status = fw_port->get_direct_mem_ptr(trans, dmi_data);
725 h.record_attribute("trans", trans);
726 h.record_attribute("dmi_data", dmi_data);
727 h.end_tx();
728 return status;
729}
730
736template <typename TYPES> void chi_lwtr<TYPES>::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) {
737 if(!(m_db && enableDmiTracing.get_value())) {
738 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
739 return;
740 }
741 tx_handle h = dmi_trInvalidateHandle->begin_tx(start_addr);
742 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
743 dmi_trInvalidateHandle->end_tx(h, end_addr);
744 return;
745}
746
752template <typename TYPES> unsigned int chi_lwtr<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) {
753 return fw_port->transport_dbg(trans);
754}
755} // namespace lwtr
756} // namespace chi
The TLM2 transaction recorder.
Definition chi_lwtr.h:72
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
Definition chi_lwtr.h:209
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_lwtr.h:460
cci::cci_param< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
Definition chi_lwtr.h:81
void b_snoop(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking snoop function.
Definition chi_lwtr.h:399
cci::cci_param< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
Definition chi_lwtr.h:84
sc_core::sc_port< chi::chi_bw_transport_if< TYPES > > bw_port
the port where bw accesses are forwarded to
Definition chi_lwtr.h:216
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
Definition chi_lwtr.h:335
cci::cci_param< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
Definition chi_lwtr.h:78
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_lwtr.h:545
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
Definition chi_lwtr.h:752
cci::cci_param< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
Definition chi_lwtr.h:75
chi_lwtr(char const *full_name, unsigned bus_width, bool recording_enabled=true, tx_db *tr_db=tx_db::get_default_db())
The constructor of the component.
Definition chi_lwtr.h:94
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
Definition chi_lwtr.h:203
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
Definition chi_lwtr.h:736
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_lwtr.h:720
sc_core::sc_port< chi::chi_fw_transport_if< TYPES > > fw_port
the port where fw accesses are forwarded to
Definition chi_lwtr.h:213
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition tlm_mm.h:218
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:894
Definition chi_lwtr.h:52
priority event queue
Definition peq.h:42
boost::optional< TYPE > get_next()
non-blocking get
Definition peq.h:125
Definition tlm2_lwtr.h:102
static tlm_mm & get()
accessor function of the singleton
Definition tlm_mm.h:338