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