16 #ifndef __TARGET_MIXIN_H__
17 #define __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 = tlm::tlm_base_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);
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> {
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); }
161 class fw_process :
public tlm::tlm_fw_transport_if<TYPES>,
public tlm::tlm_mm_interface {
163 using NBTransportPtr = std::function<sync_enum_type(transaction_type&, phase_type&, sc_core::sc_time&)>;
164 using BTransportPtr = std::function<void(transaction_type&, sc_core::sc_time&)>;
165 using TransportDbgPtr = std::function<
unsigned int(transaction_type&)>;
166 using GetDirectMemPtr = std::function<bool(transaction_type&, tlm::tlm_dmi&)>;
169 : m_name(p_own->name())
171 , m_nb_transport_ptr(0)
172 , m_b_transport_ptr(0)
173 , m_transport_dbg_ptr(0)
174 , m_get_direct_mem_ptr(0)
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) {
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;
192 void set_b_transport_ptr(BTransportPtr p) {
193 if(m_b_transport_ptr) {
195 s << m_name <<
": blocking callback allready registered";
196 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
198 m_b_transport_ptr = p;
202 void set_transport_dbg_ptr(TransportDbgPtr p) {
203 if(m_transport_dbg_ptr) {
205 s << m_name <<
": debug callback allready registered";
206 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
208 m_transport_dbg_ptr = p;
212 void set_get_direct_mem_ptr(GetDirectMemPtr p) {
213 if(m_get_direct_mem_ptr) {
215 s << m_name <<
": get DMI pointer callback allready registered";
216 SC_REPORT_WARNING(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
218 m_get_direct_mem_ptr = p;
222 sync_enum_type nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {
223 if(m_nb_transport_ptr) {
225 return m_nb_transport_ptr(trans, phase, t);
226 }
else if(m_b_transport_ptr) {
227 if(phase == tlm::BEGIN_REQ) {
229 process_handle_class* ph = m_process_handle.get_handle(&trans);
232 ph =
new process_handle_class(&trans);
233 m_process_handle.put_handle(ph);
235 sc_core::sc_spawn_options opts;
236 opts.dont_initialize();
237 opts.set_sensitivity(&ph->m_e);
238 sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,
this, ph), sc_core::sc_gen_unique_name(
"nb2b_thread"), &opts);
241 phase = tlm::END_REQ;
242 return tlm::TLM_UPDATED;
243 }
else if(phase == tlm::END_RESP) {
244 m_response_in_progress =
false;
245 m_end_response.notify(t);
246 return tlm::TLM_COMPLETED;
253 s << m_name <<
": no non-blocking transport callback registered";
254 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
256 return tlm::TLM_ACCEPTED;
259 void b_transport(transaction_type& trans, sc_core::sc_time& t) {
260 if(m_b_transport_ptr) {
262 m_b_transport_ptr(trans, t);
265 }
else if(m_nb_transport_ptr) {
266 m_peq.notify(trans, t);
267 t = sc_core::SC_ZERO_TIME;
269 mm_end_event_ext mm_ext;
270 const bool mm_added = !trans.has_mm();
274 trans.set_auto_extension(&mm_ext);
279 sc_core::sc_event end_event;
280 m_owner->m_pending_trans[&trans] = &end_event;
281 sc_core::wait(end_event);
286 if(trans.get_ref_count()) {
287 sc_core::wait(mm_ext.done);
294 s << m_name <<
": no blocking transport callback registered";
295 SC_REPORT_ERROR(
"/OSCI_TLM-2/simple_socket", s.str().c_str());
299 unsigned int transport_dbg(transaction_type& trans) {
300 if(m_transport_dbg_ptr) {
302 return m_transport_dbg_ptr(trans);
309 bool get_direct_mem_ptr(transaction_type& trans, tlm::tlm_dmi& dmi_data) {
310 if(m_get_direct_mem_ptr) {
312 return m_get_direct_mem_ptr(trans, dmi_data);
316 dmi_data.allow_read_write();
317 dmi_data.set_start_address(0x0);
318 dmi_data.set_end_address((sc_dt::uint64)-1);
326 class process_handle_class {
328 explicit process_handle_class(transaction_type* trans)
330 , m_suspend(false) {}
332 transaction_type* m_trans;
333 sc_core::sc_event m_e;
337 class process_handle_list {
339 process_handle_list() =
default;
341 ~process_handle_list() {
342 for(
typename std::vector<process_handle_class*>::iterator it = v.begin(), end = v.end(); it != end; ++it)
346 process_handle_class* get_handle(transaction_type* trans) {
347 typename std::vector<process_handle_class*>::iterator it;
349 for(it = v.begin(); it != v.end(); it++) {
350 if((*it)->m_suspend) {
351 (*it)->m_trans = trans;
352 (*it)->m_suspend =
false;
359 void put_handle(process_handle_class* ph) { v.push_back(ph); }
362 std::vector<process_handle_class*> v;
365 process_handle_list m_process_handle;
367 void nb2b_thread(process_handle_class* h) {
370 transaction_type* trans = h->m_trans;
371 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
374 m_b_transport_ptr(*trans, t);
379 while(m_response_in_progress) {
380 sc_core::wait(m_end_response);
382 t = sc_core::SC_ZERO_TIME;
383 phase_type phase = tlm::BEGIN_RESP;
384 sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
385 if(!(sync == tlm::TLM_COMPLETED || (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP))) {
386 m_response_in_progress =
true;
397 sc_core::wait(m_peq.get_event());
399 transaction_type* trans;
400 while((trans = m_peq.get_next_transaction()) != 0) {
401 assert(m_nb_transport_ptr);
402 phase_type phase = tlm::BEGIN_REQ;
403 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
405 switch(m_nb_transport_ptr(*trans, phase, t)) {
406 case tlm::TLM_COMPLETED: {
408 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
409 assert(it != m_owner->m_pending_trans.end());
410 it->second->notify(t);
411 m_owner->m_pending_trans.erase(it);
415 case tlm::TLM_ACCEPTED:
416 case tlm::TLM_UPDATED:
419 m_owner->m_current_transaction = trans;
420 sc_core::wait(m_owner->m_end_request);
421 m_owner->m_current_transaction = 0;
428 case tlm::BEGIN_RESP: {
429 phase = tlm::END_RESP;
431 t = sc_core::SC_ZERO_TIME;
432 m_nb_transport_ptr(*trans, phase, t);
435 typename std::map<transaction_type*, sc_core::sc_event*>::iterator it = m_owner->m_pending_trans.find(trans);
436 assert(it != m_owner->m_pending_trans.end());
437 it->second->notify(t);
438 m_owner->m_pending_trans.erase(it);
456 void free(tlm::tlm_generic_payload* trans) {
457 mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
465 class mm_end_event_ext :
public tlm::tlm_extension<mm_end_event_ext> {
467 tlm::tlm_extension_base* clone()
const {
return NULL; }
469 void copy_from(tlm::tlm_extension_base
const&) {}
470 sc_core::sc_event done;
474 const std::string m_name;
476 NBTransportPtr m_nb_transport_ptr;
477 BTransportPtr m_b_transport_ptr;
478 TransportDbgPtr m_transport_dbg_ptr;
479 GetDirectMemPtr m_get_direct_mem_ptr;
480 tlm_utils::peq_with_get<transaction_type> m_peq;
481 bool m_response_in_progress;
482 sc_core::sc_event m_end_response;
486 fw_process m_fw_process;
487 bw_process m_bw_process;
488 std::map<transaction_type*, sc_core::sc_event*> m_pending_trans;
489 sc_core::sc_event m_end_request;
490 transaction_type* m_current_transaction;
void register_transport_dbg(std::function< unsigned int(transaction_type &)> 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)
void register_get_direct_mem_ptr(std::function< bool(transaction_type &, tlm::tlm_dmi &)> cb)
void register_b_transport(std::function< void(transaction_type &, sc_core::sc_time &)> cb)
tlm::tlm_bw_transport_if< TYPES > * operator->()