diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh --- a/src/arch/x86/bios/acpi.hh +++ b/src/arch/x86/bios/acpi.hh @@ -46,8 +46,6 @@ #include "base/types.hh" #include "sim/sim_object.hh" -class Port; - struct X86ACPIRSDPParams; struct X86ACPISysDescTableParams; diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh --- a/src/dev/etherdevice.hh +++ b/src/dev/etherdevice.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,8 +46,11 @@ class EtherInt; /** - * The base EtherObject class, allows for an accesor function to a - * simobj that returns the Port. + * EtherDevice is a base class for PCI-based network interfaces. + * These SimObjects have both Ethernet ports and memory ports. The + * SimObject port accessor functions use a single getEthPort() method + * to do port lookups, falling back on the MemPort lookup if that + * fails. EtherDevice also collects common NIC statistics. */ class EtherDevice : public PciDev { @@ -63,9 +67,29 @@ } public: - /** Additional function to return the Port of a memory object. */ + /** + * Look up an Ethernet port (EtherInt) by name. + * @sa EtherObject::getEthPort + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A pointer to the given interface, or NULL if there is none. + */ virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0; + /** + * Override of SimObject::getLHSPort. Maps to getEthPort(), falling + * back to PciDev::getLHSPort() if no Ethernet port is found. + */ + virtual Port& getLHSPort(const std::string& if_name, PortID idx); + + /** + * Override of SimObject::getRHSPort. Maps to getEthPort(), falling + * back to PciDev::getRHSPort() if no Ethernet port is found. + */ + virtual Port& getRHSPort(const std::string& if_name, PortID idx); + public: void regStats(); diff --git a/src/dev/etherdevice.cc b/src/dev/etherdevice.cc --- a/src/dev/etherdevice.cc +++ b/src/dev/etherdevice.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,8 +31,37 @@ */ #include "dev/etherdevice.hh" +#include "dev/etherint.hh" #include "sim/stats.hh" + +Port& +EtherDevice::getLHSPort(const std::string& if_name, PortID idx) +{ + EtherInt *i = getEthPort(if_name, idx); + + if (i != NULL) { + return *i; + } + + return PciDev::getLHSPort(if_name, idx); +} + + +Port& +EtherDevice::getRHSPort(const std::string& if_name, PortID idx) +{ + EtherInt *i = getEthPort(if_name, idx); + + if (i != NULL) { + return *i; + } + + return PciDev::getRHSPort(if_name, idx); +} + + + void EtherDevice::regStats() { diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh --- a/src/dev/etherint.hh +++ b/src/dev/etherint.hh @@ -39,29 +39,28 @@ #include #include "dev/etherpkt.hh" +#include "sim/port.hh" /* * Class representing the actual interface between two ethernet * components. These components are intended to attach to another * ethernet interface on one side and whatever device on the other. */ -class EtherInt +class EtherInt : public Port { protected: - mutable std::string portName; EtherInt *peer; public: EtherInt(const std::string &name) - : portName(name), peer(NULL) {} + : Port(name), peer(NULL) {} virtual ~EtherInt() {} - /** Return port name (for DPRINTF). */ - const std::string &name() const { return portName; } - void setPeer(EtherInt *p); EtherInt* getPeer() { return peer; } + virtual void bind(Port& peer); + void recvDone() { peer->sendDone(); } virtual void sendDone() = 0; diff --git a/src/dev/etherint.cc b/src/dev/etherint.cc --- a/src/dev/etherint.cc +++ b/src/dev/etherint.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,3 +42,18 @@ peer = p; } + + +void +EtherInt::bind(Port& peer) +{ + EtherInt *peer_int = dynamic_cast(&peer); + + if (peer_int == NULL) { + fatal("Attempt to bind non-EtherInt %s to EtherInt %s!\n", + peer.name(), name()); + } + + setPeer(peer_int); + peer_int->setPeer(this); +} diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh --- a/src/dev/etherlink.hh +++ b/src/dev/etherlink.hh @@ -133,11 +133,11 @@ return dynamic_cast(_params); } + /** Implementation for abstract EtherObject::getEthPort() */ virtual EtherInt *getEthPort(const std::string &if_name, int idx); virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - }; #endif // __ETHERLINK_HH__ diff --git a/src/dev/etherobject.hh b/src/dev/etherobject.hh --- a/src/dev/etherobject.hh +++ b/src/dev/etherobject.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,14 +37,16 @@ #ifndef __DEV_ETHEROBJECT_HH__ #define __DEV_ETHEROBJECT_HH__ +#include "dev/etherint.hh" #include "params/EtherObject.hh" #include "sim/sim_object.hh" class EtherInt; /** - * The base EtherObject class, allows for an accesor function to a - * simobj that returns the Port. + * EtherObject is a base class for SimObjects that have Ethernet ports + * but not memory ports. The SimObject port accessor functions use a + * single getEthPort() method to do port lookups. */ class EtherObject : public SimObject { @@ -59,9 +62,42 @@ } public: - /** Additional function to return the Port of a memory object. */ + + /** + * Look up an Ethernet port (EtherInt) by name. + * @sa EtherDevice::getEthPort + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A pointer to the given interface, or NULL if there is none. + */ virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0; + /** + * Override of SimObject::getLHSPort. Maps to getEthPort(), failing + * if no Ethernet port is found. + */ + Port& getLHSPort(const std::string& if_name, PortID idx) + { + EtherInt *i = getEthPort(if_name, idx); + + if (i == NULL) + fatal("No Ethernet port %s[%d] found on %s.", + if_name, idx, name()); + + return *i; + } + + /** + * Override of SimObject::getRHSPort. Since Ethernet port binding + * is symmetrical, simply reuse getLHSPort() implementation. + */ + Port& getRHSPort(const std::string& if_name, PortID idx) + { + return getLHSPort(if_name, idx); + } + }; #endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh --- a/src/mem/mem_object.hh +++ b/src/mem/mem_object.hh @@ -91,6 +91,18 @@ */ virtual BaseSlavePort& getSlavePort(const std::string& if_name, PortID idx = InvalidPortID); + + /** + * Override of Port::getLHSPort for MemObjects. + * Maps to getMasterPort(). + */ + virtual Port& getLHSPort(const std::string& if_name, PortID idx); + + /** + * Override of Port::getRHSPort for MemObjects. + * Maps to getSlavePort(). + */ + virtual Port& getRHSPort(const std::string& if_name, PortID idx); }; #endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc --- a/src/mem/mem_object.cc +++ b/src/mem/mem_object.cc @@ -59,3 +59,16 @@ { fatal("%s does not have any slave port named %s\n", name(), if_name); } + + +Port & +MemObject::getLHSPort(const std::string& if_name, PortID idx) +{ + return (Port&)getMasterPort(if_name, idx); +} + +Port & +MemObject::getRHSPort(const std::string& if_name, PortID idx) +{ + return (Port&)getSlavePort(if_name, idx); +} diff --git a/src/mem/port.hh b/src/mem/port.hh --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -54,6 +54,7 @@ #include "base/addr_range.hh" #include "mem/packet.hh" +#include "sim/port.hh" /** * This typedef is used to clean up getAddrRanges(). It's declared @@ -73,14 +74,8 @@ * either a master or a slave and the connected peer is always of the * opposite role. Each port has a name, an owner, and an identifier. */ -class Port +class MemPort : public Port { - - private: - - /** Descriptive name (for DPRINTF output) */ - std::string portName; - protected: /** @@ -99,18 +94,15 @@ * @param _owner The MemObject that is the structural owner of this port * @param _id A port identifier for vector ports */ - Port(const std::string& _name, MemObject& _owner, PortID _id); + MemPort(const std::string& _name, MemObject& _owner, PortID _id); /** * Virtual destructor due to inheritance. */ - virtual ~Port(); + virtual ~MemPort(); public: - /** Return port name (for DPRINTF). */ - const std::string name() const { return portName; } - /** Get the port id. */ PortID getId() const { return id; } @@ -125,7 +117,7 @@ * master port that inherits from the base class must override the * bind member function for the specific slave port class. */ -class BaseMasterPort : public Port +class BaseMasterPort : public MemPort { protected: @@ -138,7 +130,6 @@ public: - virtual void bind(BaseSlavePort& slave_port) = 0; virtual void unbind() = 0; BaseSlavePort& getSlavePort() const; bool isConnected() const; @@ -149,7 +140,7 @@ * A BaseSlavePort is a protocol-agnostic slave port, responsible * only for the structural connection to a master port. */ -class BaseSlavePort : public Port +class BaseSlavePort : public MemPort { protected: @@ -196,7 +187,7 @@ * Bind this master port to a slave port. This also does the * mirror action and binds the slave port to the master port. */ - void bind(BaseSlavePort& slave_port); + void bind(Port& slave_port); /** * Unbind this master port and the associated slave port. @@ -449,7 +440,7 @@ * Called by the master port to bind. Should never be called * directly. */ - void bind(MasterPort& master_port); + void bindToMaster(MasterPort& master_port); /** * Receive an atomic request packet from the master port. diff --git a/src/mem/port.cc b/src/mem/port.cc --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -50,18 +50,18 @@ #include "mem/mem_object.hh" #include "mem/port.hh" -Port::Port(const std::string &_name, MemObject& _owner, PortID _id) - : portName(_name), id(_id), owner(_owner) +MemPort::MemPort(const std::string &_name, MemObject& _owner, PortID _id) + : Port(_name), id(_id), owner(_owner) { } -Port::~Port() +MemPort::~MemPort() { } BaseMasterPort::BaseMasterPort(const std::string& name, MemObject* owner, PortID _id) - : Port(name, *owner, _id), _baseSlavePort(NULL) + : MemPort(name, *owner, _id), _baseSlavePort(NULL) { } @@ -87,7 +87,7 @@ BaseSlavePort::BaseSlavePort(const std::string& name, MemObject* owner, PortID _id) - : Port(name, *owner, _id), _baseMasterPort(NULL) + : MemPort(name, *owner, _id), _baseMasterPort(NULL) { } @@ -124,10 +124,10 @@ } void -MasterPort::bind(BaseSlavePort& slave_port) +MasterPort::bind(Port& slave_port) { // bind on the level of the base ports - _baseSlavePort = &slave_port; + _baseSlavePort = dynamic_cast(&slave_port); // also attempt to base the slave to the appropriate type SlavePort* cast_slave_port = dynamic_cast(&slave_port); @@ -137,7 +137,7 @@ // master port keeps track of the slave port _slavePort = cast_slave_port; // slave port also keeps track of master port - _slavePort->bind(*this); + _slavePort->bindToMaster(*this); } else { fatal("Master port %s cannot bind to %s\n", name(), slave_port.name()); @@ -232,7 +232,7 @@ } void -SlavePort::bind(MasterPort& master_port) +SlavePort::bindToMaster(MasterPort& master_port) { _baseMasterPort = &master_port; _masterPort = &master_port; diff --git a/src/python/swig/pyobject.cc b/src/python/swig/pyobject.cc --- a/src/python/swig/pyobject.cc +++ b/src/python/swig/pyobject.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,79 +35,30 @@ #include "base/inifile.hh" #include "base/output.hh" -#include "dev/etherdevice.hh" -#include "dev/etherobject.hh" -#include "mem/mem_object.hh" -#include "mem/port.hh" +#include "debug/Config.hh" #include "python/swig/pyobject.hh" -#include "sim/full_system.hh" +#include "sim/port.hh" #include "sim/sim_object.hh" using namespace std; -EtherInt * -lookupEthPort(SimObject *so, const std::string &name, int i) -{ - EtherObject *eo = dynamic_cast(so); - EtherDevice *ed = dynamic_cast(so); - if (eo == NULL && ed == NULL) { - warn("error casting SimObject %s", so->name()); - return NULL; - } - - EtherInt *p = NULL; - if (eo) - p = eo->getEthPort(name, i); - else - p = ed->getEthPort(name, i); - return p; -} - /** - * Connect the described MemObject ports. Called from Python via SWIG. + * Connect the described SimObject ports. Called from Python via SWIG. * The indices i1 & i2 will be -1 for regular ports, >= 0 for vector ports. - * SimObject1 is the master, and SimObject2 is the slave + * SimObject1 is the LHS of the assignment (master for MemPorts), and + * SimObject2 is the RHS (slave for MemPorts). */ int connectPorts(SimObject *o1, const std::string &name1, int i1, SimObject *o2, const std::string &name2, int i2) { - if (FullSystem) { - EtherObject *eo1, *eo2; - EtherDevice *ed1, *ed2; - eo1 = dynamic_cast(o1); - ed1 = dynamic_cast(o1); - eo2 = dynamic_cast(o2); - ed2 = dynamic_cast(o2); + DPRINTF(Config, "Binding port %s.%s[%d] to %s.%s[%d]\n", + o1->name(), name1, i1, o2->name(), name2, i2); - if ((eo1 || ed1) && (eo2 || ed2)) { - EtherInt *p1 = lookupEthPort(o1, name1, i1); - EtherInt *p2 = lookupEthPort(o2, name2, i2); + Port &lhsPort = o1->getLHSPort(name1, i1); + Port &rhsPort = o2->getRHSPort(name2, i2); - if (p1 != NULL && p2 != NULL) { - - p1->setPeer(p2); - p2->setPeer(p1); - - return 1; - } - } - } - MemObject *mo1, *mo2; - mo1 = dynamic_cast(o1); - mo2 = dynamic_cast(o2); - - if(mo1 == NULL || mo2 == NULL) { - panic ("Error casting SimObjects %s and %s to MemObject", o1->name(), - o2->name()); - } - - // generic master/slave port connection - BaseMasterPort& masterPort = mo1->getMasterPort(name1, i1); - BaseSlavePort& slavePort = mo2->getSlavePort(name2, i2); - - masterPort.bind(slavePort); - + lhsPort.bind(rhsPort); return 1; } diff --git a/src/sim/port.hh b/src/sim/port.hh --- /dev/null +++ b/src/sim/port.hh @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 Advanced Micro Devices, Inc. + * All rights reserved. + * + * 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: Steve Reinhardt + */ + +#ifndef __SIM__PORT_HH +#define __SIM__PORT_HH + +#include + +#include "base/misc.hh" + +/** + * Represents a generic "port" associated with a SimObject. Pairs of + * ports can be connected (bound) during configuration (using a Python + * assignment statement), allowing two SimObjects to communicate. The + * two ports must be of appropriate types, e.g., two memory ports or + * two Ethernet ports. + */ +class Port +{ + private: + + /** Descriptive name (for DPRINTF output) */ + std::string portName; + + public: + Port(const std::string &_name) + : portName(_name) + { + } + + /** Return port name (for DPRINTF). */ + const std::string name() const { return portName; } + + /** + * Bind another port to this port. bind() is always called on the + * port on the LHS of the Python assignment in the configuration + * file. The called Port is responsible for verifying that the + * two Port instances are of compatible subtypes, calling fatal() + * if they are not. + * + * @param peer The port on the RHS of the binding assignment. + */ + virtual void bind(Port& peer) + { + panic("Port::bind() unimplemented!\n"); + } + +}; + + +#endif // __SIM__PORT_HH diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2005 The Regents of The University of Michigan - * Copyright (c) 2010 Advanced Micro Devices, Inc. + * Copyright (c) 2010, 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ #include "params/SimObject.hh" #include "sim/drain.hh" #include "sim/eventq_impl.hh" +#include "sim/port.hh" #include "sim/serialize.hh" class BaseCPU; @@ -162,6 +163,28 @@ */ static void serializeAll(std::ostream &os); + /** + * Look up a port reference by name that appears on the LHS of a + * port-binding assignment statement. + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A reference to the given port + */ + virtual Port& getLHSPort(const std::string& if_name, PortID idx); + + /** + * Look up a port reference by name that appears on the RHS of a + * port-binding assignment statement. + * + * @param if_name Port name + * @param idx Index in the case of a VectorPort + * + * @return A reference to the given port + */ + virtual Port& getRHSPort(const std::string& if_name, PortID idx); + #ifdef DEBUG public: bool doDebugBreak; diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -1,6 +1,6 @@ /* * Copyright (c) 2001-2005 The Regents of The University of Michigan - * Copyright (c) 2010 Advanced Micro Devices, Inc. + * Copyright (c) 2010, 2013 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -125,6 +125,19 @@ } +Port & +SimObject::getLHSPort(const std::string& if_name, PortID idx) +{ + fatal("%s does not have an LHS port named %s\n", name(), if_name); +} + +Port & +SimObject::getRHSPort(const std::string& if_name, PortID idx) +{ + fatal("%s does not have an RHS port named %s\n", name(), if_name); +} + + #ifdef DEBUG // // static function: flag which objects should have the debugger break