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