TLM-2.0  2.0.3
Accellera TLM-2.0 proof-of-concept library
simple_target_socket.h
Go to the documentation of this file.
1 /*****************************************************************************
2 
3  The following code is derived, directly or indirectly, from the SystemC
4  source code Copyright (c) 1996-2014 by all Contributors.
5  All Rights reserved.
6 
7  The contents of this file are subject to the restrictions and limitations
8  set forth in the SystemC Open Source License (the "License");
9  You may not use this file except in compliance with such restrictions and
10  limitations. You may obtain instructions on how to receive a copy of the
11  License at http://www.accellera.org/. Software distributed by Contributors
12  under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
13  ANY KIND, either express or implied. See the License for the specific
14  language governing rights and limitations under the License.
15 
16  *****************************************************************************/
17 
18 // *****************************************************************************
19 // Modified by John Aynsley, Doulos, Feb 2009,
20 // Fix a bug in simple_target_socket and simple_target_socket_tagged
21 // with the addition of one new line of code in each: wait(*e);
22 // *****************************************************************************
23 
24 // *****************************************************************************
25 // Modified by John Aynsley on behalf of Robert Guenzel, May 2011,
26 // Fix a bug in simple_target_socket and simple_target_socket_tagged
27 // with the addition of one new line of code in each: wait(t);
28 // *****************************************************************************
29 
30 
31 #ifndef __SIMPLE_TARGET_SOCKET_H__
32 #define __SIMPLE_TARGET_SOCKET_H__
33 
34 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn
35 # define SC_INCLUDE_DYNAMIC_PROCESSES
36 #endif
37 
38 #include <systemc>
39 #include <tlm>
40 #include "tlm_utils/peq_with_get.h"
41 #include <sstream>
42 
43 namespace tlm_utils {
44 
45 template <typename MODULE,
46  unsigned int BUSWIDTH = 32,
47  typename TYPES = tlm::tlm_base_protocol_types>
49  public tlm::tlm_target_socket<BUSWIDTH, TYPES>
50 {
51  friend class fw_process;
52  friend class bw_process;
53 public:
54  typedef typename TYPES::tlm_payload_type transaction_type;
55  typedef typename TYPES::tlm_phase_type phase_type;
60 
61 public:
63  base_type(sc_core::sc_gen_unique_name("simple_target_socket")),
64  m_fw_process(this),
65  m_bw_process(this)
66  {
67  bind(m_fw_process);
68  }
69 
70  explicit simple_target_socket(const char* n) :
71  base_type(n),
72  m_fw_process(this),
73  m_bw_process(this)
74  {
75  bind(m_fw_process);
76  }
77 
79 
80  // bw transport must come thru us.
81  tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
82 
83  // REGISTER_XXX
84  void register_nb_transport_fw(MODULE* mod,
85  sync_enum_type (MODULE::*cb)(transaction_type&,
86  phase_type&,
88  {
89  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
90  m_fw_process.set_nb_transport_ptr(mod, cb);
91  }
92 
93  void register_b_transport(MODULE* mod,
94  void (MODULE::*cb)(transaction_type&,
96  {
97  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
98  m_fw_process.set_b_transport_ptr(mod, cb);
99  }
100 
101  void register_transport_dbg(MODULE* mod,
102  unsigned int (MODULE::*cb)(transaction_type&))
103  {
104  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
105  m_fw_process.set_transport_dbg_ptr(mod, cb);
106  }
107 
108  void register_get_direct_mem_ptr(MODULE* mod,
109  bool (MODULE::*cb)(transaction_type&,
110  tlm::tlm_dmi&))
111  {
112  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
113  m_fw_process.set_get_direct_mem_ptr(mod, cb);
114  }
115 
116 private:
117  //make call on bw path.
118  sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
119  {
120  return base_type::operator ->()->nb_transport_bw(trans, phase, t);
121  }
122 
123  void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
124  {
126  }
127 
128  //Helper class to handle bw path calls
129  // Needed to detect transaction end when called from b_transport.
130  class bw_process : public tlm::tlm_bw_transport_if<TYPES>
131  {
132  public:
133  bw_process(simple_target_socket *p_own) : m_owner(p_own)
134  {
135  }
136 
137  sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
138  {
139  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
140 
141  it = m_owner->m_pending_trans.find(&trans);
142  if(it == m_owner->m_pending_trans.end()) {
143  // Not a blocking call, forward.
144  return m_owner->bw_nb_transport(trans, phase, t);
145 
146  } else {
147  if (phase == tlm::END_REQ) {
148  m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
149  return tlm::TLM_ACCEPTED;
150 
151  } else if (phase == tlm::BEGIN_RESP) {
152  if (m_owner->m_current_transaction == &trans) {
153  m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
154  }
155  //TODO: add response-accept delay?
156  it->second->notify(t);
157  m_owner->m_pending_trans.erase(it);
158  return tlm::TLM_COMPLETED;
159 
160  } else {
161  assert(0); exit(1);
162  }
163 
164 // return tlm::TLM_COMPLETED; //Should not reach here
165  }
166  }
167 
168  void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
169  {
170  return m_owner->bw_invalidate_direct_mem_ptr(s, e);
171  }
172 
173  private:
174  simple_target_socket *m_owner;
175  };
176 
177  class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
178  public tlm::tlm_mm_interface
179  {
180  public:
181  typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&,
182  phase_type&,
184  typedef void (MODULE::*BTransportPtr)(transaction_type&,
186  typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&);
187  typedef bool (MODULE::*GetDirectMemPtr)(transaction_type&,
188  tlm::tlm_dmi&);
189 
191  m_name(p_own->name()),
192  m_owner(p_own),
193  m_mod(0),
194  m_nb_transport_ptr(0),
195  m_b_transport_ptr(0),
196  m_transport_dbg_ptr(0),
197  m_get_direct_mem_ptr(0),
198  m_peq(sc_core::sc_gen_unique_name("m_peq")),
199  m_response_in_progress(false)
200  {
202  opts.set_sensitivity(&m_peq.get_event());
203  sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
204  sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
205  }
206 
207  void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
208  {
209  if (m_nb_transport_ptr) {
210  std::stringstream s;
211  s << m_name << ": non-blocking callback allready registered";
212  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
213  } else {
214  assert(!m_mod || m_mod == mod);
215  m_mod = mod;
216  m_nb_transport_ptr = p;
217  }
218  }
219 
220  void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
221  {
222  if (m_b_transport_ptr) {
223  std::stringstream s;
224  s << m_name << ": blocking callback allready registered";
225  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
226  } else {
227  assert(!m_mod || m_mod == mod);
228  m_mod = mod;
229  m_b_transport_ptr = p;
230  }
231  }
232 
233  void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
234  {
235  if (m_transport_dbg_ptr) {
236  std::stringstream s;
237  s << m_name << ": debug callback allready registered";
238  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
239  } else {
240  assert(!m_mod || m_mod == mod);
241  m_mod = mod;
242  m_transport_dbg_ptr = p;
243  }
244  }
245 
246  void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
247  {
248  if (m_get_direct_mem_ptr) {
249  std::stringstream s;
250  s << m_name << ": get DMI pointer callback allready registered";
251  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
252  } else {
253  assert(!m_mod || m_mod == mod);
254  m_mod = mod;
255  m_get_direct_mem_ptr = p;
256  }
257  }
258 // Interface implementation
259  sync_enum_type nb_transport_fw(transaction_type& trans,
260  phase_type& phase,
261  sc_core::sc_time& t)
262  {
263  if (m_nb_transport_ptr) {
264  // forward call
265  assert(m_mod);
266  return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
267 
268  } else if (m_b_transport_ptr) {
269  if (phase == tlm::BEGIN_REQ) {
270  // prepare thread to do blocking call
271  process_handle_class * ph = m_process_handle.get_handle(&trans);
272 
273  if (!ph) { // create new dynamic process
274  ph = new process_handle_class(&trans);
275  m_process_handle.put_handle(ph);
276 
278  opts.dont_initialize();
279  opts.set_sensitivity(&ph->m_e);
280 
281  sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,this, ph),
282  sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
283  }
284 
285  ph->m_e.notify(t);
286  return tlm::TLM_ACCEPTED;
287 
288  } else if (phase == tlm::END_RESP) {
289  m_response_in_progress = false;
290  m_end_response.notify(t);
291  return tlm::TLM_COMPLETED;
292 
293  } else {
294  assert(0); exit(1);
295 // return tlm::TLM_COMPLETED; ///< unreachable code
296  }
297 
298  } else {
299  std::stringstream s;
300  s << m_name << ": no non-blocking transport callback registered";
301  SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
302  }
303  return tlm::TLM_ACCEPTED;
304  }
305 
306  void b_transport(transaction_type& trans, sc_core::sc_time& t)
307  {
308  if (m_b_transport_ptr) {
309  // forward call
310  assert(m_mod);
311  (m_mod->*m_b_transport_ptr)(trans, t);
312  return;
313 
314  } else if (m_nb_transport_ptr) {
315  m_peq.notify(trans, t);
317 
318  mm_end_event_ext mm_ext;
319  const bool mm_added = !trans.has_mm();
320 
321  if (mm_added) {
322  trans.set_mm(this);
323  trans.set_auto_extension(&mm_ext);
324  trans.acquire();
325  }
326 
327  // wait until transaction is finished
328  sc_core::sc_event end_event;
329  m_owner->m_pending_trans[&trans] = &end_event;
330  sc_core::wait(end_event);
331 
332  if (mm_added) {
333  // release will not delete the transaction, it will notify mm_ext.done
334  trans.release();
335  if (trans.get_ref_count()) {
336  sc_core::wait(mm_ext.done);
337  }
338  trans.set_mm(0);
339  }
340 
341  } else {
342  std::stringstream s;
343  s << m_name << ": no blocking transport callback registered";
344  SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
345  }
346  }
347 
348  unsigned int transport_dbg(transaction_type& trans)
349  {
350  if (m_transport_dbg_ptr) {
351  // forward call
352  assert(m_mod);
353  return (m_mod->*m_transport_dbg_ptr)(trans);
354 
355  } else {
356  // No debug support
357  return 0;
358  }
359  }
360 
361  bool get_direct_mem_ptr(transaction_type& trans,
362  tlm::tlm_dmi& dmi_data)
363  {
364  if (m_get_direct_mem_ptr) {
365  // forward call
366  assert(m_mod);
367  return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
368 
369  } else {
370  // No DMI support
371  dmi_data.allow_read_write();
372  dmi_data.set_start_address(0x0);
373  dmi_data.set_end_address((sc_dt::uint64)-1);
374  return false;
375  }
376  }
377 
378  private:
379 
380 // dynamic process handler for nb2b conversion
381 
382  class process_handle_class {
383  public:
384  explicit process_handle_class(transaction_type * trans)
385  : m_trans(trans),m_suspend(false) {}
386 
387  transaction_type* m_trans;
388  sc_core::sc_event m_e;
389  bool m_suspend;
390  };
391 
392  class process_handle_list {
393  public:
394  process_handle_list() {}
395 
396  ~process_handle_list() {
397  for( typename std::vector<process_handle_class*>::iterator
398  it=v.begin(), end = v.end(); it != end; ++it )
399  delete *it;
400  }
401 
402  process_handle_class* get_handle(transaction_type *trans)
403  {
404  typename std::vector<process_handle_class*>::iterator it;
405 
406  for(it = v.begin(); it != v.end(); it++) {
407  if ((*it)->m_suspend) { // found suspended dynamic process, re-use it
408  (*it)->m_trans = trans; // replace to new one
409  (*it)->m_suspend = false;
410  return *it;
411  }
412  }
413  return NULL; // no suspended process
414  }
415 
416  void put_handle(process_handle_class* ph)
417  {
418  v.push_back(ph);
419  }
420 
421  private:
422  std::vector<process_handle_class*> v;
423  };
424 
425  process_handle_list m_process_handle;
426 
427 
428  void nb2b_thread(process_handle_class* h)
429  {
430 
431  while(1) {
432  transaction_type *trans = h->m_trans;
434 
435  // forward call
436  assert(m_mod);
437  (m_mod->*m_b_transport_ptr)(*trans, t);
438 
439  sc_core::wait(t);
440 
441  // return path
442  while (m_response_in_progress) {
443  sc_core::wait(m_end_response);
444  }
446  phase_type phase = tlm::BEGIN_RESP;
447  sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
448  if ( !(sync == tlm::TLM_COMPLETED ||
449  (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) {
450  m_response_in_progress = true;
451  }
452 
453  // suspend until next transaction
454  h->m_suspend = true;
455  sc_core::wait();
456  }
457  }
458 
459  void b2nb_thread()
460  {
461  while (true) {
462  sc_core::wait(m_peq.get_event());
463 
464  transaction_type* trans;
465  while ((trans = m_peq.get_next_transaction())!=0) {
466  assert(m_mod);
467  assert(m_nb_transport_ptr);
468  phase_type phase = tlm::BEGIN_REQ;
470 
471  switch ((m_mod->*m_nb_transport_ptr)(*trans, phase, t)) {
472  case tlm::TLM_COMPLETED:
473  {
474  // notify transaction is finished
475  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
476  m_owner->m_pending_trans.find(trans);
477  assert(it != m_owner->m_pending_trans.end());
478  it->second->notify(t);
479  m_owner->m_pending_trans.erase(it);
480  break;
481  }
482 
483  case tlm::TLM_ACCEPTED:
484  case tlm::TLM_UPDATED:
485  switch (phase) {
486  case tlm::BEGIN_REQ:
487  m_owner->m_current_transaction = trans;
488  sc_core::wait(m_owner->m_end_request);
489  m_owner->m_current_transaction = 0;
490  break;
491 
492  case tlm::END_REQ:
493  sc_core::wait(t);
494  break;
495 
496  case tlm::BEGIN_RESP:
497  {
498  phase = tlm::END_RESP;
499  sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2
501  (m_mod->*m_nb_transport_ptr)(*trans, phase, t);
502 
503  // notify transaction is finished
504  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
505  m_owner->m_pending_trans.find(trans);
506  assert(it != m_owner->m_pending_trans.end());
507  it->second->notify(t);
508  m_owner->m_pending_trans.erase(it);
509  break;
510  }
511 
512  default:
513  assert(0); exit(1);
514  };
515  break;
516 
517  default:
518  assert(0); exit(1);
519  };
520  }
521  }
522  }
523 
524  void free(tlm::tlm_generic_payload* trans)
525  {
526  mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
527  assert(ext);
528  // notif event first before freeing extensions (reset)
529  ext->done.notify();
530  trans->reset();
531  }
532 
533  private:
534  struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
535  {
536  tlm::tlm_extension_base* clone() const { return NULL; }
537  void free() {}
538  void copy_from(tlm::tlm_extension_base const &) {}
539  sc_core::sc_event done;
540  };
541 
542  private:
543  const std::string m_name;
544  simple_target_socket *m_owner;
545  MODULE* m_mod;
546  NBTransportPtr m_nb_transport_ptr;
547  BTransportPtr m_b_transport_ptr;
548  TransportDbgPtr m_transport_dbg_ptr;
549  GetDirectMemPtr m_get_direct_mem_ptr;
550  peq_with_get<transaction_type> m_peq;
551  bool m_response_in_progress;
552  sc_core::sc_event m_end_response;
553  };
554 
555 private:
556  fw_process m_fw_process;
557  bw_process m_bw_process;
558  std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
559  sc_core::sc_event m_end_request;
560  transaction_type* m_current_transaction;
561 };
562 
563 //ID Tagged version
564 template <typename MODULE,
565  unsigned int BUSWIDTH = 32,
566  typename TYPES = tlm::tlm_base_protocol_types>
568  public tlm::tlm_target_socket<BUSWIDTH, TYPES>
569 {
570  friend class fw_process;
571  friend class bw_process;
572 public:
573  typedef typename TYPES::tlm_payload_type transaction_type;
574  typedef typename TYPES::tlm_phase_type phase_type;
579 
580 public:
582  base_type(sc_core::sc_gen_unique_name("simple_target_socket_tagged")),
583  m_fw_process(this),
584  m_bw_process(this)
585  {
586  bind(m_fw_process);
587  }
588 
589  explicit simple_target_socket_tagged(const char* n) :
590  base_type(n),
591  m_fw_process(this),
592  m_bw_process(this)
593  {
594  bind(m_fw_process);
595  }
596 
598 
599  // bw transport must come thru us.
600  tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
601 
602  // REGISTER_XXX
603  void register_nb_transport_fw(MODULE* mod,
604  sync_enum_type (MODULE::*cb)(int id,
606  phase_type&,
608  int id)
609  {
610  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
611  m_fw_process.set_nb_transport_ptr(mod, cb);
612  m_fw_process.set_nb_transport_user_id(id);
613  }
614 
615  void register_b_transport(MODULE* mod,
616  void (MODULE::*cb)(int id,
619  int id)
620  {
621  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
622  m_fw_process.set_b_transport_ptr(mod, cb);
623  m_fw_process.set_b_transport_user_id(id);
624  }
625 
626  void register_transport_dbg(MODULE* mod,
627  unsigned int (MODULE::*cb)(int id,
629  int id)
630  {
631  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
632  m_fw_process.set_transport_dbg_ptr(mod, cb);
633  m_fw_process.set_transport_dbg_user_id(id);
634  }
635 
636  void register_get_direct_mem_ptr(MODULE* mod,
637  bool (MODULE::*cb)(int id,
639  tlm::tlm_dmi&),
640  int id)
641  {
642  assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
643  m_fw_process.set_get_direct_mem_ptr(mod, cb);
644  m_fw_process.set_get_dmi_user_id(id);
645  }
646 
647 private:
648  //make call on bw path.
649  sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
650  {
651  return base_type::operator ->()->nb_transport_bw(trans, phase, t);
652  }
653 
654  void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
655  {
657  }
658 
659  //Helper class to handle bw path calls
660  // Needed to detect transaction end when called from b_transport.
661  class bw_process : public tlm::tlm_bw_transport_if<TYPES>
662  {
663  public:
664  bw_process(simple_target_socket_tagged *p_own) : m_owner(p_own)
665  {
666  }
667 
668  sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
669  {
670  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
671 
672  it = m_owner->m_pending_trans.find(&trans);
673  if(it == m_owner->m_pending_trans.end()) {
674  // Not a blocking call, forward.
675  return m_owner->bw_nb_transport(trans, phase, t);
676 
677  } else {
678  if (phase == tlm::END_REQ) {
679  m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
680  return tlm::TLM_ACCEPTED;
681 
682  } else if (phase == tlm::BEGIN_RESP) {
683  if (m_owner->m_current_transaction == &trans) {
684  m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
685  }
686  //TODO: add response-accept delay?
687  it->second->notify(t);
688  m_owner->m_pending_trans.erase(it);
689  return tlm::TLM_COMPLETED;
690 
691  } else {
692  assert(0); exit(1);
693  }
694 
695 // return tlm::TLM_COMPLETED; //Should not reach here
696  }
697  }
698 
699  void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
700  {
701  return m_owner->bw_invalidate_direct_mem_ptr(s, e);
702  }
703 
704  private:
706  };
707 
708  class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
709  public tlm::tlm_mm_interface
710  {
711  public:
712  typedef sync_enum_type (MODULE::*NBTransportPtr)(int id,
714  phase_type&,
716  typedef void (MODULE::*BTransportPtr)(int id,
719  typedef unsigned int (MODULE::*TransportDbgPtr)(int id,
721  typedef bool (MODULE::*GetDirectMemPtr)(int id,
723  tlm::tlm_dmi&);
724 
726  m_name(p_own->name()),
727  m_owner(p_own),
728  m_mod(0),
729  m_nb_transport_ptr(0),
730  m_b_transport_ptr(0),
731  m_transport_dbg_ptr(0),
732  m_get_direct_mem_ptr(0),
733  m_nb_transport_user_id(0),
734  m_b_transport_user_id(0),
735  m_transport_dbg_user_id(0),
736  m_get_dmi_user_id(0),
737  m_peq(sc_core::sc_gen_unique_name("m_peq")),
738  m_response_in_progress(false)
739  {
741  opts.set_sensitivity(&m_peq.get_event());
742  sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
743  sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
744  }
745 
746  void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
747  void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
748  void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; }
749  void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
750 
751  void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
752  {
753  if (m_nb_transport_ptr) {
754  std::stringstream s;
755  s << m_name << ": non-blocking callback allready registered";
756  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
757  } else {
758  assert(!m_mod || m_mod == mod);
759  m_mod = mod;
760  m_nb_transport_ptr = p;
761  }
762  }
763 
764  void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
765  {
766  if (m_b_transport_ptr) {
767  std::stringstream s;
768  s << m_name << ": blocking callback allready registered";
769  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
770  } else {
771  assert(!m_mod || m_mod == mod);
772  m_mod = mod;
773  m_b_transport_ptr = p;
774  }
775  }
776 
777  void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
778  {
779  if (m_transport_dbg_ptr) {
780  std::stringstream s;
781  s << m_name << ": debug callback allready registered";
782  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
783  } else {
784  assert(!m_mod || m_mod == mod);
785  m_mod = mod;
786  m_transport_dbg_ptr = p;
787  }
788  }
789 
790  void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
791  {
792  if (m_get_direct_mem_ptr) {
793  std::stringstream s;
794  s << m_name << ": get DMI pointer callback allready registered";
795  SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
796  } else {
797  assert(!m_mod || m_mod == mod);
798  m_mod = mod;
799  m_get_direct_mem_ptr = p;
800  }
801  }
802 // Interface implementation
803  sync_enum_type nb_transport_fw(transaction_type& trans,
804  phase_type& phase,
805  sc_core::sc_time& t)
806  {
807  if (m_nb_transport_ptr) {
808  // forward call
809  assert(m_mod);
810  return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t);
811 
812  } else if (m_b_transport_ptr) {
813  if (phase == tlm::BEGIN_REQ) {
814 
815  // prepare thread to do blocking call
816  process_handle_class * ph = m_process_handle.get_handle(&trans);
817 
818  if (!ph) { // create new dynamic process
819  ph = new process_handle_class(&trans);
820  m_process_handle.put_handle(ph);
821 
823  opts.dont_initialize();
824  opts.set_sensitivity(&ph->m_e);
825 
826  sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, ph),
827  sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
828  }
829 
830  ph->m_e.notify(t);
831  return tlm::TLM_ACCEPTED;
832 
833  } else if (phase == tlm::END_RESP) {
834  m_response_in_progress = false;
835  m_end_response.notify(t);
836  return tlm::TLM_COMPLETED;
837 
838  } else {
839  assert(0); exit(1);
840 // return tlm::TLM_COMPLETED; ///< unreachable code
841  }
842 
843  } else {
844  std::stringstream s;
845  s << m_name << ": no non-blocking transport callback registered";
846  SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
847  }
848  return tlm::TLM_ACCEPTED;
849  }
850 
851  void b_transport(transaction_type& trans, sc_core::sc_time& t)
852  {
853  if (m_b_transport_ptr) {
854  // forward call
855  assert(m_mod);
856  (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
857  return;
858 
859  } else if (m_nb_transport_ptr) {
860  m_peq.notify(trans, t);
862 
863  mm_end_event_ext mm_ext;
864  const bool mm_added = !trans.has_mm();
865 
866  if (mm_added){
867  trans.set_mm(this);
868  trans.set_auto_extension(&mm_ext);
869  trans.acquire();
870  }
871 
872  // wait until transaction is finished
873  sc_core::sc_event end_event;
874  m_owner->m_pending_trans[&trans] = &end_event;
875  sc_core::wait(end_event);
876 
877  if (mm_added) {
878  // release will not delete the transaction, it will notify mm_ext.done
879  trans.release();
880  if (trans.get_ref_count()) {
881  sc_core::wait(mm_ext.done);
882  }
883  trans.set_mm(0);
884  }
885 
886  } else {
887  std::stringstream s;
888  s << m_name << ": no transport callback registered";
889  SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
890  }
891  }
892 
893  unsigned int transport_dbg(transaction_type& trans)
894  {
895  if (m_transport_dbg_ptr) {
896  // forward call
897  assert(m_mod);
898  return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans);
899 
900  } else {
901  // No debug support
902  return 0;
903  }
904  }
905 
906  bool get_direct_mem_ptr(transaction_type& trans,
907  tlm::tlm_dmi& dmi_data)
908  {
909  if (m_get_direct_mem_ptr) {
910  // forward call
911  assert(m_mod);
912  return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data);
913 
914  } else {
915  // No DMI support
916  dmi_data.allow_read_write();
917  dmi_data.set_start_address(0x0);
918  dmi_data.set_end_address((sc_dt::uint64)-1);
919  return false;
920  }
921  }
922 
923  private:
924 // dynamic process handler for nb2b conversion
925 
926  class process_handle_class {
927  public:
928  explicit process_handle_class(transaction_type * trans)
929  : m_trans(trans),m_suspend(false){}
930 
931  transaction_type* m_trans;
932  sc_core::sc_event m_e;
933  bool m_suspend;
934  };
935 
936  class process_handle_list {
937  public:
938  process_handle_list() {}
939 
940  ~process_handle_list() {
941  for( typename std::vector<process_handle_class*>::iterator
942  it=v.begin(), end = v.end(); it != end; ++it )
943  delete *it;
944  }
945 
946  process_handle_class* get_handle(transaction_type *trans)
947  {
948  typename std::vector<process_handle_class*>::iterator it;
949 
950  for(it = v.begin(); it != v.end(); it++) {
951  if ((*it)->m_suspend) { // found suspended dynamic process, re-use it
952  (*it)->m_trans = trans; // replace to new one
953  (*it)->m_suspend = false;
954  return *it;
955  }
956  }
957  return NULL; // no suspended process
958  }
959 
960  void put_handle(process_handle_class* ph)
961  {
962  v.push_back(ph);
963  }
964 
965  private:
966  std::vector<process_handle_class*> v;
967  };
968 
969  process_handle_list m_process_handle;
970 
971  void nb2b_thread(process_handle_class* h)
972  {
973 
974  while(1) {
975  transaction_type * trans = h->m_trans;
977 
978  // forward call
979  assert(m_mod);
980  (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, *trans, t);
981 
982  sc_core::wait(t);
983 
984  // return path
985  while (m_response_in_progress) {
986  sc_core::wait(m_end_response);
987  }
989  phase_type phase = tlm::BEGIN_RESP;
990  sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
991  if ( !(sync == tlm::TLM_COMPLETED ||
992  (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) {
993  m_response_in_progress = true;
994  }
995 
996  // suspend until next transaction
997  h->m_suspend = true;
998  sc_core::wait();
999  }
1000  }
1001 
1002  void b2nb_thread()
1003  {
1004  while (true) {
1005  sc_core::wait(m_peq.get_event());
1006 
1007  transaction_type* trans;
1008  while ((trans = m_peq.get_next_transaction())!=0) {
1009  assert(m_mod);
1010  assert(m_nb_transport_ptr);
1011  phase_type phase = tlm::BEGIN_REQ;
1013 
1014  switch ((m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t)) {
1015  case tlm::TLM_COMPLETED:
1016  {
1017  // notify transaction is finished
1018  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
1019  m_owner->m_pending_trans.find(trans);
1020  assert(it != m_owner->m_pending_trans.end());
1021  it->second->notify(t);
1022  m_owner->m_pending_trans.erase(it);
1023  break;
1024  }
1025 
1026  case tlm::TLM_ACCEPTED:
1027  case tlm::TLM_UPDATED:
1028  switch (phase) {
1029  case tlm::BEGIN_REQ:
1030  m_owner->m_current_transaction = trans;
1031  sc_core::wait(m_owner->m_end_request);
1032  m_owner->m_current_transaction = 0;
1033  break;
1034 
1035  case tlm::END_REQ:
1036  sc_core::wait(t);
1037  break;
1038 
1039  case tlm::BEGIN_RESP:
1040  {
1041  phase = tlm::END_RESP;
1042  sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2
1044  (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t);
1045 
1046  // notify transaction is finished
1047  typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
1048  m_owner->m_pending_trans.find(trans);
1049  assert(it != m_owner->m_pending_trans.end());
1050  it->second->notify(t);
1051  m_owner->m_pending_trans.erase(it);
1052  break;
1053  }
1054 
1055  default:
1056  assert(0); exit(1);
1057  };
1058  break;
1059 
1060  default:
1061  assert(0); exit(1);
1062  };
1063  }
1064  }
1065  }
1066 
1067  void free(tlm::tlm_generic_payload* trans)
1068  {
1069  mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
1070  assert(ext);
1071  // notif event first before freeing extensions (reset)
1072  ext->done.notify();
1073  trans->reset();
1074  }
1075 
1076  private:
1077  struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
1078  {
1079  tlm::tlm_extension_base* clone() const { return NULL; }
1080  void free() {}
1081  void copy_from(tlm::tlm_extension_base const &) {}
1082  sc_core::sc_event done;
1083  };
1084 
1085  private:
1086  const std::string m_name;
1087  simple_target_socket_tagged *m_owner;
1088  MODULE* m_mod;
1089  NBTransportPtr m_nb_transport_ptr;
1090  BTransportPtr m_b_transport_ptr;
1091  TransportDbgPtr m_transport_dbg_ptr;
1092  GetDirectMemPtr m_get_direct_mem_ptr;
1093  int m_nb_transport_user_id;
1094  int m_b_transport_user_id;
1095  int m_transport_dbg_user_id;
1096  int m_get_dmi_user_id;
1097  peq_with_get<transaction_type> m_peq;
1098  bool m_response_in_progress;
1099  sc_core::sc_event m_end_response;
1100  };
1101 
1102 private:
1103  fw_process m_fw_process;
1104  bw_process m_bw_process;
1105  std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
1106  sc_core::sc_event m_end_request;
1107  transaction_type* m_current_transaction;
1108 };
1109 
1110 }
1111 
1112 #endif
void register_nb_transport_fw(MODULE *mod, sync_enum_type(MODULE::*cb)(int id, transaction_type &, phase_type &, sc_core::sc_time &), int id)
void wait(int, sc_simcontext *)
TYPES::tlm_payload_type transaction_type
#define sc_bind
tlm::tlm_bw_transport_if< TYPES > bw_interface_type
virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range)=0
void register_get_direct_mem_ptr(MODULE *mod, bool(MODULE::*cb)(transaction_type &, tlm::tlm_dmi &))
uint64_t uint64
void set_end_address(sc_dt::uint64 addr)
Definition: tlm_dmi.h:69
tlm::tlm_bw_transport_if< TYPES > bw_interface_type
void set_sensitivity(const sc_event *event)
#define SC_REPORT_WARNING(msg_type, msg)
tlm::tlm_fw_transport_if< TYPES > fw_interface_type
void register_b_transport(MODULE *mod, void(MODULE::*cb)(transaction_type &, sc_core::sc_time &))
sc_simcontext * sc_get_curr_simcontext()
void set_start_address(sc_dt::uint64 addr)
Definition: tlm_dmi.h:68
tlm::tlm_target_socket< BUSWIDTH, TYPES > base_type
tlm::tlm_fw_transport_if< TYPES > fw_interface_type
bw_interface_type * operator->()
sc_process_handle sc_spawn(T object, const char *name_p=0, const sc_spawn_options *opt_p=0)
virtual tlm_sync_enum nb_transport_bw(TRANS &trans, PHASE &phase, sc_core::sc_time &t)=0
const char * sc_gen_unique_name(const char *, bool preserve_first)
void register_get_direct_mem_ptr(MODULE *mod, bool(MODULE::*cb)(int id, transaction_type &, tlm::tlm_dmi &), int id)
void allow_read_write(void)
Definition: tlm_dmi.h:76
tlm::tlm_bw_transport_if< TYPES > * operator->()
tlm_sync_enum
Definition: tlm_fw_bw_ifs.h:27
virtual void bind(base_initiator_socket_type &s)
void register_transport_dbg(MODULE *mod, unsigned int(MODULE::*cb)(int id, transaction_type &), int id)
const sc_time SC_ZERO_TIME
void register_nb_transport_fw(MODULE *mod, sync_enum_type(MODULE::*cb)(transaction_type &, phase_type &, sc_core::sc_time &))
void register_transport_dbg(MODULE *mod, unsigned int(MODULE::*cb)(transaction_type &))
tlm::tlm_bw_transport_if< TYPES > * operator->()
#define SC_REPORT_ERROR(msg_type, msg)
tlm::tlm_target_socket< BUSWIDTH, TYPES > base_type
void register_b_transport(MODULE *mod, void(MODULE::*cb)(int id, transaction_type &, sc_core::sc_time &), int id)