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