From: Andrew Bardsley Date: Thu, 16 Oct 2014 09:49:56 +0000 (-0400) Subject: mem: Add ExternalMaster and ExternalSlave ports X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d6732895a5c2e81da47ada339b5d9269c02e5e8b;p=gem5.git mem: Add ExternalMaster and ExternalSlave ports This patch adds two MemoryObject's: ExternalMaster and ExternalSlave. Each object has a single port which can be bound to an externally- provided bridge to a port of another simulation system at initialisation. --- diff --git a/src/mem/ExternalMaster.py b/src/mem/ExternalMaster.py new file mode 100644 index 000000000..492da1dd1 --- /dev/null +++ b/src/mem/ExternalMaster.py @@ -0,0 +1,52 @@ +# Copyright (c) 2014 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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: Andrew Bardsley +# Curtis Dunham + +from m5.params import * +from MemObject import MemObject + +class ExternalMaster(MemObject): + type = 'ExternalMaster' + cxx_header = "mem/external_master.hh" + + port = MasterPort("Master port") + + port_type = Param.String('stub', 'Registered external port handler' + ' to pass this port to in instantiation') + port_data = Param.String('stub', 'A string to pass to the port' + ' handler (in a format specific to the handler) to describe how' + ' the port should be bound/bindable/discoverable') diff --git a/src/mem/ExternalSlave.py b/src/mem/ExternalSlave.py new file mode 100644 index 000000000..15f529de6 --- /dev/null +++ b/src/mem/ExternalSlave.py @@ -0,0 +1,54 @@ +# Copyright (c) 2014 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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: Andrew Bardsley + +from m5.params import * +from MemObject import MemObject + +class ExternalSlave(MemObject): + type = 'ExternalSlave' + cxx_header = "mem/external_slave.hh" + + port = SlavePort("Slave port") + + addr_ranges = VectorParam.AddrRange([], 'Addresses served by' + ' this port\'s external agent') + + port_type = Param.String('stub', 'Registered external port handler' + ' to pass this port to in instantiation') + port_data = Param.String('stub', 'A string to pass to the port' + ' handler (in a format specific to the handler) to describe how' + ' the port should be bound/bindable/discoverable') diff --git a/src/mem/SConscript b/src/mem/SConscript index 6d225385b..e7d2c1bac 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -40,6 +40,8 @@ SimObject('AbstractMemory.py') SimObject('AddrMapper.py') SimObject('Bridge.py') SimObject('DRAMCtrl.py') +SimObject('ExternalMaster.py') +SimObject('ExternalSlave.py') SimObject('MemObject.py') SimObject('SimpleMemory.py') SimObject('XBar.py') @@ -50,6 +52,8 @@ Source('bridge.cc') Source('coherent_xbar.cc') Source('drampower.cc') Source('dram_ctrl.cc') +Source('external_master.cc') +Source('external_slave.cc') Source('mem_object.cc') Source('mport.cc') Source('noncoherent_xbar.cc') @@ -88,6 +92,7 @@ DebugFlag('CommMonitor') DebugFlag('DRAM') DebugFlag('DRAMPower') DebugFlag('DRAMState') +DebugFlag('ExternalPort') DebugFlag('LLSC') DebugFlag('MMU') DebugFlag('MemoryAccess') diff --git a/src/mem/external_master.cc b/src/mem/external_master.cc new file mode 100644 index 000000000..74c5a6f43 --- /dev/null +++ b/src/mem/external_master.cc @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012-2014 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andrew Bardsley + * Curtis Dunham + */ + +#include +#include + +#include "debug/ExternalPort.hh" +#include "mem/external_master.hh" + +std::map + ExternalMaster::portHandlers; + +ExternalMaster::ExternalMaster(ExternalMasterParams *params) : + MemObject(params), + externalPort(NULL), + portName(params->name + ".port"), + portType(params->port_type), + portData(params->port_data) +{} + +BaseMasterPort & +ExternalMaster::getMasterPort(const std::string &if_name, + PortID idx) +{ + if (if_name == "port") { + DPRINTF(ExternalPort, "Trying to bind external port: %s %s\n", + portType, portName); + + if (!externalPort) { + auto handlerIter = portHandlers.find(portType); + + if (handlerIter == portHandlers.end()) + fatal("Can't find port handler type '%s'\n", portType); + + externalPort = portHandlers[portType]->getExternalPort(portName, + *this, portData); + + if (!externalPort) { + fatal("%s: Can't find external port type: %s" + " port_data: '%s'\n", portName, portType, portData); + } + } + return *externalPort; + } else { + return MemObject::getMasterPort(if_name, idx); + } +} + +void +ExternalMaster::init() +{ + if (!externalPort) { + fatal("ExternalMaster %s: externalPort not set!\n", name()); + } else if (!externalPort->isConnected()) { + fatal("ExternalMaster %s is unconnected!\n", name()); + } +} + +ExternalMaster * +ExternalMasterParams::create() +{ + return new ExternalMaster(this); +} + +void +ExternalMaster::registerHandler(const std::string &handler_name, + Handler *handler) +{ + portHandlers[handler_name] = handler; +} diff --git a/src/mem/external_master.hh b/src/mem/external_master.hh new file mode 100644 index 000000000..3a5627d49 --- /dev/null +++ b/src/mem/external_master.hh @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012-2014 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andrew Bardsley + * Curtis Dunham + */ + +/** + * @file + * + * ExternalMaster is a memory object representing a binding from + * a gem5 slave to a master port in a system external to gem5. + * + * During initialisation, a `handler' for the port type specified in the + * port's port_type parameter is found from the registered port handlers + * provided with registerHandler. Once a handler is found, it is passed the + * port_data parameter of the port which can be used to identify the external + * port which is to be bound to. A port handler will usually construct a + * bridge object in the external system to accomodate the port-to-port + * mapping but this bridge is not exposed to gem5 other than be the + * presentation of the MasterPort which can be bound. + * + * The external port must provide a gem5 MasterPort interface. + */ + +#ifndef __MEM_EXTERNAL_MASTER__ +#define __MEM_EXTERNAL_MASTER__ + +#include "mem/mem_object.hh" +#include "params/ExternalMaster.hh" + +class ExternalMaster : public MemObject +{ + public: + /** Derive from this class to create an external port interface */ + class Port : public MasterPort + { + protected: + ExternalMaster &owner; + + public: + Port(const std::string &name_, + ExternalMaster &owner_) : + MasterPort(name_, &owner_), owner(owner_) + { } + + ~Port() { } + + /** Any or all of recv... can be overloaded to provide the port's + * functionality */ + }; + + /* Handlers are specific to *types* of port not specific port + * instantiations. A handler will typically build a bridge to the + * external port from gem5 and provide gem5 with a MasterPort that can be + * bound to for each call to Handler::getExternalPort.*/ + class Handler + { + public: + /** Create or find an external port which can be bound. Returns + * NULL on failure */ + virtual Port *getExternalPort( + const std::string &name, ExternalMaster &owner, + const std::string &port_data) = 0; + }; + + protected: + /** The peer port for the gem5 port "port" */ + Port *externalPort; + + /** Name of the bound port. This will be name() + ".port" */ + std::string portName; + + /** Key to select a port handler */ + std::string portType; + + /** Handler-specific port configuration */ + std::string portData; + + /** Registered handlers. Handlers are chosen using the port_type + * parameter on ExternalMasters. port_types form a global namespace + * across the simulation and so handlers are registered into a global + * structure */ + static std::map portHandlers; + + public: + ExternalMaster(ExternalMasterParams *params); + + /** MasterPort interface. Responds only to port "port" */ + BaseMasterPort &getMasterPort(const std::string &if_name, + PortID idx = InvalidPortID); + + /** Register a handler which can provide ports with port_type == + * handler_name */ + static void registerHandler(const std::string &handler_name, + Handler *handler); + + void init(); +}; + + +#endif // __MEM_EXTERNAL_MASTER__ diff --git a/src/mem/external_slave.cc b/src/mem/external_slave.cc new file mode 100644 index 000000000..c7ad521c9 --- /dev/null +++ b/src/mem/external_slave.cc @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2012-2014 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andrew Bardsley + */ + +#include +#include + +#include "debug/ExternalPort.hh" +#include "mem/external_slave.hh" + +/** Implement a `stub' port which just responds to requests by printing + * a message. The stub port can be used to configure and test a system + * where the external port is used for a peripheral before connecting + * the external port */ +class StubSlavePort : public ExternalSlave::Port +{ + public: + class ResponseEvent : public Event + { + public: + StubSlavePort &owner; + + ResponseEvent(StubSlavePort &owner_) : owner(owner_) { } + + void process(); + }; + + ResponseEvent responseEvent; + + /** Stub can handle a single request at a time. This will be + * NULL when no packet is in flight */ + PacketPtr responsePacket; + + /** Received a new request while processing a first. Need to ask for + * a retry after completing this packet */ + bool mustRetry; + + StubSlavePort(const std::string &name_, + ExternalSlave &owner_) : + ExternalSlave::Port(name_, owner_), + responseEvent(*this), responsePacket(NULL) + { } + + Tick recvAtomic(PacketPtr packet); + void recvFunctional(PacketPtr packet); + bool recvTimingReq(PacketPtr packet); + bool recvTimingSnoopResp(PacketPtr packet); + void recvRetry(); + void recvFunctionalSnoop(PacketPtr packet); +}; + +class StubSlavePortHandler : public + ExternalSlave::Handler +{ + public: + ExternalSlave::Port *getExternalPort( + const std::string &name_, + ExternalSlave &owner, + const std::string &port_data) + { + StringWrap name(name_); + + DPRINTF(ExternalPort, "finding stub port '%s'\n", port_data); + return new StubSlavePort(name_, owner); + } +}; + +Tick +StubSlavePort::recvAtomic(PacketPtr packet) +{ + if (DTRACE(ExternalPort)) { + unsigned int M5_VAR_USED size = packet->getSize(); + + DPRINTF(ExternalPort, "StubSlavePort: recvAtomic a: 0x%x size: %d" + " data: ...\n", packet->getAddr(), size); + DDUMP(ExternalPort, packet->getPtr(), size); + } + + return 0; +} + +void +StubSlavePort::recvFunctional(PacketPtr packet) +{ + recvAtomic(packet); +} + +void +StubSlavePort::ResponseEvent::process() +{ + owner.responsePacket->makeResponse(); + owner.responsePacket->firstWordDelay = 0; + owner.responsePacket->lastWordDelay = 0; + + if (owner.sendTimingResp(owner.responsePacket)) { + owner.responsePacket = NULL; + + if (owner.mustRetry) + owner.sendRetry(); + owner.mustRetry = false; + } +} + +bool +StubSlavePort::recvTimingReq(PacketPtr packet) +{ + if (responsePacket) { + mustRetry = true; + + return false; + } else { + recvAtomic(packet); + + responsePacket = packet; + owner.schedule(responseEvent, curTick()); + + return true; + } +} + +bool +StubSlavePort::recvTimingSnoopResp(PacketPtr packet) +{ + fatal("StubSlavePort: function: %s\n", __func__); + return false; +} + +void +StubSlavePort::recvRetry() +{ + assert(responsePacket); + /* Stub handles only one response at a time so responseEvent should never + * be scheduled at this point. Retrys shouldn't need to schedule, we + * can safely send the response here */ + responseEvent.process(); +} + +void +StubSlavePort::recvFunctionalSnoop(PacketPtr packet) +{ + fatal("StubSlavePort: unimplemented function: %s\n", __func__); +} + +std::map + ExternalSlave::portHandlers; + +AddrRangeList +ExternalSlave::Port::getAddrRanges() const +{ + return owner.addrRanges; +} + +ExternalSlave::ExternalSlave(ExternalSlaveParams *params) : + MemObject(params), + externalPort(NULL), + portName(params->name + ".port"), + portType(params->port_type), + portData(params->port_data), + addrRanges(params->addr_ranges.begin(), params->addr_ranges.end()) +{ + /* Register the stub handler if it hasn't already been registered */ + if (portHandlers.find("stub") == portHandlers.end()) + registerHandler("stub", new StubSlavePortHandler); +} + +BaseSlavePort & +ExternalSlave::getSlavePort(const std::string &if_name, + PortID idx) +{ + if (if_name == "port") { + DPRINTF(ExternalPort, "Trying to bind external port: %s %s\n", + portType, portName); + + if (!externalPort) { + auto handlerIter = portHandlers.find(portType); + + if (handlerIter == portHandlers.end()) + fatal("Can't find port handler type '%s'\n", portType); + + externalPort = portHandlers[portType]->getExternalPort(portName, + *this, portData); + + if (!externalPort) { + fatal("%s: Can't find external port type: %s" + " port_data: '%s'\n", portName, portType, portData); + } + } + return *externalPort; + } else { + return MemObject::getSlavePort(if_name, idx); + } +} + +void +ExternalSlave::init() +{ + if (!externalPort) { + fatal("ExternalSlave %s: externalPort not set!\n", name()); + } else if (!externalPort->isConnected()) { + fatal("ExternalSlave %s is unconnected!\n", name()); + } else { + externalPort->sendRangeChange(); + } +} + +ExternalSlave * +ExternalSlaveParams::create() +{ + return new ExternalSlave(this); +} + +void +ExternalSlave::registerHandler(const std::string &handler_name, + Handler *handler) +{ + portHandlers[handler_name] = handler; +} diff --git a/src/mem/external_slave.hh b/src/mem/external_slave.hh new file mode 100644 index 000000000..d1782237c --- /dev/null +++ b/src/mem/external_slave.hh @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2012-2014 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andrew Bardsley + */ + +/** + * @file + * + * ExternalSlave is a memory object representing a binding from + * a gem5 master to a slave port in a system external to gem5. + * + * During initialisation, a `handler' for the port type specified in the + * port's port_type parameter is found from the registered port handlers + * provided with registerHandler. Once a handler is found, it is passed the + * port_data parameter of the port which can be used to identify the external + * port which is to be bound to. A port handler will usually construct a + * bridge object in the external system to accomodate the port-to-port + * mapping but this bridge is not exposed to gem5 other than be the + * presentation of the SlavePort which can be bound. + * + * The external port must provide a gem5 SlavePort interface (with the + * exception of getAddrRanges which is provided by the ExternalSlave + * object). + */ + +#ifndef __MEM_EXTERNAL_SLAVE__ +#define __MEM_EXTERNAL_SLAVE__ + +#include "mem/mem_object.hh" +#include "params/ExternalSlave.hh" + +class ExternalSlave : public MemObject +{ + public: + /** Derive from this class to create an external port interface */ + class Port : public SlavePort + { + protected: + ExternalSlave &owner; + + public: + Port(const std::string &name_, + ExternalSlave &owner_) : + SlavePort(name_, &owner_), owner(owner_) + { } + + ~Port() { } + + /** Any or all of recv... can be overloaded to provide the port's + * functionality */ + + AddrRangeList getAddrRanges() const; + }; + + /* Handlers are specific to *types* of port not specific port + * instantiations. A handler will typically build a bridge to the + * external port from gem5 and provide gem5 with a SlavePort that can be + * bound to for each call to Handler::getExternalPort.*/ + class Handler + { + public: + /** Create or find an external port which can be bound. Returns + * NULL on failure */ + virtual Port *getExternalPort( + const std::string &name, ExternalSlave &owner, + const std::string &port_data) = 0; + }; + + protected: + /** The peer port for the gem5 port "port" */ + Port *externalPort; + + /** Name of the bound port. This will be name() + ".port" */ + std::string portName; + + /** Key to select a port handler */ + std::string portType; + + /** Handler-specific port configuration */ + std::string portData; + + /** The Range of addresses supported by the devices on the external + * side of this port */ + AddrRangeList addrRanges; + + /** Registered handlers. Handlers are chosen using the port_type + * parameter on ExternalSlaves. port_types form a global namespace + * across the simulation and so handlers are registered into a global + * structure */ + static std::map portHandlers; + + public: + ExternalSlave(ExternalSlaveParams *params); + + /** SlavePort interface. Responds only to port "port" */ + BaseSlavePort &getSlavePort(const std::string &if_name, + PortID idx = InvalidPortID); + + /** Register a handler which can provide ports with port_type == + * handler_name */ + static void registerHandler(const std::string &handler_name, + Handler *handler); + + void init(); +}; + + +#endif // __MEM_EXTERNAL_SLAVE__