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