multi_socket_bases.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
20#ifndef TLM_UTILS_MULTI_SOCKET_BASES_H_INCLUDED_
21#define TLM_UTILS_MULTI_SOCKET_BASES_H_INCLUDED_
22
23#include <tlm>
24#include "tlm_utils/convenience_socket_bases.h"
25
26#include <map>
27
28namespace tlm_utils {
29
30template <typename signature>
31struct fn_container{
32  signature function;
33};
34
35#define TLM_DEFINE_FUNCTOR(name) \
36template <typename MODULE, typename TRAITS> \
37inline TLM_RET_VAL static_##name( void* mod \
38                                       , void* fn \
39                                       , int index \
40                                       , TLM_FULL_ARG_LIST) \
41{ \
42  typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
43  MODULE* tmp_mod=static_cast<MODULE*>(mod); \
44  fn_container_type* tmp_cb =static_cast<fn_container_type*> (fn); \
45  return (tmp_mod->*(tmp_cb->function))(index, TLM_ARG_LIST_WITHOUT_TYPES); \
46}\
47\
48template <typename MODULE, typename TRAITS> \
49inline void delete_fn_container_of_##name(void* fn) \
50{ \
51  typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
52  fn_container_type* tmp_cb =static_cast<fn_container_type*> (fn); \
53  if (tmp_cb) delete tmp_cb;\
54} \
55\
56template <typename TRAITS> \
57class name##_functor{ \
58public: \
59  typedef typename TRAITS::tlm_payload_type payload_type; \
60  typedef typename TRAITS::tlm_phase_type   phase_type; \
61  typedef TLM_RET_VAL (*call_fn)(void*,void*, int, TLM_FULL_ARG_LIST); \
62  typedef void (*del_fn)(void*); \
63\
64  name##_functor(): m_fn(0), m_del_fn(0), m_mod(0), m_mem_fn(0){} \
65  ~name##_functor(){if (m_del_fn) (*m_del_fn)(m_mem_fn);}  \
66\
67  template <typename MODULE> \
68  void set_function(MODULE* mod, TLM_RET_VAL (MODULE::*cb)(int, TLM_FULL_ARG_LIST)){ \
69    typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
70    m_fn=&static_##name<MODULE,TRAITS>;\
71    m_del_fn=&delete_fn_container_of_##name<MODULE,TRAITS>;\
72    m_del_fn(m_mem_fn); \
73    fn_container_type* tmp= new fn_container_type(); \
74    tmp->function=cb; \
75    m_mod=static_cast<void*>(mod); \
76    m_mem_fn=static_cast<void*>(tmp); \
77  } \
78  \
79  TLM_RET_VAL operator()(int index, TLM_FULL_ARG_LIST){ \
80    return m_fn(m_mod,m_mem_fn, index, TLM_ARG_LIST_WITHOUT_TYPES); \
81  } \
82\
83  bool is_valid(){return (m_mod!=0 && m_mem_fn!=0 && m_fn!=0);}\
84\
85protected: \
86  call_fn m_fn;\
87  del_fn m_del_fn; \
88  void* m_mod; \
89  void* m_mem_fn; \
90private: \
91  name##_functor& operator=(const name##_functor&); \
92}
93
94
95#define TLM_RET_VAL tlm::tlm_sync_enum
96#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, typename TRAITS::tlm_phase_type& ph, sc_core::sc_time& t
97#define TLM_ARG_LIST_WITHOUT_TYPES txn,ph,t
98TLM_DEFINE_FUNCTOR(nb_transport);
99#undef TLM_RET_VAL
100#undef TLM_FULL_ARG_LIST
101#undef TLM_ARG_LIST_WITHOUT_TYPES
102
103#define TLM_RET_VAL void
104#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, sc_core::sc_time& t
105#define TLM_ARG_LIST_WITHOUT_TYPES txn,t
106TLM_DEFINE_FUNCTOR(b_transport);
107#undef TLM_RET_VAL
108#undef TLM_FULL_ARG_LIST
109#undef TLM_ARG_LIST_WITHOUT_TYPES
110
111#define TLM_RET_VAL unsigned int
112#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn
113#define TLM_ARG_LIST_WITHOUT_TYPES txn
114TLM_DEFINE_FUNCTOR(debug_transport);
115#undef TLM_RET_VAL
116#undef TLM_FULL_ARG_LIST
117#undef TLM_ARG_LIST_WITHOUT_TYPES
118
119#define TLM_RET_VAL bool
120#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, tlm::tlm_dmi& dmi
121#define TLM_ARG_LIST_WITHOUT_TYPES txn,dmi
122TLM_DEFINE_FUNCTOR(get_dmi_ptr);
123#undef TLM_RET_VAL
124#undef TLM_FULL_ARG_LIST
125#undef TLM_ARG_LIST_WITHOUT_TYPES
126
127#define TLM_RET_VAL void
128#define TLM_FULL_ARG_LIST sc_dt::uint64 l, sc_dt::uint64 u
129#define TLM_ARG_LIST_WITHOUT_TYPES l,u
130TLM_DEFINE_FUNCTOR(invalidate_dmi);
131#undef TLM_RET_VAL
132#undef TLM_FULL_ARG_LIST
133#undef TLM_ARG_LIST_WITHOUT_TYPES
134
135#undef TLM_DEFINE_FUNCTOR
136
137/*
138This class implements the fw interface.
139It allows to register a callback for each of the fw interface methods.
140The callbacks simply forward the fw interface call, but add the id (an int)
141of the callback binder to the signature of the call.
142*/
143template <typename TYPES>
144class callback_binder_fw
145  : public tlm::tlm_fw_transport_if<TYPES>
146  , protected convenience_socket_cb_holder
147{
148  public:
149    //typedefs according to the used TYPES class
150    typedef typename TYPES::tlm_payload_type              transaction_type;
151    typedef typename TYPES::tlm_phase_type                phase_type;
152    typedef tlm::tlm_sync_enum                            sync_enum_type;
153
154    //typedefs for the callbacks
155    typedef nb_transport_functor<TYPES>    nb_func_type;
156    typedef b_transport_functor<TYPES>     b_func_type;
157    typedef debug_transport_functor<TYPES> debug_func_type;
158    typedef get_dmi_ptr_functor<TYPES>     dmi_func_type;
159
160    //ctor: an ID is needed to create a callback binder
161    callback_binder_fw(multi_socket_base* owner, int id)
162      : convenience_socket_cb_holder(owner), m_id(id)
163      , m_nb_f(0), m_b_f(0), m_dbg_f(0), m_dmi_f(0)
164      , m_caller_port(0)
165    {}
166
167    //the nb_transport method of the fw interface
168    sync_enum_type nb_transport_fw(transaction_type& txn,
169                                phase_type& p,
170                                sc_core::sc_time& t){
171      //check if a callback is registered
172      if (m_nb_f && m_nb_f->is_valid()) {
173        return (*m_nb_f)(m_id, txn, p, t); //do the callback
174      }
175
176      display_error("Call to nb_transport_fw without a registered callback for nb_transport_fw.");
177      return tlm::TLM_COMPLETED;
178    }
179
180    //the b_transport method of the fw interface
181    void b_transport(transaction_type& trans,sc_core::sc_time& t){
182      //check if a callback is registered
183      if (m_b_f && m_b_f->is_valid()) {
184        (*m_b_f)(m_id, trans,t); //do the callback
185        return;
186      }
187
188      display_error("Call to b_transport without a registered callback for b_transport.");
189    }
190
191    //the DMI method of the fw interface
192    bool get_direct_mem_ptr(transaction_type& trans, tlm::tlm_dmi&  dmi_data){
193      //check if a callback is registered
194      if (m_dmi_f && m_dmi_f->is_valid()) {
195        return (*m_dmi_f)(m_id, trans,dmi_data); //do the callback
196      }
197
198      dmi_data.allow_none();
199      dmi_data.set_start_address(0x0);
200      dmi_data.set_end_address((sc_dt::uint64)-1);
201      return false;
202    }
203
204    //the debug method of the fw interface
205    unsigned int transport_dbg(transaction_type& trans){
206      //check if a callback is registered
207      if (m_dbg_f && m_dbg_f->is_valid()) {
208        return (*m_dbg_f)(m_id, trans); //do the callback
209      }
210
211      return 0;
212    }
213
214    //the SystemC standard callback register_port:
215    // - called when a port if bound to the interface
216    // - allowd to find out who is bound to that callback binder
217    void register_port(sc_core::sc_port_base& b, const char* /*name*/){
218      m_caller_port=&b;
219    }
220
221    //register callbacks for all fw interface methods at once
222    void set_callbacks(nb_func_type& cb1, b_func_type& cb2, dmi_func_type& cb3, debug_func_type& cb4){
223      m_nb_f=&cb1;
224      m_b_f=&cb2;
225      m_dmi_f=&cb3;
226      m_dbg_f=&cb4;
227    }
228
229    //getter method to get the port that is bound to that callback binder
230    // NOTE: this will only return a valid value at end of elaboration
231    //  (but not before end of elaboration!)
232    sc_core::sc_port_base* get_other_side(){return m_caller_port;}
233
234  private:
235    //the ID of the callback binder
236    int m_id;
237
238    //the callbacks
239    nb_func_type* m_nb_f;
240    b_func_type*  m_b_f;
241    debug_func_type* m_dbg_f;
242    dmi_func_type* m_dmi_f;
243
244    //the port bound to that callback binder
245    sc_core::sc_port_base* m_caller_port;
246};
247
248/*
249This class implements the bw interface.
250It allows to register a callback for each of the bw interface methods.
251The callbacks simply forward the bw interface call, but add the id (an int)
252of the callback binder to the signature of the call.
253*/
254template <typename TYPES>
255class callback_binder_bw
256  : public tlm::tlm_bw_transport_if<TYPES>
257  , protected convenience_socket_cb_holder
258{
259  public:
260    //typedefs according to the used TYPES class
261    typedef typename TYPES::tlm_payload_type              transaction_type;
262    typedef typename TYPES::tlm_phase_type                phase_type;
263    typedef tlm::tlm_sync_enum                            sync_enum_type;
264
265    //typedefs for the callbacks
266    typedef nb_transport_functor<TYPES>   nb_func_type;
267    typedef invalidate_dmi_functor<TYPES> dmi_func_type;
268
269    //ctor: an ID is needed to create a callback binder
270    callback_binder_bw(multi_socket_base* owner, int id)
271      : convenience_socket_cb_holder(owner), m_id(id)
272      , m_nb_f(0), m_dmi_f(0) {}
273
274    //the nb_transport method of the bw interface
275    sync_enum_type nb_transport_bw(transaction_type& txn,
276                                phase_type& p,
277                                sc_core::sc_time& t){
278      //check if a callback is registered
279      if (m_nb_f && m_nb_f->is_valid()) {
280        return (*m_nb_f)(m_id, txn, p, t); //do the callback
281      }
282
283      display_error("Call to nb_transport_bw without a registered callback for nb_transport_bw");
284      return tlm::TLM_COMPLETED;
285    }
286
287    //the DMI method of the bw interface
288    void invalidate_direct_mem_ptr(sc_dt::uint64 l, sc_dt::uint64 u){
289      //check if a callback is registered
290      if (m_dmi_f && m_dmi_f->is_valid()) {
291        (*m_dmi_f)(m_id,l,u); //do the callback
292      }
293    }
294
295    //register callbacks for all bw interface methods at once
296    void set_callbacks(nb_func_type& cb1, dmi_func_type& cb2){
297      m_nb_f=&cb1;
298      m_dmi_f=&cb2;
299    }
300
301  private:
302    //the ID of the callback binder
303    int m_id;
304    //the callbacks
305    nb_func_type* m_nb_f;
306    dmi_func_type* m_dmi_f;
307};
308
309/*
310This class forms the base for multi initiator sockets,
311with fewer template parameters than the multi_init_base.
312This class is implementation-defined.
313*/
314template <typename TYPES = tlm::tlm_base_protocol_types>
315class multi_init_base_if {
316public:
317  //this method shall return a vector of the callback binders of multi initiator socket
318  virtual std::vector<callback_binder_bw<TYPES>* >& get_binders()=0;
319  //this method shall return a vector of all target interfaces bound to this multi init socket
320  virtual std::vector<tlm::tlm_fw_transport_if<TYPES>*>& get_sockets()=0;
321protected:
322  virtual ~multi_init_base_if() {}
323};
324
325/*
326This class forms the base for multi initiator sockets.
327It enforces a multi initiator socket to implement all functions
328needed to do hierarchical bindings.
329*/
330template <unsigned int BUSWIDTH = 32,
331          typename TYPES = tlm::tlm_base_protocol_types,
332          unsigned int N=0,
333          sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
334class multi_init_base
335  : public tlm::tlm_initiator_socket<BUSWIDTH, TYPES, N, POL>
336  , public multi_init_base_if<TYPES>
337  , protected multi_socket_base
338{
339public:
340  //typedef for the base type: the standard tlm initiator socket
341  typedef tlm::tlm_initiator_socket<BUSWIDTH, TYPES, N, POL> base_type;
342
343  //this method shall disable the code that does the callback binding
344  // that registers callbacks to binders
345  virtual void disable_cb_bind()=0;
346
347  //this method shall return the multi_init_base to which the
348  // multi_init_base is bound hierarchically
349  //  If the base is not bound hierarchically it shall return a pointer to itself
350  virtual multi_init_base* get_hierarch_bind()=0;
351
352  virtual tlm::tlm_socket_category get_socket_category() const
353  {
354    return tlm::TLM_MULTI_INITIATOR_SOCKET;
355  }
356
357  //ctor and dtor
358  virtual ~multi_init_base(){}
359  multi_init_base():base_type(sc_core::sc_gen_unique_name("multi_init_base")){}
360  multi_init_base(const char* name):base_type(name){}
361
362private:
363  const sc_core::sc_object* get_socket() const { return this; }
364};
365
366/*
367This class forms the base for multi target sockets,
368with fewer template parameters than the multi_target_base.
369This class is implementation-defined.
370*/
371template <typename TYPES = tlm::tlm_base_protocol_types>
372class multi_target_base_if {
373public:
374  //this method shall return a vector of the callback binders of multi initiator socket
375  virtual std::vector<callback_binder_fw<TYPES>* >& get_binders()=0;
376
377  //this method shall return a map of all multi initiator sockets that are
378  // bound to this multi target the key of the map is the index at which the
379  // multi initiator i bound, while the value is the interface of the multi
380  // initiator socket that is bound at that index
381  virtual std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& get_multi_binds()=0;
382protected:
383  virtual ~multi_target_base_if() {}
384};
385
386/*
387This class forms the base for multi target sockets.
388It enforces a multi target socket to implement all functions
389needed to do hierarchical bindings.
390*/
391template <unsigned int BUSWIDTH = 32,
392          typename TYPES = tlm::tlm_base_protocol_types,
393          unsigned int N=0,
394          sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
395class multi_target_base
396  : public tlm::tlm_target_socket<BUSWIDTH, TYPES, N, POL>
397  , public multi_target_base_if<TYPES>
398  , protected multi_socket_base
399{
400public:
401  //typedef for the base type: the standard tlm target socket
402  typedef tlm::tlm_target_socket<BUSWIDTH, TYPES, N, POL > base_type;
403
404  //this method shall return the multi_init_base to which the
405  // multi_init_base is bound hierarchically
406  //  If the base is not bound hierarchically it shall return a pointer to itself
407  virtual multi_target_base* get_hierarch_bind()=0;
408
409  //this method shall inform the multi target socket that it is bound
410  // hierarchically and to which other multi target socket it is bound hierarchically
411  virtual void set_hierarch_bind(multi_target_base*)=0;
412
413  virtual tlm::tlm_socket_category get_socket_category() const
414  {
415    return tlm::TLM_MULTI_TARGET_SOCKET;
416  }
417
418  //ctor and dtor
419  virtual ~multi_target_base(){}
420  multi_target_base():base_type(sc_core::sc_gen_unique_name("multi_target_base")){}
421  multi_target_base(const char* name):base_type(name){}
422
423private:
424  const sc_core::sc_object* get_socket() const { return this; }
425};
426
427/*
428All multi sockets must additionally derive from this class.
429It enforces a multi socket to implement a function
430needed to do multi init to multi target bindings.
431*/
432template <typename TYPES>
433class multi_to_multi_bind_base{
434public:
435  virtual ~multi_to_multi_bind_base(){}
436  virtual tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>*)=0;
437};
438
439} // namespace tlm_utils
440#endif // TLM_UTILS_MULTI_SOCKET_BASES_H_INCLUDED_
441