multi_passthrough_target_socket.h revision 13511
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 *****************************************************************************/
1913511Sgabeblack@google.com#ifndef TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_
2013511Sgabeblack@google.com#define TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_
2113511Sgabeblack@google.com
2213511Sgabeblack@google.com#include "tlm_utils/multi_socket_bases.h"
2313511Sgabeblack@google.com
2413511Sgabeblack@google.comnamespace tlm_utils {
2513511Sgabeblack@google.com
2613511Sgabeblack@google.com/*
2713511Sgabeblack@google.comThis class implements a trivial multi target socket.
2813511Sgabeblack@google.comThe triviality refers to the fact that the socket does not
2913511Sgabeblack@google.comdo blocking to non-blocking or non-blocking to blocking conversions.
3013511Sgabeblack@google.com
3113511Sgabeblack@google.comIt allows to connect multiple initiators to this socket.
3213511Sgabeblack@google.comThe user has to register callbacks for the fw interface methods
3313511Sgabeblack@google.comhe likes to use. The callbacks are basically equal to the fw interface
3413511Sgabeblack@google.commethods but carry an additional integer that indicates to which
3513511Sgabeblack@google.comindex of this socket the calling initiator is connected.
3613511Sgabeblack@google.com*/
3713511Sgabeblack@google.comtemplate <typename MODULE,
3813511Sgabeblack@google.com          unsigned int BUSWIDTH = 32,
3913511Sgabeblack@google.com          typename TYPES = tlm::tlm_base_protocol_types,
4013511Sgabeblack@google.com          unsigned int N=0,
4113511Sgabeblack@google.com          sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
4213511Sgabeblack@google.comclass multi_passthrough_target_socket
4313511Sgabeblack@google.com  : public multi_target_base< BUSWIDTH, TYPES, N, POL>
4413511Sgabeblack@google.com  , public multi_to_multi_bind_base<TYPES>
4513511Sgabeblack@google.com{
4613511Sgabeblack@google.com
4713511Sgabeblack@google.compublic:
4813511Sgabeblack@google.com
4913511Sgabeblack@google.com  //typedefs
5013511Sgabeblack@google.com  //  tlm 2.0 types for nb_transport
5113511Sgabeblack@google.com  typedef typename TYPES::tlm_payload_type              transaction_type;
5213511Sgabeblack@google.com  typedef typename TYPES::tlm_phase_type                phase_type;
5313511Sgabeblack@google.com  typedef tlm::tlm_sync_enum                            sync_enum_type;
5413511Sgabeblack@google.com
5513511Sgabeblack@google.com  //  typedefs to keep the fn ptr notations short
5613511Sgabeblack@google.com  typedef sync_enum_type (MODULE::*nb_cb)(int, transaction_type&, phase_type&, sc_core::sc_time&);
5713511Sgabeblack@google.com  typedef void (MODULE::*b_cb)(int, transaction_type&, sc_core::sc_time&);
5813511Sgabeblack@google.com  typedef unsigned int (MODULE::*dbg_cb)(int, transaction_type& txn);
5913511Sgabeblack@google.com  typedef bool (MODULE::*dmi_cb)(int, transaction_type& txn, tlm::tlm_dmi& dmi);
6013511Sgabeblack@google.com
6113511Sgabeblack@google.com  typedef multi_target_base<BUSWIDTH, TYPES, N, POL> base_type;
6213511Sgabeblack@google.com
6313511Sgabeblack@google.com  typedef typename base_type::base_initiator_socket_type base_initiator_socket_type;
6413511Sgabeblack@google.com
6513511Sgabeblack@google.com  static const char* default_name()
6613511Sgabeblack@google.com    { return sc_core::sc_gen_unique_name("multi_passthrough_target_socket"); }
6713511Sgabeblack@google.com
6813511Sgabeblack@google.com  //CTOR
6913511Sgabeblack@google.com  explicit multi_passthrough_target_socket(const char* name = default_name())
7013511Sgabeblack@google.com      : base_type(name)
7113511Sgabeblack@google.com      , m_hierarch_bind(0)
7213511Sgabeblack@google.com      , m_eoe_disabled(false)
7313511Sgabeblack@google.com      , m_export_callback_created(false)
7413511Sgabeblack@google.com  {
7513511Sgabeblack@google.com  }
7613511Sgabeblack@google.com
7713511Sgabeblack@google.com  ~multi_passthrough_target_socket(){
7813511Sgabeblack@google.com    //clean up everything allocated by 'new'
7913511Sgabeblack@google.com    for (unsigned int i=0; i<m_binders.size(); i++) delete m_binders[i];
8013511Sgabeblack@google.com  }
8113511Sgabeblack@google.com
8213511Sgabeblack@google.com  void check_export_binding()
8313511Sgabeblack@google.com  {
8413511Sgabeblack@google.com    //if our export hasn't been bound yet (due to a hierarch binding)
8513511Sgabeblack@google.com    //  we bind it now.
8613511Sgabeblack@google.com    //We do that here as the user of the target port HAS to bind at least on callback,
8713511Sgabeblack@google.com    //otherwise the socket was useless. Nevertheless, the target socket may still
8813511Sgabeblack@google.com    // stay unbound afterwards.
8913511Sgabeblack@google.com    if (!sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::get_interface())
9013511Sgabeblack@google.com    {
9113511Sgabeblack@google.com      // We bind to a callback_binder that will be used as the first interface
9213511Sgabeblack@google.com      // i.e. calls to the sc_export will have the same ID as calls from the first initator
9313511Sgabeblack@google.com      // socket bound
9413511Sgabeblack@google.com      callback_binder_fw<TYPES> * binder;
9513511Sgabeblack@google.com
9613511Sgabeblack@google.com      if (m_binders.size() == 0)
9713511Sgabeblack@google.com      {
9813511Sgabeblack@google.com        binder = new callback_binder_fw<TYPES>(this, m_binders.size());
9913511Sgabeblack@google.com        m_binders.push_back(binder);
10013511Sgabeblack@google.com        m_export_callback_created = true;
10113511Sgabeblack@google.com      }
10213511Sgabeblack@google.com      else
10313511Sgabeblack@google.com      {
10413511Sgabeblack@google.com        binder = m_binders[0];
10513511Sgabeblack@google.com      }
10613511Sgabeblack@google.com
10713511Sgabeblack@google.com      sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::bind(*binder);
10813511Sgabeblack@google.com    }
10913511Sgabeblack@google.com  }
11013511Sgabeblack@google.com
11113511Sgabeblack@google.com  //register callback for nb transport of fw interface
11213511Sgabeblack@google.com  void register_nb_transport_fw(MODULE* mod,
11313511Sgabeblack@google.com                              nb_cb cb)
11413511Sgabeblack@google.com  {
11513511Sgabeblack@google.com    check_export_binding();
11613511Sgabeblack@google.com
11713511Sgabeblack@google.com    //warn if there already is a callback
11813511Sgabeblack@google.com    if (m_nb_f.is_valid()){
11913511Sgabeblack@google.com      display_warning("NBTransport_bw callback already registered.");
12013511Sgabeblack@google.com      return;
12113511Sgabeblack@google.com    }
12213511Sgabeblack@google.com
12313511Sgabeblack@google.com    //set the functor
12413511Sgabeblack@google.com    m_nb_f.set_function(mod, cb);
12513511Sgabeblack@google.com  }
12613511Sgabeblack@google.com
12713511Sgabeblack@google.com  //register callback for b transport of fw interface
12813511Sgabeblack@google.com  void register_b_transport(MODULE* mod,
12913511Sgabeblack@google.com                              b_cb cb)
13013511Sgabeblack@google.com  {
13113511Sgabeblack@google.com    check_export_binding();
13213511Sgabeblack@google.com
13313511Sgabeblack@google.com    //warn if there already is a callback
13413511Sgabeblack@google.com    if (m_b_f.is_valid()){
13513511Sgabeblack@google.com      display_warning("BTransport callback already registered.");
13613511Sgabeblack@google.com      return;
13713511Sgabeblack@google.com    }
13813511Sgabeblack@google.com
13913511Sgabeblack@google.com    //set the functor
14013511Sgabeblack@google.com    m_b_f.set_function(mod, cb);
14113511Sgabeblack@google.com  }
14213511Sgabeblack@google.com
14313511Sgabeblack@google.com  //register callback for debug transport of fw interface
14413511Sgabeblack@google.com  void register_transport_dbg(MODULE* mod,
14513511Sgabeblack@google.com                              dbg_cb cb)
14613511Sgabeblack@google.com  {
14713511Sgabeblack@google.com    check_export_binding();
14813511Sgabeblack@google.com
14913511Sgabeblack@google.com    //warn if there already is a callback
15013511Sgabeblack@google.com    if (m_dbg_f.is_valid()){
15113511Sgabeblack@google.com      display_warning("DebugTransport callback already registered.");
15213511Sgabeblack@google.com      return;
15313511Sgabeblack@google.com    }
15413511Sgabeblack@google.com
15513511Sgabeblack@google.com    //set the functor
15613511Sgabeblack@google.com    m_dbg_f.set_function(mod, cb);
15713511Sgabeblack@google.com  }
15813511Sgabeblack@google.com
15913511Sgabeblack@google.com  //register callback for DMI of fw interface
16013511Sgabeblack@google.com  void register_get_direct_mem_ptr(MODULE* mod,
16113511Sgabeblack@google.com                                   dmi_cb cb)
16213511Sgabeblack@google.com  {
16313511Sgabeblack@google.com    check_export_binding();
16413511Sgabeblack@google.com
16513511Sgabeblack@google.com    //warn if there already is a callback
16613511Sgabeblack@google.com    if (m_dmi_f.is_valid()){
16713511Sgabeblack@google.com      display_warning("DMI callback already registered.");
16813511Sgabeblack@google.com      return;
16913511Sgabeblack@google.com    }
17013511Sgabeblack@google.com
17113511Sgabeblack@google.com    //set the functor
17213511Sgabeblack@google.com    m_dmi_f.set_function(mod, cb);
17313511Sgabeblack@google.com  }
17413511Sgabeblack@google.com
17513511Sgabeblack@google.com
17613511Sgabeblack@google.com  //Override virtual functions of the tlm_target_socket:
17713511Sgabeblack@google.com  // this function is called whenever an sc_port (as part of a init socket)
17813511Sgabeblack@google.com  //  wants to bind to the export of the underlying tlm_target_socket
17913511Sgabeblack@google.com  //At this time a callback binder is created an returned to the sc_port
18013511Sgabeblack@google.com  // of the init socket, so that it binds to the callback binder
18113511Sgabeblack@google.com  virtual tlm::tlm_fw_transport_if<TYPES>& get_base_interface()
18213511Sgabeblack@google.com  {
18313511Sgabeblack@google.com    //error if this socket is already bound hierarchically
18413511Sgabeblack@google.com    if (m_hierarch_bind) display_error("Socket already bound hierarchically.");
18513511Sgabeblack@google.com
18613511Sgabeblack@google.com    if (m_export_callback_created) {
18713511Sgabeblack@google.com      // consume binder created from the callback registration
18813511Sgabeblack@google.com      m_export_callback_created = false;
18913511Sgabeblack@google.com    } else {
19013511Sgabeblack@google.com      m_binders.push_back(new callback_binder_fw<TYPES>(this, m_binders.size()));
19113511Sgabeblack@google.com    }
19213511Sgabeblack@google.com
19313511Sgabeblack@google.com    return *m_binders[m_binders.size()-1];
19413511Sgabeblack@google.com  }
19513511Sgabeblack@google.com
19613511Sgabeblack@google.com  // const overload not allowed for multi-sockets
19713511Sgabeblack@google.com  virtual const tlm::tlm_fw_transport_if<TYPES>& get_base_interface() const
19813511Sgabeblack@google.com  {
19913511Sgabeblack@google.com    display_error("'get_base_interface() const' not allowed for multi-sockets.");
20013511Sgabeblack@google.com    return base_type::get_base_interface();
20113511Sgabeblack@google.com  }
20213511Sgabeblack@google.com
20313511Sgabeblack@google.com  //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
20413511Sgabeblack@google.com  virtual sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export()
20513511Sgabeblack@google.com  {
20613511Sgabeblack@google.com    return *this;
20713511Sgabeblack@google.com  }
20813511Sgabeblack@google.com
20913511Sgabeblack@google.com  //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
21013511Sgabeblack@google.com  virtual const sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export() const
21113511Sgabeblack@google.com  {
21213511Sgabeblack@google.com    return base_type::get_base_export();
21313511Sgabeblack@google.com  }
21413511Sgabeblack@google.com
21513511Sgabeblack@google.com  //the standard end of elaboration callback
21613511Sgabeblack@google.com  void end_of_elaboration(){
21713511Sgabeblack@google.com    //'break' here if the socket was told not to do callback binding
21813511Sgabeblack@google.com    if (m_eoe_disabled) return;
21913511Sgabeblack@google.com
22013511Sgabeblack@google.com    //get the callback binders and the multi binds of the top of the hierachical bind chain
22113511Sgabeblack@google.com    // NOTE: this could be the same socket if there is no hierachical bind
22213511Sgabeblack@google.com    std::vector<callback_binder_fw<TYPES>* >& binders=get_hierarch_bind()->get_binders();
22313511Sgabeblack@google.com    std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>&  multi_binds=get_hierarch_bind()->get_multi_binds();
22413511Sgabeblack@google.com
22513511Sgabeblack@google.com    // complete binding only if there has been a real bind
22613511Sgabeblack@google.com    bool unbound = (binders.size() == 1 && m_export_callback_created);
22713511Sgabeblack@google.com    // no call to get_base_interface has consumed the export - ignore
22813511Sgabeblack@google.com    if (unbound) return;
22913511Sgabeblack@google.com
23013511Sgabeblack@google.com    // iterate over all binders
23113511Sgabeblack@google.com    for (unsigned int i=0; i<binders.size(); i++) {
23213511Sgabeblack@google.com      binders[i]->set_callbacks(m_nb_f, m_b_f, m_dmi_f, m_dbg_f); //set the callbacks for the binder
23313511Sgabeblack@google.com      if (multi_binds.find(i)!=multi_binds.end()) //check if this connection is multi-multi
23413511Sgabeblack@google.com        //if so remember the interface
23513511Sgabeblack@google.com        m_sockets.push_back(multi_binds[i]);
23613511Sgabeblack@google.com      else{ //if we are bound to a normal socket
23713511Sgabeblack@google.com        //get the calling port and try to cast it into a tlm socket base
23813511Sgabeblack@google.com        base_initiator_socket_type* test=dynamic_cast<base_initiator_socket_type*>(binders[i]->get_other_side());
23913511Sgabeblack@google.com        if (!test){display_error("Not bound to tlm_socket.");}
24013511Sgabeblack@google.com        m_sockets.push_back(&test->get_base_interface()); //remember the interface
24113511Sgabeblack@google.com      }
24213511Sgabeblack@google.com    }
24313511Sgabeblack@google.com  }
24413511Sgabeblack@google.com
24513511Sgabeblack@google.com  //
24613511Sgabeblack@google.com  // Bind multi target socket to multi target socket (hierarchical bind)
24713511Sgabeblack@google.com  //
24813511Sgabeblack@google.com  virtual void bind(base_type& s)
24913511Sgabeblack@google.com  {
25013511Sgabeblack@google.com    //warn if already bound hierarchically
25113511Sgabeblack@google.com    if (m_eoe_disabled){
25213511Sgabeblack@google.com      display_warning("Socket already bound hierarchically. Bind attempt ignored.");
25313511Sgabeblack@google.com      return;
25413511Sgabeblack@google.com    }
25513511Sgabeblack@google.com
25613511Sgabeblack@google.com    //disable our own end of elaboration call
25713511Sgabeblack@google.com    disable_cb_bind();
25813511Sgabeblack@google.com
25913511Sgabeblack@google.com    //inform the bound target socket that it is bound hierarchically now
26013511Sgabeblack@google.com    s.set_hierarch_bind((base_type*)this);
26113511Sgabeblack@google.com    base_type::bind(s); //satisfy SystemC
26213511Sgabeblack@google.com  }
26313511Sgabeblack@google.com
26413511Sgabeblack@google.com  //operator notation for hierarchical bind
26513511Sgabeblack@google.com  void operator() (base_type& s)
26613511Sgabeblack@google.com  {
26713511Sgabeblack@google.com    bind(s);
26813511Sgabeblack@google.com  }
26913511Sgabeblack@google.com
27013511Sgabeblack@google.com  //get access to sub port
27113511Sgabeblack@google.com  tlm::tlm_bw_transport_if<TYPES>* operator[](int i){return m_sockets[i];}
27213511Sgabeblack@google.com
27313511Sgabeblack@google.com  //get number of bound initiators
27413511Sgabeblack@google.com  // NOTE: this is only valid at end of elaboration!
27513511Sgabeblack@google.com  unsigned int size(){return get_hierarch_bind()->get_binders().size();}
27613511Sgabeblack@google.com
27713511Sgabeblack@google.comprotected:
27813511Sgabeblack@google.com  using base_type::display_warning;
27913511Sgabeblack@google.com  using base_type::display_error;
28013511Sgabeblack@google.com
28113511Sgabeblack@google.com  //implementation of base class interface
28213511Sgabeblack@google.com  base_type* get_hierarch_bind(){if (m_hierarch_bind) return m_hierarch_bind->get_hierarch_bind(); else return this;}
28313511Sgabeblack@google.com  std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>&  get_multi_binds(){return m_multi_binds;}
28413511Sgabeblack@google.com  void set_hierarch_bind(base_type* h){m_hierarch_bind=h;}
28513511Sgabeblack@google.com  tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>* other){
28613511Sgabeblack@google.com    m_multi_binds[m_binders.size()-1]=other;
28713511Sgabeblack@google.com    return m_binders[m_binders.size()-1];
28813511Sgabeblack@google.com  }
28913511Sgabeblack@google.com
29013511Sgabeblack@google.com  //map that stores to which index a multi init socket is connected
29113511Sgabeblack@google.com  // and the interface of the multi init socket
29213511Sgabeblack@google.com  std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*> m_multi_binds;
29313511Sgabeblack@google.com
29413511Sgabeblack@google.com  void disable_cb_bind(){ m_eoe_disabled=true;}
29513511Sgabeblack@google.com  std::vector<callback_binder_fw<TYPES>* >& get_binders(){return m_binders;}
29613511Sgabeblack@google.com  //vector of connected sockets
29713511Sgabeblack@google.com  std::vector<tlm::tlm_bw_transport_if<TYPES>*> m_sockets;
29813511Sgabeblack@google.com  //vector of binders that convert untagged interface into tagged interface
29913511Sgabeblack@google.com  std::vector<callback_binder_fw<TYPES>*> m_binders;
30013511Sgabeblack@google.com
30113511Sgabeblack@google.com  base_type*  m_hierarch_bind; //pointer to hierarchical bound multi port
30213511Sgabeblack@google.com  bool m_eoe_disabled; //bool that disables callback bindings at end of elaboration
30313511Sgabeblack@google.com  bool m_export_callback_created; //bool that indicates that a binder has been created from a callback registration
30413511Sgabeblack@google.com
30513511Sgabeblack@google.com  //callbacks as functors
30613511Sgabeblack@google.com  // (allows to pass the callback to another socket that does not know the type of the module that owns
30713511Sgabeblack@google.com  //  the callbacks)
30813511Sgabeblack@google.com  typename callback_binder_fw<TYPES>::nb_func_type    m_nb_f;
30913511Sgabeblack@google.com  typename callback_binder_fw<TYPES>::b_func_type     m_b_f;
31013511Sgabeblack@google.com  typename callback_binder_fw<TYPES>::debug_func_type m_dbg_f;
31113511Sgabeblack@google.com  typename callback_binder_fw<TYPES>::dmi_func_type   m_dmi_f;
31213511Sgabeblack@google.com};
31313511Sgabeblack@google.com
31413511Sgabeblack@google.comtemplate <typename MODULE,
31513511Sgabeblack@google.com          unsigned int BUSWIDTH = 32,
31613511Sgabeblack@google.com          typename TYPES = tlm::tlm_base_protocol_types,
31713511Sgabeblack@google.com          unsigned int N=0>
31813511Sgabeblack@google.comclass multi_passthrough_target_socket_optional
31913511Sgabeblack@google.com  : public multi_passthrough_target_socket<MODULE,BUSWIDTH,TYPES,N,sc_core::SC_ZERO_OR_MORE_BOUND>
32013511Sgabeblack@google.com{
32113511Sgabeblack@google.com  typedef multi_passthrough_target_socket<MODULE,BUSWIDTH,TYPES,N,sc_core::SC_ZERO_OR_MORE_BOUND> socket_b;
32213511Sgabeblack@google.compublic:
32313511Sgabeblack@google.com  multi_passthrough_target_socket_optional() : socket_b() {}
32413511Sgabeblack@google.com  explicit multi_passthrough_target_socket_optional(const char* name) : socket_b(name) {}
32513511Sgabeblack@google.com};
32613511Sgabeblack@google.com
32713511Sgabeblack@google.com} // namespace tlm_utils
32813511Sgabeblack@google.com#endif // TLM_UTILS_MULTI_PASSTHROUGH_TARGET_SOCKET_H_INCLUDED_
329