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