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