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