TLM-2.0  2.0.3
Accellera TLM-2.0 proof-of-concept library
multi_passthrough_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 #ifndef __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
18 #define __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
19 
21 #include <sstream>
22 
23 namespace tlm_utils {
24 
25 /*
26 This class implements a trivial multi target socket.
27 The triviality refers to the fact that the socket does not
28 do blocking to non-blocking or non-blocking to blocking conversions.
29 
30 It allows to connect multiple initiators to this socket.
31 The user has to register callbacks for the fw interface methods
32 he likes to use. The callbacks are basically equal to the fw interface
33 methods but carry an additional integer that indicates to which
34 index of this socket the calling initiator is connected.
35 */
36 template <typename MODULE,
37  unsigned int BUSWIDTH = 32,
38  typename TYPES = tlm::tlm_base_protocol_types,
39  unsigned int N=0
40 #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
42 #endif
43  >
45  TYPES,
46  N
47 #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
48  ,POL
49 #endif
50  >
51  , public multi_to_multi_bind_base<TYPES>
52 {
53 
54 public:
55 
56  //typedefs
57  // tlm 2.0 types for nb_transport
58  typedef typename TYPES::tlm_payload_type transaction_type;
59  typedef typename TYPES::tlm_phase_type phase_type;
60  typedef tlm::tlm_sync_enum sync_enum_type;
61 
62  // typedefs to keep the fn ptr notations short
63  typedef sync_enum_type (MODULE::*nb_cb)(int, transaction_type&, phase_type&, sc_core::sc_time&);
64  typedef void (MODULE::*b_cb)(int, transaction_type&, sc_core::sc_time&);
65  typedef unsigned int (MODULE::*dbg_cb)(int, transaction_type& txn);
66  typedef bool (MODULE::*dmi_cb)(int, transaction_type& txn, tlm::tlm_dmi& dmi);
67 
68  typedef multi_target_base<BUSWIDTH,
69  TYPES,
70  N
71 #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
72  ,POL
73 #endif
74  > base_type;
75 
76  typedef typename base_type::base_initiator_socket_type base_initiator_socket_type;
77 
78  //CTOR
79  multi_passthrough_target_socket()
80  : base_type(sc_core::sc_gen_unique_name("multi_passthrough_target_socket"))
81  , m_hierarch_bind(0)
82  , m_eoe_disabled(false)
83  , m_export_callback_created(false)
84  {
85  }
86 
87  //CTOR
88  multi_passthrough_target_socket(const char* name)
89  : base_type(name)
90  , m_hierarch_bind(0)
91  , m_eoe_disabled(false)
92  , m_export_callback_created(false)
93  {
94  }
95 
96  ~multi_passthrough_target_socket(){
97  //clean up everything allocated by 'new'
98  for (unsigned int i=0; i<m_binders.size(); i++) delete m_binders[i];
99  }
100 
101  //simple helpers for warnings an errors to shorten in code notation
102  void display_warning(const std::string& text) const {
103  std::stringstream s;
104  s<<"WARNING in instance "<<base_type::name()<<": "<<text;
105  SC_REPORT_WARNING("/OSCI_TLM-2/multi_socket", s.str().c_str());
106  }
107 
108  void display_error(const std::string& text) const {
109  std::stringstream s;
110  s<<"ERROR in instance "<<base_type::name()<<": "<<text;
111  SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket", s.str().c_str());
112  }
113 
114  void check_export_binding()
115  {
116  //if our export hasn't been bound yet (due to a hierarch binding)
117  // we bind it now.
118  //We do that here as the user of the target port HAS to bind at least on callback,
119  //otherwise the socket was useless. Nevertheless, the target socket may still
120  // stay unbound afterwards.
121  if (!sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::get_interface())
122  {
123  // We bind to a callback_binder that will be used as the first interface
124  // i.e. calls to the sc_export will have the same ID as calls from the first initator
125  // socket bound
126  callback_binder_fw<TYPES> * binder;
127 
128  if (m_binders.size() == 0)
129  {
130  binder = new callback_binder_fw<TYPES>(m_binders.size());
131  m_binders.push_back(binder);
132  m_export_callback_created = true;
133  }
134  else
135  {
136  binder = m_binders[0];
137  }
138 
139  sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::bind(*binder);
140  }
141  }
142 
143  //register callback for nb transport of fw interface
144  void register_nb_transport_fw(MODULE* mod,
145  nb_cb cb)
146  {
147  check_export_binding();
148 
149  //warn if there already is a callback
150  if (!m_nb_f.empty()){
151  display_warning("NBTransport_bw callback already registered.");
152  return;
153  }
154 
155  //set the functor
156  m_nb_f.set_function(mod, cb);
157  }
158 
159  //register callback for b transport of fw interface
160  void register_b_transport(MODULE* mod,
161  b_cb cb)
162  {
163  check_export_binding();
164 
165  //warn if there already is a callback
166  if (!m_b_f.empty()){
167  display_warning("BTransport callback already registered.");
168  return;
169  }
170 
171  //set the functor
172  m_b_f.set_function(mod, cb);
173  }
174 
175  //register callback for debug transport of fw interface
176  void register_transport_dbg(MODULE* mod,
177  dbg_cb cb)
178  {
179  check_export_binding();
180 
181  //warn if there already is a callback
182  if (!m_dbg_f.empty()){
183  display_warning("DebugTransport callback already registered.");
184  return;
185  }
186 
187  //set the functor
188  m_dbg_f.set_function(mod, cb);
189  }
190 
191  //register callback for DMI of fw interface
192  void register_get_direct_mem_ptr(MODULE* mod,
193  dmi_cb cb)
194  {
195  check_export_binding();
196 
197  //warn if there already is a callback
198  if (!m_dmi_f.empty()){
199  display_warning("DMI callback already registered.");
200  return;
201  }
202 
203  //set the functor
204  m_dmi_f.set_function(mod, cb);
205  }
206 
207 
208  //Override virtual functions of the tlm_target_socket:
209  // this function is called whenever an sc_port (as part of a init socket)
210  // wants to bind to the export of the underlying tlm_target_socket
211  //At this time a callback binder is created an returned to the sc_port
212  // of the init socket, so that it binds to the callback binder
213  virtual tlm::tlm_fw_transport_if<TYPES>& get_base_interface()
214  {
215  //error if this socket is already bound hierarchically
216  if (m_hierarch_bind) display_error("Socket already bound hierarchically.");
217 
218  if (!m_export_callback_created)
219  m_binders.push_back(new callback_binder_fw<TYPES>(m_binders.size()));
220  else
221  m_export_callback_created = false;
222 
223  return *m_binders[m_binders.size()-1];
224  }
225 
226  // const overload not allowed for multi-sockets
227  virtual const tlm::tlm_fw_transport_if<TYPES>& get_base_interface() const
228  {
229  display_error("'get_base_interface()' const not allowed for multi-sockets.");
230  return base_type::get_base_interface();
231  }
232 
233  //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
234  virtual sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export()
235  {
236  return *this;
237  }
238 
239  //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
240  virtual const sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export() const
241  {
242  return base_type::get_base_export();
243  }
244 
245  //the standard end of elaboration callback
246  void end_of_elaboration(){
247  //'break' here if the socket was told not to do callback binding
248  if (m_eoe_disabled) return;
249 
250  //get the callback binders and the multi binds of the top of the hierachical bind chain
251  // NOTE: this could be the same socket if there is no hierachical bind
252  std::vector<callback_binder_fw<TYPES>* >& binders=get_hierarch_bind()->get_binders();
253  std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& multi_binds=get_hierarch_bind()->get_multi_binds();
254 
255  //iterate over all binders
256  for (unsigned int i=0; i<binders.size(); i++) {
257  binders[i]->set_callbacks(m_nb_f, m_b_f, m_dmi_f, m_dbg_f); //set the callbacks for the binder
258  if (multi_binds.find(i)!=multi_binds.end()) //check if this connection is multi-multi
259  //if so remember the interface
260  m_sockets.push_back(multi_binds[i]);
261  else{ //if we are bound to a normal socket
262  //get the calling port and try to cast it into a tlm socket base
263  base_initiator_socket_type* test=dynamic_cast<base_initiator_socket_type*>(binders[i]->get_other_side());
264  if (!test){display_error("Not bound to tlm_socket.");}
265  m_sockets.push_back(&test->get_base_interface()); //remember the interface
266  }
267  }
268  }
269 
270  //
271  // Bind multi target socket to multi target socket (hierarchical bind)
272  //
273  virtual void bind(base_type& s)
274  {
275  //warn if already bound hierarchically
276  if (m_eoe_disabled){
277  display_warning("Socket already bound hierarchically. Bind attempt ignored.");
278  return;
279  }
280 
281  //disable our own end of elaboration call
282  disable_cb_bind();
283 
284  //inform the bound target socket that it is bound hierarchically now
285  s.set_hierarch_bind((base_type*)this);
286  base_type::bind(s); //satisfy SystemC
287  }
288 
289  //operator notation for hierarchical bind
290  void operator() (base_type& s)
291  {
292  bind(s);
293  }
294 
295  //get access to sub port
296  tlm::tlm_bw_transport_if<TYPES>* operator[](int i){return m_sockets[i];}
297 
298  //get number of bound initiators
299  // NOTE: this is only valid at end of elaboration!
300  unsigned int size(){return get_hierarch_bind()->get_binders().size();}
301 
302 protected:
303  //implementation of base class interface
304  base_type* get_hierarch_bind(){if (m_hierarch_bind) return m_hierarch_bind->get_hierarch_bind(); else return this;}
305  std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& get_multi_binds(){return m_multi_binds;}
306  void set_hierarch_bind(base_type* h){m_hierarch_bind=h;}
307  tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>* other){
308  m_multi_binds[m_binders.size()-1]=other;
309  return m_binders[m_binders.size()-1];
310  }
311 
312  //map that stores to which index a multi init socket is connected
313  // and the interface of the multi init socket
314  std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*> m_multi_binds;
315 
316  void disable_cb_bind(){ m_eoe_disabled=true;}
317  std::vector<callback_binder_fw<TYPES>* >& get_binders(){return m_binders;}
318  //vector of connected sockets
319  std::vector<tlm::tlm_bw_transport_if<TYPES>*> m_sockets;
320  //vector of binders that convert untagged interface into tagged interface
321  std::vector<callback_binder_fw<TYPES>*> m_binders;
322 
323  base_type* m_hierarch_bind; //pointer to hierarchical bound multi port
324  bool m_eoe_disabled; //bool that diables callback bindings at end of elaboration
325  bool m_export_callback_created; // bool to indicate that a callback has already been created for export binding
326 
327  //callbacks as functors
328  // (allows to pass the callback to another socket that does not know the type of the module that owns
329  // the callbacks)
330  typename callback_binder_fw<TYPES>::nb_func_type m_nb_f;
331  typename callback_binder_fw<TYPES>::b_func_type m_b_f;
332  typename callback_binder_fw<TYPES>::debug_func_type m_dbg_f;
333  typename callback_binder_fw<TYPES>::dmi_func_type m_dmi_f;
334 };
335 
336 }
337 
338 #endif