16 #ifndef __TAGGED_TARGET_MIXIN_H__
17 #define __TAGGED_TARGET_MIXIN_H__
19 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
20 #define SC_INCLUDE_DYNAMIC_PROCESSES
23 #include <scc/utilities.h>
26 #include <tlm_utils/peq_with_get.h>
33 template <
typename base_type,
typename TYPES = tlm::tlm_base_protocol_types>
class tagged_target_mixin :
public base_type {
34 friend class fw_process;
35 friend class bw_process;
38 using transaction_type =
typename TYPES::tlm_payload_type;
39 using phase_type =
typename TYPES::tlm_phase_type;
40 using sync_enum_type = tlm::tlm_sync_enum;
41 using fw_interface_type = tlm::tlm_fw_transport_if<TYPES>;
42 using bw_interface_type = tlm::tlm_bw_transport_if<TYPES>;
58 , m_current_transaction(nullptr) {
62 using base_type::bind;
69 tlm::tlm_bw_transport_if<TYPES>*
operator->() {
return &m_bw_process; }
76 void register_nb_transport_fw(std::function<sync_enum_type(
unsigned int, transaction_type&, phase_type&, sc_core::sc_time&)> cb,
78 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
79 m_fw_process.set_nb_transport_ptr(cb, tag);
86 void register_b_transport(std::function<
void(
unsigned int, transaction_type&, sc_core::sc_time&)> cb,
unsigned int tag) {
87 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
88 m_fw_process.set_b_transport_ptr(cb, tag);
96 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
97 m_fw_process.set_transport_dbg_ptr(cb, tag);
105 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
106 m_fw_process.set_get_direct_mem_ptr(cb, tag);
111 sync_enum_type bw_nb_transport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
112 return base_type::operator->()->nb_transport_bw(trans, phase, t);
115 void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e) { base_type::operator->()->invalidate_direct_mem_ptr(s, e); }
119 class bw_process :
public tlm::tlm_bw_transport_if<TYPES> {
121 bw_process(tagged_target_mixin* p_own)
124 sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
125 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it;
127 it = m_owner->m_pending_trans.find(&trans);
128 if(it == m_owner->m_pending_trans.end()) {
130 return m_owner->bw_nb_transport(trans, phase, t);
133 if(phase == tlm::END_REQ) {
134 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
135 return tlm::TLM_ACCEPTED;
137 }
else if(phase == tlm::BEGIN_RESP) {
138 if(m_owner->m_current_transaction == &trans) {
139 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
142 it->second->notify(t);
143 m_owner->m_pending_trans.erase(it);
144 return tlm::TLM_COMPLETED;
155 void invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e) { m_owner->bw_invalidate_direct_mem_ptr(s, e); }
158 tagged_target_mixin* m_owner{
nullptr};
161 class fw_process :
public tlm::tlm_fw_transport_if<TYPES>,
public tlm::tlm_mm_interface {
163 using NBTransportPtr = std::function<sync_enum_type(
unsigned int, transaction_type&, phase_type&, sc_core::sc_time&)>;
164 using BTransportPtr = std::function<void(
unsigned int, transaction_type&, sc_core::sc_time&)>;
165 using TransportDbgPtr = std::function<
unsigned int(
unsigned int, transaction_type&)>;
166 using GetDirectMemPtr = std::function<bool(
unsigned int, transaction_type&, tlm::tlm_dmi&)>;
168 fw_process(tagged_target_mixin* p_own)
169 : m_name(p_own->name())
171 , m_nb_transport_ptr(nullptr)
172 , m_b_transport_ptr(nullptr)
173 , m_transport_dbg_ptr(nullptr)
174 , m_get_direct_mem_ptr(nullptr)
175 , m_peq(sc_core::sc_gen_unique_name(
"m_peq"))
176 , m_response_in_progress(false) {
177 sc_core::sc_spawn_options opts;
178 opts.set_sensitivity(&m_peq.get_event());
179 sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread,
this), sc_core::sc_gen_unique_name(
"b2nb_thread"), &opts);
182 void set_nb_transport_ptr(NBTransportPtr p,
unsigned int tag) {
183 if(m_nb_transport_ptr) {
185 s << m_name <<
": non-blocking callback allready registered";
186 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
188 m_nb_transport_ptr = p;
193 void set_b_transport_ptr(BTransportPtr p,
unsigned int tag) {
194 if(m_b_transport_ptr) {
196 s << m_name <<
": blocking callback allready registered";
197 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
199 m_b_transport_ptr = p;
204 void set_transport_dbg_ptr(TransportDbgPtr p,
unsigned int tag) {
205 if(m_transport_dbg_ptr) {
207 s << m_name <<
": debug callback allready registered";
208 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
210 m_transport_dbg_ptr = p;
215 void set_get_direct_mem_ptr(GetDirectMemPtr p,
unsigned int tag) {
216 if(m_get_direct_mem_ptr) {
218 s << m_name <<
": get DMI pointer callback allready registered";
219 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
221 m_get_direct_mem_ptr = p;
226 sync_enum_type nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
227 if(m_nb_transport_ptr) {
229 return m_nb_transport_ptr(tags[1], trans, phase, t);
230 }
else if(m_b_transport_ptr) {
231 if(phase == tlm::BEGIN_REQ) {
233 process_handle_class* ph = m_process_handle.get_handle(&trans);
236 ph =
new process_handle_class(&trans);
237 m_process_handle.put_handle(ph);
239 sc_core::sc_spawn_options opts;
240 opts.dont_initialize();
241 opts.set_sensitivity(&ph->m_e);
242 sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,
this, ph), sc_core::sc_gen_unique_name(
"nb2b_thread"), &opts);
246 return tlm::TLM_ACCEPTED;
248 }
else if(phase == tlm::END_RESP) {
249 m_response_in_progress =
false;
250 m_end_response.notify(t);
251 return tlm::TLM_COMPLETED;
261 s << m_name <<
": no non-blocking transport callback registered";
262 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
264 return tlm::TLM_ACCEPTED;
267 void b_transport(transaction_type& trans, sc_core::sc_time& t) {
268 if(m_b_transport_ptr) {
270 m_b_transport_ptr(tags[0], trans, t);
273 }
else if(m_nb_transport_ptr) {
274 m_peq.notify(trans, t);
275 t = sc_core::SC_ZERO_TIME;
277 mm_end_event_ext mm_ext;
278 const bool mm_added = !trans.has_mm();
282 trans.set_auto_extension(&mm_ext);
287 sc_core::sc_event end_event;
288 m_owner->m_pending_trans[&trans] = &end_event;
289 sc_core::wait(end_event);
294 if(trans.get_ref_count()) {
295 sc_core::wait(mm_ext.done);
302 s << m_name <<
": no blocking transport callback registered";
303 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
307 unsigned int transport_dbg(transaction_type& trans) {
308 if(m_transport_dbg_ptr) {
310 return m_transport_dbg_ptr(tags[2], trans);
317 bool get_direct_mem_ptr(transaction_type& trans, tlm::tlm_dmi& dmi_data) {
318 if(m_get_direct_mem_ptr) {
320 return m_get_direct_mem_ptr(tags[3], trans, dmi_data);
324 dmi_data.allow_read_write();
325 dmi_data.set_start_address(0x0);
326 dmi_data.set_end_address((sc_dt::uint64)-1);
334 class process_handle_class {
336 explicit process_handle_class(transaction_type* trans)
338 , m_suspend(false) {}
340 transaction_type* m_trans{
nullptr};
341 sc_core::sc_event m_e{};
342 bool m_suspend{
false};
345 class process_handle_list {
347 process_handle_list() =
default;
349 ~process_handle_list() {
350 for(
typename std::vector<process_handle_class*>::iterator it = v.begin(), end = v.end(); it != end; ++it)
354 process_handle_class* get_handle(transaction_type* trans) {
355 typename std::vector<process_handle_class*>::iterator it;
357 for(it = v.begin(); it != v.end(); it++) {
358 if((*it)->m_suspend) {
359 (*it)->m_trans = trans;
360 (*it)->m_suspend =
false;
367 void put_handle(process_handle_class* ph) { v.push_back(ph); }
370 std::vector<process_handle_class*> v{};
373 process_handle_list m_process_handle{};
375 void nb2b_thread(process_handle_class* h) {
378 transaction_type* trans = h->m_trans;
379 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
382 m_b_transport_ptr(tags[0], *trans, t);
387 while(m_response_in_progress) {
388 sc_core::wait(m_end_response);
390 t = sc_core::SC_ZERO_TIME;
391 phase_type phase = tlm::BEGIN_RESP;
392 sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
393 if(!(sync == tlm::TLM_COMPLETED || (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP))) {
394 m_response_in_progress =
true;
405 sc_core::wait(m_peq.get_event());
407 transaction_type* trans;
408 while((trans = m_peq.get_next_transaction()) != 0) {
409 assert(m_nb_transport_ptr);
410 phase_type phase = tlm::BEGIN_REQ;
411 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
413 switch(m_nb_transport_ptr(tags[1], *trans, phase, t)) {
414 case tlm::TLM_COMPLETED: {
416 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
417 assert(it != m_owner->m_pending_trans.end());
418 it->second->notify(t);
419 m_owner->m_pending_trans.erase(it);
423 case tlm::TLM_ACCEPTED:
424 case tlm::TLM_UPDATED:
427 m_owner->m_current_transaction = trans;
428 sc_core::wait(m_owner->m_end_request);
429 m_owner->m_current_transaction = 0;
436 case tlm::BEGIN_RESP: {
437 phase = tlm::END_RESP;
439 t = sc_core::SC_ZERO_TIME;
440 m_nb_transport_ptr(tags[1], *trans, phase, t);
443 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
444 assert(it != m_owner->m_pending_trans.end());
445 it->second->notify(t);
446 m_owner->m_pending_trans.erase(it);
464 void free(tlm::tlm_generic_payload* trans) {
465 mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
473 class mm_end_event_ext :
public tlm::tlm_extension<mm_end_event_ext> {
475 tlm::tlm_extension_base* clone()
const {
return NULL; }
477 void copy_from(tlm::tlm_extension_base
const&) {}
478 sc_core::sc_event done{};
482 const std::string m_name;
483 tagged_target_mixin* m_owner{
nullptr};
484 unsigned int tags[4];
485 NBTransportPtr m_nb_transport_ptr{};
486 BTransportPtr m_b_transport_ptr{};
487 TransportDbgPtr m_transport_dbg_ptr{};
488 GetDirectMemPtr m_get_direct_mem_ptr{};
489 tlm_utils::peq_with_get<transaction_type> m_peq{};
490 bool m_response_in_progress{
false};
491 sc_core::sc_event m_end_response{};
495 fw_process m_fw_process;
496 bw_process m_bw_process;
497 std::map<transaction_type*, sc_core::sc_event*> m_pending_trans{};
498 sc_core::sc_event m_end_request{};
499 transaction_type* m_current_transaction{
nullptr};
void register_get_direct_mem_ptr(std::function< bool(unsigned int, transaction_type &, tlm::tlm_dmi &)> cb, unsigned int tag)
void register_transport_dbg(std::function< unsigned int(unsigned int, transaction_type &)> cb, unsigned int tag)
void register_b_transport(std::function< void(unsigned int, transaction_type &, sc_core::sc_time &)> cb, unsigned int tag)
tagged_target_mixin(const char *n)
void register_nb_transport_fw(std::function< sync_enum_type(unsigned int, transaction_type &, phase_type &, sc_core::sc_time &)> cb, unsigned int tag)
tlm::tlm_bw_transport_if< TYPES > * operator->()