16 #ifndef _TLM_NW_TARGET_MIXIN_H_
17 #define _TLM_NW_TARGET_MIXIN_H_
19 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
20 #define SC_INCLUDE_DYNAMIC_PROCESSES
23 #include "scc/utilities.h"
27 #include <tlm_utils/peq_with_get.h>
36 template <
typename BASE_TYPE,
typename TYPES =
typename BASE_TYPE::protocol_types>
class target_mixin :
public BASE_TYPE {
41 using transaction_type =
typename TYPES::tlm_payload_type;
42 using phase_type =
typename TYPES::tlm_phase_type;
43 using sync_enum_type = tlm::tlm_sync_enum;
44 using fw_interface_type = tlm::tlm_fw_transport_if<TYPES>;
45 using bw_interface_type = tlm::tlm_bw_transport_if<TYPES>;
52 :
target_mixin(sc_core::sc_gen_unique_name(
"target_mixin_socket")) {}
62 , m_current_transaction(nullptr) {
66 using BASE_TYPE::bind;
72 tlm::tlm_bw_transport_if<TYPES>*
operator->() {
return &m_bw_process; }
79 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
80 m_fw_process.set_nb_transport_ptr(cb);
88 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
89 m_fw_process.set_b_transport_ptr(cb);
96 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
97 m_fw_process.set_transport_dbg_ptr(cb);
105 assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
106 m_fw_process.set_get_direct_mem_ptr(cb);
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);
122 sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
123 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it;
125 it = m_owner->m_pending_trans.find(&trans);
126 if(it == m_owner->m_pending_trans.end()) {
128 return m_owner->bw_nb_transport(trans, phase, t);
131 if(phase == tlm::END_REQ) {
132 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
133 return tlm::TLM_ACCEPTED;
135 }
else if(phase == tlm::BEGIN_RESP) {
136 if(m_owner->m_current_transaction == &trans) {
137 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
140 it->second->notify(t);
141 m_owner->m_pending_trans.erase(it);
142 return tlm::TLM_COMPLETED;
159 using NBTransportPtr = std::function<sync_enum_type(transaction_type&, phase_type&, sc_core::sc_time&)>;
160 using BTransportPtr = std::function<void(transaction_type&, sc_core::sc_time&)>;
161 using TransportDbgPtr = std::function<
unsigned int(transaction_type&)>;
162 using GetDirectMemPtr = std::function<bool(transaction_type&, tlm::tlm_dmi&)>;
165 : m_name(p_own->name())
167 , m_nb_transport_ptr(0)
168 , m_b_transport_ptr(0)
169 , m_transport_dbg_ptr(0)
170 , m_get_direct_mem_ptr(0)
171 , m_peq(sc_core::sc_gen_unique_name(
"m_peq"))
172 , m_response_in_progress(false) {
173 sc_core::sc_spawn_options opts;
174 opts.set_sensitivity(&m_peq.get_event());
175 sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread,
this), sc_core::sc_gen_unique_name(
"b2nb_thread"), &opts);
178 void set_nb_transport_ptr(NBTransportPtr p) {
179 if(m_nb_transport_ptr) {
181 s << m_name <<
": non-blocking callback allready registered";
182 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
184 m_nb_transport_ptr = p;
188 void set_b_transport_ptr(BTransportPtr p) {
189 if(m_b_transport_ptr) {
191 s << m_name <<
": blocking callback allready registered";
192 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
194 m_b_transport_ptr = p;
198 void set_transport_dbg_ptr(TransportDbgPtr p) {
199 if(m_transport_dbg_ptr) {
201 s << m_name <<
": debug callback allready registered";
202 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
204 m_transport_dbg_ptr = p;
208 void set_get_direct_mem_ptr(GetDirectMemPtr p) {
209 if(m_get_direct_mem_ptr) {
211 s << m_name <<
": get DMI pointer callback allready registered";
212 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
214 m_get_direct_mem_ptr = p;
218 sync_enum_type nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
219 if(m_nb_transport_ptr) {
221 return m_nb_transport_ptr(trans, phase, t);
222 }
else if(m_b_transport_ptr) {
223 if(phase == tlm::BEGIN_REQ) {
225 process_handle_class* ph = m_process_handle.get_handle(&trans);
228 ph =
new process_handle_class(&trans);
229 m_process_handle.put_handle(ph);
231 sc_core::sc_spawn_options opts;
232 opts.dont_initialize();
233 opts.set_sensitivity(&ph->m_e);
234 sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,
this, ph), sc_core::sc_gen_unique_name(
"nb2b_thread"), &opts);
237 phase = tlm::END_REQ;
238 return tlm::TLM_UPDATED;
239 }
else if(phase == tlm::END_RESP) {
240 m_response_in_progress =
false;
241 m_end_response.notify(t);
242 return tlm::TLM_COMPLETED;
249 s << m_name <<
": no non-blocking transport callback registered";
250 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
252 return tlm::TLM_ACCEPTED;
255 void b_transport(transaction_type& trans, sc_core::sc_time& t) {
256 if(m_b_transport_ptr) {
258 m_b_transport_ptr(trans, t);
261 }
else if(m_nb_transport_ptr) {
262 m_peq.notify(trans, t);
263 t = sc_core::SC_ZERO_TIME;
265 mm_end_event_ext mm_ext;
266 const bool mm_added = !trans.has_mm();
270 trans.set_auto_extension(&mm_ext);
275 sc_core::sc_event end_event;
276 m_owner->m_pending_trans[&trans] = &end_event;
277 sc_core::wait(end_event);
282 if(trans.get_ref_count()) {
283 sc_core::wait(mm_ext.done);
290 s << m_name <<
": no blocking transport callback registered";
291 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
295 unsigned int transport_dbg(transaction_type& trans) {
296 if(m_transport_dbg_ptr) {
298 return m_transport_dbg_ptr(trans);
305 bool get_direct_mem_ptr(transaction_type& trans, tlm::tlm_dmi& dmi_data) {
306 if(m_get_direct_mem_ptr) {
308 return m_get_direct_mem_ptr(trans, dmi_data);
312 dmi_data.allow_read_write();
313 dmi_data.set_start_address(0x0);
314 dmi_data.set_end_address((sc_dt::uint64)-1);
322 class process_handle_class {
324 explicit process_handle_class(transaction_type* trans)
326 , m_suspend(false) {}
328 transaction_type* m_trans;
329 sc_core::sc_event m_e;
333 class process_handle_list {
335 process_handle_list() =
default;
337 ~process_handle_list() {
338 for(
typename std::vector<process_handle_class*>::iterator it = v.begin(), end = v.end(); it != end; ++it)
342 process_handle_class* get_handle(transaction_type* trans) {
343 typename std::vector<process_handle_class*>::iterator it;
345 for(it = v.begin(); it != v.end(); it++) {
346 if((*it)->m_suspend) {
347 (*it)->m_trans = trans;
348 (*it)->m_suspend =
false;
355 void put_handle(process_handle_class* ph) { v.push_back(ph); }
358 std::vector<process_handle_class*> v;
361 process_handle_list m_process_handle;
363 void nb2b_thread(process_handle_class* h) {
366 transaction_type* trans = h->m_trans;
367 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
370 m_b_transport_ptr(*trans, t);
375 while(m_response_in_progress) {
376 sc_core::wait(m_end_response);
378 t = sc_core::SC_ZERO_TIME;
379 phase_type phase = tlm::BEGIN_RESP;
380 sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
381 if(!(sync == tlm::TLM_COMPLETED || (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP))) {
382 m_response_in_progress =
true;
393 sc_core::wait(m_peq.get_event());
395 transaction_type* trans;
396 while((trans = m_peq.get_next_transaction()) != 0) {
397 assert(m_nb_transport_ptr);
398 phase_type phase = tlm::BEGIN_REQ;
399 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
401 switch(m_nb_transport_ptr(*trans, phase, t)) {
402 case tlm::TLM_COMPLETED: {
404 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
405 assert(it != m_owner->m_pending_trans.end());
406 it->second->notify(t);
407 m_owner->m_pending_trans.erase(it);
411 case tlm::TLM_ACCEPTED:
412 case tlm::TLM_UPDATED:
415 m_owner->m_current_transaction = trans;
416 sc_core::wait(m_owner->m_end_request);
417 m_owner->m_current_transaction = 0;
424 case tlm::BEGIN_RESP: {
425 phase = tlm::END_RESP;
427 t = sc_core::SC_ZERO_TIME;
428 m_nb_transport_ptr(*trans, phase, t);
431 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
432 assert(it != m_owner->m_pending_trans.end());
433 it->second->notify(t);
434 m_owner->m_pending_trans.erase(it);
453 mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
461 class mm_end_event_ext :
public tlm::tlm_extension<mm_end_event_ext> {
463 tlm::tlm_extension_base* clone()
const {
return NULL; }
465 void copy_from(tlm::tlm_extension_base
const&) {}
466 sc_core::sc_event done;
470 const std::string m_name;
472 NBTransportPtr m_nb_transport_ptr;
473 BTransportPtr m_b_transport_ptr;
474 TransportDbgPtr m_transport_dbg_ptr;
475 GetDirectMemPtr m_get_direct_mem_ptr;
476 tlm_utils::peq_with_get<transaction_type> m_peq;
477 bool m_response_in_progress;
478 sc_core::sc_event m_end_response;
482 fw_process m_fw_process;
483 bw_process m_bw_process;
484 std::map<transaction_type*, sc_core::sc_event*> m_pending_trans;
485 sc_core::sc_event m_end_request;
486 transaction_type* m_current_transaction;
tlm::tlm_bw_transport_if< TYPES > * operator->()
void register_transport_dbg(std::function< unsigned int(transaction_type &)> cb)
void register_b_transport(std::function< void(transaction_type &, sc_core::sc_time &)> cb)
void register_get_direct_mem_ptr(std::function< bool(transaction_type &, tlm::tlm_dmi &)> cb)
target_mixin(const sc_core::sc_module_name &n)
void register_nb_transport_fw(std::function< sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb)