| /***************************************************************************** |
| |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or |
| more contributor license agreements. See the NOTICE file distributed |
| with this work for additional information regarding copyright ownership. |
| Accellera licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
| |
| *****************************************************************************/ |
| |
| #ifndef __SYSTEMC_EXT_TLM_UTILS_MULTI_SOCKET_BASES_H__ |
| #define __SYSTEMC_EXT_TLM_UTILS_MULTI_SOCKET_BASES_H__ |
| |
| #include <map> |
| |
| #include "../core/sc_port.hh" |
| #include "../tlm_core/2/interfaces/fw_bw_ifs.hh" |
| #include "convenience_socket_bases.h" |
| |
| namespace tlm_utils |
| { |
| |
| template <typename signature> |
| struct fn_container |
| { |
| signature function; |
| }; |
| |
| #define TLM_DEFINE_FUNCTOR(name) \ |
| template <typename MODULE, typename TRAITS> \ |
| inline TLM_RET_VAL \ |
| static_##name(void *mod, void *fn, int index, TLM_FULL_ARG_LIST) \ |
| { \ |
| typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> \ |
| fn_container_type; \ |
| MODULE *tmp_mod = static_cast<MODULE *>(mod); \ |
| fn_container_type *tmp_cb = static_cast<fn_container_type *> (fn); \ |
| return (tmp_mod->*(tmp_cb->function))( \ |
| index, TLM_ARG_LIST_WITHOUT_TYPES); \ |
| } \ |
| \ |
| template <typename MODULE, typename TRAITS> \ |
| inline void \ |
| delete_fn_container_of_##name(void *fn) \ |
| { \ |
| typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> \ |
| fn_container_type; \ |
| fn_container_type *tmp_cb = static_cast<fn_container_type *>(fn); \ |
| if (tmp_cb) \ |
| delete tmp_cb; \ |
| } \ |
| \ |
| template <typename TRAITS> \ |
| class name##_functor{ \ |
| public: \ |
| typedef typename TRAITS::tlm_payload_type payload_type; \ |
| typedef typename TRAITS::tlm_phase_type phase_type; \ |
| typedef TLM_RET_VAL (*call_fn)(void *,void *, int, TLM_FULL_ARG_LIST); \ |
| typedef void (*del_fn)(void *); \ |
| \ |
| name##_functor() : m_fn(0), m_del_fn(0), m_mod(0), m_mem_fn(0) {} \ |
| ~name##_functor() \ |
| { \ |
| if (m_del_fn) \ |
| (*m_del_fn)(m_mem_fn); \ |
| } \ |
| \ |
| template <typename MODULE> \ |
| void \ |
| set_function(MODULE *mod, TLM_RET_VAL (MODULE::*cb)( \ |
| int, TLM_FULL_ARG_LIST)) \ |
| { \ |
| typedef fn_container<TLM_RET_VAL (MODULE::*)( \ |
| int, TLM_FULL_ARG_LIST)> fn_container_type; \ |
| m_fn = &static_##name<MODULE,TRAITS>; \ |
| m_del_fn = &delete_fn_container_of_##name<MODULE, TRAITS>; \ |
| m_del_fn(m_mem_fn); \ |
| fn_container_type *tmp =new fn_container_type(); \ |
| tmp->function = cb; \ |
| m_mod = static_cast<void *>(mod); \ |
| m_mem_fn = static_cast<void *>(tmp); \ |
| } \ |
| \ |
| TLM_RET_VAL \ |
| operator ()(int index, TLM_FULL_ARG_LIST) \ |
| { \ |
| return m_fn(m_mod, m_mem_fn, index, TLM_ARG_LIST_WITHOUT_TYPES); \ |
| } \ |
| \ |
| bool is_valid() { return (m_mod != 0 && m_mem_fn != 0 && m_fn != 0); } \ |
| \ |
| protected: \ |
| call_fn m_fn;\ |
| del_fn m_del_fn; \ |
| void *m_mod; \ |
| void *m_mem_fn; \ |
| private: \ |
| name##_functor &operator = (const name##_functor &); \ |
| } |
| |
| |
| #define TLM_RET_VAL tlm::tlm_sync_enum |
| #define TLM_FULL_ARG_LIST \ |
| typename TRAITS::tlm_payload_type &txn, \ |
| typename TRAITS::tlm_phase_type &ph, sc_core::sc_time &t |
| #define TLM_ARG_LIST_WITHOUT_TYPES txn, ph, t |
| TLM_DEFINE_FUNCTOR(nb_transport); |
| #undef TLM_RET_VAL |
| #undef TLM_FULL_ARG_LIST |
| #undef TLM_ARG_LIST_WITHOUT_TYPES |
| |
| #define TLM_RET_VAL void |
| #define TLM_FULL_ARG_LIST \ |
| typename TRAITS::tlm_payload_type &txn, sc_core::sc_time &t |
| #define TLM_ARG_LIST_WITHOUT_TYPES txn, t |
| TLM_DEFINE_FUNCTOR(b_transport); |
| #undef TLM_RET_VAL |
| #undef TLM_FULL_ARG_LIST |
| #undef TLM_ARG_LIST_WITHOUT_TYPES |
| |
| #define TLM_RET_VAL unsigned int |
| #define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type &txn |
| #define TLM_ARG_LIST_WITHOUT_TYPES txn |
| TLM_DEFINE_FUNCTOR(debug_transport); |
| #undef TLM_RET_VAL |
| #undef TLM_FULL_ARG_LIST |
| #undef TLM_ARG_LIST_WITHOUT_TYPES |
| |
| #define TLM_RET_VAL bool |
| #define TLM_FULL_ARG_LIST \ |
| typename TRAITS::tlm_payload_type &txn, tlm::tlm_dmi &dmi |
| #define TLM_ARG_LIST_WITHOUT_TYPES txn, dmi |
| TLM_DEFINE_FUNCTOR(get_dmi_ptr); |
| #undef TLM_RET_VAL |
| #undef TLM_FULL_ARG_LIST |
| #undef TLM_ARG_LIST_WITHOUT_TYPES |
| |
| #define TLM_RET_VAL void |
| #define TLM_FULL_ARG_LIST sc_dt::uint64 l, sc_dt::uint64 u |
| #define TLM_ARG_LIST_WITHOUT_TYPES l, u |
| TLM_DEFINE_FUNCTOR(invalidate_dmi); |
| #undef TLM_RET_VAL |
| #undef TLM_FULL_ARG_LIST |
| #undef TLM_ARG_LIST_WITHOUT_TYPES |
| |
| #undef TLM_DEFINE_FUNCTOR |
| |
| /* |
| This class implements the fw interface. |
| It allows to register a callback for each of the fw interface methods. |
| The callbacks simply forward the fw interface call, but add the id (an int) |
| of the callback binder to the signature of the call. |
| */ |
| template <typename TYPES> |
| class callback_binder_fw : public tlm::tlm_fw_transport_if<TYPES>, |
| protected convenience_socket_cb_holder |
| { |
| public: |
| // typedefs according to the used TYPES class. |
| typedef typename TYPES::tlm_payload_type transaction_type; |
| typedef typename TYPES::tlm_phase_type phase_type; |
| typedef tlm::tlm_sync_enum sync_enum_type; |
| |
| // typedefs for the callbacks. |
| typedef nb_transport_functor<TYPES> nb_func_type; |
| typedef b_transport_functor<TYPES> b_func_type; |
| typedef debug_transport_functor<TYPES> debug_func_type; |
| typedef get_dmi_ptr_functor<TYPES> dmi_func_type; |
| |
| callback_binder_fw(multi_socket_base *owner, int id) : |
| convenience_socket_cb_holder(owner), m_id(id), |
| m_nb_f(0), m_b_f(0), m_dbg_f(0), m_dmi_f(0) , m_caller_port(0) |
| {} |
| |
| // The nb_transport method of the fw interface |
| sync_enum_type nb_transport_fw( |
| transaction_type &txn, phase_type &p, sc_core::sc_time &t) |
| { |
| // Check if a callback is registered. |
| if (m_nb_f && m_nb_f->is_valid()) { |
| return (*m_nb_f)(m_id, txn, p, t); // Do the callback. |
| } |
| |
| display_error("Call to nb_transport_fw without a " |
| "registered callback for nb_transport_fw."); |
| return tlm::TLM_COMPLETED; |
| } |
| |
| // The b_transport method of the fw interface. |
| void |
| b_transport(transaction_type &trans, sc_core::sc_time &t) |
| { |
| // Check if a callback is registered. |
| if (m_b_f && m_b_f->is_valid()) { |
| (*m_b_f)(m_id, trans, t); // Do the callback |
| return; |
| } |
| |
| display_error("Call to b_transport without a " |
| "registered callback for b_transport."); |
| } |
| |
| // The DMI method of the fw interface. |
| bool |
| get_direct_mem_ptr(transaction_type &trans, tlm::tlm_dmi &dmi_data) |
| { |
| // Check if a callback is registered. |
| if (m_dmi_f && m_dmi_f->is_valid()) { |
| // Do the callback. |
| return (*m_dmi_f)(m_id, trans, dmi_data); |
| } |
| |
| dmi_data.allow_none(); |
| dmi_data.set_start_address(0x0); |
| dmi_data.set_end_address((sc_dt::uint64)-1); |
| return false; |
| } |
| |
| // The debug method of the fw interface. |
| unsigned int |
| transport_dbg(transaction_type &trans) |
| { |
| // check if a callback is registered |
| if (m_dbg_f && m_dbg_f->is_valid()) { |
| return (*m_dbg_f)(m_id, trans); // Do the callback. |
| } |
| |
| return 0; |
| } |
| |
| // The SystemC standard callback register_port: |
| // - Called when a port if bound to the interface. |
| // - Allowd to find out who is bound to that callback binder. |
| void |
| register_port(sc_core::sc_port_base &b, const char * /* name */) |
| { |
| m_caller_port = &b; |
| } |
| |
| // Register callbacks for all fw interface methods at once. |
| void |
| set_callbacks(nb_func_type &cb1, b_func_type &cb2, |
| dmi_func_type &cb3, debug_func_type &cb4) |
| { |
| m_nb_f = &cb1; |
| m_b_f = &cb2; |
| m_dmi_f = &cb3; |
| m_dbg_f = &cb4; |
| } |
| |
| // Getter method to get the port that is bound to that callback binder. |
| // NOTE: This will only return a valid value at end of elaboration |
| // (but not before end of elaboration!) |
| sc_core::sc_port_base *get_other_side() { return m_caller_port; } |
| |
| private: |
| // The ID of the callback binder. |
| int m_id; |
| |
| // The callbacks. |
| nb_func_type *m_nb_f; |
| b_func_type *m_b_f; |
| debug_func_type *m_dbg_f; |
| dmi_func_type *m_dmi_f; |
| |
| // The port bound to that callback binder. |
| sc_core::sc_port_base *m_caller_port; |
| }; |
| |
| /* |
| This class implements the bw interface. |
| It allows to register a callback for each of the bw interface methods. |
| The callbacks simply forward the bw interface call, but add the id (an int) |
| of the callback binder to the signature of the call. |
| */ |
| template <typename TYPES> |
| class callback_binder_bw : public tlm::tlm_bw_transport_if<TYPES>, |
| protected convenience_socket_cb_holder |
| { |
| public: |
| // typedefs according to the used TYPES class |
| typedef typename TYPES::tlm_payload_type transaction_type; |
| typedef typename TYPES::tlm_phase_type phase_type; |
| typedef tlm::tlm_sync_enum sync_enum_type; |
| |
| // typedefs for the callbacks |
| typedef nb_transport_functor<TYPES> nb_func_type; |
| typedef invalidate_dmi_functor<TYPES> dmi_func_type; |
| |
| callback_binder_bw(multi_socket_base *owner, int id) : |
| convenience_socket_cb_holder(owner), m_id(id), |
| m_nb_f(0), m_dmi_f(0) |
| {} |
| |
| // The nb_transport method of the bw interface. |
| sync_enum_type |
| nb_transport_bw(transaction_type &txn, phase_type& p, |
| sc_core::sc_time &t) |
| { |
| // Check if a callback is registered. |
| if (m_nb_f && m_nb_f->is_valid()) { |
| return (*m_nb_f)(m_id, txn, p, t); // Do the callback. |
| } |
| |
| display_error("Call to nb_transport_bw without a " |
| "registered callback for nb_transport_bw"); |
| return tlm::TLM_COMPLETED; |
| } |
| |
| // The DMI method of the bw interface. |
| void |
| invalidate_direct_mem_ptr(sc_dt::uint64 l, sc_dt::uint64 u) |
| { |
| // Check if a callback is registered. |
| if (m_dmi_f && m_dmi_f->is_valid()) { |
| (*m_dmi_f)(m_id,l,u); // Do the callback. |
| } |
| } |
| |
| // Register callbacks for all bw interface methods at once. |
| void |
| set_callbacks(nb_func_type &cb1, dmi_func_type &cb2) |
| { |
| m_nb_f = &cb1; |
| m_dmi_f = &cb2; |
| } |
| |
| private: |
| // The ID of the callback binder. |
| int m_id; |
| // The callbacks. |
| nb_func_type *m_nb_f; |
| dmi_func_type *m_dmi_f; |
| }; |
| |
| /* |
| This class forms the base for multi initiator sockets, |
| with fewer template parameters than the multi_init_base. |
| This class is implementation-defined. |
| */ |
| template <typename TYPES=tlm::tlm_base_protocol_types> |
| class multi_init_base_if |
| { |
| public: |
| // This method shall return a vector of the callback binders of multi |
| // initiator socket. |
| virtual std::vector<callback_binder_bw<TYPES> *> &get_binders()=0; |
| // This method shall return a vector of all target interfaces bound to |
| // this multi init socket. |
| virtual std::vector<tlm::tlm_fw_transport_if<TYPES> *> &get_sockets()=0; |
| protected: |
| virtual ~multi_init_base_if() {} |
| }; |
| |
| /* |
| This class forms the base for multi initiator sockets. |
| It enforces a multi initiator socket to implement all functions |
| needed to do hierarchical bindings. |
| */ |
| template <unsigned int BUSWIDTH=32, |
| typename TYPES=tlm::tlm_base_protocol_types, unsigned int N=0, |
| sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND> |
| class multi_init_base : |
| public tlm::tlm_initiator_socket<BUSWIDTH, TYPES, N, POL>, |
| public multi_init_base_if<TYPES>, protected multi_socket_base |
| { |
| public: |
| // typedef for the base type: the standard tlm initiator socket. |
| typedef tlm::tlm_initiator_socket<BUSWIDTH, TYPES, N, POL> base_type; |
| |
| // This method shall disable the code that does the callback binding |
| // that registers callbacks to binders. |
| virtual void disable_cb_bind()=0; |
| |
| // This method shall return the multi_init_base to which the |
| // multi_init_base is bound hierarchically. If the base is not bound |
| // hierarchically it shall return a pointer to itself. |
| virtual multi_init_base *get_hierarch_bind() = 0; |
| |
| virtual tlm::tlm_socket_category |
| get_socket_category() const |
| { |
| return tlm::TLM_MULTI_INITIATOR_SOCKET; |
| } |
| |
| virtual ~multi_init_base() {} |
| multi_init_base() : |
| base_type(sc_core::sc_gen_unique_name("multi_init_base")) |
| {} |
| multi_init_base(const char *name) : base_type(name) {} |
| |
| private: |
| const sc_core::sc_object *get_socket() const { return this; } |
| }; |
| |
| /* |
| This class forms the base for multi target sockets, |
| with fewer template parameters than the multi_target_base. |
| This class is implementation-defined. |
| */ |
| template <typename TYPES=tlm::tlm_base_protocol_types> |
| class multi_target_base_if |
| { |
| public: |
| // This method shall return a vector of the callback binders of multi |
| // initiator socket. |
| virtual std::vector<callback_binder_fw<TYPES> *> &get_binders() = 0; |
| |
| // This method shall return a map of all multi initiator sockets that are |
| // bound to this multi target the key of the map is the index at which the |
| // multi initiator i bound, while the value is the interface of the multi |
| // initiator socket that is bound at that index. |
| virtual std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*> & |
| get_multi_binds() = 0; |
| |
| protected: |
| virtual ~multi_target_base_if() {} |
| }; |
| |
| /* |
| This class forms the base for multi target sockets. |
| It enforces a multi target socket to implement all functions |
| needed to do hierarchical bindings. |
| */ |
| template <unsigned int BUSWIDTH=32, |
| typename TYPES=tlm::tlm_base_protocol_types, unsigned int N=0, |
| sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND> |
| class multi_target_base : |
| public tlm::tlm_target_socket<BUSWIDTH, TYPES, N, POL>, |
| public multi_target_base_if<TYPES>, protected multi_socket_base |
| { |
| public: |
| // Typedef for the base type: the standard tlm target socket. |
| typedef tlm::tlm_target_socket<BUSWIDTH, TYPES, N, POL > base_type; |
| |
| // This method shall return the multi_init_base to which the |
| // multi_init_base is bound hierarchically. If the base is not bound |
| // hierarchically it shall return a pointer to itself. |
| virtual multi_target_base *get_hierarch_bind() = 0; |
| |
| // This method shall inform the multi target socket that it is bound |
| // hierarchically and to which other multi target socket it is bound |
| // hierarchically. |
| virtual void set_hierarch_bind(multi_target_base*) = 0; |
| |
| virtual tlm::tlm_socket_category |
| get_socket_category() const |
| { |
| return tlm::TLM_MULTI_TARGET_SOCKET; |
| } |
| |
| virtual ~multi_target_base() {} |
| multi_target_base() : |
| base_type(sc_core::sc_gen_unique_name("multi_target_base")) |
| {} |
| multi_target_base(const char *name) : base_type(name) {} |
| |
| private: |
| const sc_core::sc_object *get_socket() const { return this; } |
| }; |
| |
| /* |
| All multi sockets must additionally derive from this class. |
| It enforces a multi socket to implement a function |
| needed to do multi init to multi target bindings. |
| */ |
| template <typename TYPES> |
| class multi_to_multi_bind_base |
| { |
| public: |
| virtual ~multi_to_multi_bind_base() {} |
| virtual tlm::tlm_fw_transport_if<TYPES> * |
| get_last_binder(tlm::tlm_bw_transport_if<TYPES> *) = 0; |
| }; |
| |
| } // namespace tlm_utils |
| |
| #endif /* __SYSTEMC_EXT_TLM_UTILS_MULTI_SOCKET_BASES_H__ */ |