19 #include "lwtr4tlm2.h"
21 #include <cci_configuration>
26 #include <sysc/kernel/sc_dynamic_processes.h>
27 #include <tlm/scc/lwtr/lwtr4tlm2_extension_registry.h>
28 #include <tlm/scc/tlm_gp_shared.h>
29 #include <tlm/scc/tlm_mm.h>
30 #include <unordered_map>
37 using tx_db = ::lwtr::tx_db;
38 using tx_fiber = ::lwtr::tx_fiber;
39 template <
typename BEGIN = ::lwtr::no_data,
typename END = ::lwtr::no_data>
using tx_generator = ::lwtr::tx_generator<BEGIN, END>;
40 using tx_handle = ::lwtr::tx_handle;
43 extern bool registered;
50 tlm_extension_base* clone()
const override {
54 void copy_from(tlm_extension_base
const& from)
override {
60 , creator(creator_) {}
67 tlm::tlm_phase
const ph;
80 template <
typename TYPES = tlm::tlm_base_protocol_types>
81 class tlm2_lwtr :
public virtual tlm::tlm_fw_transport_if<TYPES>,
public virtual tlm::tlm_bw_transport_if<TYPES> {
105 tlm2_lwtr(
bool recording_enabled =
true, tx_db* tr_db = tx_db::get_default_db())
106 :
tlm2_lwtr(sc_core::sc_gen_unique_name(
"tlm_recorder"), recording_enabled, tr_db) {}
118 tlm2_lwtr(
const char* full_name,
bool recording_enabled =
true, tx_db* tr_db = tx_db::get_default_db())
121 , full_name(full_name)
124 sc_core::sc_spawn_options opts;
126 opts.dont_initialize();
127 opts.set_sensitivity(&nb_timed_peq.event());
128 sc_core::sc_spawn([
this]() { nbtx_cb(); },
nullptr, &opts);
129 initialize_streams();
132 virtual ~tlm2_lwtr()
override {
133 nbtx_req_handle_map.clear();
134 nbtx_last_req_handle_map.clear();
135 delete b_streamHandle;
136 for(
auto* p : b_trHandle)
138 delete b_streamHandleTimed;
139 for(
auto* p : b_trTimedHandle)
141 delete nb_streamHandle;
142 for(
auto* p : nb_trHandle)
144 delete nb_streamHandleTimed;
145 for(
auto* p : nb_trTimedHandle)
147 delete dmi_streamHandle;
148 delete dmi_trGetHandle;
149 delete dmi_trInvalidateHandle;
163 tlm::tlm_sync_enum
nb_transport_fw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
164 sc_core::sc_time& delay)
override;
175 tlm::tlm_sync_enum
nb_transport_bw(
typename TYPES::tlm_payload_type& trans,
typename TYPES::tlm_phase_type& phase,
176 sc_core::sc_time& delay)
override;
186 void b_transport(
typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay)
override;
208 unsigned int transport_dbg(
typename TYPES::tlm_payload_type& trans)
override;
224 sc_core::sc_port<tlm::tlm_fw_transport_if<TYPES>>
fw_port{
"fw_port"};
227 sc_core::sc_port<tlm::tlm_bw_transport_if<TYPES>>
bw_port{
"bw_port"};
230 std::string
const full_name;
239 tx_db* m_db{
nullptr};
241 ::lwtr::tx_relation_handle pred_succ_hndl{0}, par_chld_hndl{0};
243 tx_fiber* b_streamHandle{
nullptr};
245 std::array<tx_generator<sc_core::sc_time, sc_core::sc_time>*, 3> b_trHandle{{
nullptr,
nullptr,
nullptr}};
247 tx_fiber* b_streamHandleTimed{
nullptr};
250 std::array<tx_generator<>*, 3> b_trTimedHandle{{
nullptr,
nullptr,
nullptr}};
252 enum DIR { FW, BW, REQ = FW, RESP = BW };
254 tx_fiber* nb_streamHandle{
nullptr};
256 tx_fiber* nb_streamHandleTimed{
nullptr};
258 std::array<tx_generator<std::string, std::string>*, 2> nb_trHandle{{
nullptr,
nullptr}};
260 std::array<tx_generator<>*, 2> nb_trTimedHandle{{
nullptr,
nullptr}};
261 std::unordered_map<uint64_t, tx_handle> nbtx_req_handle_map;
262 std::unordered_map<uint64_t, tx_handle> nbtx_last_req_handle_map;
265 tx_fiber* dmi_streamHandle{
nullptr};
267 tx_generator<>* dmi_trGetHandle{
nullptr};
268 tx_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle{
nullptr};
271 void initialize_streams() {
273 pred_succ_hndl = m_db->create_relation(
"PREDECESSOR_SUCCESSOR");
274 par_chld_hndl = m_db->create_relation(
"PARENT_CHILD");
277 b_streamHandle =
new tx_fiber((full_name +
"_bl").c_str(),
"[TLM][base-protocol][b]", m_db);
278 b_trHandle[tlm::TLM_READ_COMMAND] =
279 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"read", *b_streamHandle,
"start_delay",
"end_delay");
280 b_trHandle[tlm::TLM_WRITE_COMMAND] =
281 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"write", *b_streamHandle,
"start_delay",
"end_delay");
282 b_trHandle[tlm::TLM_IGNORE_COMMAND] =
283 new tx_generator<sc_core::sc_time, sc_core::sc_time>(
"ignore", *b_streamHandle,
"start_delay",
"end_delay");
285 b_streamHandleTimed =
new tx_fiber((full_name +
"_bl_timed").c_str(),
"[TLM][base-protocol][b][timed]", m_db);
286 b_trTimedHandle[tlm::TLM_READ_COMMAND] =
new tx_generator<>(
"read", *b_streamHandleTimed);
287 b_trTimedHandle[tlm::TLM_WRITE_COMMAND] =
new tx_generator<>(
"write", *b_streamHandleTimed);
288 b_trTimedHandle[tlm::TLM_IGNORE_COMMAND] =
new tx_generator<>(
"ignore", *b_streamHandleTimed);
292 nb_streamHandle =
new tx_fiber((full_name +
"_nb").c_str(),
"[TLM][base-protocol][nb]", m_db);
293 nb_trHandle[FW] =
new tx_generator<std::string, std::string>(
"fw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
294 nb_trHandle[BW] =
new tx_generator<std::string, std::string>(
"bw", *nb_streamHandle,
"tlm_phase",
"tlm_phase[return_path]");
296 nb_streamHandleTimed =
new tx_fiber((full_name +
"_nb_timed").c_str(),
"[TLM][base-protocol][nb][timed]", m_db);
297 nb_trTimedHandle[FW] =
new tx_generator<>(
"request", *nb_streamHandleTimed);
298 nb_trTimedHandle[BW] =
new tx_generator<>(
"response", *nb_streamHandleTimed);
302 dmi_streamHandle =
new tx_fiber((full_name +
"_dmi").c_str(),
"[TLM][base-protocol][dmi]", m_db);
303 dmi_trGetHandle =
new tx_generator<>(
"get", *dmi_streamHandle);
304 dmi_trInvalidateHandle =
305 new tx_generator<sc_dt::uint64, sc_dt::uint64>(
"invalidate", *dmi_streamHandle,
"start_addr",
"end_addr");
310 inline std::string phase2string(
const tlm::tlm_phase& p) {
311 std::stringstream ss;
317 template <
unsigned BUSWIDTH = 32,
typename TYPES = tlm::tlm_base_protocol_types,
int N = 1,
318 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
321 tlm::tlm_target_socket<BUSWIDTH, TYPES, N, POL> ts{
"ts"};
322 tlm::tlm_initiator_socket<BUSWIDTH, TYPES, N, POL> is{
"is"};
324 tlm2_lwtr_recorder(sc_core::sc_module_name nm,
bool recording_enabled =
true, tx_db* tr_db = tx_db::get_default_db())
325 : sc_core::sc_module(nm)
329 this->
bw_port(ts.get_base_port());
330 this->
fw_port(is.get_base_port());
339 if(!isRecordingBlockingTxEnabled()) {
340 fw_port->b_transport(trans, delay);
344 tx_handle h = b_trHandle[trans.get_command()]->begin_tx(delay);
349 if(b_streamHandleTimed)
350 htim = b_trTimedHandle[trans.get_command()]->begin_tx_delayed(sc_core::sc_time_stamp() + delay, par_chld_hndl, h);
354 if(extensionRecording) {
355 extensionRecording->recordBeginTx(h, trans);
357 extensionRecording->recordBeginTx(htim, trans);
361 trans.get_extension(preExt);
362 if(preExt ==
nullptr) {
365 trans.set_auto_extension(preExt);
367 trans.set_extension(preExt);
369 h.add_relation(pred_succ_hndl, preExt->txHandle);
371 tx_handle preTx{preExt->txHandle};
372 preExt->txHandle = h;
373 fw_port->b_transport(trans, delay);
374 trans.get_extension(preExt);
375 if(preExt->creator ==
this) {
378 if(!trans.has_mm()) {
382 preExt->txHandle = preTx;
384 h.record_attribute(
"trans", trans);
387 if(extensionRecording) {
388 extensionRecording->recordEndTx(h, trans);
390 extensionRecording->recordEndTx(htim, trans);
395 if(htim.is_valid()) {
396 htim.record_attribute(
"trans", trans);
397 htim.end_tx_delayed(sc_core::sc_time_stamp() + delay);
401 template <
typename TYPES>
403 sc_core::sc_time& delay) {
404 if(!isRecordingNonBlockingTxEnabled())
405 return fw_port->nb_transport_fw(trans, phase, delay);
410 tx_handle h = nb_trHandle[FW]->begin_tx(phase2string(phase));
412 trans.get_extension(preExt);
413 if(preExt ==
nullptr) {
416 trans.set_auto_extension(preExt);
418 trans.set_extension(preExt);
421 h.add_relation(pred_succ_hndl, preExt->txHandle);
424 preExt->txHandle = h;
425 h.record_attribute(
"delay", delay);
428 if(extensionRecording)
429 extensionRecording->recordBeginTx(h, trans);
433 if(nb_streamHandleTimed) {
435 rec.tr->deep_copy_from(trans);
436 nb_timed_peq.
notify(rec, delay);
441 tlm::tlm_sync_enum status = fw_port->nb_transport_fw(trans, phase, delay);
445 h.record_attribute(
"tlm_sync", status);
446 h.record_attribute(
"delay[return_path]", delay);
447 h.record_attribute(
"trans", trans);
450 if(extensionRecording)
451 extensionRecording->recordEndTx(h, trans);
453 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) {
454 trans.get_extension(preExt);
455 if(preExt && preExt->creator ==
this) {
457 if(!trans.has_mm()) {
464 if(nb_streamHandleTimed) {
466 rec.tr->deep_copy_from(trans);
467 nb_timed_peq.
notify(rec, delay);
469 }
else if(nb_streamHandleTimed && status == tlm::TLM_UPDATED) {
471 rec.tr->deep_copy_from(trans);
472 nb_timed_peq.
notify(rec, delay);
475 nb_trHandle[FW]->end_tx(h, phase2string(phase));
479 template <
typename TYPES>
481 sc_core::sc_time& delay) {
482 if(!isRecordingNonBlockingTxEnabled())
483 return bw_port->nb_transport_bw(trans, phase, delay);
488 trans.get_extension(preExt);
490 tx_handle h = nb_trHandle[BW]->begin_tx(phase2string(phase));
493 h.add_relation(pred_succ_hndl, preExt->txHandle);
495 preExt->txHandle = h;
498 h.record_attribute(
"delay", delay);
500 if(extensionRecording)
501 extensionRecording->recordBeginTx(h, trans);
505 if(nb_streamHandleTimed) {
507 rec.tr->deep_copy_from(trans);
508 nb_timed_peq.
notify(rec, delay);
513 tlm::tlm_sync_enum status = bw_port->nb_transport_bw(trans, phase, delay);
517 h.record_attribute(
"tlm_sync", status);
518 h.record_attribute(
"delay[return_path]", delay);
519 h.record_attribute(
"trans", trans);
522 if(extensionRecording)
523 extensionRecording->recordEndTx(h, trans);
525 nb_trHandle[BW]->end_tx(h, phase2string(phase));
527 if(status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
529 if(preExt && preExt->creator ==
this) {
532 if(!trans.has_mm()) {
539 if(nb_streamHandleTimed) {
541 rec.tr->deep_copy_from(trans);
542 nb_timed_peq.
notify(rec, delay);
555 h = nb_trTimedHandle[REQ]->begin_tx(par_chld_hndl, e.parent);
556 nbtx_req_handle_map[e.id] = h;
559 auto it = nbtx_req_handle_map.find(e.id);
560 sc_assert(it != nbtx_req_handle_map.end());
562 nbtx_req_handle_map.erase(it);
563 h.record_attribute(
"trans", *e.tr);
565 nbtx_last_req_handle_map[e.id] = h;
567 case tlm::BEGIN_RESP: {
568 auto it = nbtx_req_handle_map.find(e.id);
569 if(it != nbtx_req_handle_map.end()) {
571 nbtx_req_handle_map.erase(it);
572 h.record_attribute(
"trans", *e.tr);
574 nbtx_last_req_handle_map[e.id] = h;
576 h = nb_trTimedHandle[RESP]->begin_tx(par_chld_hndl, e.parent);
577 nbtx_req_handle_map[e.id] = h;
578 it = nbtx_last_req_handle_map.find(e.id);
579 if(it != nbtx_last_req_handle_map.end()) {
580 tx_handle pred = it->second;
581 nbtx_last_req_handle_map.erase(it);
582 h.add_relation(pred_succ_hndl, pred);
585 case tlm::END_RESP: {
586 auto it = nbtx_req_handle_map.find(e.id);
587 if(it != nbtx_req_handle_map.end()) {
589 nbtx_req_handle_map.erase(it);
590 h.record_attribute(
"trans", *e.tr);
603 if(!(m_db && enableDmiTracing.get_value()))
604 return fw_port->get_direct_mem_ptr(trans, dmi_data);
605 tx_handle h = dmi_trGetHandle->begin_tx();
606 bool status = fw_port->get_direct_mem_ptr(trans, dmi_data);
607 h.record_attribute(
"trans", trans);
608 h.record_attribute(
"dmi_data", dmi_data);
619 if(!(m_db && enableDmiTracing.get_value())) {
620 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
623 tx_handle h = dmi_trInvalidateHandle->begin_tx(start_addr);
624 bw_port->invalidate_direct_mem_ptr(start_addr, end_addr);
625 dmi_trInvalidateHandle->end_tx(h, end_addr);
635 return fw_port->transport_dbg(trans);
The TLM transaction extensions recorder registry.
The TLM2 transaction recorder.
cci::cci_param< bool > enableNbTracing
the attribute to selectively enable/disable recording of non-blocking protocol tx
void b_transport(typename TYPES::tlm_payload_type &trans, sc_core::sc_time &delay) override
The blocking transport function.
bool isRecordingBlockingTxEnabled() const
get the current state of transaction recording
cci::cci_param< bool > enableDmiTracing
the attribute to selectively enable/disable DMI recording
sc_core::sc_port< tlm::tlm_bw_transport_if< TYPES > > bw_port
the port where bw accesses are forwarded to
void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) override
The direct memory interface backward function.
bool get_direct_mem_ptr(typename TYPES::tlm_payload_type &trans, tlm::tlm_dmi &dmi_data) override
The direct memory interface forward function.
bool isRecordingNonBlockingTxEnabled() const
get the current state of transaction recording
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.
unsigned int transport_dbg(typename TYPES::tlm_payload_type &trans) override
The debug transportfunction.
cci::cci_param< bool > enableTimedTracing
the attribute to selectively enable/disable timed recording
sc_core::sc_port< tlm::tlm_fw_transport_if< TYPES > > fw_port
the port where fw accesses are forwarded to
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.
cci::cci_param< bool > enableBlTracing
the attribute to selectively enable/disable recording of blocking protocol tx
payload_type * allocate()
get a plain tlm_payload_type without extensions
static tlm_mm & get()
accessor function of the singleton
void notify(const TYPE &entry, const sc_core::sc_time &t)
non-blocking push.
boost::optional< TYPE > get_next()
non-blocking get