multi_passthrough_target_socket.h revision 13511
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#ifndef TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_ 20#define TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_ 21 22#include "tlm_utils/multi_socket_bases.h" 23 24namespace tlm_utils { 25 26/* 27This class implements a trivial multi target socket. 28The triviality refers to the fact that the socket does not 29do blocking to non-blocking or non-blocking to blocking conversions. 30 31It allows to connect multiple initiators to this socket. 32The user has to register callbacks for the fw interface methods 33he likes to use. The callbacks are basically equal to the fw interface 34methods but carry an additional integer that indicates to which 35index of this socket the calling initiator is connected. 36*/ 37template <typename MODULE, 38 unsigned int BUSWIDTH = 32, 39 typename TYPES = tlm::tlm_base_protocol_types, 40 unsigned int N=0, 41 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND> 42class multi_passthrough_target_socket 43 : public multi_target_base< BUSWIDTH, TYPES, N, POL> 44 , public multi_to_multi_bind_base<TYPES> 45{ 46 47public: 48 49 //typedefs 50 // tlm 2.0 types for nb_transport 51 typedef typename TYPES::tlm_payload_type transaction_type; 52 typedef typename TYPES::tlm_phase_type phase_type; 53 typedef tlm::tlm_sync_enum sync_enum_type; 54 55 // typedefs to keep the fn ptr notations short 56 typedef sync_enum_type (MODULE::*nb_cb)(int, transaction_type&, phase_type&, sc_core::sc_time&); 57 typedef void (MODULE::*b_cb)(int, transaction_type&, sc_core::sc_time&); 58 typedef unsigned int (MODULE::*dbg_cb)(int, transaction_type& txn); 59 typedef bool (MODULE::*dmi_cb)(int, transaction_type& txn, tlm::tlm_dmi& dmi); 60 61 typedef multi_target_base<BUSWIDTH, TYPES, N, POL> base_type; 62 63 typedef typename base_type::base_initiator_socket_type base_initiator_socket_type; 64 65 static const char* default_name() 66 { return sc_core::sc_gen_unique_name("multi_passthrough_target_socket"); } 67 68 //CTOR 69 explicit multi_passthrough_target_socket(const char* name = default_name()) 70 : base_type(name) 71 , m_hierarch_bind(0) 72 , m_eoe_disabled(false) 73 , m_export_callback_created(false) 74 { 75 } 76 77 ~multi_passthrough_target_socket(){ 78 //clean up everything allocated by 'new' 79 for (unsigned int i=0; i<m_binders.size(); i++) delete m_binders[i]; 80 } 81 82 void check_export_binding() 83 { 84 //if our export hasn't been bound yet (due to a hierarch binding) 85 // we bind it now. 86 //We do that here as the user of the target port HAS to bind at least on callback, 87 //otherwise the socket was useless. Nevertheless, the target socket may still 88 // stay unbound afterwards. 89 if (!sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::get_interface()) 90 { 91 // We bind to a callback_binder that will be used as the first interface 92 // i.e. calls to the sc_export will have the same ID as calls from the first initator 93 // socket bound 94 callback_binder_fw<TYPES> * binder; 95 96 if (m_binders.size() == 0) 97 { 98 binder = new callback_binder_fw<TYPES>(this, m_binders.size()); 99 m_binders.push_back(binder); 100 m_export_callback_created = true; 101 } 102 else 103 { 104 binder = m_binders[0]; 105 } 106 107 sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::bind(*binder); 108 } 109 } 110 111 //register callback for nb transport of fw interface 112 void register_nb_transport_fw(MODULE* mod, 113 nb_cb cb) 114 { 115 check_export_binding(); 116 117 //warn if there already is a callback 118 if (m_nb_f.is_valid()){ 119 display_warning("NBTransport_bw callback already registered."); 120 return; 121 } 122 123 //set the functor 124 m_nb_f.set_function(mod, cb); 125 } 126 127 //register callback for b transport of fw interface 128 void register_b_transport(MODULE* mod, 129 b_cb cb) 130 { 131 check_export_binding(); 132 133 //warn if there already is a callback 134 if (m_b_f.is_valid()){ 135 display_warning("BTransport callback already registered."); 136 return; 137 } 138 139 //set the functor 140 m_b_f.set_function(mod, cb); 141 } 142 143 //register callback for debug transport of fw interface 144 void register_transport_dbg(MODULE* mod, 145 dbg_cb cb) 146 { 147 check_export_binding(); 148 149 //warn if there already is a callback 150 if (m_dbg_f.is_valid()){ 151 display_warning("DebugTransport callback already registered."); 152 return; 153 } 154 155 //set the functor 156 m_dbg_f.set_function(mod, cb); 157 } 158 159 //register callback for DMI of fw interface 160 void register_get_direct_mem_ptr(MODULE* mod, 161 dmi_cb cb) 162 { 163 check_export_binding(); 164 165 //warn if there already is a callback 166 if (m_dmi_f.is_valid()){ 167 display_warning("DMI callback already registered."); 168 return; 169 } 170 171 //set the functor 172 m_dmi_f.set_function(mod, cb); 173 } 174 175 176 //Override virtual functions of the tlm_target_socket: 177 // this function is called whenever an sc_port (as part of a init socket) 178 // wants to bind to the export of the underlying tlm_target_socket 179 //At this time a callback binder is created an returned to the sc_port 180 // of the init socket, so that it binds to the callback binder 181 virtual tlm::tlm_fw_transport_if<TYPES>& get_base_interface() 182 { 183 //error if this socket is already bound hierarchically 184 if (m_hierarch_bind) display_error("Socket already bound hierarchically."); 185 186 if (m_export_callback_created) { 187 // consume binder created from the callback registration 188 m_export_callback_created = false; 189 } else { 190 m_binders.push_back(new callback_binder_fw<TYPES>(this, m_binders.size())); 191 } 192 193 return *m_binders[m_binders.size()-1]; 194 } 195 196 // const overload not allowed for multi-sockets 197 virtual const tlm::tlm_fw_transport_if<TYPES>& get_base_interface() const 198 { 199 display_error("'get_base_interface() const' not allowed for multi-sockets."); 200 return base_type::get_base_interface(); 201 } 202 203 //just return the export of the underlying tlm_target_socket in case of a hierarchical bind 204 virtual sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export() 205 { 206 return *this; 207 } 208 209 //just return the export of the underlying tlm_target_socket in case of a hierarchical bind 210 virtual const sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export() const 211 { 212 return base_type::get_base_export(); 213 } 214 215 //the standard end of elaboration callback 216 void end_of_elaboration(){ 217 //'break' here if the socket was told not to do callback binding 218 if (m_eoe_disabled) return; 219 220 //get the callback binders and the multi binds of the top of the hierachical bind chain 221 // NOTE: this could be the same socket if there is no hierachical bind 222 std::vector<callback_binder_fw<TYPES>* >& binders=get_hierarch_bind()->get_binders(); 223 std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& multi_binds=get_hierarch_bind()->get_multi_binds(); 224 225 // complete binding only if there has been a real bind 226 bool unbound = (binders.size() == 1 && m_export_callback_created); 227 // no call to get_base_interface has consumed the export - ignore 228 if (unbound) return; 229 230 // iterate over all binders 231 for (unsigned int i=0; i<binders.size(); i++) { 232 binders[i]->set_callbacks(m_nb_f, m_b_f, m_dmi_f, m_dbg_f); //set the callbacks for the binder 233 if (multi_binds.find(i)!=multi_binds.end()) //check if this connection is multi-multi 234 //if so remember the interface 235 m_sockets.push_back(multi_binds[i]); 236 else{ //if we are bound to a normal socket 237 //get the calling port and try to cast it into a tlm socket base 238 base_initiator_socket_type* test=dynamic_cast<base_initiator_socket_type*>(binders[i]->get_other_side()); 239 if (!test){display_error("Not bound to tlm_socket.");} 240 m_sockets.push_back(&test->get_base_interface()); //remember the interface 241 } 242 } 243 } 244 245 // 246 // Bind multi target socket to multi target socket (hierarchical bind) 247 // 248 virtual void bind(base_type& s) 249 { 250 //warn if already bound hierarchically 251 if (m_eoe_disabled){ 252 display_warning("Socket already bound hierarchically. Bind attempt ignored."); 253 return; 254 } 255 256 //disable our own end of elaboration call 257 disable_cb_bind(); 258 259 //inform the bound target socket that it is bound hierarchically now 260 s.set_hierarch_bind((base_type*)this); 261 base_type::bind(s); //satisfy SystemC 262 } 263 264 //operator notation for hierarchical bind 265 void operator() (base_type& s) 266 { 267 bind(s); 268 } 269 270 //get access to sub port 271 tlm::tlm_bw_transport_if<TYPES>* operator[](int i){return m_sockets[i];} 272 273 //get number of bound initiators 274 // NOTE: this is only valid at end of elaboration! 275 unsigned int size(){return get_hierarch_bind()->get_binders().size();} 276 277protected: 278 using base_type::display_warning; 279 using base_type::display_error; 280 281 //implementation of base class interface 282 base_type* get_hierarch_bind(){if (m_hierarch_bind) return m_hierarch_bind->get_hierarch_bind(); else return this;} 283 std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& get_multi_binds(){return m_multi_binds;} 284 void set_hierarch_bind(base_type* h){m_hierarch_bind=h;} 285 tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>* other){ 286 m_multi_binds[m_binders.size()-1]=other; 287 return m_binders[m_binders.size()-1]; 288 } 289 290 //map that stores to which index a multi init socket is connected 291 // and the interface of the multi init socket 292 std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*> m_multi_binds; 293 294 void disable_cb_bind(){ m_eoe_disabled=true;} 295 std::vector<callback_binder_fw<TYPES>* >& get_binders(){return m_binders;} 296 //vector of connected sockets 297 std::vector<tlm::tlm_bw_transport_if<TYPES>*> m_sockets; 298 //vector of binders that convert untagged interface into tagged interface 299 std::vector<callback_binder_fw<TYPES>*> m_binders; 300 301 base_type* m_hierarch_bind; //pointer to hierarchical bound multi port 302 bool m_eoe_disabled; //bool that disables callback bindings at end of elaboration 303 bool m_export_callback_created; //bool that indicates that a binder has been created from a callback registration 304 305 //callbacks as functors 306 // (allows to pass the callback to another socket that does not know the type of the module that owns 307 // the callbacks) 308 typename callback_binder_fw<TYPES>::nb_func_type m_nb_f; 309 typename callback_binder_fw<TYPES>::b_func_type m_b_f; 310 typename callback_binder_fw<TYPES>::debug_func_type m_dbg_f; 311 typename callback_binder_fw<TYPES>::dmi_func_type m_dmi_f; 312}; 313 314template <typename MODULE, 315 unsigned int BUSWIDTH = 32, 316 typename TYPES = tlm::tlm_base_protocol_types, 317 unsigned int N=0> 318class multi_passthrough_target_socket_optional 319 : public multi_passthrough_target_socket<MODULE,BUSWIDTH,TYPES,N,sc_core::SC_ZERO_OR_MORE_BOUND> 320{ 321 typedef multi_passthrough_target_socket<MODULE,BUSWIDTH,TYPES,N,sc_core::SC_ZERO_OR_MORE_BOUND> socket_b; 322public: 323 multi_passthrough_target_socket_optional() : socket_b() {} 324 explicit multi_passthrough_target_socket_optional(const char* name) : socket_b(name) {} 325}; 326 327} // namespace tlm_utils 328#endif // TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_ 329