| /***************************************************************************** | |
| 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 __MULTI_SOCKET_BASES_H__ | |
| #define __MULTI_SOCKET_BASES_H__ | |
| #include <systemc> | |
| #include <tlm> | |
| #include <map> | |
| #include <sstream> | |
| 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 empty(){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>{ | |
| 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; | |
| //ctor: an ID is needed to create a callback binder | |
| 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) { | |
| } | |
| //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 == 0) || (m_nb_f && m_nb_f->empty())) { | |
| //std::cerr<<"No function registered"<<std::endl; | |
| SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to nb_transport_fw without a registered callback for nb_transport_fw."); | |
| } | |
| else | |
| return (*m_nb_f)(m_id, txn, p, t); //do the callback | |
| return tlm::TLM_ACCEPTED; //unreachable | |
| } | |
| //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 == 0) || (m_b_f && m_b_f->empty())) { | |
| SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to b_transport without a registered callback for b_transport."); | |
| } | |
| else | |
| (*m_b_f)(m_id, trans,t); //do the callback | |
| } | |
| //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 == 0) && (m_dmi_f && m_dmi_f->empty())) { | |
| dmi_data.allow_none(); | |
| dmi_data.set_start_address(0x0); | |
| dmi_data.set_end_address((sc_dt::uint64)-1); | |
| return false; | |
| } | |
| else | |
| return (*m_dmi_f)(m_id, trans,dmi_data); //do the callback | |
| } | |
| //the debug method of the fw interface | |
| unsigned int transport_dbg(transaction_type& trans){ | |
| //check if a callback is registered | |
| if ((m_dbg_f == 0) || (m_dbg_f && m_dbg_f->empty())) { | |
| return 0; | |
| } | |
| else | |
| return (*m_dbg_f)(m_id, trans); //do the callback | |
| } | |
| //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>{ | |
| 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; | |
| //ctor: an ID is needed to create a callback binder | |
| callback_binder_bw(int id): 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 == 0) || (m_nb_f && m_nb_f->empty())) { | |
| SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to nb_transport_bw without a registered callback for nb_transport_bw"); | |
| } | |
| else | |
| return (*m_nb_f)(m_id, txn, p, t); //do the callback | |
| return tlm::TLM_ACCEPTED; //unreachable | |
| } | |
| //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 == 0) || (m_dmi_f && m_dmi_f->empty())) { | |
| return; | |
| } | |
| else | |
| (*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. | |
| 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 | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND | |
| #endif | |
| > | |
| class multi_init_base: public tlm::tlm_initiator_socket<BUSWIDTH, | |
| TYPES, | |
| N | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,POL | |
| #endif | |
| >{ | |
| public: | |
| //typedef for the base type: the standard tlm initiator socket | |
| typedef tlm::tlm_initiator_socket<BUSWIDTH, | |
| TYPES, | |
| N | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,POL | |
| #endif | |
| > 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; | |
| //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; | |
| //ctor and dtor | |
| 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){} | |
| }; | |
| /* | |
| 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 | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND | |
| #endif | |
| > | |
| class multi_target_base: public tlm::tlm_target_socket<BUSWIDTH, | |
| TYPES, | |
| N | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,POL | |
| #endif | |
| >{ | |
| public: | |
| //typedef for the base type: the standard tlm target socket | |
| typedef tlm::tlm_target_socket<BUSWIDTH, | |
| TYPES, | |
| N | |
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | |
| ,POL | |
| #endif | |
| > 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; | |
| //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; | |
| //ctor and dtor | |
| 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){} | |
| }; | |
| /* | |
| 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; | |
| }; | |
| } | |
| #endif |