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