From: Andreas Hansson Date: Thu, 31 May 2012 17:30:04 +0000 (-0400) Subject: Bus: Split the bus into a non-coherent and coherent bus X-Git-Tag: stable_2012_06_28~37 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0d329407116921cd9aed6f02da551cc5a8ec5131;p=gem5.git Bus: Split the bus into a non-coherent and coherent bus This patch introduces a class hierarchy of buses, a non-coherent one, and a coherent one, splitting the existing bus functionality. By doing so it also enables further specialisation of the two types of buses. A non-coherent bus connects a number of non-snooping masters and slaves, and routes the request and response packets based on the address. The request packets issued by the master connected to a non-coherent bus could still snoop in caches attached to a coherent bus, as is the case with the I/O bus and memory bus in most system configurations. No snoops will, however, reach any master on the non-coherent bus itself. The non-coherent bus can be used as a template for modelling PCI, PCIe, and non-coherent AMBA and OCP buses, and is typically used for the I/O buses. A coherent bus connects a number of (potentially) snooping masters and slaves, and routes the request and response packets based on the address, and also forwards all requests to the snoopers and deals with the snoop responses. The coherent bus can be used as a template for modelling QPI, HyperTransport, ACE and coherent OCP buses, and is typically used for the L1-to-L2 buses and as the main system interconnect. The configuration scripts are updated to use a NoncoherentBus for all peripheral and I/O buses. A bit of minor tidying up has also been done. --HG-- rename : src/mem/bus.cc => src/mem/coherent_bus.cc rename : src/mem/bus.hh => src/mem/coherent_bus.hh rename : src/mem/bus.cc => src/mem/noncoherent_bus.cc rename : src/mem/bus.hh => src/mem/noncoherent_bus.hh --- diff --git a/configs/common/CacheConfig.py b/configs/common/CacheConfig.py index 009cb1bf6..bc724f65f 100644 --- a/configs/common/CacheConfig.py +++ b/configs/common/CacheConfig.py @@ -43,7 +43,7 @@ def config_cache(options, system): system.l2 = L2Cache(size = options.l2_size, assoc = options.l2_assoc, block_size=options.cacheline_size) - system.tol2bus = Bus() + system.tol2bus = CoherentBus() system.l2.cpu_side = system.tol2bus.master system.l2.mem_side = system.membus.slave diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 8e4be3137..c9e28a5f6 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -50,7 +50,7 @@ class CowIdeDisk(IdeDisk): def childImage(self, ci): self.image.child.image_file = ci -class MemBus(Bus): +class MemBus(CoherentBus): badaddr_responder = BadAddr() default = Self.badaddr_responder.pio @@ -67,8 +67,8 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None): # generic system mdesc = SysConfig() self.readfile = mdesc.script() - self.iobus = Bus(bus_id=0) - self.membus = MemBus(bus_id=1) + self.iobus = NoncoherentBus() + self.membus = MemBus() # By default the bridge responds to all addresses above the I/O # base address (including the PCI config space) self.bridge = Bridge(delay='50ns', nack_delay='4ns', @@ -117,7 +117,7 @@ def makeLinuxAlphaRubySystem(mem_mode, mdesc = None): self.readfile = mdesc.script() # Create pio bus to connect all device pio ports to rubymem's pio port - self.piobus = Bus(bus_id=0) + self.piobus = NoncoherentBus() # # Pio functional accesses from devices need direct access to memory @@ -172,8 +172,8 @@ def makeSparcSystem(mem_mode, mdesc = None): # generic system mdesc = SysConfig() self.readfile = mdesc.script() - self.iobus = Bus(bus_id=0) - self.membus = MemBus(bus_id=1) + self.iobus = NoncoherentBus() + self.membus = MemBus() self.bridge = Bridge(delay='50ns', nack_delay='4ns') self.t1000 = T1000() self.t1000.attachOnChipIO(self.membus) @@ -237,8 +237,8 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False): mdesc = SysConfig() self.readfile = mdesc.script() - self.iobus = Bus(bus_id=0) - self.membus = MemBus(bus_id=1) + self.iobus = NoncoherentBus() + self.membus = MemBus() self.membus.badaddr_responder.warn_access = "warn" self.bridge = Bridge(delay='50ns', nack_delay='4ns') self.bridge.master = self.iobus.slave @@ -320,8 +320,8 @@ def makeLinuxMipsSystem(mem_mode, mdesc = None): # generic system mdesc = SysConfig() self.readfile = mdesc.script() - self.iobus = Bus(bus_id=0) - self.membus = MemBus(bus_id=1) + self.iobus = NoncoherentBus() + self.membus = MemBus() self.bridge = Bridge(delay='50ns', nack_delay='4ns') self.physmem = SimpleMemory(range = AddrRange('1GB')) self.bridge.master = self.iobus.slave @@ -363,11 +363,11 @@ def connectX86ClassicSystem(x86_sys, numCPUs): interrupts_address_space_base = 0xa000000000000000 APIC_range_size = 1 << 12; - x86_sys.membus = MemBus(bus_id=1) + x86_sys.membus = MemBus() x86_sys.physmem.port = x86_sys.membus.master # North Bridge - x86_sys.iobus = Bus(bus_id=0) + x86_sys.iobus = NoncoherentBus() x86_sys.bridge = Bridge(delay='50ns', nack_delay='4ns') x86_sys.bridge.master = x86_sys.iobus.slave x86_sys.bridge.slave = x86_sys.membus.master @@ -402,7 +402,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs): def connectX86RubySystem(x86_sys): # North Bridge - x86_sys.piobus = Bus(bus_id=0) + x86_sys.piobus = NoncoherentBus() # # Pio functional accesses from devices need direct access to memory diff --git a/configs/example/memtest.py b/configs/example/memtest.py index 2dcccbba6..590378920 100644 --- a/configs/example/memtest.py +++ b/configs/example/memtest.py @@ -148,7 +148,7 @@ def make_level(spec, prototypes, attach_obj, attach_port): parent = attach_obj # use attach obj as config parent too if len(spec) > 1 and (fanout > 1 or options.force_bus): port = getattr(attach_obj, attach_port) - new_bus = Bus(clock="500MHz", width=16) + new_bus = CoherentBus(clock="500MHz", width=16) if (port.role == 'MASTER'): new_bus.slave = port attach_port = "master" diff --git a/configs/example/se.py b/configs/example/se.py index 8324bea4e..83abbd2f3 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -153,7 +153,7 @@ np = options.num_cpus system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)], physmem = SimpleMemory(range=AddrRange("512MB")), - membus = Bus(), mem_mode = test_mem_mode) + membus = CoherentBus(), mem_mode = test_mem_mode) # Sanity check if options.fastmem and (options.caches or options.l2cache): diff --git a/configs/splash2/cluster.py b/configs/splash2/cluster.py index dd8ab784a..d7e32a414 100644 --- a/configs/splash2/cluster.py +++ b/configs/splash2/cluster.py @@ -173,7 +173,7 @@ if options.timing: for j in xrange(options.numclusters): clusters[j].id = j for cluster in clusters: - cluster.clusterbus = Bus(clock=busFrequency) + cluster.clusterbus = CoherentBus(clock=busFrequency) all_l1buses += [cluster.clusterbus] cluster.cpus = [TimingSimpleCPU(cpu_id = i + cluster.id, clock=options.frequency) @@ -186,7 +186,7 @@ elif options.detailed: for j in xrange(options.numclusters): clusters[j].id = j for cluster in clusters: - cluster.clusterbus = Bus(clock=busFrequency) + cluster.clusterbus = CoherentBus(clock=busFrequency) all_l1buses += [cluster.clusterbus] cluster.cpus = [DerivO3CPU(cpu_id = i + cluster.id, clock=options.frequency) @@ -199,7 +199,7 @@ else: for j in xrange(options.numclusters): clusters[j].id = j for cluster in clusters: - cluster.clusterbus = Bus(clock=busFrequency) + cluster.clusterbus = CoherentBus(clock=busFrequency) all_l1buses += [cluster.clusterbus] cluster.cpus = [AtomicSimpleCPU(cpu_id = i + cluster.id, clock=options.frequency) @@ -212,9 +212,10 @@ else: # Create a system, and add system wide objects # ---------------------- system = System(cpu = all_cpus, l1_ = all_l1s, l1bus_ = all_l1buses, - physmem = SimpleMemory(), membus = Bus(clock = busFrequency)) + physmem = SimpleMemory(), + membus = CoherentBus(clock = busFrequency)) -system.toL2bus = Bus(clock = busFrequency) +system.toL2bus = CoherentBus(clock = busFrequency) system.l2 = L2(size = options.l2size, assoc = 8) # ---------------------- diff --git a/configs/splash2/run.py b/configs/splash2/run.py index 40dafceff..48e255c52 100644 --- a/configs/splash2/run.py +++ b/configs/splash2/run.py @@ -198,9 +198,9 @@ else: # Create a system, and add system wide objects # ---------------------- system = System(cpu = cpus, physmem = SimpleMemory(), - membus = Bus(clock = busFrequency)) + membus = CoherentBus(clock = busFrequency)) -system.toL2bus = Bus(clock = busFrequency) +system.toL2bus = CoherentBus(clock = busFrequency) system.l2 = L2(size = options.l2size, assoc = 8) # ---------------------- diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 60d06b209..9ed2cb789 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -47,7 +47,7 @@ from m5.defines import buildEnv from m5.params import * from m5.proxy import * -from Bus import Bus +from Bus import CoherentBus from InstTracer import InstTracer from ExeTracer import ExeTracer from MemObject import MemObject @@ -223,7 +223,7 @@ class BaseCPU(MemObject): def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None): self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) - self.toL2Bus = Bus() + self.toL2Bus = CoherentBus() self.connectCachedPorts(self.toL2Bus) self.l2cache = l2c self.toL2Bus.master = self.l2cache.cpu_side diff --git a/src/mem/Bus.py b/src/mem/Bus.py index 91043da80..05033d382 100644 --- a/src/mem/Bus.py +++ b/src/mem/Bus.py @@ -1,3 +1,15 @@ +# Copyright (c) 2012 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) 2005-2008 The Regents of The University of Michigan # All rights reserved. # @@ -25,22 +37,36 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Nathan Binkert +# Andreas Hansson -from m5.defines import buildEnv -from m5.params import * -from m5.proxy import * from MemObject import MemObject +from m5.params import * -class Bus(MemObject): - type = 'Bus' +class BaseBus(MemObject): + type = 'BaseBus' + abstract = True slave = VectorSlavePort("vector port for connecting masters") master = VectorMasterPort("vector port for connecting slaves") - bus_id = Param.Int(0, "blah") clock = Param.Clock("1GHz", "bus clock speed") header_cycles = Param.Int(1, "cycles of overhead per transaction") width = Param.Int(64, "bus width (bytes)") - block_size = Param.Int(64, "The default block size if one isn't set by a device attached to the bus.") - default = MasterPort("Default port for requests that aren't handled " \ - "by a device.") - use_default_range = \ - Param.Bool(False, "Query default port device for legal range.") + block_size = Param.Int(64, "The default block size if not set by " \ + "any connected module") + + # The default port can be left unconnected, or be used to connect + # a default slave port + default = MasterPort("Port for connecting an optional default slave") + + # The default port can be used unconditionally, or based on + # address range, in which case it may overlap with other + # ports. The default range is always checked first, thus creating + # a two-level hierarchical lookup. This is useful e.g. for the PCI + # bus configuration. + use_default_range = Param.Bool(False, "Perform address mapping for " \ + "the default port") + +class NoncoherentBus(BaseBus): + type = 'NoncoherentBus' + +class CoherentBus(BaseBus): + type = 'CoherentBus' diff --git a/src/mem/SConscript b/src/mem/SConscript index 3ffb3503a..1961204f7 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -37,9 +37,11 @@ SimObject('MemObject.py') Source('bridge.cc') Source('bus.cc') +Source('coherent_bus.cc') Source('comm_monitor.cc') Source('mem_object.cc') Source('mport.cc') +Source('noncoherent_bus.cc') Source('packet.cc') Source('port.cc') Source('packet_queue.cc') @@ -56,8 +58,13 @@ if env['TARGET_ISA'] != 'no': Source('page_table.cc') Source('physical.cc') -DebugFlag('Bus') +DebugFlag('BaseBus') DebugFlag('BusAddrRanges') +DebugFlag('CoherentBus') +DebugFlag('NoncoherentBus') +CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus', + 'NoncoherentBus']) + DebugFlag('BusBridge') DebugFlag('CommMonitor') DebugFlag('LLSC') diff --git a/src/mem/bus.cc b/src/mem/bus.cc index a22b0e7fd..8040118d2 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -53,7 +53,7 @@ #include "debug/BusAddrRanges.hh" #include "mem/bus.hh" -Bus::Bus(const BusParams *p) +BaseBus::BaseBus(const BaseBusParams *p) : MemObject(p), clock(p->clock), headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), drainEvent(NULL), busIdleEvent(this), inRetry(false), @@ -69,37 +69,23 @@ Bus::Bus(const BusParams *p) fatal("Bus clock period must be positive\n"); if (headerCycles <= 0) fatal("Number of header cycles must be positive\n"); +} - // create the ports based on the size of the master and slave - // vector ports, and the presence of the default port, the ports - // are enumerated starting from zero - for (int i = 0; i < p->port_master_connection_count; ++i) { - std::string portName = csprintf("%s-p%d", name(), i); - MasterPort* bp = new BusMasterPort(portName, this, i); - masterPorts.push_back(bp); - } - - // see if we have a default slave device connected and if so add - // our corresponding master port - if (p->port_default_connection_count) { - defaultPortID = masterPorts.size(); - std::string portName = csprintf("%s-default", name()); - MasterPort* bp = new BusMasterPort(portName, this, defaultPortID); - masterPorts.push_back(bp); +BaseBus::~BaseBus() +{ + for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); + ++m) { + delete *m; } - // create the slave ports, once again starting at zero - for (int i = 0; i < p->port_slave_connection_count; ++i) { - std::string portName = csprintf("%s-p%d", name(), i); - SlavePort* bp = new BusSlavePort(portName, this, i); - slavePorts.push_back(bp); + for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); + ++s) { + delete *s; } - - clearPortCache(); } MasterPort & -Bus::getMasterPort(const std::string &if_name, int idx) +BaseBus::getMasterPort(const std::string &if_name, int idx) { if (if_name == "master" && idx < masterPorts.size()) { // the master port index translates directly to the vector position @@ -112,7 +98,7 @@ Bus::getMasterPort(const std::string &if_name, int idx) } SlavePort & -Bus::getSlavePort(const std::string &if_name, int idx) +BaseBus::getSlavePort(const std::string &if_name, int idx) { if (if_name == "slave" && idx < slavePorts.size()) { // the slave port index translates directly to the vector position @@ -122,23 +108,8 @@ Bus::getSlavePort(const std::string &if_name, int idx) } } -void -Bus::init() -{ - // iterate over our slave ports and determine which of our - // neighbouring master ports are snooping and add them as snoopers - for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); - ++p) { - if ((*p)->getMasterPort().isSnooping()) { - DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", - (*p)->getMasterPort().name()); - snoopPorts.push_back(*p); - } - } -} - Tick -Bus::calcPacketTiming(PacketPtr pkt) +BaseBus::calcPacketTiming(PacketPtr pkt) { // determine the current time rounded to the closest following // clock edge @@ -169,7 +140,7 @@ Bus::calcPacketTiming(PacketPtr pkt) return headerTime; } -void Bus::occupyBus(Tick until) +void BaseBus::occupyBus(Tick until) { if (until == 0) { // shortcut for express snoop packets @@ -179,12 +150,12 @@ void Bus::occupyBus(Tick until) tickNextIdle = until; reschedule(busIdleEvent, tickNextIdle, true); - DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", + DPRINTF(BaseBus, "The bus is now occupied from tick %d to %d\n", curTick(), tickNextIdle); } bool -Bus::isOccupied(Port* port) +BaseBus::isOccupied(Port* port) { // first we see if the next idle tick is in the future, next the // bus is considered occupied if there are ports on the retry list @@ -197,220 +168,15 @@ Bus::isOccupied(Port* port) return false; } -bool -Bus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) -{ - // determine the source port based on the id - SlavePort *src_port = slavePorts[slave_port_id]; - - // test if the bus should be considered occupied for the current - // port, and exclude express snoops from the check - if (!pkt->isExpressSnoop() && isOccupied(src_port)) { - DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - - DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - // set the source port for routing of the response - pkt->setSrc(slave_port_id); - - Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); - Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable()) { - // the packet is a memory-mapped request and should be - // broadcasted to our snoopers but the source - forwardTiming(pkt, slave_port_id); - } - - // remember if we add an outstanding req so we can undo it if - // necessary, if the packet needs a response, we should add it - // as outstanding and express snoops never fail so there is - // not need to worry about them - bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse(); - - // keep track that we have an outstanding request packet - // matching this request, this is used by the coherency - // mechanism in determining what to do with snoop responses - // (in recvTimingSnoop) - if (add_outstanding) { - // we should never have an exsiting request outstanding - assert(outstandingReq.find(pkt->req) == outstandingReq.end()); - outstandingReq.insert(pkt->req); - } - - // since it is a normal request, determine the destination - // based on the address and attempt to send the packet - bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); - - if (!success) { - // inhibited packets should never be forced to retry - assert(!pkt->memInhibitAsserted()); - - // if it was added as outstanding and the send failed, then - // erase it again - if (add_outstanding) - outstandingReq.erase(pkt->req); - - DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x RETRY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - addToRetryList(src_port); - occupyBus(headerFinishTime); - - return false; - } - - succeededTiming(packetFinishTime); - - return true; -} - -bool -Bus::recvTimingResp(PacketPtr pkt, PortID master_port_id) -{ - // determine the source port based on the id - MasterPort *src_port = masterPorts[master_port_id]; - - // test if the bus should be considered occupied for the current - // port - if (isOccupied(src_port)) { - DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - - DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - calcPacketTiming(pkt); - Tick packetFinishTime = pkt->finishTime; - - // the packet is a normal response to a request that we should - // have seen passing through the bus - assert(outstandingReq.find(pkt->req) != outstandingReq.end()); - - // remove it as outstanding - outstandingReq.erase(pkt->req); - - // send the packet to the destination through one of our slave - // ports, as determined by the destination field - bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); - - // currently it is illegal to block responses... can lead to - // deadlock - assert(success); - - succeededTiming(packetFinishTime); - - return true; -} - void -Bus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) -{ - DPRINTF(Bus, "recvTimingSnoopReq: src %s %s 0x%x\n", - masterPorts[master_port_id]->name(), pkt->cmdString(), - pkt->getAddr()); - - // we should only see express snoops from caches - assert(pkt->isExpressSnoop()); - - // set the source port for routing of the response - pkt->setSrc(master_port_id); - - // forward to all snoopers - forwardTiming(pkt, InvalidPortID); - - // a snoop request came from a connected slave device (one of - // our master ports), and if it is not coming from the slave - // device responsible for the address range something is - // wrong, hence there is nothing further to do as the packet - // would be going back to where it came from - assert(master_port_id == findPort(pkt->getAddr())); - - // this is an express snoop and is never forced to retry - assert(!inRetry); -} - -bool -Bus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) -{ - // determine the source port based on the id - SlavePort* src_port = slavePorts[slave_port_id]; - - // test if the bus should be considered occupied for the current - // port - if (isOccupied(src_port)) { - DPRINTF(Bus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - - DPRINTF(Bus, "recvTimingSnoop: src %s %s 0x%x\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - // get the destination from the packet - PortID dest = pkt->getDest(); - - // responses are never express snoops - assert(!pkt->isExpressSnoop()); - - calcPacketTiming(pkt); - Tick packetFinishTime = pkt->finishTime; - - // determine if the response is from a snoop request we - // created as the result of a normal request (in which case it - // should be in the outstandingReq), or if we merely forwarded - // someone else's snoop request - if (outstandingReq.find(pkt->req) == outstandingReq.end()) { - // this is a snoop response to a snoop request we - // forwarded, e.g. coming from the L1 and going to the L2 - // this should be forwarded as a snoop response - bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); - assert(success); - } else { - // we got a snoop response on one of our slave ports, - // i.e. from a coherent master connected to the bus, and - // since we created the snoop request as part of - // recvTiming, this should now be a normal response again - outstandingReq.erase(pkt->req); - - // this is a snoop response from a coherent master, with a - // destination field set on its way through the bus as - // request, hence it should never go back to where the - // snoop response came from, but instead to where the - // original request came from - assert(slave_port_id != dest); - - // as a normal response, it should go back to a master - // through one of our slave ports - bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); - - // currently it is illegal to block responses... can lead - // to deadlock - assert(success); - } - - succeededTiming(packetFinishTime); - - return true; -} - - -void -Bus::succeededTiming(Tick busy_time) +BaseBus::succeededTiming(Tick busy_time) { // occupy the bus accordingly occupyBus(busy_time); // if a retrying port succeeded, also take it off the retry list if (inRetry) { - DPRINTF(Bus, "Remove retry from list %s\n", + DPRINTF(BaseBus, "Remove retry from list %s\n", retryList.front()->name()); retryList.pop_front(); inRetry = false; @@ -418,24 +184,7 @@ Bus::succeededTiming(Tick busy_time) } void -Bus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) -{ - for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { - SlavePort *p = *s; - // we could have gotten this request from a snooping master - // (corresponding to our own slave port that is also in - // snoopPorts) and should not send it back to where it came - // from - if (exclude_slave_port_id == InvalidPortID || - p->getId() != exclude_slave_port_id) { - // cache is not allowed to refuse snoop - p->sendTimingSnoopReq(pkt); - } - } -} - -void -Bus::releaseBus() +BaseBus::releaseBus() { // releasing the bus means we should now be idle assert(curTick() >= tickNextIdle); @@ -458,7 +207,7 @@ Bus::releaseBus() } void -Bus::retryWaiting() +BaseBus::retryWaiting() { // this should never be called with an empty retry list assert(!retryList.empty()); @@ -489,7 +238,7 @@ Bus::retryWaiting() } void -Bus::recvRetry() +BaseBus::recvRetry() { // we got a retry from a peer that we tried to send something to // and failed, but we sent it on the account of someone else, and @@ -509,7 +258,7 @@ Bus::recvRetry() } PortID -Bus::findPort(Addr addr) +BaseBus::findPort(Addr addr) { /* An interval tree would be a better way to do this. --ali. */ PortID dest_id = checkPortCache(addr); @@ -529,12 +278,13 @@ Bus::findPort(Addr addr) AddrRangeIter a_end = defaultRange.end(); for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { if (*i == addr) { - DPRINTF(Bus, " found addr %#llx on default\n", addr); + DPRINTF(BusAddrRanges, " found addr %#llx on default\n", + addr); return defaultPortID; } } } else if (defaultPortID != InvalidPortID) { - DPRINTF(Bus, "Unable to find destination for addr %#llx, " + DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " "will use default port\n", addr); return defaultPortID; } @@ -545,170 +295,9 @@ Bus::findPort(Addr addr) name()); } -Tick -Bus::recvAtomic(PacketPtr pkt, PortID slave_port_id) -{ - DPRINTF(Bus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", - slavePorts[slave_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - - MemCmd snoop_response_cmd = MemCmd::InvalidCmd; - Tick snoop_response_latency = 0; - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable()) { - // forward to all snoopers but the source - std::pair snoop_result = - forwardAtomic(pkt, slave_port_id); - snoop_response_cmd = snoop_result.first; - snoop_response_latency = snoop_result.second; - } - - // even if we had a snoop response, we must continue and also - // perform the actual request at the destination - PortID dest_id = findPort(pkt->getAddr()); - - // forward the request to the appropriate destination - Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); - - // if we got a response from a snooper, restore it here - if (snoop_response_cmd != MemCmd::InvalidCmd) { - // no one else should have responded - assert(!pkt->isResponse()); - pkt->cmd = snoop_response_cmd; - response_latency = snoop_response_latency; - } - - pkt->finishTime = curTick() + response_latency; - return response_latency; -} - -Tick -Bus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) -{ - DPRINTF(Bus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", - masterPorts[master_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - - // forward to all snoopers - std::pair snoop_result = - forwardAtomic(pkt, InvalidPortID); - MemCmd snoop_response_cmd = snoop_result.first; - Tick snoop_response_latency = snoop_result.second; - - if (snoop_response_cmd != MemCmd::InvalidCmd) - pkt->cmd = snoop_response_cmd; - - pkt->finishTime = curTick() + snoop_response_latency; - return snoop_response_latency; -} - -std::pair -Bus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) -{ - // the packet may be changed on snoops, record the original - // command to enable us to restore it between snoops so that - // additional snoops can take place properly - MemCmd orig_cmd = pkt->cmd; - MemCmd snoop_response_cmd = MemCmd::InvalidCmd; - Tick snoop_response_latency = 0; - - for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { - SlavePort *p = *s; - // we could have gotten this request from a snooping master - // (corresponding to our own slave port that is also in - // snoopPorts) and should not send it back to where it came - // from - if (exclude_slave_port_id == InvalidPortID || - p->getId() != exclude_slave_port_id) { - Tick latency = p->sendAtomicSnoop(pkt); - // in contrast to a functional access, we have to keep on - // going as all snoopers must be updated even if we get a - // response - if (pkt->isResponse()) { - // response from snoop agent - assert(pkt->cmd != orig_cmd); - assert(pkt->memInhibitAsserted()); - // should only happen once - assert(snoop_response_cmd == MemCmd::InvalidCmd); - // save response state - snoop_response_cmd = pkt->cmd; - snoop_response_latency = latency; - // restore original packet state for remaining snoopers - pkt->cmd = orig_cmd; - } - } - } - - // the packet is restored as part of the loop and any potential - // snoop response is part of the returned pair - return std::make_pair(snoop_response_cmd, snoop_response_latency); -} - -void -Bus::recvFunctional(PacketPtr pkt, PortID slave_port_id) -{ - if (!pkt->isPrint()) { - // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(Bus, - "recvFunctional: packet src %s addr 0x%x cmd %s\n", - slavePorts[slave_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - } - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable()) { - // forward to all snoopers but the source - forwardFunctional(pkt, slave_port_id); - } - - // there is no need to continue if the snooping has found what we - // were looking for and the packet is already a response - if (!pkt->isResponse()) { - PortID dest_id = findPort(pkt->getAddr()); - - masterPorts[dest_id]->sendFunctional(pkt); - } -} - -void -Bus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) -{ - if (!pkt->isPrint()) { - // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(Bus, - "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", - masterPorts[master_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - } - - // forward to all snoopers - forwardFunctional(pkt, InvalidPortID); -} - -void -Bus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) -{ - for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { - SlavePort *p = *s; - // we could have gotten this request from a snooping master - // (corresponding to our own slave port that is also in - // snoopPorts) and should not send it back to where it came - // from - if (exclude_slave_port_id == InvalidPortID || - p->getId() != exclude_slave_port_id) - p->sendFunctionalSnoop(pkt); - - // if we get a response we are done - if (pkt->isResponse()) { - break; - } - } -} - /** Function called by the port when the bus is receiving a range change.*/ void -Bus::recvRangeChange(PortID master_port_id) +BaseBus::recvRangeChange(PortID master_port_id) { AddrRangeList ranges; AddrRangeIter iter; @@ -773,7 +362,7 @@ Bus::recvRangeChange(PortID master_port_id) } AddrRangeList -Bus::getAddrRanges() +BaseBus::getAddrRanges() { AddrRangeList ranges; @@ -813,29 +402,22 @@ Bus::getAddrRanges() return ranges; } -bool -Bus::isSnooping() const -{ - // in essence, answer the question if there are snooping ports - return !snoopPorts.empty(); -} - unsigned -Bus::findBlockSize() +BaseBus::findBlockSize() { if (cachedBlockSizeValid) return cachedBlockSize; unsigned max_bs = 0; - PortIter p_end = portMap.end(); - for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { - unsigned tmp_bs = masterPorts[p_iter->second]->peerBlockSize(); + for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); + ++m) { + unsigned tmp_bs = (*m)->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; } - for (SlavePortConstIter s = snoopPorts.begin(); s != snoopPorts.end(); + for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); ++s) { unsigned tmp_bs = (*s)->peerBlockSize(); if (tmp_bs > max_bs) @@ -853,7 +435,7 @@ Bus::findBlockSize() unsigned int -Bus::drain(Event * de) +BaseBus::drain(Event * de) { //We should check that we're not "doing" anything, and that noone is //waiting. We might be idle but have someone waiting if the device we @@ -867,14 +449,8 @@ Bus::drain(Event * de) } void -Bus::startup() +BaseBus::startup() { if (tickNextIdle < curTick()) tickNextIdle = (curTick() / clock) * clock + clock; } - -Bus * -BusParams::create() -{ - return new Bus(this); -} diff --git a/src/mem/bus.hh b/src/mem/bus.hh index c35b46cc2..4f0e44b1c 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -45,7 +45,7 @@ /** * @file - * Declaration of a bus object. + * Declaration of an abstract bus base class. */ #ifndef __MEM_BUS_HH__ @@ -53,155 +53,26 @@ #include #include -#include #include "base/range.hh" #include "base/range_map.hh" #include "base/types.hh" #include "mem/mem_object.hh" -#include "mem/packet.hh" -#include "mem/port.hh" -#include "params/Bus.hh" -#include "sim/eventq.hh" +#include "params/BaseBus.hh" -class Bus : public MemObject +/** + * The base bus contains the common elements of the non-coherent and + * coherent bus. It is an abstract class that does not have any of the + * functionality relating to the actual reception and transmission of + * packets, as this is left for the subclasses. + * + * The BaseBus is responsible for the basic flow control (busy or + * not), the administration of retries, and the address decoding. + */ +class BaseBus : public MemObject { - /** - * Declaration of the bus slave port type, one will be - * instantiated for each of the master interfaces connecting to - * the bus. - */ - class BusSlavePort : public SlavePort - { - private: - /** A pointer to the bus to which this port belongs. */ - Bus *bus; - - public: - - /** Constructor for the BusSlavePort.*/ - BusSlavePort(const std::string &_name, Bus *_bus, PortID _id) - : SlavePort(_name, _bus, _id), bus(_bus) - { } - - protected: - - /** - * When receiving a timing request, pass it to the bus. - */ - virtual bool recvTimingReq(PacketPtr pkt) - { return bus->recvTimingReq(pkt, id); } - - /** - * When receiving a timing snoop response, pass it to the bus. - */ - virtual bool recvTimingSnoopResp(PacketPtr pkt) - { return bus->recvTimingSnoopResp(pkt, id); } - - /** - * When receiving an atomic request, pass it to the bus. - */ - virtual Tick recvAtomic(PacketPtr pkt) - { return bus->recvAtomic(pkt, id); } - - /** - * When receiving a functional request, pass it to the bus. - */ - virtual void recvFunctional(PacketPtr pkt) - { bus->recvFunctional(pkt, id); } - - /** - * When receiving a retry, pass it to the bus. - */ - virtual void recvRetry() - { panic("Bus slave ports always succeed and should never retry.\n"); } - - // This should return all the 'owned' addresses that are - // downstream from this bus, yes? That is, the union of all - // the 'owned' address ranges of all the other interfaces on - // this bus... - virtual AddrRangeList getAddrRanges() - { return bus->getAddrRanges(); } - - // 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 - // support multiple block sizes. - virtual unsigned deviceBlockSize() const - { return bus->findBlockSize(); } - - }; - - /** - * Declaration of the bus master port type, one will be - * instantiated for each of the slave interfaces connecting to the - * bus. - */ - class BusMasterPort : public MasterPort - { - private: - /** A pointer to the bus to which this port belongs. */ - Bus *bus; - - public: - - /** Constructor for the BusMasterPort.*/ - BusMasterPort(const std::string &_name, Bus *_bus, PortID _id) - : MasterPort(_name, _bus, _id), bus(_bus) - { } - - /** - * 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() const - { return bus->isSnooping(); } - - protected: - - /** - * When receiving a timing response, pass it to the bus. - */ - virtual bool recvTimingResp(PacketPtr pkt) - { return bus->recvTimingResp(pkt, id); } - - /** - * When receiving a timing snoop request, pass it to the bus. - */ - virtual void recvTimingSnoopReq(PacketPtr pkt) - { return bus->recvTimingSnoopReq(pkt, id); } - - /** - * When receiving an atomic snoop request, pass it to the bus. - */ - virtual Tick recvAtomicSnoop(PacketPtr pkt) - { return bus->recvAtomicSnoop(pkt, id); } - - /** - * When receiving a functional snoop request, pass it to the bus. - */ - virtual void recvFunctionalSnoop(PacketPtr pkt) - { bus->recvFunctionalSnoop(pkt, id); } - - /** When reciving a range change from the peer port (at id), - pass it to the bus. */ - virtual void recvRangeChange() - { bus->recvRangeChange(id); } - - /** When reciving a retry from the peer port (at id), - pass it to the bus. */ - virtual void recvRetry() - { bus->recvRetry(); } - - // 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 - // support multiple block sizes. - virtual unsigned deviceBlockSize() const - { return bus->findBlockSize(); } - - }; + protected: /** the clock speed for the bus */ int clock; @@ -219,41 +90,6 @@ class Bus : public MemObject AddrRangeList defaultRange; - std::vector snoopPorts; - - /** - * Store the outstanding requests so we can determine which ones - * we generated and which ones were merely forwarded. This is used - * in the coherent bus when coherency responses come back. - */ - std::set outstandingReq; - - /** Function called by the port when the bus is recieving a Timing - request packet.*/ - bool recvTimingReq(PacketPtr pkt, PortID slave_port_id); - - /** Function called by the port when the bus is recieving a Timing - response packet.*/ - bool recvTimingResp(PacketPtr pkt, PortID master_port_id); - - /** Function called by the port when the bus is recieving a timing - snoop request.*/ - void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id); - - /** Function called by the port when the bus is recieving a timing - snoop response.*/ - bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id); - - /** - * Forward a timing packet to our snoopers, potentially excluding - * one of the connected coherent masters to avoid sending a packet - * back to where it came from. - * - * @param pkt Packet to forward - * @param exclude_slave_port_id Id of slave port to exclude - */ - void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id); - /** * Determine if the bus is to be considered occupied when being * presented with a packet from a specific port. If so, the port @@ -274,45 +110,6 @@ class Bus : public MemObject */ void succeededTiming(Tick busy_time); - /** Function called by the port when the bus is recieving a Atomic - transaction.*/ - Tick recvAtomic(PacketPtr pkt, PortID slave_port_id); - - /** Function called by the port when the bus is recieving an - atomic snoop transaction.*/ - Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id); - - /** - * Forward an atomic packet to our snoopers, potentially excluding - * one of the connected coherent masters to avoid sending a packet - * back to where it came from. - * - * @param pkt Packet to forward - * @param exclude_slave_port_id Id of slave port to exclude - * - * @return a pair containing the snoop response and snoop latency - */ - std::pair forwardAtomic(PacketPtr pkt, - PortID exclude_slave_port_id); - - /** Function called by the port when the bus is recieving a Functional - transaction.*/ - void recvFunctional(PacketPtr pkt, PortID slave_port_id); - - /** Function called by the port when the bus is recieving a functional - snoop transaction.*/ - void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id); - - /** - * Forward a functional packet to our snoopers, potentially - * excluding one of the connected coherent masters to avoid - * sending a packet back to where it came from. - * - * @param pkt Packet to forward - * @param exclude_slave_port_id Id of slave port to exclude - */ - void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id); - /** Timing function called by port when it is once again able to process * requests. */ void recvRetry(); @@ -392,13 +189,6 @@ class Bus : public MemObject */ AddrRangeList getAddrRanges(); - /** - * Determine if the bus port is snooping or not. - * - * @return a boolean indicating if this port is snooping or not - */ - bool isSnooping() const; - /** Calculate the timing parameters for the packet. Updates the * firstWordTime and finishTime fields of the packet object. * Returns the tick at which the packet header is completed (which @@ -430,7 +220,7 @@ class Bus : public MemObject unsigned findBlockSize(); // event used to schedule a release of the bus - EventWrapper busIdleEvent; + EventWrapper busIdleEvent; bool inRetry; std::set inRecvRangeChange; @@ -439,8 +229,11 @@ class Bus : public MemObject std::vector slavePorts; std::vector masterPorts; + /** Convenience typedefs. */ typedef std::vector::iterator SlavePortIter; + typedef std::vector::iterator MasterPortIter; typedef std::vector::const_iterator SlavePortConstIter; + typedef std::vector::const_iterator MasterPortConstIter; /** An array of pointers to ports that retry should be called on because the * original send failed for whatever reason.*/ @@ -478,18 +271,20 @@ class Bus : public MemObject unsigned cachedBlockSize; bool cachedBlockSizeValid; + BaseBus(const BaseBusParams *p); + + virtual ~BaseBus(); + public: /** A function used to return the port associated with this bus object. */ virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); - virtual void init(); virtual void startup(); unsigned int drain(Event *de); - Bus(const BusParams *p); }; #endif //__MEM_BUS_HH__ diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc new file mode 100644 index 000000000..b40e84762 --- /dev/null +++ b/src/mem/coherent_bus.cc @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2011-2012 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. + * + * 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: Ali Saidi + * Andreas Hansson + * William Wang + */ + +/** + * @file + * Definition of a bus object. + */ + +#include "base/misc.hh" +#include "base/trace.hh" +#include "debug/BusAddrRanges.hh" +#include "debug/CoherentBus.hh" +#include "mem/coherent_bus.hh" + +CoherentBus::CoherentBus(const CoherentBusParams *p) + : BaseBus(p) +{ + // create the ports based on the size of the master and slave + // vector ports, and the presence of the default port, the ports + // are enumerated starting from zero + for (int i = 0; i < p->port_master_connection_count; ++i) { + std::string portName = csprintf("%s-p%d", name(), i); + MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); + masterPorts.push_back(bp); + } + + // see if we have a default slave device connected and if so add + // our corresponding master port + if (p->port_default_connection_count) { + defaultPortID = masterPorts.size(); + std::string portName = csprintf("%s-default", name()); + MasterPort* bp = new CoherentBusMasterPort(portName, *this, + defaultPortID); + masterPorts.push_back(bp); + } + + // create the slave ports, once again starting at zero + for (int i = 0; i < p->port_slave_connection_count; ++i) { + std::string portName = csprintf("%s-p%d", name(), i); + SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); + slavePorts.push_back(bp); + } + + clearPortCache(); +} + +void +CoherentBus::init() +{ + // iterate over our slave ports and determine which of our + // neighbouring master ports are snooping and add them as snoopers + for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); + ++p) { + if ((*p)->getMasterPort().isSnooping()) { + DPRINTF(BusAddrRanges, "Adding snooping master %s\n", + (*p)->getMasterPort().name()); + snoopPorts.push_back(*p); + } + } + + if (snoopPorts.empty()) + warn("CoherentBus %s has no snooping ports attached!\n", name()); +} + +bool +CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +{ + // determine the source port based on the id + SlavePort *src_port = slavePorts[slave_port_id]; + + // test if the bus should be considered occupied for the current + // port, and exclude express snoops from the check + if (!pkt->isExpressSnoop() && isOccupied(src_port)) { + DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // set the source port for routing of the response + pkt->setSrc(slave_port_id); + + Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); + Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; + + // uncacheable requests need never be snooped + if (!pkt->req->isUncacheable()) { + // the packet is a memory-mapped request and should be + // broadcasted to our snoopers but the source + forwardTiming(pkt, slave_port_id); + } + + // remember if we add an outstanding req so we can undo it if + // necessary, if the packet needs a response, we should add it + // as outstanding and express snoops never fail so there is + // not need to worry about them + bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse(); + + // keep track that we have an outstanding request packet + // matching this request, this is used by the coherency + // mechanism in determining what to do with snoop responses + // (in recvTimingSnoop) + if (add_outstanding) { + // we should never have an exsiting request outstanding + assert(outstandingReq.find(pkt->req) == outstandingReq.end()); + outstandingReq.insert(pkt->req); + } + + // since it is a normal request, determine the destination + // based on the address and attempt to send the packet + bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); + + if (!success) { + // inhibited packets should never be forced to retry + assert(!pkt->memInhibitAsserted()); + + // if it was added as outstanding and the send failed, then + // erase it again + if (add_outstanding) + outstandingReq.erase(pkt->req); + + DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + addToRetryList(src_port); + occupyBus(headerFinishTime); + + return false; + } + + succeededTiming(packetFinishTime); + + return true; +} + +bool +CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) +{ + // determine the source port based on the id + MasterPort *src_port = masterPorts[master_port_id]; + + // test if the bus should be considered occupied for the current + // port + if (isOccupied(src_port)) { + DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + calcPacketTiming(pkt); + Tick packetFinishTime = pkt->finishTime; + + // the packet is a normal response to a request that we should + // have seen passing through the bus + assert(outstandingReq.find(pkt->req) != outstandingReq.end()); + + // remove it as outstanding + outstandingReq.erase(pkt->req); + + // send the packet to the destination through one of our slave + // ports, as determined by the destination field + bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); + + // currently it is illegal to block responses... can lead to + // deadlock + assert(success); + + succeededTiming(packetFinishTime); + + return true; +} + +void +CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) +{ + DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", + masterPorts[master_port_id]->name(), pkt->cmdString(), + pkt->getAddr()); + + // we should only see express snoops from caches + assert(pkt->isExpressSnoop()); + + // set the source port for routing of the response + pkt->setSrc(master_port_id); + + // forward to all snoopers + forwardTiming(pkt, InvalidPortID); + + // a snoop request came from a connected slave device (one of + // our master ports), and if it is not coming from the slave + // device responsible for the address range something is + // wrong, hence there is nothing further to do as the packet + // would be going back to where it came from + assert(master_port_id == findPort(pkt->getAddr())); + + // this is an express snoop and is never forced to retry + assert(!inRetry); +} + +bool +CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) +{ + // determine the source port based on the id + SlavePort* src_port = slavePorts[slave_port_id]; + + // test if the bus should be considered occupied for the current + // port + if (isOccupied(src_port)) { + DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // get the destination from the packet + PortID dest = pkt->getDest(); + + // responses are never express snoops + assert(!pkt->isExpressSnoop()); + + calcPacketTiming(pkt); + Tick packetFinishTime = pkt->finishTime; + + // determine if the response is from a snoop request we + // created as the result of a normal request (in which case it + // should be in the outstandingReq), or if we merely forwarded + // someone else's snoop request + if (outstandingReq.find(pkt->req) == outstandingReq.end()) { + // this is a snoop response to a snoop request we + // forwarded, e.g. coming from the L1 and going to the L2 + // this should be forwarded as a snoop response + bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); + assert(success); + } else { + // we got a snoop response on one of our slave ports, + // i.e. from a coherent master connected to the bus, and + // since we created the snoop request as part of + // recvTiming, this should now be a normal response again + outstandingReq.erase(pkt->req); + + // this is a snoop response from a coherent master, with a + // destination field set on its way through the bus as + // request, hence it should never go back to where the + // snoop response came from, but instead to where the + // original request came from + assert(slave_port_id != dest); + + // as a normal response, it should go back to a master + // through one of our slave ports + bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); + + // currently it is illegal to block responses... can lead + // to deadlock + assert(success); + } + + succeededTiming(packetFinishTime); + + return true; +} + + +void +CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) +{ + for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { + SlavePort *p = *s; + // we could have gotten this request from a snooping master + // (corresponding to our own slave port that is also in + // snoopPorts) and should not send it back to where it came + // from + if (exclude_slave_port_id == InvalidPortID || + p->getId() != exclude_slave_port_id) { + // cache is not allowed to refuse snoop + p->sendTimingSnoopReq(pkt); + } + } +} + +Tick +CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) +{ + DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + + MemCmd snoop_response_cmd = MemCmd::InvalidCmd; + Tick snoop_response_latency = 0; + + // uncacheable requests need never be snooped + if (!pkt->req->isUncacheable()) { + // forward to all snoopers but the source + std::pair snoop_result = + forwardAtomic(pkt, slave_port_id); + snoop_response_cmd = snoop_result.first; + snoop_response_latency = snoop_result.second; + } + + // even if we had a snoop response, we must continue and also + // perform the actual request at the destination + PortID dest_id = findPort(pkt->getAddr()); + + // forward the request to the appropriate destination + Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); + + // if we got a response from a snooper, restore it here + if (snoop_response_cmd != MemCmd::InvalidCmd) { + // no one else should have responded + assert(!pkt->isResponse()); + pkt->cmd = snoop_response_cmd; + response_latency = snoop_response_latency; + } + + pkt->finishTime = curTick() + response_latency; + return response_latency; +} + +Tick +CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) +{ + DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", + masterPorts[master_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + + // forward to all snoopers + std::pair snoop_result = + forwardAtomic(pkt, InvalidPortID); + MemCmd snoop_response_cmd = snoop_result.first; + Tick snoop_response_latency = snoop_result.second; + + if (snoop_response_cmd != MemCmd::InvalidCmd) + pkt->cmd = snoop_response_cmd; + + pkt->finishTime = curTick() + snoop_response_latency; + return snoop_response_latency; +} + +std::pair +CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) +{ + // the packet may be changed on snoops, record the original + // command to enable us to restore it between snoops so that + // additional snoops can take place properly + MemCmd orig_cmd = pkt->cmd; + MemCmd snoop_response_cmd = MemCmd::InvalidCmd; + Tick snoop_response_latency = 0; + + for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { + SlavePort *p = *s; + // we could have gotten this request from a snooping master + // (corresponding to our own slave port that is also in + // snoopPorts) and should not send it back to where it came + // from + if (exclude_slave_port_id == InvalidPortID || + p->getId() != exclude_slave_port_id) { + Tick latency = p->sendAtomicSnoop(pkt); + // in contrast to a functional access, we have to keep on + // going as all snoopers must be updated even if we get a + // response + if (pkt->isResponse()) { + // response from snoop agent + assert(pkt->cmd != orig_cmd); + assert(pkt->memInhibitAsserted()); + // should only happen once + assert(snoop_response_cmd == MemCmd::InvalidCmd); + // save response state + snoop_response_cmd = pkt->cmd; + snoop_response_latency = latency; + // restore original packet state for remaining snoopers + pkt->cmd = orig_cmd; + } + } + } + + // the packet is restored as part of the loop and any potential + // snoop response is part of the returned pair + return std::make_pair(snoop_response_cmd, snoop_response_latency); +} + +void +CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) +{ + if (!pkt->isPrint()) { + // don't do DPRINTFs on PrintReq as it clutters up the output + DPRINTF(CoherentBus, + "recvFunctional: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + } + + // uncacheable requests need never be snooped + if (!pkt->req->isUncacheable()) { + // forward to all snoopers but the source + forwardFunctional(pkt, slave_port_id); + } + + // there is no need to continue if the snooping has found what we + // were looking for and the packet is already a response + if (!pkt->isResponse()) { + PortID dest_id = findPort(pkt->getAddr()); + + masterPorts[dest_id]->sendFunctional(pkt); + } +} + +void +CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) +{ + if (!pkt->isPrint()) { + // don't do DPRINTFs on PrintReq as it clutters up the output + DPRINTF(CoherentBus, + "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", + masterPorts[master_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + } + + // forward to all snoopers + forwardFunctional(pkt, InvalidPortID); +} + +void +CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) +{ + for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { + SlavePort *p = *s; + // we could have gotten this request from a snooping master + // (corresponding to our own slave port that is also in + // snoopPorts) and should not send it back to where it came + // from + if (exclude_slave_port_id == InvalidPortID || + p->getId() != exclude_slave_port_id) + p->sendFunctionalSnoop(pkt); + + // if we get a response we are done + if (pkt->isResponse()) { + break; + } + } +} + +CoherentBus * +CoherentBusParams::create() +{ + return new CoherentBus(this); +} diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_bus.hh new file mode 100644 index 000000000..760ff8add --- /dev/null +++ b/src/mem/coherent_bus.hh @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2011-2012 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. + * + * 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: Ron Dreslinski + * Ali Saidi + * Andreas Hansson + * William Wang + */ + +/** + * @file + * Declaration of a coherent bus. + */ + +#ifndef __MEM_COHERENT_BUS_HH__ +#define __MEM_COHERENT_BUS_HH__ + +#include "mem/bus.hh" +#include "params/CoherentBus.hh" + +/** + * A coherent bus connects a number of (potentially) snooping masters + * and slaves, and routes the request and response packets based on + * the address, and also forwards all requests to the snoopers and + * deals with the snoop responses. + * + * The coherent bus can be used as a template for modelling QPI, +* HyperTransport, ACE and coherent OCP buses, and is typically used + * for the L1-to-L2 buses and as the main system interconnect. + */ +class CoherentBus : public BaseBus +{ + + protected: + + /** + * Declaration of the coherent bus slave port type, one will be + * instantiated for each of the master ports connecting to the + * bus. + */ + class CoherentBusSlavePort : public SlavePort + { + + private: + + /** A reference to the bus to which this port belongs. */ + CoherentBus &bus; + + public: + + CoherentBusSlavePort(const std::string &_name, + CoherentBus &_bus, PortID _id) + : SlavePort(_name, &_bus, _id), bus(_bus) + { } + + protected: + + /** + * When receiving a timing request, pass it to the bus. + */ + virtual bool recvTimingReq(PacketPtr pkt) + { return bus.recvTimingReq(pkt, id); } + + /** + * When receiving a timing snoop response, pass it to the bus. + */ + virtual bool recvTimingSnoopResp(PacketPtr pkt) + { return bus.recvTimingSnoopResp(pkt, id); } + + /** + * When receiving an atomic request, pass it to the bus. + */ + virtual Tick recvAtomic(PacketPtr pkt) + { return bus.recvAtomic(pkt, id); } + + /** + * When receiving a functional request, pass it to the bus. + */ + virtual void recvFunctional(PacketPtr pkt) + { bus.recvFunctional(pkt, id); } + + /** + * When receiving a retry, pass it to the bus. + */ + virtual void recvRetry() + { panic("Bus slave ports always succeed and should never retry.\n"); } + + /** + * Return the union of all adress ranges seen by this bus. + */ + virtual AddrRangeList getAddrRanges() + { return bus.getAddrRanges(); } + + /** + * Get the maximum block size as seen by the bus. + */ + virtual unsigned deviceBlockSize() const + { return bus.findBlockSize(); } + + }; + + /** + * Declaration of the coherent bus master port type, one will be + * instantiated for each of the slave interfaces connecting to the + * bus. + */ + class CoherentBusMasterPort : public MasterPort + { + private: + /** A reference to the bus to which this port belongs. */ + CoherentBus &bus; + + public: + + CoherentBusMasterPort(const std::string &_name, + CoherentBus &_bus, PortID _id) + : MasterPort(_name, &_bus, _id), bus(_bus) + { } + + protected: + + /** + * Determine if this port should be considered a snooper. For + * a coherent bus master port this is always true. + * + * @return a boolean that is true if this port is snooping + */ + virtual bool isSnooping() const + { return true; } + + /** + * When receiving a timing response, pass it to the bus. + */ + virtual bool recvTimingResp(PacketPtr pkt) + { return bus.recvTimingResp(pkt, id); } + + /** + * When receiving a timing snoop request, pass it to the bus. + */ + virtual void recvTimingSnoopReq(PacketPtr pkt) + { return bus.recvTimingSnoopReq(pkt, id); } + + /** + * When receiving an atomic snoop request, pass it to the bus. + */ + virtual Tick recvAtomicSnoop(PacketPtr pkt) + { return bus.recvAtomicSnoop(pkt, id); } + + /** + * When receiving a functional snoop request, pass it to the bus. + */ + virtual void recvFunctionalSnoop(PacketPtr pkt) + { bus.recvFunctionalSnoop(pkt, id); } + + /** When reciving a range change from the peer port (at id), + pass it to the bus. */ + virtual void recvRangeChange() + { bus.recvRangeChange(id); } + + /** When reciving a retry from the peer port (at id), + pass it to the bus. */ + virtual void recvRetry() + { bus.recvRetry(); } + + // 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 + // support multiple block sizes. + virtual unsigned deviceBlockSize() const + { return bus.findBlockSize(); } + + }; + + std::vector snoopPorts; + + /** + * Store the outstanding requests so we can determine which ones + * we generated and which ones were merely forwarded. This is used + * in the coherent bus when coherency responses come back. + */ + std::set outstandingReq; + + /** Function called by the port when the bus is recieving a Timing + request packet.*/ + bool recvTimingReq(PacketPtr pkt, PortID slave_port_id); + + /** Function called by the port when the bus is recieving a Timing + response packet.*/ + bool recvTimingResp(PacketPtr pkt, PortID master_port_id); + + /** Function called by the port when the bus is recieving a timing + snoop request.*/ + void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id); + + /** Function called by the port when the bus is recieving a timing + snoop response.*/ + bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id); + + /** + * Forward a timing packet to our snoopers, potentially excluding + * one of the connected coherent masters to avoid sending a packet + * back to where it came from. + * + * @param pkt Packet to forward + * @param exclude_slave_port_id Id of slave port to exclude + */ + void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(PacketPtr pkt, PortID slave_port_id); + + /** Function called by the port when the bus is recieving an + atomic snoop transaction.*/ + Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id); + + /** + * Forward an atomic packet to our snoopers, potentially excluding + * one of the connected coherent masters to avoid sending a packet + * back to where it came from. + * + * @param pkt Packet to forward + * @param exclude_slave_port_id Id of slave port to exclude + * + * @return a pair containing the snoop response and snoop latency + */ + std::pair forwardAtomic(PacketPtr pkt, + PortID exclude_slave_port_id); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(PacketPtr pkt, PortID slave_port_id); + + /** Function called by the port when the bus is recieving a functional + snoop transaction.*/ + void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id); + + /** + * Forward a functional packet to our snoopers, potentially + * excluding one of the connected coherent masters to avoid + * sending a packet back to where it came from. + * + * @param pkt Packet to forward + * @param exclude_slave_port_id Id of slave port to exclude + */ + void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id); + + public: + + virtual void init(); + + CoherentBus(const CoherentBusParams *p); +}; + +#endif //__MEM_COHERENT_BUS_HH__ diff --git a/src/mem/noncoherent_bus.cc b/src/mem/noncoherent_bus.cc new file mode 100644 index 000000000..4faad757a --- /dev/null +++ b/src/mem/noncoherent_bus.cc @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2011-2012 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. + * + * 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: Ali Saidi + * Andreas Hansson + * William Wang + */ + +/** + * @file + * Definition of a bus object. + */ + +#include "base/misc.hh" +#include "base/trace.hh" +#include "debug/Bus.hh" +#include "debug/BusAddrRanges.hh" +#include "debug/NoncoherentBus.hh" +#include "mem/noncoherent_bus.hh" + +NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) + : BaseBus(p) +{ + // create the ports based on the size of the master and slave + // vector ports, and the presence of the default port, the ports + // are enumerated starting from zero + for (int i = 0; i < p->port_master_connection_count; ++i) { + std::string portName = csprintf("%s-p%d", name(), i); + MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, i); + masterPorts.push_back(bp); + } + + // see if we have a default slave device connected and if so add + // our corresponding master port + if (p->port_default_connection_count) { + defaultPortID = masterPorts.size(); + std::string portName = csprintf("%s-default", name()); + MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, + defaultPortID); + masterPorts.push_back(bp); + } + + // create the slave ports, once again starting at zero + for (int i = 0; i < p->port_slave_connection_count; ++i) { + std::string portName = csprintf("%s-p%d", name(), i); + SlavePort* bp = new NoncoherentBusSlavePort(portName, *this, i); + slavePorts.push_back(bp); + } + + clearPortCache(); +} + +bool +NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +{ + // determine the source port based on the id + SlavePort *src_port = slavePorts[slave_port_id]; + + // we should never see express snoops on a non-coherent bus + assert(!pkt->isExpressSnoop()); + + // test if the bus should be considered occupied for the current + // port + if (isOccupied(src_port)) { + DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // set the source port for routing of the response + pkt->setSrc(slave_port_id); + + Tick headerFinishTime = calcPacketTiming(pkt); + Tick packetFinishTime = pkt->finishTime; + + // since it is a normal request, determine the destination + // based on the address and attempt to send the packet + bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); + + if (!success) { + // inhibited packets should never be forced to retry + assert(!pkt->memInhibitAsserted()); + + DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + addToRetryList(src_port); + occupyBus(headerFinishTime); + + return false; + } + + succeededTiming(packetFinishTime); + + return true; +} + +bool +NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) +{ + // determine the source port based on the id + MasterPort *src_port = masterPorts[master_port_id]; + + // test if the bus should be considered occupied for the current + // port + if (isOccupied(src_port)) { + DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + calcPacketTiming(pkt); + Tick packetFinishTime = pkt->finishTime; + + // send the packet to the destination through one of our slave + // ports, as determined by the destination field + bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); + + // currently it is illegal to block responses... can lead to + // deadlock + assert(success); + + succeededTiming(packetFinishTime); + + return true; +} + +Tick +NoncoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) +{ + DPRINTF(NoncoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + + // determine the destination port + PortID dest_id = findPort(pkt->getAddr()); + + // forward the request to the appropriate destination + Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); + + pkt->finishTime = curTick() + response_latency; + return response_latency; +} + +void +NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) +{ + if (!pkt->isPrint()) { + // don't do DPRINTFs on PrintReq as it clutters up the output + DPRINTF(NoncoherentBus, + "recvFunctional: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + } + + // determine the destination port + PortID dest_id = findPort(pkt->getAddr()); + + // forward the request to the appropriate destination + masterPorts[dest_id]->sendFunctional(pkt); +} + +NoncoherentBus* +NoncoherentBusParams::create() +{ + return new NoncoherentBus(this); +} diff --git a/src/mem/noncoherent_bus.hh b/src/mem/noncoherent_bus.hh new file mode 100644 index 000000000..8bd6c0e74 --- /dev/null +++ b/src/mem/noncoherent_bus.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2011-2012 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. + * + * 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: Ron Dreslinski + * Ali Saidi + * Andreas Hansson + * William Wang + */ + +/** + * @file + * Declaration of a non-coherent bus. + */ + +#ifndef __MEM_NONCOHERENT_BUS_HH__ +#define __MEM_NONCOHERENT_BUS_HH__ + +#include "mem/bus.hh" +#include "params/NoncoherentBus.hh" + +/** + * A non-coherent bus connects a number of non-snooping masters and + * slaves, and routes the request and response packets based on the + * address. The request packets issued by the master connected to a + * non-coherent bus could still snoop in caches attached to a coherent + * bus, as is the case with the I/O bus and memory bus in most system + * configurations. No snoops will, however, reach any master on the + * non-coherent bus itself. + * + * The non-coherent bus can be used as a template for modelling PCI, + * PCIe, and non-coherent AMBA and OCP buses, and is typically used + * for the I/O buses. + */ +class NoncoherentBus : public BaseBus +{ + + protected: + + /** + * Declaration of the non-coherent bus slave port type, one will + * be instantiated for each of the master ports connecting to the + * bus. + */ + class NoncoherentBusSlavePort : public SlavePort + { + private: + + /** A reference to the bus to which this port belongs. */ + NoncoherentBus &bus; + + public: + + NoncoherentBusSlavePort(const std::string &_name, + NoncoherentBus &_bus, PortID _id) + : SlavePort(_name, &_bus, _id), bus(_bus) + { } + + protected: + + /** + * When receiving a timing request, pass it to the bus. + */ + virtual bool recvTimingReq(PacketPtr pkt) + { return bus.recvTimingReq(pkt, id); } + + /** + * When receiving an atomic request, pass it to the bus. + */ + virtual Tick recvAtomic(PacketPtr pkt) + { return bus.recvAtomic(pkt, id); } + + /** + * When receiving a functional request, pass it to the bus. + */ + virtual void recvFunctional(PacketPtr pkt) + { bus.recvFunctional(pkt, id); } + + /** + * When receiving a retry, pass it to the bus. + */ + virtual void recvRetry() + { panic("Bus slave ports always succeed and should never retry.\n"); } + + /** + * Return the union of all adress ranges seen by this bus. + */ + virtual AddrRangeList getAddrRanges() + { return bus.getAddrRanges(); } + + /** + * Get the maximum block size as seen by the bus. + */ + virtual unsigned deviceBlockSize() const + { return bus.findBlockSize(); } + + }; + + /** + * Declaration of the bus master port type, one will be + * instantiated for each of the slave ports connecting to the + * bus. + */ + class NoncoherentBusMasterPort : public MasterPort + { + private: + + /** A reference to the bus to which this port belongs. */ + NoncoherentBus &bus; + + public: + + NoncoherentBusMasterPort(const std::string &_name, + NoncoherentBus &_bus, PortID _id) + : MasterPort(_name, &_bus, _id), bus(_bus) + { } + + protected: + + /** + * When receiving a timing response, pass it to the bus. + */ + virtual bool recvTimingResp(PacketPtr pkt) + { return bus.recvTimingResp(pkt, id); } + + /** When reciving a range change from the peer port (at id), + pass it to the bus. */ + virtual void recvRangeChange() + { bus.recvRangeChange(id); } + + /** When reciving a retry from the peer port (at id), + pass it to the bus. */ + virtual void recvRetry() + { bus.recvRetry(); } + + /** + * Get the maximum block size as seen by the bus. + */ + virtual unsigned deviceBlockSize() const + { return bus.findBlockSize(); } + + }; + + /** Function called by the port when the bus is recieving a Timing + request packet.*/ + bool recvTimingReq(PacketPtr pkt, PortID slave_port_id); + + /** Function called by the port when the bus is recieving a Timing + response packet.*/ + bool recvTimingResp(PacketPtr pkt, PortID master_port_id); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(PacketPtr pkt, PortID slave_port_id); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(PacketPtr pkt, PortID slave_port_id); + + public: + + NoncoherentBus(const NoncoherentBusParams *p); + +}; + +#endif //__MEM_NONCOHERENT_BUS_HH__ diff --git a/tests/configs/inorder-timing.py b/tests/configs/inorder-timing.py index ea9c37ef9..3e285af77 100644 --- a/tests/configs/inorder-timing.py +++ b/tests/configs/inorder-timing.py @@ -49,7 +49,7 @@ cpu.clock = '2GHz' system = System(cpu = cpu, physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master # create the interrupt controller diff --git a/tests/configs/memtest.py b/tests/configs/memtest.py index 9876c07b9..0add2158f 100644 --- a/tests/configs/memtest.py +++ b/tests/configs/memtest.py @@ -58,10 +58,10 @@ cpus = [ MemTest() for i in xrange(nb_cores) ] # system simulated system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False), physmem = SimpleMemory(), - membus = Bus(clock="500GHz", width=16)) + membus = CoherentBus(clock="500GHz", width=16)) # l2cache & bus -system.toL2Bus = Bus(clock="500GHz", width=16) +system.toL2Bus = CoherentBus(clock="500GHz", width=16) system.l2c = L2(size='64kB', assoc=8) system.l2c.cpu_side = system.toL2Bus.master diff --git a/tests/configs/o3-timing-checker.py b/tests/configs/o3-timing-checker.py index 68429de04..0bbe9b00a 100644 --- a/tests/configs/o3-timing-checker.py +++ b/tests/configs/o3-timing-checker.py @@ -60,7 +60,7 @@ cpu.clock = '2GHz' system = System(cpu = cpu, physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master cpu.connectAllPorts(system.membus) diff --git a/tests/configs/o3-timing-mp-ruby.py b/tests/configs/o3-timing-mp-ruby.py index 0bc54f0f0..a58bc50ec 100644 --- a/tests/configs/o3-timing-mp-ruby.py +++ b/tests/configs/o3-timing-mp-ruby.py @@ -37,7 +37,7 @@ import ruby_config ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores) # system simulated -system = System(cpu = cpus, physmem = ruby_memory, membus = Bus()) +system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus()) for cpu in cpus: # create the interrupt controller diff --git a/tests/configs/o3-timing-mp.py b/tests/configs/o3-timing-mp.py index ee0f29570..2aec2bb1d 100644 --- a/tests/configs/o3-timing-mp.py +++ b/tests/configs/o3-timing-mp.py @@ -56,10 +56,10 @@ nb_cores = 4 cpus = [ DerivO3CPU(cpu_id=i) for i in xrange(nb_cores) ] # system simulated -system = System(cpu = cpus, physmem = SimpleMemory(), membus = Bus()) +system = System(cpu = cpus, physmem = SimpleMemory(), membus = CoherentBus()) # l2cache & bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.l2c = L2(size='4MB', assoc=8) system.l2c.cpu_side = system.toL2Bus.master diff --git a/tests/configs/o3-timing-ruby.py b/tests/configs/o3-timing-ruby.py index 8debc7d3d..db8ccdc7b 100644 --- a/tests/configs/o3-timing-ruby.py +++ b/tests/configs/o3-timing-ruby.py @@ -39,7 +39,7 @@ cpu.clock = '2GHz' system = System(cpu = cpu, physmem = ruby_memory, - membus = Bus()) + membus = CoherentBus()) system.physmem.port = system.membus.master # create the interrupt controller cpu.createInterruptController() diff --git a/tests/configs/o3-timing.py b/tests/configs/o3-timing.py index 732cd2d43..a10079ab8 100644 --- a/tests/configs/o3-timing.py +++ b/tests/configs/o3-timing.py @@ -49,7 +49,7 @@ cpu.clock = '2GHz' system = System(cpu = cpu, physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master # create the interrupt controller diff --git a/tests/configs/pc-o3-timing.py b/tests/configs/pc-o3-timing.py index 0b8b9381f..2d3019daf 100644 --- a/tests/configs/pc-o3-timing.py +++ b/tests/configs/pc-o3-timing.py @@ -92,7 +92,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/pc-simple-atomic.py b/tests/configs/pc-simple-atomic.py index 77cd1319f..f0d168c1a 100644 --- a/tests/configs/pc-simple-atomic.py +++ b/tests/configs/pc-simple-atomic.py @@ -94,7 +94,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/pc-simple-timing.py b/tests/configs/pc-simple-timing.py index fbe6b4c4f..4347b78d3 100644 --- a/tests/configs/pc-simple-timing.py +++ b/tests/configs/pc-simple-timing.py @@ -90,7 +90,7 @@ system.kernel = FSConfig.binary('x86_64-vmlinux-2.6.22.9') system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/realview-o3-checker.py b/tests/configs/realview-o3-checker.py index c07c2ca9e..b263adee0 100644 --- a/tests/configs/realview-o3-checker.py +++ b/tests/configs/realview-o3-checker.py @@ -83,7 +83,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False) system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/realview-o3-dual.py b/tests/configs/realview-o3-dual.py index 71b4f06dd..e6ca2d7bd 100644 --- a/tests/configs/realview-o3-dual.py +++ b/tests/configs/realview-o3-dual.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/realview-o3.py b/tests/configs/realview-o3.py index db64ccc60..e231df9f2 100644 --- a/tests/configs/realview-o3.py +++ b/tests/configs/realview-o3.py @@ -74,7 +74,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False) system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/realview-simple-atomic-dual.py b/tests/configs/realview-simple-atomic-dual.py index eef5e90c5..e3a73305c 100644 --- a/tests/configs/realview-simple-atomic-dual.py +++ b/tests/configs/realview-simple-atomic-dual.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/realview-simple-atomic.py b/tests/configs/realview-simple-atomic.py index 0544c98b6..fdfac1cc6 100644 --- a/tests/configs/realview-simple-atomic.py +++ b/tests/configs/realview-simple-atomic.py @@ -76,7 +76,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/realview-simple-timing-dual.py b/tests/configs/realview-simple-timing-dual.py index edc2b7a95..825b67d05 100644 --- a/tests/configs/realview-simple-timing-dual.py +++ b/tests/configs/realview-simple-timing-dual.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/realview-simple-timing.py b/tests/configs/realview-simple-timing.py index 6e539624b..786b42e20 100644 --- a/tests/configs/realview-simple-timing.py +++ b/tests/configs/realview-simple-timing.py @@ -74,7 +74,7 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False) system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/simple-atomic-dummychecker.py b/tests/configs/simple-atomic-dummychecker.py index 2e672924d..5192afb1c 100644 --- a/tests/configs/simple-atomic-dummychecker.py +++ b/tests/configs/simple-atomic-dummychecker.py @@ -40,7 +40,7 @@ from m5.objects import * system = System(cpu = AtomicSimpleCPU(cpu_id=0), physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master system.cpu.addCheckerCpu() diff --git a/tests/configs/simple-atomic-mp-ruby.py b/tests/configs/simple-atomic-mp-ruby.py index a9ee3c4d0..50d3349dd 100644 --- a/tests/configs/simple-atomic-mp-ruby.py +++ b/tests/configs/simple-atomic-mp-ruby.py @@ -37,7 +37,7 @@ import ruby_config ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores) # system simulated -system = System(cpu = cpus, physmem = ruby_memory, membus = Bus()) +system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentBus()) # add L1 caches for cpu in cpus: diff --git a/tests/configs/simple-atomic-mp.py b/tests/configs/simple-atomic-mp.py index af9f3bc09..8161a93f2 100644 --- a/tests/configs/simple-atomic-mp.py +++ b/tests/configs/simple-atomic-mp.py @@ -57,10 +57,10 @@ cpus = [ AtomicSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ] # system simulated system = System(cpu = cpus, physmem = SimpleMemory(range = AddrRange('1024MB')), - membus = Bus()) + membus = CoherentBus()) # l2cache & bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.l2c = L2(size='4MB', assoc=8) system.l2c.cpu_side = system.toL2Bus.master diff --git a/tests/configs/simple-atomic.py b/tests/configs/simple-atomic.py index b1aa31d80..3b81d9769 100644 --- a/tests/configs/simple-atomic.py +++ b/tests/configs/simple-atomic.py @@ -31,7 +31,7 @@ from m5.objects import * system = System(cpu = AtomicSimpleCPU(cpu_id=0), physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master # create the interrupt controller diff --git a/tests/configs/simple-timing-mp.py b/tests/configs/simple-timing-mp.py index 5bb0194aa..2a4075624 100644 --- a/tests/configs/simple-timing-mp.py +++ b/tests/configs/simple-timing-mp.py @@ -55,10 +55,10 @@ nb_cores = 4 cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ] # system simulated -system = System(cpu = cpus, physmem = SimpleMemory(), membus = Bus()) +system = System(cpu = cpus, physmem = SimpleMemory(), membus = CoherentBus()) # l2cache & bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.l2c = L2(size='4MB', assoc=8) system.l2c.cpu_side = system.toL2Bus.master diff --git a/tests/configs/simple-timing.py b/tests/configs/simple-timing.py index 5269f4127..33d03f6cf 100644 --- a/tests/configs/simple-timing.py +++ b/tests/configs/simple-timing.py @@ -45,7 +45,7 @@ cpu.addTwoLevelCacheHierarchy(MyL1Cache(size = '128kB'), MyCache(size = '2MB', latency='10ns')) system = System(cpu = cpu, physmem = SimpleMemory(), - membus = Bus()) + membus = CoherentBus()) system.system_port = system.membus.slave system.physmem.port = system.membus.master # create the interrupt controller diff --git a/tests/configs/tsunami-inorder.py b/tests/configs/tsunami-inorder.py index 41df45fab..6435e5a78 100644 --- a/tests/configs/tsunami-inorder.py +++ b/tests/configs/tsunami-inorder.py @@ -78,7 +78,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing') system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/tsunami-o3-dual.py b/tests/configs/tsunami-o3-dual.py index d50a45b07..c4e69266d 100644 --- a/tests/configs/tsunami-o3-dual.py +++ b/tests/configs/tsunami-o3-dual.py @@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing') system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/tsunami-o3.py b/tests/configs/tsunami-o3.py index c5a3236a5..dba8f9dd3 100644 --- a/tests/configs/tsunami-o3.py +++ b/tests/configs/tsunami-o3.py @@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing') system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave diff --git a/tests/configs/tsunami-simple-atomic-dual.py b/tests/configs/tsunami-simple-atomic-dual.py index 57672b0e1..90f6c7f0b 100644 --- a/tests/configs/tsunami-simple-atomic-dual.py +++ b/tests/configs/tsunami-simple-atomic-dual.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/tsunami-simple-atomic.py b/tests/configs/tsunami-simple-atomic.py index 8a03760e3..5065f3346 100644 --- a/tests/configs/tsunami-simple-atomic.py +++ b/tests/configs/tsunami-simple-atomic.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/tsunami-simple-timing-dual.py b/tests/configs/tsunami-simple-timing-dual.py index 1b905a8d0..c9bcc59c7 100644 --- a/tests/configs/tsunami-simple-timing-dual.py +++ b/tests/configs/tsunami-simple-timing-dual.py @@ -77,7 +77,7 @@ system.iocache.mem_side = system.membus.slave system.cpu = cpus #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() #connect up the l2 cache system.l2c = L2(size='4MB', assoc=8) diff --git a/tests/configs/tsunami-simple-timing.py b/tests/configs/tsunami-simple-timing.py index e4920ddf4..eb62b20d8 100644 --- a/tests/configs/tsunami-simple-timing.py +++ b/tests/configs/tsunami-simple-timing.py @@ -75,7 +75,7 @@ system = FSConfig.makeLinuxAlphaSystem('timing') system.cpu = cpu #create the l1/l2 bus -system.toL2Bus = Bus() +system.toL2Bus = CoherentBus() system.iocache = IOCache() system.iocache.cpu_side = system.iobus.master system.iocache.mem_side = system.membus.slave