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