113511Sgabeblack@google.com/***************************************************************************** 213511Sgabeblack@google.com 313511Sgabeblack@google.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 413511Sgabeblack@google.com more contributor license agreements. See the NOTICE file distributed 513511Sgabeblack@google.com with this work for additional information regarding copyright ownership. 613511Sgabeblack@google.com Accellera licenses this file to you under the Apache License, Version 2.0 713511Sgabeblack@google.com (the "License"); you may not use this file except in compliance with the 813511Sgabeblack@google.com License. You may obtain a copy of the License at 913511Sgabeblack@google.com 1013511Sgabeblack@google.com http://www.apache.org/licenses/LICENSE-2.0 1113511Sgabeblack@google.com 1213511Sgabeblack@google.com Unless required by applicable law or agreed to in writing, software 1313511Sgabeblack@google.com distributed under the License is distributed on an "AS IS" BASIS, 1413511Sgabeblack@google.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1513511Sgabeblack@google.com implied. See the License for the specific language governing 1613511Sgabeblack@google.com permissions and limitations under the License. 1713511Sgabeblack@google.com 1813511Sgabeblack@google.com *****************************************************************************/ 1913513Sgabeblack@google.com#ifndef __SYSTEMC_EXT_TLM_UTILS_MULTI_PASSTHROUGH_INITIATOR_SOCKET_H__ 2013513Sgabeblack@google.com#define __SYSTEMC_EXT_TLM_UTILS_MULTI_PASSTHROUGH_INITIATOR_SOCKET_H__ 2113511Sgabeblack@google.com 2213513Sgabeblack@google.com#include "tlm_utils/multi_socket_bases.h" 2313511Sgabeblack@google.com 2413513Sgabeblack@google.comnamespace tlm_utils 2513513Sgabeblack@google.com{ 2613511Sgabeblack@google.com 2713511Sgabeblack@google.com/* 2813511Sgabeblack@google.comThis class implements a trivial multi initiator socket. 2913511Sgabeblack@google.comThe triviality refers to the fact that the socket does not 3013511Sgabeblack@google.comdo blocking to non-blocking or non-blocking to blocking conversions. 3113511Sgabeblack@google.com 3213511Sgabeblack@google.comIt allows to connect multiple targets to this socket. 3313511Sgabeblack@google.comThe user has to register callbacks for the bw interface methods 3413511Sgabeblack@google.comhe likes to use. The callbacks are basically equal to the bw interface 3513511Sgabeblack@google.commethods but carry an additional integer that indicates to which 3613511Sgabeblack@google.comindex of this socket the calling target is connected. 3713511Sgabeblack@google.com*/ 3813513Sgabeblack@google.comtemplate <typename MODULE, unsigned int BUSWIDTH=32, 3913513Sgabeblack@google.com typename TYPES=tlm::tlm_base_protocol_types, unsigned int N=0, 4013513Sgabeblack@google.com sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND> 4113513Sgabeblack@google.comclass multi_passthrough_initiator_socket : 4213513Sgabeblack@google.com public multi_init_base< BUSWIDTH, TYPES, N, POL> 4313511Sgabeblack@google.com{ 4413513Sgabeblack@google.com public: 4513511Sgabeblack@google.com 4613513Sgabeblack@google.com //typedefs 4713513Sgabeblack@google.com // tlm 2.0 types for nb_transport 4813513Sgabeblack@google.com typedef typename TYPES::tlm_payload_type transaction_type; 4913513Sgabeblack@google.com typedef typename TYPES::tlm_phase_type phase_type; 5013513Sgabeblack@google.com typedef tlm::tlm_sync_enum sync_enum_type; 5113511Sgabeblack@google.com 5213513Sgabeblack@google.com // typedefs to keep the fn ptr notations short 5313513Sgabeblack@google.com typedef sync_enum_type (MODULE::*nb_cb)( 5413513Sgabeblack@google.com int, transaction_type &, phase_type &, sc_core::sc_time &); 5513513Sgabeblack@google.com typedef void (MODULE::*dmi_cb)(int, sc_dt::uint64, sc_dt::uint64); 5613511Sgabeblack@google.com 5713513Sgabeblack@google.com typedef multi_init_base<BUSWIDTH, TYPES, N, POL> base_type; 5813511Sgabeblack@google.com 5913513Sgabeblack@google.com typedef typename base_type::base_target_socket_type 6013513Sgabeblack@google.com base_target_socket_type; 6113511Sgabeblack@google.com 6213513Sgabeblack@google.com static const char * 6313513Sgabeblack@google.com default_name() 6413513Sgabeblack@google.com { 6513513Sgabeblack@google.com return sc_core::sc_gen_unique_name( 6613513Sgabeblack@google.com "multi_passthrough_initiator_socket"); 6713511Sgabeblack@google.com } 6813511Sgabeblack@google.com 6913513Sgabeblack@google.com explicit multi_passthrough_initiator_socket( 7013513Sgabeblack@google.com const char *name=default_name()) : 7113513Sgabeblack@google.com base_type(name), m_hierarch_bind(nullptr), m_beoe_disabled(false), 7213513Sgabeblack@google.com m_dummy(this, 42) 7313513Sgabeblack@google.com {} 7413511Sgabeblack@google.com 7513513Sgabeblack@google.com ~multi_passthrough_initiator_socket() 7613513Sgabeblack@google.com { 7713513Sgabeblack@google.com // Clean up everything allocated by 'new'. 7813513Sgabeblack@google.com for (unsigned int i = 0; i < m_binders.size(); i++) 7913513Sgabeblack@google.com delete m_binders[i]; 8013511Sgabeblack@google.com } 8113511Sgabeblack@google.com 8213513Sgabeblack@google.com // Register callback for nb transport of bw interface. 8313513Sgabeblack@google.com void 8413513Sgabeblack@google.com register_nb_transport_bw(MODULE *mod, sync_enum_type (MODULE::*cb)( 8513513Sgabeblack@google.com int, transaction_type &, phase_type &, sc_core::sc_time &)) 8613513Sgabeblack@google.com { 8713513Sgabeblack@google.com // Warn if there already is a callback. 8813513Sgabeblack@google.com if (m_nb_f.is_valid()) { 8913513Sgabeblack@google.com display_warning("NBTransport_bw callback already registered."); 9013513Sgabeblack@google.com return; 9113513Sgabeblack@google.com } 9213511Sgabeblack@google.com 9313513Sgabeblack@google.com // Set the functor. 9413513Sgabeblack@google.com m_nb_f.set_function(mod, cb); 9513511Sgabeblack@google.com } 9613511Sgabeblack@google.com 9713513Sgabeblack@google.com // Register callback for dmi function of bw interface. 9813513Sgabeblack@google.com void 9913513Sgabeblack@google.com register_invalidate_direct_mem_ptr(MODULE *mod, void (MODULE::*cb)( 10013513Sgabeblack@google.com int, sc_dt::uint64, sc_dt::uint64)) 10113513Sgabeblack@google.com { 10213513Sgabeblack@google.com // Warn if there already is a callback. 10313513Sgabeblack@google.com if (m_dmi_f.is_valid()) { 10413513Sgabeblack@google.com display_warning("InvalidateDMI callback already registered."); 10513513Sgabeblack@google.com return; 10613513Sgabeblack@google.com } 10713511Sgabeblack@google.com 10813513Sgabeblack@google.com // Set the functor. 10913513Sgabeblack@google.com m_dmi_f.set_function(mod, cb); 11013511Sgabeblack@google.com } 11113511Sgabeblack@google.com 11213513Sgabeblack@google.com // Override virtual functions of the tlm_initiator_socket: 11313513Sgabeblack@google.com // this function is called whenever an sc_port (as part of a target socket) 11413513Sgabeblack@google.com // wants to bind to the export of the underlying tlm_initiator_socket. 11513513Sgabeblack@google.com // At this time a callback binder is created an returned to the sc_port 11613513Sgabeblack@google.com // of the target socket, so that it binds to the callback binder. 11713513Sgabeblack@google.com virtual tlm::tlm_bw_transport_if<TYPES> & 11813513Sgabeblack@google.com get_base_interface() 11913513Sgabeblack@google.com { 12013513Sgabeblack@google.com m_binders.push_back( 12113513Sgabeblack@google.com new callback_binder_bw<TYPES>(this, m_binders.size())); 12213513Sgabeblack@google.com return *m_binders[m_binders.size() - 1]; 12313511Sgabeblack@google.com } 12413511Sgabeblack@google.com 12513513Sgabeblack@google.com // Const overload not allowed for multi-sockets. 12613513Sgabeblack@google.com virtual const tlm::tlm_bw_transport_if<TYPES> & 12713513Sgabeblack@google.com get_base_interface() const 12813513Sgabeblack@google.com { 12913513Sgabeblack@google.com display_error("'get_base_interface()'" 13013513Sgabeblack@google.com " const not allowed for multi-sockets."); 13113513Sgabeblack@google.com return base_type::get_base_interface(); 13213511Sgabeblack@google.com } 13313511Sgabeblack@google.com 13413513Sgabeblack@google.com // Override virtual functions of the tlm_initiator_socket: 13513513Sgabeblack@google.com // This function is called whenever an sc_export (as part of a initiator 13613513Sgabeblack@google.com // socket) wants to bind to the export of the underlying 13713513Sgabeblack@google.com // tlm_initiator_socket, i.e. a hierarchical bind takes place. 13813513Sgabeblack@google.com virtual sc_core::sc_export<tlm::tlm_bw_transport_if<TYPES>> & 13913513Sgabeblack@google.com get_base_export() 14013513Sgabeblack@google.com { 14113513Sgabeblack@google.com if (!m_beoe_disabled) { // We are not bound hierarchically. 14213513Sgabeblack@google.com // So we bind the dummy to avoid a SystemC error. 14313513Sgabeblack@google.com base_type::m_export.bind(m_dummy); 14413513Sgabeblack@google.com } 14513529Sgabeblack@google.com // and then return our own export so that the hierarchical 14613529Sgabeblack@google.com // binding is set up properly. 14713529Sgabeblack@google.com return base_type::get_base_export(); 14813513Sgabeblack@google.com } 14913511Sgabeblack@google.com 15013513Sgabeblack@google.com virtual const sc_core::sc_export<tlm::tlm_bw_transport_if<TYPES>> & 15113513Sgabeblack@google.com get_base_export() const 15213513Sgabeblack@google.com { 15313513Sgabeblack@google.com return base_type::get_base_export(); 15413513Sgabeblack@google.com } 15513511Sgabeblack@google.com 15613513Sgabeblack@google.com // Bind against a target socket. 15713513Sgabeblack@google.com virtual void 15813513Sgabeblack@google.com bind(base_target_socket_type &s) 15913513Sgabeblack@google.com { 16013513Sgabeblack@google.com // Error if this socket is already bound hierarchically. 16113513Sgabeblack@google.com if (m_hierarch_bind) { 16213513Sgabeblack@google.com display_error("Already hierarchically bound."); 16313513Sgabeblack@google.com return; 16413513Sgabeblack@google.com } 16513511Sgabeblack@google.com 16613513Sgabeblack@google.com // Satisfy systemC, leads to a call to get_base_interface(). 16713513Sgabeblack@google.com base_type::bind(s); 16813511Sgabeblack@google.com 16913513Sgabeblack@google.com // Try to cast the target socket into a fw interface. 17013513Sgabeblack@google.com sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES>> *p_ex_s = 17113513Sgabeblack@google.com dynamic_cast<sc_core::sc_export< 17213513Sgabeblack@google.com tlm::tlm_fw_transport_if<TYPES>> *>(&s); 17313513Sgabeblack@google.com if (!p_ex_s) { 17413513Sgabeblack@google.com display_error("Multi socket not bound to tlm_socket."); 17513513Sgabeblack@google.com return; 17613513Sgabeblack@google.com } 17713511Sgabeblack@google.com 17813513Sgabeblack@google.com // Try a cast into a multi sockets. 17913513Sgabeblack@google.com multi_to_multi_bind_base<TYPES> *test = 18013513Sgabeblack@google.com dynamic_cast<multi_to_multi_bind_base<TYPES> *>(p_ex_s); 18113513Sgabeblack@google.com if (test) { 18213513Sgabeblack@google.com // Did we just do a multi-multi bind?? 18313513Sgabeblack@google.com // If that is the case the multi target socket must have just 18413513Sgabeblack@google.com // created a callback binder which we want to get from it. 18513513Sgabeblack@google.com // Moreover, we also just created one, which we will pass to it. 18613513Sgabeblack@google.com m_sockets.push_back(test->get_last_binder( 18713513Sgabeblack@google.com m_binders[m_binders.size() - 1])); 18813513Sgabeblack@google.com } else { // If not just bind normally, 18913513Sgabeblack@google.com sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES>> &ex_s = 19013513Sgabeblack@google.com *p_ex_s; 19113513Sgabeblack@google.com // Store the interface we are bound against. 19213513Sgabeblack@google.com m_sockets.push_back(&((tlm::tlm_fw_transport_if<TYPES> &)ex_s)); 19313513Sgabeblack@google.com } 19413513Sgabeblack@google.com } 19513511Sgabeblack@google.com 19613513Sgabeblack@google.com // Operator notation for direct bind. 19713513Sgabeblack@google.com void operator() (base_target_socket_type &s) { bind(s); } 19813511Sgabeblack@google.com 19913513Sgabeblack@google.com // SystemC standard callback before end of elaboration. 20013513Sgabeblack@google.com void 20113513Sgabeblack@google.com before_end_of_elaboration() 20213513Sgabeblack@google.com { 20313513Sgabeblack@google.com // If our export hasn't been bound yet (due to a hierarch binding) 20413513Sgabeblack@google.com // we bind it now to avoid a SystemC error. We must do that because it 20513513Sgabeblack@google.com // is legal not to register a callback on this socket as the user 20613513Sgabeblack@google.com // might only use b_transport. 20713513Sgabeblack@google.com if (!base_type::m_export.get_interface()) { 20813513Sgabeblack@google.com base_type::m_export.bind(m_dummy); 20913513Sgabeblack@google.com } 21013513Sgabeblack@google.com 21113513Sgabeblack@google.com // 'break' here if the socket was told not to do callback binding. 21213513Sgabeblack@google.com if (m_beoe_disabled) 21313513Sgabeblack@google.com return; 21413513Sgabeblack@google.com 21513513Sgabeblack@google.com // Get the callback binders of the top of the hierachical bind chain. 21613513Sgabeblack@google.com // NOTE: this could be the same socket if there is no hierachical bind. 21713513Sgabeblack@google.com std::vector<callback_binder_bw<TYPES> *> &binders = 21813513Sgabeblack@google.com get_hierarch_bind()->get_binders(); 21913513Sgabeblack@google.com 22013513Sgabeblack@google.com // Get the interfaces bound to the top of the hierachical bind chain. 22113513Sgabeblack@google.com // NOTE: this could be the same socket if there is no hierachical bind. 22213513Sgabeblack@google.com m_used_sockets = get_hierarch_bind()->get_sockets(); 22313513Sgabeblack@google.com 22413513Sgabeblack@google.com // Register the callbacks of this socket with the callback binders 22513513Sgabeblack@google.com // we just got from the top of the hierachical bind chain. 22613513Sgabeblack@google.com for (unsigned int i = 0; i < binders.size(); i++) { 22713513Sgabeblack@google.com binders[i]->set_callbacks(m_nb_f, m_dmi_f); 22813513Sgabeblack@google.com } 22913513Sgabeblack@google.com } 23013513Sgabeblack@google.com 23113513Sgabeblack@google.com // 23213513Sgabeblack@google.com // Bind multi initiator socket to multi initiator socket (hierarchical 23313513Sgabeblack@google.com // bind). 23413513Sgabeblack@google.com // 23513513Sgabeblack@google.com virtual void 23613513Sgabeblack@google.com bind(base_type& s) 23713513Sgabeblack@google.com { 23813513Sgabeblack@google.com if (m_binders.size()) { 23913513Sgabeblack@google.com // A multi socket is either bound hierarchically or directly. 24013513Sgabeblack@google.com display_error("Socket already directly bound."); 24113513Sgabeblack@google.com return; 24213513Sgabeblack@google.com } 24313513Sgabeblack@google.com if (m_hierarch_bind) { 24413513Sgabeblack@google.com display_warning("Socket already bound hierarchically. " 24513513Sgabeblack@google.com "Bind attempt ignored."); 24613513Sgabeblack@google.com return; 24713513Sgabeblack@google.com } 24813513Sgabeblack@google.com 24913513Sgabeblack@google.com // Remember to which socket we are hierarchically bound and disable it, 25013513Sgabeblack@google.com // so that it won't try to register callbacks itself. 25113513Sgabeblack@google.com s.disable_cb_bind(); 25213513Sgabeblack@google.com m_hierarch_bind = &s; 25313513Sgabeblack@google.com base_type::bind(s); // Satisfy SystemC. 25413513Sgabeblack@google.com } 25513513Sgabeblack@google.com 25613513Sgabeblack@google.com // Operator notation for hierarchical bind. 25713513Sgabeblack@google.com void operator() (base_type &s) { bind(s); } 25813513Sgabeblack@google.com 25913513Sgabeblack@google.com // Get access to sub port. 26013513Sgabeblack@google.com tlm::tlm_fw_transport_if<TYPES> * 26113513Sgabeblack@google.com operator [] (int i) 26213513Sgabeblack@google.com { 26313513Sgabeblack@google.com return m_used_sockets[i]; 26413513Sgabeblack@google.com } 26513513Sgabeblack@google.com 26613513Sgabeblack@google.com // Get the number of bound targets. 26713513Sgabeblack@google.com // NOTE: This is only valid at end of elaboration! 26813513Sgabeblack@google.com unsigned int size() { return get_hierarch_bind()->get_sockets().size(); } 26913513Sgabeblack@google.com 27013513Sgabeblack@google.com protected: 27113513Sgabeblack@google.com using base_type::display_warning; 27213513Sgabeblack@google.com using base_type::display_error; 27313513Sgabeblack@google.com 27413513Sgabeblack@google.com // Implementation of base class interface. 27513513Sgabeblack@google.com base_type * 27613513Sgabeblack@google.com get_hierarch_bind() 27713513Sgabeblack@google.com { 27813513Sgabeblack@google.com if (m_hierarch_bind) 27913513Sgabeblack@google.com return m_hierarch_bind->get_hierarch_bind(); 28013513Sgabeblack@google.com else 28113513Sgabeblack@google.com return this; 28213513Sgabeblack@google.com } 28313513Sgabeblack@google.com void disable_cb_bind() { m_beoe_disabled = true; } 28413513Sgabeblack@google.com std::vector<callback_binder_bw<TYPES> *> & 28513513Sgabeblack@google.com get_binders() 28613513Sgabeblack@google.com { 28713513Sgabeblack@google.com return m_binders; 28813513Sgabeblack@google.com } 28913513Sgabeblack@google.com std::vector<tlm::tlm_fw_transport_if<TYPES> *> & 29013513Sgabeblack@google.com get_sockets() 29113513Sgabeblack@google.com { 29213513Sgabeblack@google.com return m_sockets; 29313513Sgabeblack@google.com } 29413513Sgabeblack@google.com // Vector of connected sockets. 29513513Sgabeblack@google.com std::vector<tlm::tlm_fw_transport_if<TYPES> *> m_sockets; 29613513Sgabeblack@google.com std::vector<tlm::tlm_fw_transport_if<TYPES> *> m_used_sockets; 29713513Sgabeblack@google.com // Vector of binders that convert untagged interface into tagged interface. 29813513Sgabeblack@google.com std::vector<callback_binder_bw<TYPES> *> m_binders; 29913513Sgabeblack@google.com 30013513Sgabeblack@google.com base_type *m_hierarch_bind; // Pointer to hierarchical bound multi port. 30113513Sgabeblack@google.com // bool that remembers whether this socket shall bind callbacks or not. 30213513Sgabeblack@google.com bool m_beoe_disabled; 30313513Sgabeblack@google.com // A callback binder that is bound to the underlying export 30413513Sgabeblack@google.com // in case there was no real bind. 30513513Sgabeblack@google.com callback_binder_bw<TYPES> m_dummy; 30613513Sgabeblack@google.com 30713513Sgabeblack@google.com //callbacks as functors 30813513Sgabeblack@google.com // (allows to pass the callback to another socket that does not know the 30913513Sgabeblack@google.com // type of the module that owns the callbacks). 31013513Sgabeblack@google.com typename callback_binder_bw<TYPES>::nb_func_type m_nb_f; 31113513Sgabeblack@google.com typename callback_binder_bw<TYPES>::dmi_func_type m_dmi_f; 31213511Sgabeblack@google.com}; 31313511Sgabeblack@google.com 31413513Sgabeblack@google.comtemplate <typename MODULE, unsigned int BUSWIDTH=32, 31513513Sgabeblack@google.com typename TYPES=tlm::tlm_base_protocol_types, unsigned int N=0> 31613513Sgabeblack@google.comclass multi_passthrough_initiator_socket_optional : 31713513Sgabeblack@google.com public multi_passthrough_initiator_socket< 31813513Sgabeblack@google.com MODULE, BUSWIDTH, TYPES, N, sc_core::SC_ZERO_OR_MORE_BOUND> 31913511Sgabeblack@google.com{ 32013513Sgabeblack@google.com typedef multi_passthrough_initiator_socket< 32113513Sgabeblack@google.com MODULE, BUSWIDTH, TYPES, N, sc_core::SC_ZERO_OR_MORE_BOUND> socket_b; 32213513Sgabeblack@google.com public: 32313513Sgabeblack@google.com multi_passthrough_initiator_socket_optional() : socket_b() {} 32413513Sgabeblack@google.com explicit multi_passthrough_initiator_socket_optional(const char *name) : 32513513Sgabeblack@google.com socket_b(name) 32613513Sgabeblack@google.com {} 32713511Sgabeblack@google.com}; 32813511Sgabeblack@google.com 32913511Sgabeblack@google.com} // namespace tlm_utils 33013513Sgabeblack@google.com 33113513Sgabeblack@google.com#endif /* __SYSTEMC_EXT_TLM_UTILS_MULTI_PASSTHROUGH_INITIATOR_SOCKET_H__ */ 332