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
20#ifndef __PASSTHROUGH_TARGET_SOCKET_H__
21#define __PASSTHROUGH_TARGET_SOCKET_H__
22
23#include <tlm>
24#include <sstream>
25
26namespace tlm_utils {
27
28template <typename MODULE,
29          unsigned int BUSWIDTH = 32,
30          typename TYPES = tlm::tlm_base_protocol_types>
31class passthrough_target_socket :
32  public tlm::tlm_target_socket<BUSWIDTH, TYPES>
33{
34public:
35  typedef typename TYPES::tlm_payload_type              transaction_type;
36  typedef typename TYPES::tlm_phase_type                phase_type;
37  typedef tlm::tlm_sync_enum                            sync_enum_type;
38  typedef tlm::tlm_fw_transport_if<TYPES>               fw_interface_type;
39  typedef tlm::tlm_bw_transport_if<TYPES>               bw_interface_type;
40  typedef tlm::tlm_target_socket<BUSWIDTH, TYPES>       base_type;
41
42public:
43  passthrough_target_socket() :
44    base_type(sc_core::sc_gen_unique_name("passthrough_target_socket")),
45    m_process(this->name())
46  {
47    bind(m_process);
48  }
49
50  explicit passthrough_target_socket(const char* n) :
51    base_type(n),
52    m_process(this->name())
53  {
54    bind(m_process);
55  }
56
57  using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
58
59  // REGISTER_XXX
60  void register_nb_transport_fw(MODULE* mod,
61                                sync_enum_type (MODULE::*cb)(transaction_type&,
62                                                             phase_type&,
63                                                             sc_core::sc_time&))
64  {
65    m_process.set_nb_transport_ptr(mod, cb);
66  }
67
68  void register_b_transport(MODULE* mod,
69                            void (MODULE::*cb)(transaction_type&,
70                                               sc_core::sc_time&))
71  {
72    m_process.set_b_transport_ptr(mod, cb);
73  }
74
75  void register_transport_dbg(MODULE* mod,
76                              unsigned int (MODULE::*cb)(transaction_type&))
77  {
78    m_process.set_transport_dbg_ptr(mod, cb);
79  }
80
81  void register_get_direct_mem_ptr(MODULE* mod,
82                                   bool (MODULE::*cb)(transaction_type&,
83                                                      tlm::tlm_dmi&))
84  {
85    m_process.set_get_direct_mem_ptr(mod, cb);
86  }
87
88private:
89  class process : public tlm::tlm_fw_transport_if<TYPES>
90  {
91  public:
92    typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&,
93                                                     phase_type&,
94                                                     sc_core::sc_time&);
95    typedef void (MODULE::*BTransportPtr)(transaction_type&,
96                                            sc_core::sc_time&);
97    typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&);
98    typedef bool (MODULE::*GetDirectMem_ptr)(transaction_type&,
99                                               tlm::tlm_dmi&);
100
101    process(const std::string& name) :
102      m_name(name),
103      m_mod(0),
104      m_nb_transport_ptr(0),
105      m_b_transport_ptr(0),
106      m_transport_dbg_ptr(0),
107      m_get_direct_mem_ptr(0)
108    {
109    }
110
111    void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
112    {
113      if (m_nb_transport_ptr) {
114        std::stringstream s;
115        s << m_name << ": non-blocking callback allready registered";
116        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
117
118      } else {
119        assert(!m_mod || m_mod == mod);
120        m_mod = mod;
121        m_nb_transport_ptr = p;
122      }
123    }
124
125    void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
126    {
127      if (m_b_transport_ptr) {
128        std::stringstream s;
129        s << m_name << ": blocking callback allready registered";
130        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
131      } else {
132        assert(!m_mod || m_mod == mod);
133        m_mod = mod;
134        m_b_transport_ptr = p;
135      }
136    }
137
138    void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
139    {
140      if (m_transport_dbg_ptr) {
141        std::stringstream s;
142        s << m_name << ": debug callback allready registered";
143        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
144      } else {
145        assert(!m_mod || m_mod == mod);
146        m_mod = mod;
147        m_transport_dbg_ptr = p;
148      }
149    }
150
151    void set_get_direct_mem_ptr(MODULE* mod, GetDirectMem_ptr p)
152    {
153      if (m_get_direct_mem_ptr) {
154        std::stringstream s;
155        s << m_name << ": get DMI pointer callback allready registered";
156        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
157      } else {
158        assert(!m_mod || m_mod == mod);
159        m_mod = mod;
160        m_get_direct_mem_ptr = p;
161      }
162    }
163
164    sync_enum_type nb_transport_fw(transaction_type& trans,
165                                   phase_type& phase,
166                                   sc_core::sc_time& t)
167    {
168      if (m_nb_transport_ptr) {
169        // forward call
170        assert(m_mod);
171        return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
172
173      } else {
174        std::stringstream s;
175        s << m_name << ": no non-blocking callback registered";
176        SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
177      }
178      return tlm::TLM_ACCEPTED;   ///< unreachable code
179    }
180
181    void b_transport(transaction_type& trans, sc_core::sc_time& t)
182    {
183      if (m_b_transport_ptr) {
184        // forward call
185        assert(m_mod);
186        return (m_mod->*m_b_transport_ptr)(trans, t);
187
188      } else {
189        std::stringstream s;
190        s << m_name << ": no blocking callback registered";
191        SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
192      }
193    }
194
195    unsigned int transport_dbg(transaction_type& trans)
196    {
197      if (m_transport_dbg_ptr) {
198        // forward call
199        assert(m_mod);
200        return (m_mod->*m_transport_dbg_ptr)(trans);
201
202      } else {
203        // No debug support
204        return 0;
205      }
206    }
207
208    bool get_direct_mem_ptr(transaction_type& trans,
209                            tlm::tlm_dmi&  dmi_data)
210    {
211      if (m_get_direct_mem_ptr) {
212        // forward call
213        assert(m_mod);
214        return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
215
216      } else {
217        // No DMI support
218        dmi_data.allow_read_write();
219        dmi_data.set_start_address(0x0);
220        dmi_data.set_end_address((sc_dt::uint64)-1);
221        return false;
222      }
223    }
224
225  private:
226    const std::string m_name;
227    MODULE* m_mod;
228    NBTransportPtr m_nb_transport_ptr;
229    BTransportPtr m_b_transport_ptr;
230    TransportDbgPtr m_transport_dbg_ptr;
231    GetDirectMem_ptr m_get_direct_mem_ptr;
232  };
233
234private:
235  process m_process;
236};
237
238//ID Tagged version
239template <typename MODULE,
240          unsigned int BUSWIDTH = 32,
241          typename TYPES = tlm::tlm_base_protocol_types>
242class passthrough_target_socket_tagged :
243  public tlm::tlm_target_socket<BUSWIDTH, TYPES>
244{
245public:
246  typedef typename TYPES::tlm_payload_type              transaction_type;
247  typedef typename TYPES::tlm_phase_type                phase_type;
248  typedef tlm::tlm_sync_enum                            sync_enum_type;
249  typedef tlm::tlm_fw_transport_if<TYPES>               fw_interface_type;
250  typedef tlm::tlm_bw_transport_if<TYPES>               bw_interface_type;
251  typedef tlm::tlm_target_socket<BUSWIDTH, TYPES>       base_type;
252
253public:
254  passthrough_target_socket_tagged() :
255    base_type(sc_core::sc_gen_unique_name("passthrough_target_socket_tagged")),
256    m_process(this->name())
257  {
258    bind(m_process);
259  }
260
261  explicit passthrough_target_socket_tagged(const char* n) :
262    base_type(n),
263    m_process(this->name())
264  {
265    bind(m_process);
266  }
267
268  using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
269
270  // REGISTER_XXX
271  void register_nb_transport_fw(MODULE* mod,
272                                sync_enum_type (MODULE::*cb)(int id,
273                                                             transaction_type&,
274                                                             phase_type&,
275                                                             sc_core::sc_time&),
276                                int id)
277  {
278    m_process.set_nb_transport_ptr(mod, cb);
279    m_process.set_nb_transport_user_id(id);
280  }
281
282  void register_b_transport(MODULE* mod,
283                            void (MODULE::*cb)(int id,
284                                               transaction_type&,
285                                               sc_core::sc_time&),
286                            int id)
287  {
288    m_process.set_b_transport_ptr(mod, cb);
289    m_process.set_b_transport_user_id(id);
290  }
291
292  void register_transport_dbg(MODULE* mod,
293                              unsigned int (MODULE::*cb)(int id,
294                                                         transaction_type&),
295                              int id)
296  {
297    m_process.set_transport_dbg_ptr(mod, cb);
298    m_process.set_transport_dbg_user_id(id);
299  }
300
301  void register_get_direct_mem_ptr(MODULE* mod,
302                                   bool (MODULE::*cb)(int id,
303                                                      transaction_type&,
304                                                      tlm::tlm_dmi&),
305                                   int id)
306  {
307    m_process.set_get_direct_mem_ptr(mod, cb);
308    m_process.set_get_dmi_user_id(id);
309  }
310
311private:
312  class process : public tlm::tlm_fw_transport_if<TYPES>
313  {
314  public:
315    typedef sync_enum_type (MODULE::*NBTransportPtr)(int id,
316                                                     transaction_type&,
317                                                     phase_type&,
318                                                     sc_core::sc_time&);
319    typedef void (MODULE::*BTransportPtr)(int id,
320                                          transaction_type&,
321                                          sc_core::sc_time&);
322    typedef unsigned int (MODULE::*TransportDbgPtr)(int id,
323                                                    transaction_type&);
324    typedef bool (MODULE::*GetDirectMem_ptr)(int id,
325                                             transaction_type&,
326                                             tlm::tlm_dmi&);
327
328    process(const std::string& name) :
329      m_name(name),
330      m_mod(0),
331      m_nb_transport_ptr(0),
332      m_b_transport_ptr(0),
333      m_transport_dbg_ptr(0),
334      m_get_direct_mem_ptr(0),
335      m_nb_transport_user_id(0),
336      m_b_transport_user_id(0),
337      m_transport_dbg_user_id(0),
338      m_get_dmi_user_id(0)
339    {
340    }
341
342    void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
343    void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
344    void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; }
345    void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
346
347    void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
348    {
349      if (m_nb_transport_ptr) {
350        std::stringstream s;
351        s << m_name << ": non-blocking callback allready registered";
352        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
353      } else {
354        assert(!m_mod || m_mod == mod);
355        m_mod = mod;
356        m_nb_transport_ptr = p;
357      }
358    }
359
360    void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
361    {
362      if (m_b_transport_ptr) {
363        std::stringstream s;
364        s << m_name << ": blocking callback allready registered";
365        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
366      } else {
367        assert(!m_mod || m_mod == mod);
368        m_mod = mod;
369        m_b_transport_ptr = p;
370      }
371    }
372
373    void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
374    {
375      if (m_transport_dbg_ptr) {
376        std::stringstream s;
377        s << m_name << ": debug callback allready registered";
378        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
379      } else {
380        assert(!m_mod || m_mod == mod);
381        m_mod = mod;
382        m_transport_dbg_ptr = p;
383      }
384    }
385
386    void set_get_direct_mem_ptr(MODULE* mod, GetDirectMem_ptr p)
387    {
388      if (m_get_direct_mem_ptr) {
389        std::stringstream s;
390        s << m_name << ": get DMI pointer callback allready registered";
391        SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
392      } else {
393        assert(!m_mod || m_mod == mod);
394        m_mod = mod;
395        m_get_direct_mem_ptr = p;
396      }
397    }
398
399    sync_enum_type nb_transport_fw(transaction_type& trans,
400                                   phase_type& phase,
401                                   sc_core::sc_time& t)
402    {
403      if (m_nb_transport_ptr) {
404        // forward call
405        assert(m_mod);
406        return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t);
407
408      } else {
409        std::stringstream s;
410        s << m_name << ": no non-blocking callback registered";
411        SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
412      }
413      return tlm::TLM_ACCEPTED;   ///< unreachable code
414    }
415
416    void b_transport(transaction_type& trans, sc_core::sc_time& t)
417    {
418      if (m_b_transport_ptr) {
419        // forward call
420        assert(m_mod);
421        return (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
422
423      } else {
424        std::stringstream s;
425        s << m_name << ": no blocking callback registered";
426        SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
427      }
428    }
429
430    unsigned int transport_dbg(transaction_type& trans)
431    {
432      if (m_transport_dbg_ptr) {
433        // forward call
434        assert(m_mod);
435        return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans);
436
437      } else {
438        // No debug support
439        return 0;
440      }
441    }
442
443    bool get_direct_mem_ptr(transaction_type& trans,
444                            tlm::tlm_dmi&  dmi_data)
445    {
446      if (m_get_direct_mem_ptr) {
447        // forward call
448        assert(m_mod);
449        return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data);
450
451      } else {
452        // No DMI support
453        dmi_data.allow_read_write();
454        dmi_data.set_start_address(0x0);
455        dmi_data.set_end_address((sc_dt::uint64)-1);
456        return false;
457      }
458    }
459
460  private:
461    const std::string m_name;
462    MODULE* m_mod;
463    NBTransportPtr m_nb_transport_ptr;
464    BTransportPtr m_b_transport_ptr;
465    TransportDbgPtr m_transport_dbg_ptr;
466    GetDirectMem_ptr m_get_direct_mem_ptr;
467    int m_nb_transport_user_id;
468    int m_b_transport_user_id;
469    int m_transport_dbg_user_id;
470    int m_get_dmi_user_id;
471  };
472
473private:
474  process m_process;
475};
476
477}
478
479#endif
480