From 07cf9d914b292008ead7021182ec2ef8fc4671f1 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 17 Jan 2012 12:55:09 -0600 Subject: MEM: Separate queries for snooping and address ranges This patch simplifies the address-range determination mechanism and also unifies the naming across ports and devices. It further splits the queries for determining if a port is snooping and what address ranges it responds to (aiming towards a separation of cache-maintenance ports and pure memory-mapped ports). Default behaviours are such that most ports do not have to define isSnooping, and master ports need not implement getAddrRanges. --- src/mem/bridge.cc | 18 ++++----- src/mem/bridge.hh | 10 ++--- src/mem/bus.cc | 82 +++++++++++++++++++++++------------------ src/mem/bus.hh | 59 ++++++++++++++++++++++------- src/mem/cache/base.cc | 8 ++-- src/mem/cache/base.hh | 2 +- src/mem/cache/cache.hh | 6 +-- src/mem/cache/cache_impl.hh | 16 ++++---- src/mem/physical.cc | 30 ++++++--------- src/mem/physical.hh | 8 ++-- src/mem/port.hh | 73 +++++++++++++++++++++--------------- src/mem/ruby/system/RubyPort.cc | 5 +-- src/mem/tport.hh | 11 ++++-- 13 files changed, 185 insertions(+), 143 deletions(-) (limited to 'src/mem') diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 6001870ff..71cbcb76c 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -338,21 +338,19 @@ Bridge::BridgePort::recvFunctional(PacketPtr pkt) otherPort->sendFunctional(pkt); } -/** Function called by the port when the bus is receiving a status change.*/ +/** Function called by the port when the bridge is receiving a range change.*/ void -Bridge::BridgePort::recvStatusChange(Port::Status status) +Bridge::BridgePort::recvRangeChange() { - otherPort->sendStatusChange(status); + otherPort->sendRangeChange(); } -void -Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) +AddrRangeList +Bridge::BridgePort::getAddrRanges() { - otherPort->getPeerAddressRanges(resp, snoop); - FilterRangeList(filterRanges, resp); - // we don't allow snooping across bridges - snoop = false; + AddrRangeList ranges = otherPort->getPeer()->getAddrRanges(); + FilterRangeList(filterRanges, ranges); + return ranges; } Bridge * diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 732717dd4..a3fa1f8f6 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -178,14 +178,14 @@ class Bridge : public MemObject pass it to the bridge. */ virtual void recvFunctional(PacketPtr pkt); - /** When receiving a status changefrom the peer port, - pass it to the bridge. */ - virtual void recvStatusChange(Status status); + /** + * When receiving a range change, pass it through the bridge. + */ + virtual void recvRangeChange(); /** When receiving a address range request the peer port, pass it to the bridge. */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual AddrRangeList getAddrRanges(); }; BridgePort portA, portB; diff --git a/src/mem/bus.cc b/src/mem/bus.cc index ce834515b..00caa8289 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -94,14 +106,21 @@ Bus::getPort(const std::string &if_name, int idx) return bp; } -/** Get the ranges of anyone other buses that we are connected to. */ void Bus::init() { m5::hash_map::iterator intIter; - for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) - intIter->second->sendStatusChange(Port::RangeChange); + // iterate over our interfaces and determine which of our neighbours + // are snooping and add them as snoopers + for (intIter = interfaces.begin(); intIter != interfaces.end(); + intIter++) { + if (intIter->second->getPeer()->isSnooping()) { + DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", + intIter->second->getPeer()->name()); + snoopPorts.push_back(intIter->second); + } + } } Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) @@ -468,20 +487,16 @@ Bus::recvFunctional(PacketPtr pkt) } } -/** Function called by the port when the bus is receiving a status change.*/ +/** Function called by the port when the bus is receiving a range change.*/ void -Bus::recvStatusChange(Port::Status status, int id) +Bus::recvRangeChange(int id) { AddrRangeList ranges; - bool snoops; AddrRangeIter iter; - if (inRecvStatusChange.count(id)) + if (inRecvRangeChange.count(id)) return; - inRecvStatusChange.insert(id); - - assert(status == Port::RangeChange && - "The other statuses need to be implemented."); + inRecvRangeChange.insert(id); DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); @@ -490,8 +505,7 @@ Bus::recvStatusChange(Port::Status status, int id) defaultRange.clear(); // Only try to update these ranges if the user set a default responder. if (useDefaultRange) { - defaultPort->getPeerAddressRanges(ranges, snoops); - assert(snoops == false); + AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges(); for(iter = ranges.begin(); iter != ranges.end(); iter++) { defaultRange.push_back(*iter); DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", @@ -512,20 +526,7 @@ Bus::recvStatusChange(Port::Status status, int id) portIter++; } - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); ) { - if ((*s_iter)->getId() == id) - s_iter = snoopPorts.erase(s_iter); - else - s_iter++; - } - - port->getPeerAddressRanges(ranges, snoops); - - if (snoops) { - DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); - snoopPorts.push_back(port); - } + ranges = port->getPeer()->getAddrRanges(); for (iter = ranges.begin(); iter != ranges.end(); iter++) { DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", @@ -546,24 +547,23 @@ Bus::recvStatusChange(Port::Status status, int id) for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) if (intIter->first != id && intIter->first != funcPortId) - intIter->second->sendStatusChange(Port::RangeChange); + intIter->second->sendRangeChange(); if (id != defaultId && defaultPort) - defaultPort->sendStatusChange(Port::RangeChange); - inRecvStatusChange.erase(id); + defaultPort->sendRangeChange(); + inRecvRangeChange.erase(id); } -void -Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) +AddrRangeList +Bus::getAddrRanges(int id) { - resp.clear(); - snoop = false; + AddrRangeList ranges; DPRINTF(BusAddrRanges, "received address range request, returning:\n"); for (AddrRangeIter dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); dflt_iter++) { - resp.push_back(*dflt_iter); + ranges.push_back(*dflt_iter); DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, dflt_iter->end); } @@ -586,12 +586,21 @@ Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) } } if (portIter->second != id && !subset) { - resp.push_back(portIter->first); + ranges.push_back(portIter->first); DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", portIter->first.start, portIter->first.end); } } + return ranges; +} + +bool +Bus::isSnooping(int id) +{ + // in essence, answer the question if there are other snooping + // ports rather than the port that is asking + bool snoop = false; for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); s_iter++) { if ((*s_iter)->getId() != id) { @@ -599,6 +608,7 @@ Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) break; } } + return snoop; } unsigned diff --git a/src/mem/bus.hh b/src/mem/bus.hh index df80063f8..6c1b4c196 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * @@ -81,6 +93,15 @@ class Bus : public MemObject int getId() { return id; } + /** + * Determine if this port should be considered a snooper. This + * is determined by the bus. + * + * @return a boolean that is true if this port is snooping + */ + virtual bool isSnooping() + { return bus->isSnooping(id); } + protected: /** When reciving a timing request from the peer port (at id), @@ -98,10 +119,10 @@ class Bus : public MemObject virtual void recvFunctional(PacketPtr pkt) { pkt->setSrc(id); bus->recvFunctional(pkt); } - /** When reciving a status changefrom the peer port (at id), + /** When reciving a range change from the peer port (at id), pass it to the bus. */ - virtual void recvStatusChange(Status status) - { bus->recvStatusChange(status, id); } + virtual void recvRangeChange() + { bus->recvRangeChange(id); } /** When reciving a retry from the peer port (at id), pass it to the bus. */ @@ -112,9 +133,8 @@ class Bus : public MemObject // downstream from this bus, yes? That is, the union of all // the 'owned' address ranges of all the other interfaces on // this bus... - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) - { bus->addressRanges(resp, snoop, id); } + virtual AddrRangeList getAddrRanges() + { return bus->getAddrRanges(id); } // Ask the bus to ask everyone on the bus what their block size is and // take the max of it. This might need to be changed a bit if we ever @@ -174,8 +194,8 @@ class Bus : public MemObject * requests. */ void recvRetry(int id); - /** Function called by the port when the bus is recieving a status change.*/ - void recvStatusChange(Port::Status status, int id); + /** Function called by the port when the bus is recieving a range change.*/ + void recvRangeChange(int id); /** Find which port connected to this bus (if any) should be given a packet * with this address. @@ -238,12 +258,23 @@ class Bus : public MemObject portCache[0].valid = false; } - /** Process address range request. - * @param resp addresses that we can respond to - * @param snoop addresses that we would like to snoop - * @param id ide of the busport that made the request. + /** + * Return the address ranges this port is responsible for. + * + * @param id id of the bus port that made the request + * + * @return a list of non-overlapping address ranges + */ + AddrRangeList getAddrRanges(int id); + + /** + * Determine if the bus port is snooping or not. + * + * @param id id of the bus port that made the request + * + * @return a boolean indicating if this port is snooping or not */ - void addressRanges(AddrRangeList &resp, bool &snoop, int id); + bool isSnooping(int id); /** Calculate the timing parameters for the packet. Updates the * firstWordTime and finishTime fields of the packet object. @@ -264,7 +295,7 @@ class Bus : public MemObject BusFreeEvent busIdle; bool inRetry; - std::set inRecvStatusChange; + std::set inRecvRangeChange; /** max number of bus ids we've handed out so far */ short maxId; diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index 023b74323..278329152 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -70,11 +70,9 @@ BaseCache::BaseCache(const Params *p) } void -BaseCache::CachePort::recvStatusChange(Port::Status status) +BaseCache::CachePort::recvRangeChange() const { - if (status == Port::RangeChange) { - otherPort->sendStatusChange(Port::RangeChange); - } + otherPort->sendRangeChange(); } @@ -136,7 +134,7 @@ BaseCache::init() { if (!cpuSidePort || !memSidePort) panic("Cache not hooked up on both sides\n"); - cpuSidePort->sendStatusChange(Port::RangeChange); + cpuSidePort->sendRangeChange(); } diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index 297692b32..e6a5c284f 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -105,7 +105,7 @@ class BaseCache : public MemObject CachePort(const std::string &_name, BaseCache *_cache, const std::string &_label); - virtual void recvStatusChange(Status status); + virtual void recvRangeChange() const; virtual unsigned deviceBlockSize() const; diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index 7b1c877f9..b5c95b301 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -90,8 +90,7 @@ class Cache : public BaseCache return static_cast *>(cache); } - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual AddrRangeList getAddrRanges(); virtual bool recvTiming(PacketPtr pkt); @@ -118,8 +117,7 @@ class Cache : public BaseCache void processSendEvent(); - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual bool isSnooping(); virtual bool recvTiming(PacketPtr pkt); diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 1e5b59e17..46692a8d3 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -1554,14 +1554,15 @@ Cache::nextMSHRReadyTime() /////////////// template -void +AddrRangeList Cache::CpuSidePort:: -getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) +getAddrRanges() { // CPU side port doesn't snoop; it's a target only. It can // potentially respond to any address. - snoop = false; - resp.push_back(myCache()->getAddrRange()); + AddrRangeList ranges; + ranges.push_back(myCache()->getAddrRange()); + return ranges; } @@ -1612,14 +1613,13 @@ CpuSidePort::CpuSidePort(const std::string &_name, Cache *_cache, /////////////// template -void -Cache::MemSidePort:: -getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) +bool +Cache::MemSidePort::isSnooping() { // Memory-side port always snoops, but never passes requests // through to targets on the cpu side (so we don't add anything to // the address range list). - snoop = true; + return true; } diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 91b9052a1..bab6e868c 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -116,7 +116,7 @@ PhysicalMemory::init() for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { if (*pi) - (*pi)->sendStatusChange(Port::RangeChange); + (*pi)->sendRangeChange(); } } @@ -398,36 +398,30 @@ PhysicalMemory::getPort(const std::string &if_name, int idx) return port; } - -void -PhysicalMemory::recvStatusChange(Port::Status status) -{ -} - PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, PhysicalMemory *_memory) : SimpleTimingPort(_name, _memory), memory(_memory) { } void -PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) +PhysicalMemory::MemoryPort::recvRangeChange() { - memory->recvStatusChange(status); + // memory is a slave and thus should never have to worry about its + // neighbours address ranges } -void -PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) +AddrRangeList +PhysicalMemory::MemoryPort::getAddrRanges() { - memory->getAddressRanges(resp, snoop); + return memory->getAddrRanges(); } -void -PhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop) +AddrRangeList +PhysicalMemory::getAddrRanges() { - snoop = false; - resp.clear(); - resp.push_back(RangeSize(start(), size())); + AddrRangeList ranges; + ranges.push_back(RangeSize(start(), size())); + return ranges; } unsigned diff --git a/src/mem/physical.hh b/src/mem/physical.hh index cd6d809e2..1e00d8f5b 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -65,10 +65,9 @@ class PhysicalMemory : public MemObject virtual void recvFunctional(PacketPtr pkt); - virtual void recvStatusChange(Status status); + virtual void recvRangeChange(); - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual AddrRangeList getAddrRanges(); virtual unsigned deviceBlockSize() const; }; @@ -172,7 +171,7 @@ class PhysicalMemory : public MemObject public: unsigned deviceBlockSize() const; - void getAddressRanges(AddrRangeList &resp, bool &snoop); + AddrRangeList getAddrRanges(); virtual Port *getPort(const std::string &if_name, int idx = -1); void virtual init(); unsigned int drain(Event *de); @@ -181,7 +180,6 @@ class PhysicalMemory : public MemObject Tick doAtomicAccess(PacketPtr pkt); void doFunctionalAccess(PacketPtr pkt); virtual Tick calculateLatency(PacketPtr pkt); - void recvStatusChange(Port::Status status); public: virtual void serialize(std::ostream &os); diff --git a/src/mem/port.hh b/src/mem/port.hh index 0399a2a0e..98b3ad5f1 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * @@ -48,8 +60,7 @@ #include "mem/packet.hh" #include "mem/request.hh" -/** This typedef is used to clean up the parameter list of - * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared +/** This typedef is used to clean up getAddrRanges(). It's declared * outside the Port object since it's also used by some mem objects. * Eventually we should move this typedef to wherever Addr is * defined. @@ -101,13 +112,6 @@ class Port virtual ~Port(); - // mey be better to use subclasses & RTTI? - /** Holds the ports status. Currently just that a range recomputation needs - * to be done. */ - enum Status { - RangeChange - }; - void setName(const std::string &name) { portName = name; } @@ -139,8 +143,8 @@ class Port /** Called to recive a functional call from the peer port. */ virtual void recvFunctional(PacketPtr pkt) = 0; - /** Called to recieve a status change from the peer port. */ - virtual void recvStatusChange(Status status) = 0; + /** Called to recieve an address range change from the peer port. */ + virtual void recvRangeChange() = 0; /** Called by a peer port if the send was unsuccesful, and had to wait. This shouldn't be valid for response paths (IO Devices). @@ -155,17 +159,31 @@ class Port */ virtual unsigned deviceBlockSize() const { return 0; } - /** The peer port is requesting us to reply with a list of the ranges we - are responsible for. - @param resp is a list of ranges responded to - @param snoop is a list of ranges snooped - */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) - { panic("??"); } - public: + /** + * Get a list of the non-overlapping address ranges we are + * responsible for. The default implementation returns an empty + * list and thus no address ranges. Any slave port must override + * this function and return a populated list with at least one + * item. + * + * @return a list of ranges responded to + */ + virtual AddrRangeList getAddrRanges() + { AddrRangeList ranges; return ranges; } + + /** + * Determine if this port is snooping or not. The default + * implementation returns false and thus tells the neighbour we + * are not snooping. Any port that is to snoop (e.g. a cache + * connected to a bus) has to override this function. + * + * @return true if the port should be considered a snooper + */ + virtual bool isSnooping() + { return false; } + /** Function called by associated memory device (cache, memory, iodevice) in order to send a timing request to the port. Simply calls the peer port receive function. @@ -193,10 +211,11 @@ class Port void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(pkt); } - /** Called by the associated device to send a status change to the device - connected to the peer interface. - */ - void sendStatusChange(Status status) {peer->recvStatusChange(status); } + /** + * Called by the associated device to send a status range to the + * peer interface. + */ + void sendRangeChange() const { peer->recvRangeChange(); } /** When a timing access doesn't return a success, some time later the Retry will be sent. @@ -208,12 +227,6 @@ class Port */ unsigned peerBlockSize() const { return peer->deviceBlockSize(); } - /** Called by the associated device if it wishes to find out the address - ranges connected to the peer ports devices. - */ - void getPeerAddressRanges(AddrRangeList &resp, bool &snoop) - { peer->getDeviceAddressRanges(resp, snoop); } - /** This function is a wrapper around sendFunctional() that breaks a larger, arbitrarily aligned access into appropriate chunks. The default implementation can use diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index 0b013f78e..59c9bb19d 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -671,9 +671,8 @@ RubyPort::PioPort::sendTiming(PacketPtr pkt) bool RubyPort::M5Port::isPhysMemAddress(Addr addr) { - AddrRangeList physMemAddrList; - bool snoop = false; - ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); + AddrRangeList physMemAddrList = + ruby_port->physMemPort->getPeer()->getAddrRanges(); for (AddrRangeIter iter = physMemAddrList.begin(); iter != physMemAddrList.end(); iter++) { diff --git a/src/mem/tport.hh b/src/mem/tport.hh index 9143562fc..eaf5acd5d 100644 --- a/src/mem/tport.hh +++ b/src/mem/tport.hh @@ -139,10 +139,13 @@ class SimpleTimingPort : public Port bool recvTiming(PacketPtr pkt); /** - * Simple ports generally don't care about any status - * changes... can always override this in cases where that's not - * true. */ - virtual void recvStatusChange(Status status) { } + * Simple ports are generally used as slave ports (i.e. the + * respond to requests) and thus do not expect to receive any + * range changes (as the neighbouring port has a master role and + * do not have any address ranges. A subclass can override the + * default behaviuor if needed. + */ + virtual void recvRangeChange() { } public: -- cgit v1.2.3