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