multi_passthrough_target_socket.h revision 12027:1eb7dc7aa10b
111666Stushar@ece.gatech.edu/*****************************************************************************
211666Stushar@ece.gatech.edu
311666Stushar@ece.gatech.edu  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
411666Stushar@ece.gatech.edu  more contributor license agreements.  See the NOTICE file distributed
511666Stushar@ece.gatech.edu  with this work for additional information regarding copyright ownership.
611666Stushar@ece.gatech.edu  Accellera licenses this file to you under the Apache License, Version 2.0
711666Stushar@ece.gatech.edu  (the "License"); you may not use this file except in compliance with the
811666Stushar@ece.gatech.edu  License.  You may obtain a copy of the License at
911666Stushar@ece.gatech.edu
1011666Stushar@ece.gatech.edu    http://www.apache.org/licenses/LICENSE-2.0
1111666Stushar@ece.gatech.edu
1211666Stushar@ece.gatech.edu  Unless required by applicable law or agreed to in writing, software
1311666Stushar@ece.gatech.edu  distributed under the License is distributed on an "AS IS" BASIS,
1411666Stushar@ece.gatech.edu  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1511666Stushar@ece.gatech.edu  implied.  See the License for the specific language governing
1611666Stushar@ece.gatech.edu  permissions and limitations under the License.
1711666Stushar@ece.gatech.edu
1811666Stushar@ece.gatech.edu *****************************************************************************/
1911666Stushar@ece.gatech.edu#ifndef __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
2011666Stushar@ece.gatech.edu#define __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
2111666Stushar@ece.gatech.edu
2211666Stushar@ece.gatech.edu#include "tlm_utils/multi_socket_bases.h"
2311666Stushar@ece.gatech.edu#include <sstream>
2411666Stushar@ece.gatech.edu
2511666Stushar@ece.gatech.edunamespace tlm_utils {
2611666Stushar@ece.gatech.edu
2711666Stushar@ece.gatech.edu/*
2811666Stushar@ece.gatech.eduThis class implements a trivial multi target socket.
2911666Stushar@ece.gatech.eduThe triviality refers to the fact that the socket does not
3011666Stushar@ece.gatech.edudo blocking to non-blocking or non-blocking to blocking conversions.
3111666Stushar@ece.gatech.edu
3211666Stushar@ece.gatech.eduIt allows to connect multiple initiators to this socket.
3311666Stushar@ece.gatech.eduThe user has to register callbacks for the fw interface methods
3411666Stushar@ece.gatech.eduhe likes to use. The callbacks are basically equal to the fw interface
3511666Stushar@ece.gatech.edumethods but carry an additional integer that indicates to which
3611666Stushar@ece.gatech.eduindex of this socket the calling initiator is connected.
3711666Stushar@ece.gatech.edu*/
3811666Stushar@ece.gatech.edutemplate <typename MODULE,
3911666Stushar@ece.gatech.edu          unsigned int BUSWIDTH = 32,
4011666Stushar@ece.gatech.edu          typename TYPES = tlm::tlm_base_protocol_types,
4111666Stushar@ece.gatech.edu          unsigned int N=0
4211666Stushar@ece.gatech.edu#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
4311797Smatthew.poremba@amd.com          ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND
4411666Stushar@ece.gatech.edu#endif
4511666Stushar@ece.gatech.edu          >
4611666Stushar@ece.gatech.educlass multi_passthrough_target_socket: public multi_target_base< BUSWIDTH,
4711666Stushar@ece.gatech.edu                                                        TYPES,
4811666Stushar@ece.gatech.edu                                                        N
4911666Stushar@ece.gatech.edu#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
5011666Stushar@ece.gatech.edu                                                        ,POL
5111666Stushar@ece.gatech.edu#endif
5211666Stushar@ece.gatech.edu                                                        >
5311666Stushar@ece.gatech.edu                              , public multi_to_multi_bind_base<TYPES>
5411666Stushar@ece.gatech.edu{
5511666Stushar@ece.gatech.edu
5611666Stushar@ece.gatech.edupublic:
5711666Stushar@ece.gatech.edu
5811666Stushar@ece.gatech.edu  //typedefs
5911666Stushar@ece.gatech.edu  //  tlm 2.0 types for nb_transport
6011666Stushar@ece.gatech.edu  typedef typename TYPES::tlm_payload_type              transaction_type;
6111666Stushar@ece.gatech.edu  typedef typename TYPES::tlm_phase_type                phase_type;
6211666Stushar@ece.gatech.edu  typedef tlm::tlm_sync_enum                            sync_enum_type;
6311666Stushar@ece.gatech.edu
6411666Stushar@ece.gatech.edu  //  typedefs to keep the fn ptr notations short
6511666Stushar@ece.gatech.edu  typedef sync_enum_type (MODULE::*nb_cb)(int, transaction_type&, phase_type&, sc_core::sc_time&);
6611666Stushar@ece.gatech.edu  typedef void (MODULE::*b_cb)(int, transaction_type&, sc_core::sc_time&);
6711666Stushar@ece.gatech.edu  typedef unsigned int (MODULE::*dbg_cb)(int, transaction_type& txn);
6811666Stushar@ece.gatech.edu  typedef bool (MODULE::*dmi_cb)(int, transaction_type& txn, tlm::tlm_dmi& dmi);
6911666Stushar@ece.gatech.edu
7011666Stushar@ece.gatech.edu  typedef multi_target_base<BUSWIDTH,
7111666Stushar@ece.gatech.edu                        TYPES,
7211666Stushar@ece.gatech.edu                        N
7311666Stushar@ece.gatech.edu#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
7411666Stushar@ece.gatech.edu                        ,POL
7511666Stushar@ece.gatech.edu#endif
7611666Stushar@ece.gatech.edu                        > base_type;
7711666Stushar@ece.gatech.edu
7811666Stushar@ece.gatech.edu  typedef typename base_type::base_initiator_socket_type base_initiator_socket_type;
7911666Stushar@ece.gatech.edu
8011666Stushar@ece.gatech.edu  //CTOR
8111666Stushar@ece.gatech.edu  multi_passthrough_target_socket()
8211666Stushar@ece.gatech.edu      : base_type(sc_core::sc_gen_unique_name("multi_passthrough_target_socket"))
8311666Stushar@ece.gatech.edu      , m_hierarch_bind(0)
8411666Stushar@ece.gatech.edu      , m_eoe_disabled(false)
8511666Stushar@ece.gatech.edu      , m_export_callback_created(false)
8611666Stushar@ece.gatech.edu  {
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