/* * Copyright 2018 Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black */ #ifndef __SYSTEMC_EXT_CORE_SC_PORT_HH__ #define __SYSTEMC_EXT_CORE_SC_PORT_HH__ #include #include #include "../channel/messages.hh" #include "../utils/sc_report_handler.hh" #include "sc_module.hh" // for sc_gen_unique_name #include "sc_object.hh" namespace sc_gem5 { class Port; }; namespace sc_core { class sc_interface; class sc_trace_file; // Nonstandard // Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this // class definition in the Accellera implementation, it appears in their // examples and test programs, and so we need to have it here as well. struct sc_trace_params { sc_trace_file *tf; std::string name; sc_trace_params(sc_trace_file *tf, const std::string &name) : tf(tf), name(name) {} }; typedef std::vector sc_trace_params_vec; enum sc_port_policy { SC_ONE_OR_MORE_BOUND, // Default SC_ZERO_OR_MORE_BOUND, SC_ALL_BOUND }; class sc_port_base : public sc_object { public: sc_port_base(const char *name, int n, sc_port_policy p); virtual ~sc_port_base(); void warn_port_constructor() const; int maxSize() const; int size() const; const char *kind() const { return "sc_port_base"; } protected: // Implementation defined, but depended on by the tests. void bind(sc_interface &); void bind(sc_port_base &); friend class ::sc_gem5::Module; // Implementation defined, but depended on by the tests. virtual int vbind(sc_interface &) = 0; virtual int vbind(sc_port_base &) = 0; virtual void before_end_of_elaboration() = 0; virtual void end_of_elaboration() = 0; virtual void start_of_simulation() = 0; virtual void end_of_simulation() = 0; void report_error(const char *id, const char *add_msg) const; private: friend class ::sc_gem5::Port; friend class ::sc_gem5::Kernel; virtual sc_interface *_gem5Interface(int n) const = 0; virtual void _gem5AddInterface(sc_interface *i) = 0; ::sc_gem5::Port *_gem5Port; virtual const char *_ifTypeName() const = 0; virtual sc_port_policy _portPolicy() const = 0; }; template class sc_port_b : public sc_port_base { public: void operator () (IF &i) { bind(i); } void operator () (sc_port_b &p) { bind(p); } virtual void bind(IF &i) { sc_port_base::bind(i); } virtual void bind(sc_port_b &p) { sc_port_base::bind(p); } IF * operator -> () { if (_interfaces.empty()) { report_error(SC_ID_GET_IF_, "port is not bound"); sc_abort(); } return _interfaces[0]; } const IF * operator -> () const { if (_interfaces.empty()) { report_error(SC_ID_GET_IF_, "port is not bound"); sc_abort(); } return _interfaces[0]; } IF * operator [] (int n) { if (n < 0 || n >= size()) { report_error(SC_ID_GET_IF_, "index out of range"); return NULL; } return _interfaces[n]; } const IF * operator [] (int n) const { if (n < 0 || n >= size()) { report_error(SC_ID_GET_IF_, "index out of range"); return NULL; } return _interfaces[n]; } sc_interface * get_interface() { if (_interfaces.empty()) return NULL; return _interfaces[0]; } const sc_interface * get_interface() const { if (_interfaces.empty()) return NULL; return _interfaces[0]; } protected: void before_end_of_elaboration() {} void end_of_elaboration() {} void start_of_simulation() {} void end_of_simulation() {} explicit sc_port_b(int n, sc_port_policy p) : sc_port_base(sc_gen_unique_name("port"), n, p) {} sc_port_b(const char *name, int n, sc_port_policy p) : sc_port_base(name, n, p) {} virtual ~sc_port_b() {} // Implementation defined, but depended on by the tests. int vbind(sc_interface &i) { IF *interface = dynamic_cast(&i); if (!interface) return 2; sc_port_base::bind(*interface); return 0; } int vbind(sc_port_base &pb) { sc_port_b *p = dynamic_cast *>(&pb); if (!p) return 2; sc_port_base::bind(*p); return 0; } private: std::vector _interfaces; sc_interface * _gem5Interface(int n) const { if (n < 0 || n >= size()) { report_error(SC_ID_GET_IF_, "index out of range"); return NULL; } return _interfaces[n]; } void _gem5AddInterface(sc_interface *iface) { IF *interface = dynamic_cast(iface); sc_assert(interface); for (int i = 0; i < _interfaces.size(); i++) { if (interface == _interfaces[i]) { report_error(SC_ID_BIND_IF_TO_PORT_, "interface already bound to port"); } } _interfaces.push_back(interface); } const char *_ifTypeName() const { return typeid(IF).name(); } // Disabled sc_port_b() {} sc_port_b(const sc_port_b &) {} sc_port_b &operator = (const sc_port_b &) { return *this; } }; template class sc_port : public sc_port_b { public: sc_port() : sc_port_b(N, P) {} explicit sc_port(const char *name) : sc_port_b(name, N, P) {} virtual ~sc_port() {} // Deprecated binding constructors. explicit sc_port(const IF &interface) : sc_port_b(N, P) { this->warn_port_constructor(); sc_port_b::bind(const_cast(interface)); } sc_port(const char *name, const IF &interface) : sc_port_b(name, N, P) { this->warn_port_constructor(); sc_port_b::bind(const_cast(interface)); } explicit sc_port(sc_port_b &parent) : sc_port_b(N, P) { this->warn_port_constructor(); sc_port_b::bind(parent); } sc_port(const char *name, sc_port_b &parent) : sc_port_b(name, N, P) { this->warn_port_constructor(); sc_port_b::bind(parent); } explicit sc_port(sc_port &parent) : sc_port_b(N, P) { this->warn_port_constructor(); sc_port_b::bind(parent); } sc_port(const char *name, sc_port &parent) : sc_port_b(name, N, P) { this->warn_port_constructor(); sc_port_b::bind(parent); } virtual const char *kind() const { return "sc_port"; } private: // Disabled sc_port(const sc_port &) {} sc_port &operator = (const sc_port &) { return *this; } virtual sc_port_policy _portPolicy() const { return P; } }; } // namespace sc_core #endif //__SYSTEMC_EXT_CORE_SC_PORT_HH__