diff options
author | Andreas Hansson <andreas.hansson@arm.com> | 2014-09-20 17:18:32 -0400 |
---|---|---|
committer | Andreas Hansson <andreas.hansson@arm.com> | 2014-09-20 17:18:32 -0400 |
commit | 1f6d5f8f849f50a3646f586b1274708537124ef3 (patch) | |
tree | 03c98c46d500fbd9ac8135baea399813ea3d5644 /src | |
parent | 1884bcc03ba2b6e734b4bd379d8542596e6d5c84 (diff) | |
download | gem5-1f6d5f8f849f50a3646f586b1274708537124ef3.tar.xz |
mem: Rename Bus to XBar to better reflect its behaviour
This patch changes the name of the Bus classes to XBar to better
reflect the actual timing behaviour. The actual instances in the
config scripts are not renamed, and remain as e.g. iobus or membus.
As part of this renaming, the code has also been clean up slightly,
making use of range-based for loops and tidying up some comments. The
only changes outside the bus/crossbar code is due to the delay
variables in the packet.
--HG--
rename : src/mem/Bus.py => src/mem/XBar.py
rename : src/mem/coherent_bus.cc => src/mem/coherent_xbar.cc
rename : src/mem/coherent_bus.hh => src/mem/coherent_xbar.hh
rename : src/mem/noncoherent_bus.cc => src/mem/noncoherent_xbar.cc
rename : src/mem/noncoherent_bus.hh => src/mem/noncoherent_xbar.hh
rename : src/mem/bus.cc => src/mem/xbar.cc
rename : src/mem/bus.hh => src/mem/xbar.hh
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/pagetable_walker.cc | 2 | ||||
-rw-r--r-- | src/cpu/BaseCPU.py | 8 | ||||
-rw-r--r-- | src/dev/io_device.cc | 6 | ||||
-rw-r--r-- | src/dev/pcidev.cc | 2 | ||||
-rw-r--r-- | src/dev/x86/intdev.hh | 2 | ||||
-rw-r--r-- | src/mem/SConscript | 24 | ||||
-rw-r--r-- | src/mem/XBar.py (renamed from src/mem/Bus.py) | 28 | ||||
-rw-r--r-- | src/mem/bridge.cc | 12 | ||||
-rw-r--r-- | src/mem/bridge.hh | 12 | ||||
-rw-r--r-- | src/mem/cache/cache_impl.hh | 30 | ||||
-rw-r--r-- | src/mem/coherent_xbar.cc (renamed from src/mem/coherent_bus.cc) | 281 | ||||
-rw-r--r-- | src/mem/coherent_xbar.hh (renamed from src/mem/coherent_bus.hh) | 150 | ||||
-rw-r--r-- | src/mem/dram_ctrl.cc | 2 | ||||
-rw-r--r-- | src/mem/dramsim2.cc | 2 | ||||
-rw-r--r-- | src/mem/noncoherent_xbar.cc (renamed from src/mem/noncoherent_bus.cc) | 142 | ||||
-rw-r--r-- | src/mem/noncoherent_xbar.hh (renamed from src/mem/noncoherent_bus.hh) | 116 | ||||
-rw-r--r-- | src/mem/packet.hh | 57 | ||||
-rw-r--r-- | src/mem/physical.cc | 8 | ||||
-rw-r--r-- | src/mem/simple_mem.cc | 2 | ||||
-rw-r--r-- | src/mem/xbar.cc (renamed from src/mem/bus.cc) | 218 | ||||
-rw-r--r-- | src/mem/xbar.hh (renamed from src/mem/bus.hh) | 147 | ||||
-rw-r--r-- | src/python/m5/params.py | 2 | ||||
-rw-r--r-- | src/python/m5/util/dot_writer.py | 8 |
23 files changed, 607 insertions, 654 deletions
diff --git a/src/arch/x86/pagetable_walker.cc b/src/arch/x86/pagetable_walker.cc index 3d8cc9292..db3b4b933 100644 --- a/src/arch/x86/pagetable_walker.cc +++ b/src/arch/x86/pagetable_walker.cc @@ -597,7 +597,7 @@ Walker::WalkerState::recvPacket(PacketPtr pkt) assert(!read); // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; state = nextState; nextState = Ready; diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index b7f0b2089..8ba90209a 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 CoherentBus +from XBar import CoherentXBar from InstTracer import InstTracer from ExeTracer import ExeTracer from MemObject import MemObject @@ -274,8 +274,8 @@ class BaseCPU(MemObject): self.itb_walker_cache = iwc self.dtb_walker_cache = dwc if buildEnv['TARGET_ISA'] in ['arm']: - self.itb_walker_cache_bus = CoherentBus() - self.dtb_walker_cache_bus = CoherentBus() + self.itb_walker_cache_bus = CoherentXBar() + self.dtb_walker_cache_bus = CoherentXBar() self.itb_walker_cache_bus.master = iwc.cpu_side self.dtb_walker_cache_bus.master = dwc.cpu_side self.itb.walker.port = self.itb_walker_cache_bus.slave @@ -308,7 +308,7 @@ class BaseCPU(MemObject): # Set a width of 32 bytes (256-bits), which is four times that # of the default bus. The clock of the CPU is inherited by # default. - self.toL2Bus = CoherentBus(width = 32) + self.toL2Bus = CoherentXBar(width = 32) self.connectCachedPorts(self.toL2Bus) self.l2cache = l2c self.toL2Bus.master = self.l2cache.cpu_side diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index 0c927651d..b118294f7 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -42,7 +42,7 @@ */ #include "base/trace.hh" -#include "debug/BusAddrRanges.hh" +#include "debug/AddrRanges.hh" #include "dev/io_device.hh" #include "sim/system.hh" @@ -55,7 +55,7 @@ Tick PioPort::recvAtomic(PacketPtr pkt) { // @todo: We need to pay for this and not just zero it out - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; return pkt->isRead() ? device->read(pkt) : device->write(pkt); } @@ -113,7 +113,7 @@ BasicPioDevice::getAddrRanges() const { assert(pioSize != 0); AddrRangeList ranges; - DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize); + DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize); ranges.push_back(RangeSize(pioAddr, pioSize)); return ranges; } diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc index adc12bb55..b27547519 100644 --- a/src/dev/pcidev.cc +++ b/src/dev/pcidev.cc @@ -80,7 +80,7 @@ PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt) assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); } diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh index 078ea2b6f..294a2b887 100644 --- a/src/dev/x86/intdev.hh +++ b/src/dev/x86/intdev.hh @@ -82,7 +82,7 @@ class IntDevice Tick recvMessage(PacketPtr pkt) { // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; return device->recvMessage(pkt); } }; diff --git a/src/mem/SConscript b/src/mem/SConscript index c351661b8..35f2e9ce4 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -39,28 +39,28 @@ if env['HAVE_PROTOBUF']: SimObject('AbstractMemory.py') SimObject('AddrMapper.py') SimObject('Bridge.py') -SimObject('Bus.py') SimObject('DRAMCtrl.py') SimObject('MemObject.py') SimObject('SimpleMemory.py') +SimObject('XBar.py') Source('abstract_mem.cc') Source('addr_mapper.cc') Source('bridge.cc') -Source('bus.cc') -Source('coherent_bus.cc') +Source('coherent_xbar.cc') Source('dram_ctrl.cc') Source('mem_object.cc') Source('mport.cc') -Source('noncoherent_bus.cc') +Source('noncoherent_xbar.cc') Source('packet.cc') Source('port.cc') Source('packet_queue.cc') -Source('tport.cc') Source('port_proxy.cc') -Source('simple_mem.cc') Source('physical.cc') +Source('simple_mem.cc') Source('snoop_filter.cc') +Source('tport.cc') +Source('xbar.cc') if env['TARGET_ISA'] != 'null': Source('fs_translating_port_proxy.cc') @@ -74,13 +74,13 @@ if env['HAVE_DRAMSIM']: Source('dramsim2_wrapper.cc') Source('dramsim2.cc') -DebugFlag('BaseBus') -DebugFlag('BusAddrRanges') -DebugFlag('CoherentBus') -DebugFlag('NoncoherentBus') +DebugFlag('AddrRanges') +DebugFlag('BaseXBar') +DebugFlag('CoherentXBar') +DebugFlag('NoncoherentXBar') DebugFlag('SnoopFilter') -CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus', - 'NoncoherentBus', 'SnoopFilter']) +CompoundFlag('XBar', ['BaseXBar', 'CoherentXBar', 'NoncoherentXBar', + 'SnoopFilter']) DebugFlag('Bridge') DebugFlag('CommMonitor') diff --git a/src/mem/Bus.py b/src/mem/XBar.py index 06fff93b5..2aeefe132 100644 --- a/src/mem/Bus.py +++ b/src/mem/XBar.py @@ -45,14 +45,14 @@ from m5.params import * from m5.proxy import * from m5.SimObject import SimObject -class BaseBus(MemObject): - type = 'BaseBus' +class BaseXBar(MemObject): + type = 'BaseXBar' abstract = True - cxx_header = "mem/bus.hh" + cxx_header = "mem/xbar.hh" slave = VectorSlavePort("vector port for connecting masters") master = VectorMasterPort("vector port for connecting slaves") header_cycles = Param.Cycles(1, "cycles of overhead per transaction") - width = Param.Unsigned(8, "bus width (bytes)") + width = Param.Unsigned(8, "xbar width (bytes)") # The default port can be left unconnected, or be used to connect # a default slave port @@ -62,24 +62,24 @@ class BaseBus(MemObject): # 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. + # xbar configuration. use_default_range = Param.Bool(False, "Perform address mapping for " \ "the default port") -class NoncoherentBus(BaseBus): - type = 'NoncoherentBus' - cxx_header = "mem/noncoherent_bus.hh" +class NoncoherentXBar(BaseXBar): + type = 'NoncoherentXBar' + cxx_header = "mem/noncoherent_xbar.hh" -class CoherentBus(BaseBus): - type = 'CoherentBus' - cxx_header = "mem/coherent_bus.hh" +class CoherentXBar(BaseXBar): + type = 'CoherentXBar' + cxx_header = "mem/coherent_xbar.hh" - system = Param.System(Parent.any, "System that the bus belongs to.") - snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter for the bus.") + system = Param.System(Parent.any, "System that the crossbar belongs to.") + snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter.") class SnoopFilter(SimObject): type = 'SnoopFilter' cxx_header = "mem/snoop_filter.hh" lookup_latency = Param.Cycles(3, "lookup latency (cycles)") - system = Param.System(Parent.any, "System that the bus belongs to.") + system = Param.System(Parent.any, "System that the crossbar belongs to.") diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 3b101ceab..085c97b53 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -44,7 +44,7 @@ /** * @file - * Implementation of a memory-mapped bus bridge that connects a master + * Implementation of a memory-mapped bridge that connects a master * and a slave through a request and response queue. */ @@ -108,7 +108,7 @@ Bridge::init() { // make sure both sides are connected and have the same block size if (!slavePort.isConnected() || !masterPort.isConnected()) - fatal("Both ports of bus bridge are not connected to a bus.\n"); + fatal("Both ports of a bridge must be connected.\n"); // notify the master side of our address ranges slavePort.sendRangeChange(); @@ -137,7 +137,7 @@ Bridge::BridgeMasterPort::recvTimingResp(PacketPtr pkt) DPRINTF(Bridge, "Request queue size: %d\n", transmitList.size()); // @todo: We need to pay for this and not just zero it out - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; slavePort.schedTimingResp(pkt, bridge.clockEdge(delay)); @@ -181,7 +181,7 @@ Bridge::BridgeSlavePort::recvTimingReq(PacketPtr pkt) if (!retryReq) { // @todo: We need to pay for this and not just zero it out - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; masterPort.schedTimingReq(pkt, bridge.clockEdge(delay)); } @@ -209,7 +209,7 @@ Bridge::BridgeMasterPort::schedTimingReq(PacketPtr pkt, Tick when) { // If we expect to see a response, we need to restore the source // and destination field that is potentially changed by a second - // bus + // crossbar if (!pkt->memInhibitAsserted() && pkt->needsResponse()) { // Update the sender state so we can deal with the response // appropriately @@ -242,7 +242,7 @@ Bridge::BridgeSlavePort::schedTimingResp(PacketPtr pkt, Tick when) pkt->setDest(req_state->origSrc); delete req_state; - // the bridge assumes that at least one bus has set the + // the bridge assumes that at least one crossbar has set the // destination field of the packet assert(pkt->isDestValid()); DPRINTF(Bridge, "response, new dest %d\n", pkt->getDest()); diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index e672c1f7a..a79d67484 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -44,7 +44,7 @@ /** * @file - * Declaration of a memory-mapped bus bridge that connects a master + * Declaration of a memory-mapped bridge that connects a master * and a slave through a request and response queue. */ @@ -58,7 +58,7 @@ #include "params/Bridge.hh" /** - * A bridge is used to interface two different busses (or in general a + * A bridge is used to interface two different crossbars (or in general a * memory-mapped master and slave), with buffering for requests and * responses. The bridge has a fixed delay for packets passing through * it and responds to a fixed set of address ranges. @@ -125,8 +125,7 @@ class Bridge : public MemObject Bridge& bridge; /** - * Master port on the other side of the bridge (connected to - * the other bus). + * Master port on the other side of the bridge. */ BridgeMasterPort& masterPort; @@ -241,8 +240,7 @@ class Bridge : public MemObject Bridge& bridge; /** - * The slave port on the other side of the bridge (connected - * to the other bus). + * The slave port on the other side of the bridge. */ BridgeSlavePort& slavePort; @@ -343,4 +341,4 @@ class Bridge : public MemObject Bridge(Params *p); }; -#endif //__MEM_BUS_HH__ +#endif //__MEM_BRIDGE_HH__ diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 8c091fa39..e4a6f3c24 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -423,7 +423,7 @@ Cache<TagStore>::recvTimingSnoopResp(PacketPtr pkt) pkt->setDest(rec->prevSrc); delete rec; // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; memSidePort->schedTimingSnoopResp(pkt, time); } @@ -482,7 +482,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt) Packet *snoopPkt = new Packet(pkt, true); // clear flags // also reset the bus time that the original packet has // not yet paid for - snoopPkt->busFirstWordDelay = snoopPkt->busLastWordDelay = 0; + snoopPkt->firstWordDelay = snoopPkt->lastWordDelay = 0; snoopPkt->setExpressSnoop(); snoopPkt->assertMemInhibit(); bool M5_VAR_USED success = memSidePort->sendTimingReq(snoopPkt); @@ -505,7 +505,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt) uncacheableFlush(pkt); // @todo: someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; // writes go in write buffer, reads use MSHR, // prefetches are acknowledged (responded to) and dropped @@ -562,7 +562,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt) if (needsResponse) { pkt->makeTimingResponse(); // @todo: Make someone pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; cpuSidePort->schedTimingResp(pkt, clockEdge(lat)); } else { /// @todo nominally we should just delete the packet here, @@ -574,7 +574,7 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt) // miss // @todo: Make someone pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; if (blk && blk->isValid() && (blk->status & BlkCanGoExclusive) && pkt->isWrite() && (pkt->cmd != MemCmd::WriteInvalidateReq)) { @@ -1115,8 +1115,8 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) // from lower level caches/memory to an upper level cache or // the core. completion_time = clockEdge(responseLatency) + - (transfer_offset ? pkt->busLastWordDelay : - pkt->busFirstWordDelay); + (transfer_offset ? pkt->lastWordDelay : + pkt->firstWordDelay); assert(!target->pkt->req->isUncacheable()); @@ -1132,7 +1132,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) // from lower level caches/memory to an upper level cache or // the core. completion_time = clockEdge(responseLatency) + - pkt->busLastWordDelay; + pkt->lastWordDelay; target->pkt->req->setExtraData(0); } else if (pkt->cmd == MemCmd::WriteInvalidateResp) { if (blk) { @@ -1165,13 +1165,13 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) // will occur for its impatience (since it will think it // has dirty data), but it really can't be helped. completion_time = clockEdge(responseLatency) + - pkt->busLastWordDelay; + pkt->lastWordDelay; } else { // not a cache fill, just forwarding response // responseLatency is the latency of the return path // from lower level cahces/memory to the core. completion_time = clockEdge(responseLatency) + - pkt->busLastWordDelay; + pkt->lastWordDelay; if (pkt->isRead() && !is_error) { target->pkt->setData(pkt->getPtr<uint8_t>()); } @@ -1191,7 +1191,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) target->pkt->getAddr()); } // reset the bus additional time as it is now accounted for - target->pkt->busFirstWordDelay = target->pkt->busLastWordDelay = 0; + target->pkt->firstWordDelay = target->pkt->lastWordDelay = 0; cpuSidePort->schedTimingResp(target->pkt, completion_time); break; @@ -1239,7 +1239,7 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) mq = mshr->queue; mq->markPending(mshr); requestMemSideBus((RequestCause)mq->index, clockEdge() + - pkt->busLastWordDelay); + pkt->lastWordDelay); } else { mq->deallocate(mshr); if (wasFull && !mq->isFull()) { @@ -1495,7 +1495,7 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk, } blk->whenReady = clockEdge() + responseLatency * clockPeriod() + - pkt->busLastWordDelay; + pkt->lastWordDelay; return blk; } @@ -1522,7 +1522,7 @@ doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data, pkt->allocate(); pkt->makeTimingResponse(); // @todo Make someone pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; if (pkt->isRead()) { pkt->setDataFromBlock(blk_data, blkSize); } @@ -1572,7 +1572,7 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk, snoopPkt.pushSenderState(new ForwardResponseRecord(pkt->getSrc())); // the snoop packet does not need to wait any additional // time - snoopPkt.busFirstWordDelay = snoopPkt.busLastWordDelay = 0; + snoopPkt.firstWordDelay = snoopPkt.lastWordDelay = 0; cpuSidePort->sendTimingSnoopReq(&snoopPkt); if (snoopPkt.memInhibitAsserted()) { // cache-to-cache response from some upper cache diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_xbar.cc index 9529e9e7d..ce5116de9 100644 --- a/src/mem/coherent_bus.cc +++ b/src/mem/coherent_xbar.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,25 +44,25 @@ /** * @file - * Definition of a bus object. + * Definition of a crossbar object. */ #include "base/misc.hh" #include "base/trace.hh" -#include "debug/BusAddrRanges.hh" -#include "debug/CoherentBus.hh" -#include "mem/coherent_bus.hh" +#include "debug/AddrRanges.hh" +#include "debug/CoherentXBar.hh" +#include "mem/coherent_xbar.hh" #include "sim/system.hh" -CoherentBus::CoherentBus(const CoherentBusParams *p) - : BaseBus(p), system(p->system), snoopFilter(p->snoop_filter) +CoherentXBar::CoherentXBar(const CoherentXBarParams *p) + : BaseXBar(p), system(p->system), snoopFilter(p->snoop_filter) { // 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.master[%d]", name(), i); - MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); + MasterPort* bp = new CoherentXBarMasterPort(portName, *this, i); masterPorts.push_back(bp); reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", i))); @@ -75,7 +75,7 @@ CoherentBus::CoherentBus(const CoherentBusParams *p) if (p->port_default_connection_count) { defaultPortID = masterPorts.size(); std::string portName = name() + ".default"; - MasterPort* bp = new CoherentBusMasterPort(portName, *this, + MasterPort* bp = new CoherentXBarMasterPort(portName, *this, defaultPortID); masterPorts.push_back(bp); reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", @@ -88,7 +88,7 @@ CoherentBus::CoherentBus(const CoherentBusParams *p) // 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.slave[%d]", name(), i); - SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); + SlavePort* bp = new CoherentXBarSlavePort(portName, *this, i); slavePorts.push_back(bp); respLayers.push_back(new RespLayer(*bp, *this, csprintf(".respLayer%d", i))); @@ -101,42 +101,41 @@ CoherentBus::CoherentBus(const CoherentBusParams *p) clearPortCache(); } -CoherentBus::~CoherentBus() +CoherentXBar::~CoherentXBar() { - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - delete *l; - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - delete *l; - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - delete *l; - for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p) - delete *p; + for (auto l: reqLayers) + delete l; + for (auto l: respLayers) + delete l; + for (auto l: snoopLayers) + delete l; + for (auto p: snoopRespPorts) + delete p; } void -CoherentBus::init() +CoherentXBar::init() { // the base class is responsible for determining the block size - BaseBus::init(); + BaseXBar::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) { + for (const auto& p: slavePorts) { // check if the connected master port is snooping - if ((*p)->isSnooping()) { - DPRINTF(BusAddrRanges, "Adding snooping master %s\n", - (*p)->getMasterPort().name()); - snoopPorts.push_back(*p); + if (p->isSnooping()) { + DPRINTF(AddrRanges, "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()); + warn("CoherentXBar %s has no snooping ports attached!\n", name()); } bool -CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +CoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id) { // determine the source port based on the id SlavePort *src_port = slavePorts[slave_port_id]; @@ -147,15 +146,15 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) // determine the destination based on the address PortID master_port_id = findPort(pkt->getAddr()); - // test if the bus should be considered occupied for the current + // test if the crossbar should be considered occupied for the current // port, and exclude express snoops from the check if (!is_express_snoop && !reqLayers[master_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n", + DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x BUSY\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); return false; } - DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", + DPRINTF(CoherentXBar, "recvTimingReq: src %s %s expr %d 0x%x\n", src_port->name(), pkt->cmdString(), is_express_snoop, pkt->getAddr()); @@ -168,7 +167,7 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) pkt->setSrc(slave_port_id); calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); // uncacheable requests need never be snooped if (!pkt->req->isUncacheable() && !system->bypassCaches()) { @@ -178,7 +177,7 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) // check with the snoop filter where to forward this packet auto sf_res = snoopFilter->lookupRequest(pkt, *src_port); packetFinishTime += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x"\ + DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x"\ " SF size: %i lat: %i\n", src_port->name(), pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), sf_res.second); @@ -228,8 +227,7 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) // if this is an express snoop, we are done at this point if (is_express_snoop) { assert(success); - snoopDataThroughBus += pkt_size; - snoopsThroughBus++; + snoops++; } else { // for normal requests, check if successful if (!success) { @@ -242,25 +240,24 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) outstandingReq.erase(pkt->req); // undo the calculation so we can check for 0 again - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", + DPRINTF(CoherentXBar, "recvTimingReq: src %s %s 0x%x RETRY\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); - // update the bus state and schedule an idle event + // update the layer state and schedule an idle event reqLayers[master_port_id]->failedTiming(src_port, clockEdge(headerCycles)); } else { - // update the bus state and schedule an idle event + // update the layer state and schedule an idle event reqLayers[master_port_id]->succeededTiming(packetFinishTime); - dataThroughBus += pkt_size; } } // stats updates only consider packets that were successfully sent if (success) { pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; + pktSize[slave_port_id][master_port_id] += pkt_size; transDist[pkt_cmd]++; } @@ -268,7 +265,7 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) } bool -CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) +CoherentXBar::recvTimingResp(PacketPtr pkt, PortID master_port_id) { // determine the source port based on the id MasterPort *src_port = masterPorts[master_port_id]; @@ -276,15 +273,15 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) // determine the destination based on what is stored in the packet PortID slave_port_id = pkt->getDest(); - // test if the bus should be considered occupied for the current - // port + // test if the crossbar should be considered occupied for the + // current port if (!respLayers[slave_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", + DPRINTF(CoherentXBar, "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", + DPRINTF(CoherentXBar, "recvTimingResp: src %s %s 0x%x\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); // store size and command as they might be modified when @@ -293,10 +290,10 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) unsigned int pkt_cmd = pkt->cmdToIndex(); calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); // the packet is a normal response to a request that we should - // have seen passing through the bus + // have seen passing through the crossbar assert(outstandingReq.find(pkt->req) != outstandingReq.end()); if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches()) { @@ -317,25 +314,23 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) respLayers[slave_port_id]->succeededTiming(packetFinishTime); // stats updates - dataThroughBus += pkt_size; pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; + pktSize[slave_port_id][master_port_id] += pkt_size; transDist[pkt_cmd]++; return true; } void -CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) +CoherentXBar::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) { - DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", + DPRINTF(CoherentXBar, "recvTimingSnoopReq: src %s %s 0x%x\n", masterPorts[master_port_id]->name(), pkt->cmdString(), pkt->getAddr()); // update stats here as we know the forwarding will succeed transDist[pkt->cmdToIndex()]++; - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; + snoops++; // we should only see express snoops from caches assert(pkt->isExpressSnoop()); @@ -347,7 +342,7 @@ CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) // let the Snoop Filter work its magic and guide probing auto sf_res = snoopFilter->lookupSnoop(pkt); // No timing here: packetFinishTime += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x"\ + DPRINTF(CoherentXBar, "recvTimingSnoopReq: src %s %s 0x%x"\ " SF size: %i lat: %i\n", masterPorts[master_port_id]->name(), pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), sf_res.second); @@ -367,7 +362,7 @@ CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) } bool -CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) +CoherentXBar::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) { // determine the source port based on the id SlavePort* src_port = slavePorts[slave_port_id]; @@ -382,13 +377,13 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) bool forwardAsSnoop = outstandingReq.find(pkt->req) == outstandingReq.end(); - // test if the bus should be considered occupied for the current - // port, note that the check is bypassed if the response is being - // passed on as a normal response since this is occupying the - // response layer rather than the snoop response layer + // test if the crossbar should be considered occupied for the + // current port, note that the check is bypassed if the response + // is being passed on as a normal response since this is occupying + // the response layer rather than the snoop response layer if (forwardAsSnoop) { if (!snoopLayers[dest_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", + DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); return false; } @@ -396,13 +391,13 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) // get the master port that mirrors this slave port internally MasterPort* snoop_port = snoopRespPorts[slave_port_id]; if (!respLayers[dest_port_id]->tryTiming(snoop_port)) { - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", + DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", snoop_port->name(), pkt->cmdString(), pkt->getAddr()); return false; } } - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n", + DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); // store size and command as they might be modified when @@ -414,7 +409,7 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) assert(!pkt->isExpressSnoop()); calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); // forward it either as a snoop response or a normal response if (forwardAsSnoop) { @@ -431,22 +426,22 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) bool success M5_VAR_USED = masterPorts[dest_port_id]->sendTimingSnoopResp(pkt); pktCount[slave_port_id][dest_port_id]++; - totPktSize[slave_port_id][dest_port_id] += pkt_size; + pktSize[slave_port_id][dest_port_id] += pkt_size; assert(success); snoopLayers[dest_port_id]->succeededTiming(packetFinishTime); } 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 + // i.e. from a coherent master connected to the crossbar, 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 + // destination field set on its way through the crossbar 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_port_id); if (snoopFilter) { @@ -455,7 +450,7 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) *slavePorts[dest_port_id]); } - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x"\ + DPRINTF(CoherentXBar, "recvTimingSnoopResp: src %s %s 0x%x"\ " FWD RESP\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); @@ -478,18 +473,17 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) // stats updates transDist[pkt_cmd]++; - snoopDataThroughBus += pkt_size; - snoopsThroughBus++; + snoops++; return true; } void -CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, +CoherentXBar::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, const std::vector<SlavePort*>& dests) { - DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__, + DPRINTF(CoherentXBar, "%s for %s address %x size %d\n", __func__, pkt->cmdString(), pkt->getAddr(), pkt->getSize()); // snoops should only happen if the system isn't bypassing caches @@ -497,8 +491,7 @@ CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, unsigned fanout = 0; - for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) { - SlavePort *p = *s; + for (const auto& p: dests) { // 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 @@ -516,7 +509,7 @@ CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, } void -CoherentBus::recvRetry(PortID master_port_id) +CoherentXBar::recvRetry(PortID master_port_id) { // responses and snoop responses never block on forwarding them, // so the retry will always be coming from a port to which we @@ -525,14 +518,14 @@ CoherentBus::recvRetry(PortID master_port_id) } Tick -CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) +CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id) { - DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", + DPRINTF(CoherentXBar, "recvAtomic: packet src %s addr 0x%x cmd %s\n", slavePorts[slave_port_id]->name(), pkt->getAddr(), pkt->cmdString()); - // add the request data - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_cmd = pkt->cmdToIndex(); MemCmd snoop_response_cmd = MemCmd::InvalidCmd; Tick snoop_response_latency = 0; @@ -546,7 +539,7 @@ CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) auto sf_res = snoopFilter->lookupRequest(pkt, *slavePorts[slave_port_id]); snoop_response_latency += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "%s: src %s %s 0x%x"\ + DPRINTF(CoherentXBar, "%s: src %s %s 0x%x"\ " SF size: %i lat: %i\n", __func__, slavePorts[slave_port_id]->name(), pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), sf_res.second); @@ -561,10 +554,15 @@ CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) // 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()); + PortID master_port_id = findPort(pkt->getAddr()); + + // stats updates for the request + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; // forward the request to the appropriate destination - Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); + Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt); // Lower levels have replied, tell the snoop filter if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches() && @@ -581,24 +579,30 @@ CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) } // add the response data - if (pkt->isResponse()) - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; + if (pkt->isResponse()) { + pkt_size = pkt->hasData() ? pkt->getSize() : 0; + pkt_cmd = pkt->cmdToIndex(); + + // stats updates + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + } // @todo: Not setting first-word time - pkt->busLastWordDelay = response_latency; + pkt->lastWordDelay = response_latency; return response_latency; } Tick -CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) +CoherentXBar::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) { - DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", + DPRINTF(CoherentXBar, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", masterPorts[master_port_id]->name(), pkt->getAddr(), pkt->cmdString()); // add the request snoop data - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; + snoops++; // forward to all snoopers std::pair<MemCmd, Tick> snoop_result; @@ -606,7 +610,7 @@ CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) if (snoopFilter) { auto sf_res = snoopFilter->lookupSnoop(pkt); snoop_response_latency += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "%s: src %s %s 0x%x SF size: %i lat: %i\n", + DPRINTF(CoherentXBar, "%s: src %s %s 0x%x SF size: %i lat: %i\n", __func__, masterPorts[master_port_id]->name(), pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), sf_res.second); snoop_result = forwardAtomic(pkt, InvalidPortID, master_port_id, @@ -622,17 +626,16 @@ CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) // add the response snoop data if (pkt->isResponse()) { - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; + snoops++; } // @todo: Not setting first-word time - pkt->busLastWordDelay = snoop_response_latency; + pkt->lastWordDelay = snoop_response_latency; return snoop_response_latency; } std::pair<MemCmd, Tick> -CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id, +CoherentXBar::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id, PortID source_master_port_id, const std::vector<SlavePort*>& dests) { @@ -648,8 +651,7 @@ CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id, unsigned fanout = 0; - for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) { - SlavePort *p = *s; + for (const auto& p: dests) { // 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 @@ -704,11 +706,11 @@ CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id, } void -CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) +CoherentXBar::recvFunctional(PacketPtr pkt, PortID slave_port_id) { if (!pkt->isPrint()) { // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(CoherentBus, + DPRINTF(CoherentXBar, "recvFunctional: packet src %s addr 0x%x cmd %s\n", slavePorts[slave_port_id]->name(), pkt->getAddr(), pkt->cmdString()); @@ -730,11 +732,11 @@ CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) } void -CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) +CoherentXBar::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) { if (!pkt->isPrint()) { // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(CoherentBus, + DPRINTF(CoherentXBar, "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", masterPorts[master_port_id]->name(), pkt->getAddr(), pkt->cmdString()); @@ -745,13 +747,12 @@ CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) } void -CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) +CoherentXBar::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) { // snoops should only happen if the system isn't bypassing caches assert(!system->bypassCaches()); - for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { - SlavePort *p = *s; + for (const auto& p: snoopPorts) { // 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 @@ -768,43 +769,33 @@ CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) } unsigned int -CoherentBus::drain(DrainManager *dm) +CoherentXBar::drain(DrainManager *dm) { // sum up the individual layers unsigned int total = 0; - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - total += (*l)->drain(dm); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - total += (*l)->drain(dm); - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - total += (*l)->drain(dm); + for (auto l: reqLayers) + total += l->drain(dm); + for (auto l: respLayers) + total += l->drain(dm); + for (auto l: snoopLayers) + total += l->drain(dm); return total; } void -CoherentBus::regStats() +CoherentXBar::regStats() { - // register the stats of the base class and our three bus layers - BaseBus::regStats(); - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - (*l)->regStats(); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - (*l)->regStats(); - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - (*l)->regStats(); - - dataThroughBus - .name(name() + ".data_through_bus") - .desc("Total data (bytes)") - ; - - snoopDataThroughBus - .name(name() + ".snoop_data_through_bus") - .desc("Total snoop data (bytes)") - ; - - snoopsThroughBus - .name(name() + ".snoops_through_bus") + // register the stats of the base class and our layers + BaseXBar::regStats(); + for (auto l: reqLayers) + l->regStats(); + for (auto l: respLayers) + l->regStats(); + for (auto l: snoopLayers) + l->regStats(); + + snoops + .name(name() + ".snoops") .desc("Total snoops (count)") ; @@ -813,18 +804,10 @@ CoherentBus::regStats() .name(name() + ".snoop_fanout") .desc("Request fanout histogram") ; - - throughput - .name(name() + ".throughput") - .desc("Throughput (bytes/s)") - .precision(0) - ; - - throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds; } -CoherentBus * -CoherentBusParams::create() +CoherentXBar * +CoherentXBarParams::create() { - return new CoherentBus(this); + return new CoherentXBar(this); } diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_xbar.hh index 26ad92791..fd4dd1cca 100644 --- a/src/mem/coherent_bus.hh +++ b/src/mem/coherent_xbar.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -45,36 +45,36 @@ /** * @file - * Declaration of a coherent bus. + * Declaration of a coherent crossbar. */ -#ifndef __MEM_COHERENT_BUS_HH__ -#define __MEM_COHERENT_BUS_HH__ +#ifndef __MEM_COHERENT_XBAR_HH__ +#define __MEM_COHERENT_XBAR_HH__ #include "base/hashmap.hh" -#include "mem/bus.hh" #include "mem/snoop_filter.hh" -#include "params/CoherentBus.hh" +#include "mem/xbar.hh" +#include "params/CoherentXBar.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. + * A coherent crossbar 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. - * @sa \ref gem5MemorySystem "gem5 Memory System" + * The coherent crossbar 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. @sa + * \ref gem5MemorySystem "gem5 Memory System" */ -class CoherentBus : public BaseBus +class CoherentXBar : public BaseXBar { protected: /** - * Declare the layers of this bus, one vector for requests, one - * for responses, and one for snoop responses + * Declare the layers of this crossbar, one vector for requests, + * one for responses, and one for snoop responses */ typedef Layer<SlavePort,MasterPort> ReqLayer; typedef Layer<MasterPort,SlavePort> RespLayer; @@ -84,88 +84,88 @@ class CoherentBus : public BaseBus std::vector<SnoopLayer*> snoopLayers; /** - * Declaration of the coherent bus slave port type, one will be - * instantiated for each of the master ports connecting to the - * bus. + * Declaration of the coherent crossbar slave port type, one will + * be instantiated for each of the master ports connecting to the + * crossbar. */ - class CoherentBusSlavePort : public SlavePort + class CoherentXBarSlavePort : public SlavePort { private: - /** A reference to the bus to which this port belongs. */ - CoherentBus &bus; + /** A reference to the crossbar to which this port belongs. */ + CoherentXBar &xbar; public: - CoherentBusSlavePort(const std::string &_name, - CoherentBus &_bus, PortID _id) - : SlavePort(_name, &_bus, _id), bus(_bus) + CoherentXBarSlavePort(const std::string &_name, + CoherentXBar &_xbar, PortID _id) + : SlavePort(_name, &_xbar, _id), xbar(_xbar) { } protected: /** - * When receiving a timing request, pass it to the bus. + * When receiving a timing request, pass it to the crossbar. */ virtual bool recvTimingReq(PacketPtr pkt) - { return bus.recvTimingReq(pkt, id); } + { return xbar.recvTimingReq(pkt, id); } /** - * When receiving a timing snoop response, pass it to the bus. + * When receiving a timing snoop response, pass it to the crossbar. */ virtual bool recvTimingSnoopResp(PacketPtr pkt) - { return bus.recvTimingSnoopResp(pkt, id); } + { return xbar.recvTimingSnoopResp(pkt, id); } /** - * When receiving an atomic request, pass it to the bus. + * When receiving an atomic request, pass it to the crossbar. */ virtual Tick recvAtomic(PacketPtr pkt) - { return bus.recvAtomic(pkt, id); } + { return xbar.recvAtomic(pkt, id); } /** - * When receiving a functional request, pass it to the bus. + * When receiving a functional request, pass it to the crossbar. */ virtual void recvFunctional(PacketPtr pkt) - { bus.recvFunctional(pkt, id); } + { xbar.recvFunctional(pkt, id); } /** - * When receiving a retry, pass it to the bus. + * When receiving a retry, pass it to the crossbar. */ virtual void recvRetry() - { panic("Bus slave ports always succeed and should never retry.\n"); } + { panic("Crossbar slave ports should never retry.\n"); } /** - * Return the union of all adress ranges seen by this bus. + * Return the union of all adress ranges seen by this crossbar. */ virtual AddrRangeList getAddrRanges() const - { return bus.getAddrRanges(); } + { return xbar.getAddrRanges(); } }; /** - * Declaration of the coherent bus master port type, one will be + * Declaration of the coherent crossbar master port type, one will be * instantiated for each of the slave interfaces connecting to the - * bus. + * crossbar. */ - class CoherentBusMasterPort : public MasterPort + class CoherentXBarMasterPort : public MasterPort { private: - /** A reference to the bus to which this port belongs. */ - CoherentBus &bus; + /** A reference to the crossbar to which this port belongs. */ + CoherentXBar &xbar; public: - CoherentBusMasterPort(const std::string &_name, - CoherentBus &_bus, PortID _id) - : MasterPort(_name, &_bus, _id), bus(_bus) + CoherentXBarMasterPort(const std::string &_name, + CoherentXBar &_xbar, PortID _id) + : MasterPort(_name, &_xbar, _id), xbar(_xbar) { } protected: /** * Determine if this port should be considered a snooper. For - * a coherent bus master port this is always true. + * a coherent crossbar master port this is always true. * * @return a boolean that is true if this port is snooping */ @@ -173,38 +173,38 @@ class CoherentBus : public BaseBus { return true; } /** - * When receiving a timing response, pass it to the bus. + * When receiving a timing response, pass it to the crossbar. */ virtual bool recvTimingResp(PacketPtr pkt) - { return bus.recvTimingResp(pkt, id); } + { return xbar.recvTimingResp(pkt, id); } /** - * When receiving a timing snoop request, pass it to the bus. + * When receiving a timing snoop request, pass it to the crossbar. */ virtual void recvTimingSnoopReq(PacketPtr pkt) - { return bus.recvTimingSnoopReq(pkt, id); } + { return xbar.recvTimingSnoopReq(pkt, id); } /** - * When receiving an atomic snoop request, pass it to the bus. + * When receiving an atomic snoop request, pass it to the crossbar. */ virtual Tick recvAtomicSnoop(PacketPtr pkt) - { return bus.recvAtomicSnoop(pkt, id); } + { return xbar.recvAtomicSnoop(pkt, id); } /** - * When receiving a functional snoop request, pass it to the bus. + * When receiving a functional snoop request, pass it to the crossbar. */ virtual void recvFunctionalSnoop(PacketPtr pkt) - { bus.recvFunctionalSnoop(pkt, id); } + { xbar.recvFunctionalSnoop(pkt, id); } /** When reciving a range change from the peer port (at id), - pass it to the bus. */ + pass it to the crossbar. */ virtual void recvRangeChange() - { bus.recvRangeChange(id); } + { xbar.recvRangeChange(id); } /** When reciving a retry from the peer port (at id), - pass it to the bus. */ + pass it to the crossbar. */ virtual void recvRetry() - { bus.recvRetry(id); } + { xbar.recvRetry(id); } }; @@ -226,8 +226,8 @@ class CoherentBus : public BaseBus /** * Create a snoop response port that mirrors a given slave port. */ - SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) : - MasterPort(slave_port.name() + ".snoopRespPort", &_bus), + SnoopRespPort(SlavePort& slave_port, CoherentXBar& _xbar) : + MasterPort(slave_port.name() + ".snoopRespPort", &_xbar), slavePort(slave_port) { } /** @@ -261,7 +261,7 @@ class CoherentBus : public BaseBus /** * 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. + * in the coherent crossbar when coherency responses come back. */ m5::hash_set<RequestPtr> outstandingReq; @@ -275,19 +275,19 @@ class CoherentBus : public BaseBus * broadcast needed for probes. NULL denotes an absent filter. */ SnoopFilter *snoopFilter; - /** Function called by the port when the bus is recieving a Timing + /** Function called by the port when the crossbar 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 + /** Function called by the port when the crossbar 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 + /** Function called by the port when the crossbar 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 + /** Function called by the port when the crossbar is recieving a timing snoop response.*/ bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id); @@ -319,11 +319,11 @@ class CoherentBus : public BaseBus void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, const std::vector<SlavePort*>& dests); - /** Function called by the port when the bus is recieving a Atomic + /** Function called by the port when the crossbar is recieving a Atomic transaction.*/ Tick recvAtomic(PacketPtr pkt, PortID slave_port_id); - /** Function called by the port when the bus is recieving an + /** Function called by the port when the crossbar is recieving an atomic snoop transaction.*/ Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id); @@ -360,11 +360,11 @@ class CoherentBus : public BaseBus PortID source_master_port_id, const std::vector<SlavePort*>& dests); - /** Function called by the port when the bus is recieving a Functional + /** Function called by the port when the crossbar 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 + /** Function called by the port when the crossbar is recieving a functional snoop transaction.*/ void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id); @@ -378,22 +378,20 @@ class CoherentBus : public BaseBus */ void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id); - Stats::Scalar dataThroughBus; - Stats::Scalar snoopDataThroughBus; - Stats::Scalar snoopsThroughBus; + Stats::Scalar snoops; Stats::Distribution snoopFanout; public: virtual void init(); - CoherentBus(const CoherentBusParams *p); + CoherentXBar(const CoherentXBarParams *p); - virtual ~CoherentBus(); + virtual ~CoherentXBar(); unsigned int drain(DrainManager *dm); virtual void regStats(); }; -#endif //__MEM_COHERENT_BUS_HH__ +#endif //__MEM_COHERENT_XBAR_HH__ diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index 38c240fcf..198cb52a4 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -819,7 +819,7 @@ DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency) assert(pkt->isResponse()); // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; // queue the packet in the response queue to be sent out after // the static latency has passed diff --git a/src/mem/dramsim2.cc b/src/mem/dramsim2.cc index 27dc36976..3356fd7d2 100644 --- a/src/mem/dramsim2.cc +++ b/src/mem/dramsim2.cc @@ -268,7 +268,7 @@ DRAMSim2::accessAndRespond(PacketPtr pkt) assert(pkt->isResponse()); // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; DPRINTF(DRAMSim2, "Queuing response for address %lld\n", pkt->getAddr()); diff --git a/src/mem/noncoherent_bus.cc b/src/mem/noncoherent_xbar.cc index d34ae6d20..bc51be5a2 100644 --- a/src/mem/noncoherent_bus.cc +++ b/src/mem/noncoherent_xbar.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,25 +44,24 @@ /** * @file - * Definition of a bus object. + * Definition of a non-coherent crossbar 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" +#include "debug/NoncoherentXBar.hh" +#include "debug/XBar.hh" +#include "mem/noncoherent_xbar.hh" -NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) - : BaseBus(p) +NoncoherentXBar::NoncoherentXBar(const NoncoherentXBarParams *p) + : BaseXBar(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.master[%d]", name(), i); - MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, i); + MasterPort* bp = new NoncoherentXBarMasterPort(portName, *this, i); masterPorts.push_back(bp); reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", i))); @@ -73,7 +72,7 @@ NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) if (p->port_default_connection_count) { defaultPortID = masterPorts.size(); std::string portName = name() + ".default"; - MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, + MasterPort* bp = new NoncoherentXBarMasterPort(portName, *this, defaultPortID); masterPorts.push_back(bp); reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", @@ -83,7 +82,7 @@ NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) // 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.slave[%d]", name(), i); - SlavePort* bp = new NoncoherentBusSlavePort(portName, *this, i); + SlavePort* bp = new NoncoherentXBarSlavePort(portName, *this, i); slavePorts.push_back(bp); respLayers.push_back(new RespLayer(*bp, *this, csprintf(".respLayer%d", i))); @@ -92,35 +91,35 @@ NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) clearPortCache(); } -NoncoherentBus::~NoncoherentBus() +NoncoherentXBar::~NoncoherentXBar() { - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - delete *l; - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - delete *l; + for (auto l: reqLayers) + delete l; + for (auto l: respLayers) + delete l; } bool -NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +NoncoherentXBar::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 + // we should never see express snoops on a non-coherent crossbar assert(!pkt->isExpressSnoop()); // determine the destination based on the address PortID master_port_id = findPort(pkt->getAddr()); - // test if the bus should be considered occupied for the current + // test if the layer should be considered occupied for the current // port if (!reqLayers[master_port_id]->tryTiming(src_port)) { - DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", + DPRINTF(NoncoherentXBar, "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", + DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); // store size and command as they might be modified when @@ -132,7 +131,7 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) pkt->setSrc(slave_port_id); calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); // since it is a normal request, attempt to send the packet bool success = masterPorts[master_port_id]->sendTimingReq(pkt); @@ -141,11 +140,11 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) // inhibited packets should never be forced to retry assert(!pkt->memInhibitAsserted()); - DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", + DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x RETRY\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); // undo the calculation so we can check for 0 again - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; // occupy until the header is sent reqLayers[master_port_id]->failedTiming(src_port, @@ -157,16 +156,15 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) reqLayers[master_port_id]->succeededTiming(packetFinishTime); // stats updates - dataThroughBus += pkt_size; pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; + pktSize[slave_port_id][master_port_id] += pkt_size; transDist[pkt_cmd]++; return true; } bool -NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) +NoncoherentXBar::recvTimingResp(PacketPtr pkt, PortID master_port_id) { // determine the source port based on the id MasterPort *src_port = masterPorts[master_port_id]; @@ -174,15 +172,15 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) // determine the destination based on what is stored in the packet PortID slave_port_id = pkt->getDest(); - // test if the bus should be considered occupied for the current + // test if the layer should be considered occupied for the current // port if (!respLayers[slave_port_id]->tryTiming(src_port)) { - DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", + DPRINTF(NoncoherentXBar, "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", + DPRINTF(NoncoherentXBar, "recvTimingResp: src %s %s 0x%x\n", src_port->name(), pkt->cmdString(), pkt->getAddr()); // store size and command as they might be modified when @@ -191,7 +189,7 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) unsigned int pkt_cmd = pkt->cmdToIndex(); calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); // send the packet through the destination slave port bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt); @@ -203,16 +201,15 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) respLayers[slave_port_id]->succeededTiming(packetFinishTime); // stats updates - dataThroughBus += pkt_size; pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; + pktSize[slave_port_id][master_port_id] += pkt_size; transDist[pkt_cmd]++; return true; } void -NoncoherentBus::recvRetry(PortID master_port_id) +NoncoherentXBar::recvRetry(PortID master_port_id) { // responses never block on forwarding them, so the retry will // always be coming from a port to which we tried to forward a @@ -221,36 +218,48 @@ NoncoherentBus::recvRetry(PortID master_port_id) } Tick -NoncoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) +NoncoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id) { - DPRINTF(NoncoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", + DPRINTF(NoncoherentXBar, "recvAtomic: packet src %s addr 0x%x cmd %s\n", slavePorts[slave_port_id]->name(), pkt->getAddr(), pkt->cmdString()); - // add the request data - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_cmd = pkt->cmdToIndex(); // determine the destination port - PortID dest_id = findPort(pkt->getAddr()); + PortID master_port_id = findPort(pkt->getAddr()); + + // stats updates for the request + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; // forward the request to the appropriate destination - Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); + Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt); // add the response data - if (pkt->isResponse()) - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; + if (pkt->isResponse()) { + pkt_size = pkt->hasData() ? pkt->getSize() : 0; + pkt_cmd = pkt->cmdToIndex(); + + // stats updates + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + } // @todo: Not setting first-word time - pkt->busLastWordDelay = response_latency; + pkt->lastWordDelay = response_latency; return response_latency; } void -NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) +NoncoherentXBar::recvFunctional(PacketPtr pkt, PortID slave_port_id) { if (!pkt->isPrint()) { // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(NoncoherentBus, + DPRINTF(NoncoherentXBar, "recvFunctional: packet src %s addr 0x%x cmd %s\n", slavePorts[slave_port_id]->name(), pkt->getAddr(), pkt->cmdString()); @@ -264,43 +273,30 @@ NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) } unsigned int -NoncoherentBus::drain(DrainManager *dm) +NoncoherentXBar::drain(DrainManager *dm) { // sum up the individual layers unsigned int total = 0; - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - total += (*l)->drain(dm); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - total += (*l)->drain(dm); + for (auto l: reqLayers) + total += l->drain(dm); + for (auto l: respLayers) + total += l->drain(dm); return total; } -NoncoherentBus* -NoncoherentBusParams::create() +NoncoherentXBar* +NoncoherentXBarParams::create() { - return new NoncoherentBus(this); + return new NoncoherentXBar(this); } void -NoncoherentBus::regStats() +NoncoherentXBar::regStats() { - // register the stats of the base class and our two bus layers - BaseBus::regStats(); - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - (*l)->regStats(); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - (*l)->regStats(); - - dataThroughBus - .name(name() + ".data_through_bus") - .desc("Total data (bytes)") - ; - - throughput - .name(name() + ".throughput") - .desc("Throughput (bytes/s)") - .precision(0) - ; - - throughput = dataThroughBus / simSeconds; + // register the stats of the base class and our layers + BaseXBar::regStats(); + for (auto l: reqLayers) + l->regStats(); + for (auto l: respLayers) + l->regStats(); } diff --git a/src/mem/noncoherent_bus.hh b/src/mem/noncoherent_xbar.hh index a1b9da6e3..122fc6b27 100644 --- a/src/mem/noncoherent_bus.hh +++ b/src/mem/noncoherent_xbar.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -45,36 +45,36 @@ /** * @file - * Declaration of a non-coherent bus. + * Declaration of a non-coherent crossbar. */ -#ifndef __MEM_NONCOHERENT_BUS_HH__ -#define __MEM_NONCOHERENT_BUS_HH__ +#ifndef __MEM_NONCOHERENT_XBAR_HH__ +#define __MEM_NONCOHERENT_XBAR_HH__ -#include "mem/bus.hh" -#include "params/NoncoherentBus.hh" +#include "mem/xbar.hh" +#include "params/NoncoherentXBar.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. + * A non-coherent crossbar 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 crossbar could still snoop in caches attached to a + * coherent crossbar, 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 crossbar itself. * - * The non-coherent bus can be used as a template for modelling PCI, + * The non-coherent crossbar can be used as a template for modelling * PCIe, and non-coherent AMBA and OCP buses, and is typically used * for the I/O buses. */ -class NoncoherentBus : public BaseBus +class NoncoherentXBar : public BaseXBar { protected: /** - * Declare the layers of this bus, one vector for requests and one - * for responses. + * Declare the layers of this crossbar, one vector for requests + * and one for responses. */ typedef Layer<SlavePort,MasterPort> ReqLayer; typedef Layer<MasterPort,SlavePort> RespLayer; @@ -82,102 +82,102 @@ class NoncoherentBus : public BaseBus std::vector<RespLayer*> respLayers; /** - * Declaration of the non-coherent bus slave port type, one will - * be instantiated for each of the master ports connecting to the - * bus. + * Declaration of the non-coherent crossbar slave port type, one + * will be instantiated for each of the master ports connecting to + * the crossbar. */ - class NoncoherentBusSlavePort : public SlavePort + class NoncoherentXBarSlavePort : public SlavePort { private: - /** A reference to the bus to which this port belongs. */ - NoncoherentBus &bus; + /** A reference to the crossbar to which this port belongs. */ + NoncoherentXBar &xbar; public: - NoncoherentBusSlavePort(const std::string &_name, - NoncoherentBus &_bus, PortID _id) - : SlavePort(_name, &_bus, _id), bus(_bus) + NoncoherentXBarSlavePort(const std::string &_name, + NoncoherentXBar &_xbar, PortID _id) + : SlavePort(_name, &_xbar, _id), xbar(_xbar) { } protected: /** - * When receiving a timing request, pass it to the bus. + * When receiving a timing request, pass it to the crossbar. */ virtual bool recvTimingReq(PacketPtr pkt) - { return bus.recvTimingReq(pkt, id); } + { return xbar.recvTimingReq(pkt, id); } /** - * When receiving an atomic request, pass it to the bus. + * When receiving an atomic request, pass it to the crossbar. */ virtual Tick recvAtomic(PacketPtr pkt) - { return bus.recvAtomic(pkt, id); } + { return xbar.recvAtomic(pkt, id); } /** - * When receiving a functional request, pass it to the bus. + * When receiving a functional request, pass it to the crossbar. */ virtual void recvFunctional(PacketPtr pkt) - { bus.recvFunctional(pkt, id); } + { xbar.recvFunctional(pkt, id); } /** - * When receiving a retry, pass it to the bus. + * When receiving a retry, pass it to the crossbar. */ virtual void recvRetry() - { panic("Bus slave ports always succeed and should never retry.\n"); } + { panic("Crossbar slave ports should never retry.\n"); } /** - * Return the union of all adress ranges seen by this bus. + * Return the union of all adress ranges seen by this crossbar. */ virtual AddrRangeList getAddrRanges() const - { return bus.getAddrRanges(); } + { return xbar.getAddrRanges(); } }; /** - * Declaration of the bus master port type, one will be + * Declaration of the crossbar master port type, one will be * instantiated for each of the slave ports connecting to the - * bus. + * crossbar. */ - class NoncoherentBusMasterPort : public MasterPort + class NoncoherentXBarMasterPort : public MasterPort { private: - /** A reference to the bus to which this port belongs. */ - NoncoherentBus &bus; + /** A reference to the crossbar to which this port belongs. */ + NoncoherentXBar &xbar; public: - NoncoherentBusMasterPort(const std::string &_name, - NoncoherentBus &_bus, PortID _id) - : MasterPort(_name, &_bus, _id), bus(_bus) + NoncoherentXBarMasterPort(const std::string &_name, + NoncoherentXBar &_xbar, PortID _id) + : MasterPort(_name, &_xbar, _id), xbar(_xbar) { } protected: /** - * When receiving a timing response, pass it to the bus. + * When receiving a timing response, pass it to the crossbar. */ virtual bool recvTimingResp(PacketPtr pkt) - { return bus.recvTimingResp(pkt, id); } + { return xbar.recvTimingResp(pkt, id); } /** When reciving a range change from the peer port (at id), - pass it to the bus. */ + pass it to the crossbar. */ virtual void recvRangeChange() - { bus.recvRangeChange(id); } + { xbar.recvRangeChange(id); } /** When reciving a retry from the peer port (at id), - pass it to the bus. */ + pass it to the crossbar. */ virtual void recvRetry() - { bus.recvRetry(id); } + { xbar.recvRetry(id); } }; - /** Function called by the port when the bus is recieving a Timing + /** Function called by the port when the crossbar is recieving a Timing request packet.*/ virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id); - /** Function called by the port when the bus is recieving a Timing + /** Function called by the port when the crossbar is recieving a Timing response packet.*/ virtual bool recvTimingResp(PacketPtr pkt, PortID master_port_id); @@ -185,19 +185,19 @@ class NoncoherentBus : public BaseBus * requests. */ void recvRetry(PortID master_port_id); - /** Function called by the port when the bus is recieving a Atomic + /** Function called by the port when the crossbar 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 + /** Function called by the port when the crossbar is recieving a Functional transaction.*/ void recvFunctional(PacketPtr pkt, PortID slave_port_id); public: - NoncoherentBus(const NoncoherentBusParams *p); + NoncoherentXBar(const NoncoherentXBarParams *p); - virtual ~NoncoherentBus(); + virtual ~NoncoherentXBar(); unsigned int drain(DrainManager *dm); @@ -205,7 +205,7 @@ class NoncoherentBus : public BaseBus * stats */ virtual void regStats(); - Stats::Scalar dataThroughBus; + Stats::Scalar totPktSize; }; -#endif //__MEM_NONCOHERENT_BUS_HH__ +#endif //__MEM_NONCOHERENT_XBAR_HH__ diff --git a/src/mem/packet.hh b/src/mem/packet.hh index c070eaea7..4ed307f66 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -293,14 +293,14 @@ class Packet : public Printable /** * Source port identifier set on a request packet to enable * appropriate routing of the responses. The source port - * identifier is set by any multiplexing component, e.g. a bus, as - * the timing responses need this information to be routed back to - * the appropriate port at a later point in time. The field can be - * updated (over-written) as the request packet passes through - * additional multiplexing components, and it is their - * responsibility to remember the original source port identifier, - * for example by using an appropriate sender state. The latter is - * done in the cache and bridge. + * identifier is set by any multiplexing component, e.g. a + * crossbar, as the timing responses need this information to be + * routed back to the appropriate port at a later point in + * time. The field can be updated (over-written) as the request + * packet passes through additional multiplexing components, and + * it is their responsibility to remember the original source port + * identifier, for example by using an appropriate sender + * state. The latter is done in the cache and bridge. */ PortID src; @@ -309,7 +309,7 @@ class Packet : public Printable * packets that passed through a multiplexing component as a * request packet. The source port identifier is turned into a * destination port identifier when the packet is turned into a - * response, and the destination is used, e.g. by the bus, to + * response, and the destination is used, e.g. by the crossbar, to * select the appropriate path through the interconnect. */ PortID dest; @@ -333,21 +333,22 @@ class Packet : public Printable /** * The extra delay from seeing the packet until the first word is - * transmitted by the bus that provided it (if any). This delay is - * used to communicate the bus waiting time to the neighbouring - * object (e.g. a cache) that actually makes the packet wait. As - * the delay is relative, a 32-bit unsigned should be sufficient. + * transmitted. This delay is used to communicate the crossbar + * forwarding latency to the neighbouring object (e.g. a cache) + * that actually makes the packet wait. As the delay is relative, + * a 32-bit unsigned should be sufficient. */ - uint32_t busFirstWordDelay; + uint32_t firstWordDelay; /** - * The extra delay from seeing the packet until the last word is - * transmitted by the bus that provided it (if any). Similar to - * the first word time, this is used to make up for the fact that - * the bus does not make the packet wait. As the delay is relative, - * a 32-bit unsigned should be sufficient. + * The extra pipelining delay from seeing the packet until the + * last word is transmitted by the component that provided it (if + * any). This includes the first word delay. Similar to the first + * word delay, this is used to make up for the fact that the + * crossbar does not make the packet wait. As the delay is + * relative, a 32-bit unsigned should be sufficient. */ - uint32_t busLastWordDelay; + uint32_t lastWordDelay; /** * A virtual base opaque structure used to hold state associated @@ -541,8 +542,6 @@ class Packet : public Printable PortID getSrc() const { assert(isSrcValid()); return src; } /// Accessor function to set the source index of the packet. void setSrc(PortID _src) { src = _src; } - /// Reset source field, e.g. to retransmit packet on different bus. - void clearSrc() { src = InvalidPortID; } bool isDestValid() const { return dest != InvalidPortID; } /// Accessor function for the destination index of the packet. @@ -604,7 +603,7 @@ class Packet : public Printable : cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false), src(InvalidPortID), dest(InvalidPortID), bytesValidStart(0), bytesValidEnd(0), - busFirstWordDelay(0), busLastWordDelay(0), + firstWordDelay(0), lastWordDelay(0), senderState(NULL) { if (req->hasPaddr()) { @@ -627,7 +626,7 @@ class Packet : public Printable : cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false), src(InvalidPortID), dest(InvalidPortID), bytesValidStart(0), bytesValidEnd(0), - busFirstWordDelay(0), busLastWordDelay(0), + firstWordDelay(0), lastWordDelay(0), senderState(NULL) { if (req->hasPaddr()) { @@ -653,8 +652,8 @@ class Packet : public Printable src(pkt->src), dest(pkt->dest), bytesValidStart(pkt->bytesValidStart), bytesValidEnd(pkt->bytesValidEnd), - busFirstWordDelay(pkt->busFirstWordDelay), - busLastWordDelay(pkt->busLastWordDelay), + firstWordDelay(pkt->firstWordDelay), + lastWordDelay(pkt->lastWordDelay), senderState(pkt->senderState) { if (!clearFlags) @@ -739,8 +738,8 @@ class Packet : public Printable dest = InvalidPortID; bytesValidStart = 0; bytesValidEnd = 0; - busFirstWordDelay = 0; - busLastWordDelay = 0; + firstWordDelay = 0; + lastWordDelay = 0; flags.set(VALID_ADDR|VALID_SIZE); deleteData(); @@ -766,7 +765,7 @@ class Packet : public Printable flags.clear(EXPRESS_SNOOP); dest = src; - clearSrc(); + src = InvalidPortID; } void diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 1b76b52e8..08ec83410 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -51,7 +51,7 @@ #include <string> #include "base/trace.hh" -#include "debug/BusAddrRanges.hh" +#include "debug/AddrRanges.hh" #include "debug/Checkpoint.hh" #include "mem/abstract_mem.hh" #include "mem/physical.hh" @@ -79,7 +79,7 @@ PhysicalMemory::PhysicalMemory(const string& _name, fatal("Memory address range for %s is overlapping\n", (*m)->name()); } else { - DPRINTF(BusAddrRanges, + DPRINTF(AddrRanges, "Skipping memory %s that is not in global address map\n", (*m)->name()); // this type of memory is used e.g. as reference memory by @@ -144,7 +144,7 @@ PhysicalMemory::createBackingStore(AddrRange range, range.to_string()); // perform the actual mmap - DPRINTF(BusAddrRanges, "Creating backing store for range %s with size %d\n", + DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n", range.to_string(), range.size()); int map_flags = MAP_ANON | MAP_PRIVATE; uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(), @@ -164,7 +164,7 @@ PhysicalMemory::createBackingStore(AddrRange range, // point the memories to their backing store for (vector<AbstractMemory*>::const_iterator m = _memories.begin(); m != _memories.end(); ++m) { - DPRINTF(BusAddrRanges, "Mapping memory %s to backing store\n", + DPRINTF(AddrRanges, "Mapping memory %s to backing store\n", (*m)->name()); (*m)->setBackingStore(pmem); } diff --git a/src/mem/simple_mem.cc b/src/mem/simple_mem.cc index b2d518dc7..11ed74b3b 100644 --- a/src/mem/simple_mem.cc +++ b/src/mem/simple_mem.cc @@ -122,7 +122,7 @@ SimpleMemory::recvTimingReq(PacketPtr pkt) } // @todo someone should pay for this - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; + pkt->firstWordDelay = pkt->lastWordDelay = 0; // update the release time according to the bandwidth limit, and // do so with respect to the time it takes to finish this request diff --git a/src/mem/bus.cc b/src/mem/xbar.cc index 730c612ca..6e4630fb6 100644 --- a/src/mem/bus.cc +++ b/src/mem/xbar.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,17 +44,17 @@ /** * @file - * Definition of a bus object. + * Definition of a crossbar object. */ #include "base/misc.hh" #include "base/trace.hh" -#include "debug/Bus.hh" -#include "debug/BusAddrRanges.hh" +#include "debug/AddrRanges.hh" #include "debug/Drain.hh" -#include "mem/bus.hh" +#include "debug/XBar.hh" +#include "mem/xbar.hh" -BaseBus::BaseBus(const BaseBusParams *p) +BaseXBar::BaseXBar(const BaseXBarParams *p) : MemObject(p), headerCycles(p->header_cycles), width(p->width), gotAddrRanges(p->port_default_connection_count + @@ -63,26 +63,22 @@ BaseBus::BaseBus(const BaseBusParams *p) useDefaultRange(p->use_default_range) {} -BaseBus::~BaseBus() +BaseXBar::~BaseXBar() { - for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); - ++m) { - delete *m; - } + for (auto m: masterPorts) + delete m; - for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); - ++s) { - delete *s; - } + for (auto s: slavePorts) + delete s; } void -BaseBus::init() +BaseXBar::init() { } BaseMasterPort & -BaseBus::getMasterPort(const std::string &if_name, PortID idx) +BaseXBar::getMasterPort(const std::string &if_name, PortID idx) { if (if_name == "master" && idx < masterPorts.size()) { // the master port index translates directly to the vector position @@ -95,7 +91,7 @@ BaseBus::getMasterPort(const std::string &if_name, PortID idx) } BaseSlavePort & -BaseBus::getSlavePort(const std::string &if_name, PortID idx) +BaseXBar::getSlavePort(const std::string &if_name, PortID idx) { if (if_name == "slave" && idx < slavePorts.size()) { // the slave port index translates directly to the vector position @@ -106,9 +102,9 @@ BaseBus::getSlavePort(const std::string &if_name, PortID idx) } void -BaseBus::calcPacketTiming(PacketPtr pkt) +BaseXBar::calcPacketTiming(PacketPtr pkt) { - // the bus will be called at a time that is not necessarily + // the crossbar will be called at a time that is not necessarily // coinciding with its own clock, so start by determining how long // until the next clock edge (could be zero) Tick offset = clockEdge() - curTick(); @@ -117,58 +113,58 @@ BaseBus::calcPacketTiming(PacketPtr pkt) unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; // before setting the bus delay fields of the packet, ensure that - // the delay from any previous bus has been accounted for - if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0) - panic("Packet %s already has bus delay (%d, %d) that should be " - "accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay, - pkt->busLastWordDelay); + // the delay from any previous crossbar has been accounted for + if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0) + panic("Packet %s already has delay (%d, %d) that should be " + "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay, + pkt->lastWordDelay); // The first word will be delivered on the cycle after the header. - pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset; + pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset; - // Note that currently busLastWordDelay can be smaller than - // busFirstWordDelay if the packet has no data - pkt->busLastWordDelay = (headerCycles + dataCycles) * clockPeriod() + + // Note that currently lastWordDelay can be smaller than + // firstWordDelay if the packet has no data + pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() + offset; } template <typename SrcType, typename DstType> -BaseBus::Layer<SrcType,DstType>::Layer(DstType& _port, BaseBus& _bus, +BaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar, const std::string& _name) : - port(_port), bus(_bus), _name(_name), state(IDLE), drainManager(NULL), + port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL), waitingForPeer(NULL), releaseEvent(this) { } template <typename SrcType, typename DstType> -void BaseBus::Layer<SrcType,DstType>::occupyLayer(Tick until) +void BaseXBar::Layer<SrcType,DstType>::occupyLayer(Tick until) { - // ensure the state is busy at this point, as the bus should + // ensure the state is busy at this point, as the layer should // transition from idle as soon as it has decided to forward the // packet to prevent any follow-on calls to sendTiming seeing an - // unoccupied bus + // unoccupied layer assert(state == BUSY); - // until should never be 0 as express snoops never occupy the bus + // until should never be 0 as express snoops never occupy the layer assert(until != 0); - bus.schedule(releaseEvent, until); + xbar.schedule(releaseEvent, until); // account for the occupied ticks occupancy += until - curTick(); - DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", + DPRINTF(BaseXBar, "The crossbar layer is now busy from tick %d to %d\n", curTick(), until); } template <typename SrcType, typename DstType> bool -BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) +BaseXBar::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) { // if we are in the retry state, we will not see anything but the // retrying port (or in the case of the snoop ports the snoop // response port that mirrors the actual slave port) as we leave // this state again in zero time if the peer does not immediately - // call the bus when receiving the retry + // call the layer when receiving the retry // first we see if the layer is busy, next we check if the // destination port is already engaged in a transaction waiting @@ -180,13 +176,12 @@ BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) // put the port at the end of the retry list waiting for the // layer to be freed up (and in the case of a busy peer, for - // that transaction to go through, and then the bus to free + // that transaction to go through, and then the layer to free // up) waitingForLayer.push_back(src_port); return false; } - // update the state to busy state = BUSY; return true; @@ -194,19 +189,19 @@ BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::succeededTiming(Tick busy_time) +BaseXBar::Layer<SrcType,DstType>::succeededTiming(Tick busy_time) { // we should have gone from idle or retry to busy in the tryTiming // test assert(state == BUSY); - // occupy the bus accordingly + // occupy the layer accordingly occupyLayer(busy_time); } template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, +BaseXBar::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, Tick busy_time) { // ensure no one got in between and tried to send something to @@ -228,7 +223,7 @@ BaseBus::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::releaseLayer() +BaseXBar::Layer<SrcType,DstType>::releaseLayer() { // releasing the bus means we should now be idle assert(state == BUSY); @@ -244,7 +239,7 @@ BaseBus::Layer<SrcType,DstType>::releaseLayer() if (waitingForPeer == NULL) retryWaiting(); } else if (waitingForPeer == NULL && drainManager) { - DPRINTF(Drain, "Bus done draining, signaling drain manager\n"); + DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n"); //If we weren't able to drain before, do it now. drainManager->signalDrainDone(); // Clear the drain event once we're done with it. @@ -254,7 +249,7 @@ BaseBus::Layer<SrcType,DstType>::releaseLayer() template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::retryWaiting() +BaseXBar::Layer<SrcType,DstType>::retryWaiting() { // this should never be called with no one waiting assert(!waitingForLayer.empty()); @@ -271,24 +266,24 @@ BaseBus::Layer<SrcType,DstType>::retryWaiting() waitingForLayer.pop_front(); // tell the port to retry, which in some cases ends up calling the - // bus + // layer again retryingPort->sendRetry(); - // If the bus is still in the retry state, sendTiming wasn't + // If the layer is still in the retry state, sendTiming wasn't // called in zero time (e.g. the cache does this), burn a cycle if (state == RETRY) { // update the state to busy and reset the retrying port, we // have done our bit and sent the retry state = BUSY; - // occupy the bus layer until the next cycle ends - occupyLayer(bus.clockEdge(Cycles(1))); + // occupy the crossbar layer until the next cycle ends + occupyLayer(xbar.clockEdge(Cycles(1))); } } template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::recvRetry() +BaseXBar::Layer<SrcType,DstType>::recvRetry() { // we should never get a retry without having failed to forward // something to this port @@ -296,13 +291,13 @@ BaseBus::Layer<SrcType,DstType>::recvRetry() // add the port where the failed packet originated to the front of // the waiting ports for the layer, this allows us to call retry - // on the port immediately if the bus layer is idle + // on the port immediately if the crossbar layer is idle waitingForLayer.push_front(waitingForPeer); // we are no longer waiting for the peer waitingForPeer = NULL; - // if the bus layer is idle, retry this port straight away, if we + // if the layer is idle, retry this port straight away, if we // are busy, then simply let the port wait for its turn if (state == IDLE) { retryWaiting(); @@ -312,7 +307,7 @@ BaseBus::Layer<SrcType,DstType>::recvRetry() } PortID -BaseBus::findPort(Addr addr) +BaseXBar::findPort(Addr addr) { // we should never see any address lookups before we've got the // ranges of all connected slave modules @@ -324,7 +319,7 @@ BaseBus::findPort(Addr addr) return dest_id; // Check the address map interval tree - PortMapConstIter i = portMap.find(addr); + auto i = portMap.find(addr); if (i != portMap.end()) { dest_id = i->second; updatePortCache(dest_id, i->first); @@ -334,27 +329,27 @@ BaseBus::findPort(Addr addr) // Check if this matches the default range if (useDefaultRange) { if (defaultRange.contains(addr)) { - DPRINTF(BusAddrRanges, " found addr %#llx on default\n", + DPRINTF(AddrRanges, " found addr %#llx on default\n", addr); return defaultPortID; } } else if (defaultPortID != InvalidPortID) { - DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " + DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, " "will use default port\n", addr); return defaultPortID; } // we should use the range for the default port and it did not // match, or the default port is not set - fatal("Unable to find destination for addr %#llx on bus %s\n", addr, + fatal("Unable to find destination for addr %#llx on %s\n", addr, name()); } -/** Function called by the port when the bus is receiving a range change.*/ +/** Function called by the port when the crossbar is receiving a range change.*/ void -BaseBus::recvRangeChange(PortID master_port_id) +BaseXBar::recvRangeChange(PortID master_port_id) { - DPRINTF(BusAddrRanges, "Received range change from slave port %s\n", + DPRINTF(AddrRanges, "Received range change from slave port %s\n", masterPorts[master_port_id]->getSlavePort().name()); // remember that we got a range from this master port and thus the @@ -371,7 +366,7 @@ BaseBus::recvRangeChange(PortID master_port_id) gotAllAddrRanges &= *r++; } if (gotAllAddrRanges) - DPRINTF(BusAddrRanges, "Got address ranges from all slaves\n"); + DPRINTF(AddrRanges, "Got address ranges from all slaves\n"); } // note that we could get the range from the default port at any @@ -386,7 +381,7 @@ BaseBus::recvRangeChange(PortID master_port_id) AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); if (ranges.size() != 1) - fatal("Bus %s may only have a single default range", + fatal("Crossbar %s may only have a single default range", name()); defaultRange = ranges.front(); @@ -395,7 +390,7 @@ BaseBus::recvRangeChange(PortID master_port_id) // the ports are allowed to update their address ranges // dynamically, so remove any existing entries if (gotAddrRanges[master_port_id]) { - for (PortMapIter p = portMap.begin(); p != portMap.end(); ) { + for (auto p = portMap.begin(); p != portMap.end(); ) { if (p->second == master_port_id) // erasing invalidates the iterator, so advance it // before the deletion takes place @@ -407,11 +402,11 @@ BaseBus::recvRangeChange(PortID master_port_id) AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); - for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r) { - DPRINTF(BusAddrRanges, "Adding range %s for id %d\n", - r->to_string(), master_port_id); - if (portMap.insert(*r, master_port_id) == portMap.end()) { - PortID conflict_id = portMap.find(*r)->second; + for (const auto& r: ranges) { + DPRINTF(AddrRanges, "Adding range %s for id %d\n", + r.to_string(), master_port_id); + if (portMap.insert(r, master_port_id) == portMap.end()) { + PortID conflict_id = portMap.find(r)->second; fatal("%s has two ports with same range:\n\t%s\n\t%s\n", name(), masterPorts[master_port_id]->getSlavePort().name(), @@ -424,52 +419,51 @@ BaseBus::recvRangeChange(PortID master_port_id) // modules, go ahead and tell our connected master modules in // turn, this effectively assumes a tree structure of the system if (gotAllAddrRanges) { - DPRINTF(BusAddrRanges, "Aggregating bus ranges\n"); - busRanges.clear(); + DPRINTF(AddrRanges, "Aggregating address ranges\n"); + xbarRanges.clear(); // start out with the default range if (useDefaultRange) { if (!gotAddrRanges[defaultPortID]) - fatal("Bus %s uses default range, but none provided", + fatal("Crossbar %s uses default range, but none provided", name()); - busRanges.push_back(defaultRange); - DPRINTF(BusAddrRanges, "-- Adding default %s\n", + xbarRanges.push_back(defaultRange); + DPRINTF(AddrRanges, "-- Adding default %s\n", defaultRange.to_string()); } // merge all interleaved ranges and add any range that is not // a subset of the default range std::vector<AddrRange> intlv_ranges; - for (AddrRangeMap<PortID>::const_iterator r = portMap.begin(); - r != portMap.end(); ++r) { + for (const auto& r: portMap) { // if the range is interleaved then save it for now - if (r->first.interleaved()) { + if (r.first.interleaved()) { // if we already got interleaved ranges that are not // part of the same range, then first do a merge // before we add the new one if (!intlv_ranges.empty() && - !intlv_ranges.back().mergesWith(r->first)) { - DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", + !intlv_ranges.back().mergesWith(r.first)) { + DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", intlv_ranges.size()); AddrRange merged_range(intlv_ranges); // next decide if we keep the merged range or not if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { - busRanges.push_back(merged_range); - DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", + xbarRanges.push_back(merged_range); + DPRINTF(AddrRanges, "-- Adding merged range %s\n", merged_range.to_string()); } intlv_ranges.clear(); } - intlv_ranges.push_back(r->first); + intlv_ranges.push_back(r.first); } else { // keep the current range if not a subset of the default if (!(useDefaultRange && - r->first.isSubset(defaultRange))) { - busRanges.push_back(r->first); - DPRINTF(BusAddrRanges, "-- Adding range %s\n", - r->first.to_string()); + r.first.isSubset(defaultRange))) { + xbarRanges.push_back(r.first); + DPRINTF(AddrRanges, "-- Adding range %s\n", + r.first.to_string()); } } } @@ -477,12 +471,12 @@ BaseBus::recvRangeChange(PortID master_port_id) // if there is still interleaved ranges waiting to be merged, // go ahead and do it if (!intlv_ranges.empty()) { - DPRINTF(BusAddrRanges, "-- Merging range from %d ranges\n", + DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", intlv_ranges.size()); AddrRange merged_range(intlv_ranges); if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { - busRanges.push_back(merged_range); - DPRINTF(BusAddrRanges, "-- Adding merged range %s\n", + xbarRanges.push_back(merged_range); + DPRINTF(AddrRanges, "-- Adding merged range %s\n", merged_range.to_string()); } } @@ -492,30 +486,28 @@ BaseBus::recvRangeChange(PortID master_port_id) // as there are no guarantees for when the default range is // update with respect to the other ones if (useDefaultRange) { - for (AddrRangeConstIter r = busRanges.begin(); - r != busRanges.end(); ++r) { + for (const auto& r: xbarRanges) { // see if the new range is partially // overlapping the default range - if (r->intersects(defaultRange) && - !r->isSubset(defaultRange)) + if (r.intersects(defaultRange) && + !r.isSubset(defaultRange)) fatal("Range %s intersects the " \ "default range of %s but is not a " \ - "subset\n", r->to_string(), name()); + "subset\n", r.to_string(), name()); } } // tell all our neighbouring master ports that our address // ranges have changed - for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); - ++s) - (*s)->sendRangeChange(); + for (const auto& s: slavePorts) + s->sendRangeChange(); } clearPortCache(); } AddrRangeList -BaseBus::getAddrRanges() const +BaseXBar::getAddrRanges() const { // we should never be asked without first having sent a range // change, and the latter is only done once we have all the ranges @@ -523,17 +515,17 @@ BaseBus::getAddrRanges() const assert(gotAllAddrRanges); // at the moment, this never happens, as there are no cycles in - // the range queries and no devices on the master side of a bus + // the range queries and no devices on the master side of a crossbar // (CPU, cache, bridge etc) actually care about the ranges of the // ports they are connected to - DPRINTF(BusAddrRanges, "Received address range request\n"); + DPRINTF(AddrRanges, "Received address range request\n"); - return busRanges; + return xbarRanges; } void -BaseBus::regStats() +BaseXBar::regStats() { using namespace Stats; @@ -556,9 +548,9 @@ BaseBus::regStats() .desc("Packet count per connected master and slave (bytes)") .flags(total | nozero | nonan); - totPktSize + pktSize .init(slavePorts.size(), masterPorts.size()) - .name(name() + ".tot_pkt_size") + .name(name() + ".pkt_size") .desc("Cumulative packet size per connected master and slave (bytes)") .flags(total | nozero | nonan); @@ -570,23 +562,23 @@ BaseBus::regStats() // forwarded to the master (responses and snoop requests) for (int i = 0; i < slavePorts.size(); i++) { pktCount.subname(i, slavePorts[i]->getMasterPort().name()); - totPktSize.subname(i, slavePorts[i]->getMasterPort().name()); + pktSize.subname(i, slavePorts[i]->getMasterPort().name()); for (int j = 0; j < masterPorts.size(); j++) { pktCount.ysubname(j, masterPorts[j]->getSlavePort().name()); - totPktSize.ysubname(j, masterPorts[j]->getSlavePort().name()); + pktSize.ysubname(j, masterPorts[j]->getSlavePort().name()); } } } template <typename SrcType, typename DstType> unsigned int -BaseBus::Layer<SrcType,DstType>::drain(DrainManager *dm) +BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm) { //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 //contacted for a retry didn't actually retry. if (state != IDLE) { - DPRINTF(Drain, "Bus not drained\n"); + DPRINTF(Drain, "Crossbar not drained\n"); drainManager = dm; return 1; } @@ -595,7 +587,7 @@ BaseBus::Layer<SrcType,DstType>::drain(DrainManager *dm) template <typename SrcType, typename DstType> void -BaseBus::Layer<SrcType,DstType>::regStats() +BaseXBar::Layer<SrcType,DstType>::regStats() { using namespace Stats; @@ -614,9 +606,9 @@ BaseBus::Layer<SrcType,DstType>::regStats() } /** - * Bus layer template instantiations. Could be removed with _impl.hh + * Crossbar layer template instantiations. Could be removed with _impl.hh * file, but since there are only two given options (MasterPort and * SlavePort) it seems a bit excessive at this point. */ -template class BaseBus::Layer<SlavePort,MasterPort>; -template class BaseBus::Layer<MasterPort,SlavePort>; +template class BaseXBar::Layer<SlavePort,MasterPort>; +template class BaseXBar::Layer<MasterPort,SlavePort>; diff --git a/src/mem/bus.hh b/src/mem/xbar.hh index f01a3ae7f..7f3c17677 100644 --- a/src/mem/bus.hh +++ b/src/mem/xbar.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 ARM Limited + * Copyright (c) 2011-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -45,53 +45,47 @@ /** * @file - * Declaration of an abstract bus base class. + * Declaration of an abstract crossbar base class. */ -#ifndef __MEM_BUS_HH__ -#define __MEM_BUS_HH__ +#ifndef __MEM_XBAR_HH__ +#define __MEM_XBAR_HH__ #include <deque> #include "base/addr_range_map.hh" #include "base/types.hh" #include "mem/mem_object.hh" -#include "params/BaseBus.hh" +#include "params/BaseXBar.hh" #include "sim/stats.hh" /** - * 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 base crossbar contains the common elements of the non-coherent + * and coherent crossbar. 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 + * The BaseXBar is responsible for the basic flow control (busy or * not), the administration of retries, and the address decoding. */ -class BaseBus : public MemObject +class BaseXBar : public MemObject { protected: /** - * A bus layer is an internal bus structure with its own flow - * control and arbitration. Hence, a single-layer bus mimics a - * traditional off-chip tri-state bus (like PCI), where only one - * set of wires are shared. For on-chip buses, a good starting - * point is to have three layers, for requests, responses, and - * snoop responses respectively (snoop requests are instantaneous - * and do not need any flow control or arbitration). This case is - * similar to AHB and some OCP configurations. - * - * As a further extensions beyond the three-layer bus, a future - * multi-layer bus has with one layer per connected slave port - * provides a full or partial crossbar, like AXI, OCP, PCIe etc. + * A layer is an internal crossbar arbitration point with its own + * flow control. Each layer is a converging multiplexer tree. By + * instantiating one layer per destination port (and per packet + * type, i.e. request, response, snoop request and snoop + * response), we model full crossbar structures like AXI, ACE, + * PCIe, etc. * * The template parameter, PortClass, indicates the destination - * port type for the bus. The retry list holds either master ports - * or slave ports, depending on the direction of the layer. Thus, - * a request layer has a retry list containing slave ports, - * whereas a response layer holds master ports. + * port type for the layer. The retry list holds either master + * ports or slave ports, depending on the direction of the + * layer. Thus, a request layer has a retry list containing slave + * ports, whereas a response layer holds master ports. */ template <typename SrcType, typename DstType> class Layer : public Drainable @@ -100,17 +94,17 @@ class BaseBus : public MemObject public: /** - * Create a bus layer and give it a name. The bus layer uses - * the bus an event manager. + * Create a layer and give it a name. The layer uses + * the crossbar an event manager. * * @param _port destination port the layer converges at - * @param _bus the bus this layer belongs to + * @param _xbar the crossbar this layer belongs to * @param _name the layer's name */ - Layer(DstType& _port, BaseBus& _bus, const std::string& _name); + Layer(DstType& _port, BaseXBar& _xbar, const std::string& _name); /** - * Drain according to the normal semantics, so that the bus + * Drain according to the normal semantics, so that the crossbar * can tell the layer to drain, and pass an event to signal * back when drained. * @@ -121,27 +115,27 @@ class BaseBus : public MemObject unsigned int drain(DrainManager *dm); /** - * Get the bus layer's name + * Get the crossbar layer's name */ - const std::string name() const { return bus.name() + _name; } + const std::string name() const { return xbar.name() + _name; } /** - * Determine if the bus layer accepts a packet from a specific + * Determine if the layer accepts a packet from a specific * port. If not, the port in question is also added to the * retry list. In either case the state of the layer is * updated accordingly. * * @param port Source port presenting the packet * - * @return True if the bus layer accepts the packet + * @return True if the layer accepts the packet */ bool tryTiming(SrcType* src_port); /** * Deal with a destination port accepting a packet by potentially * removing the source port from the retry list (if retrying) and - * occupying the bus layer accordingly. + * occupying the layer accordingly. * * @param busy_time Time to spend as a result of a successful send */ @@ -150,7 +144,7 @@ class BaseBus : public MemObject /** * Deal with a destination port not accepting a packet by * potentially adding the source port to the retry list (if - * not already at the front) and occupying the bus layer + * not already at the front) and occupying the layer * accordingly. * * @param src_port Source port @@ -158,7 +152,7 @@ class BaseBus : public MemObject */ void failedTiming(SrcType* src_port, Tick busy_time); - /** Occupy the bus layer until until */ + /** Occupy the layer until until */ void occupyLayer(Tick until); /** @@ -184,31 +178,31 @@ class BaseBus : public MemObject /** The destination port this layer converges at. */ DstType& port; - /** The bus this layer is a part of. */ - BaseBus& bus; + /** The crossbar this layer is a part of. */ + BaseXBar& xbar; /** A name for this layer. */ std::string _name; /** - * We declare an enum to track the state of the bus layer. The - * starting point is an idle state where the bus layer is - * waiting for a packet to arrive. Upon arrival, the bus layer + * We declare an enum to track the state of the layer. The + * starting point is an idle state where the layer is waiting + * for a packet to arrive. Upon arrival, the layer * transitions to the busy state, where it remains either * until the packet transfer is done, or the header time is - * spent. Once the bus layer leaves the busy state, it can + * spent. Once the layer leaves the busy state, it can * either go back to idle, if no packets have arrived while it - * was busy, or the bus layer goes on to retry the first port + * was busy, or the layer goes on to retry the first port * in waitingForLayer. A similar transition takes place from - * idle to retry if the bus layer receives a retry from one of + * idle to retry if the layer receives a retry from one of * its connected ports. The retry state lasts until the port * in questions calls sendTiming and returns control to the - * bus layer, or goes to a busy state if the port does not + * layer, or goes to a busy state if the port does not * immediately react to the retry by calling sendTiming. */ enum State { IDLE, BUSY, RETRY }; - /** track the state of the bus layer */ + /** track the state of the layer */ State state; /** manager to signal when drained */ @@ -227,7 +221,7 @@ class BaseBus : public MemObject SrcType* waitingForPeer; /** - * Release the bus layer after being occupied and return to an + * Release the layer after being occupied and return to an * idle state where we proceed to send a retry to any * potential waiting port, or drain if asked to do so. */ @@ -238,7 +232,7 @@ class BaseBus : public MemObject /** * Stats for occupancy and utilization. These stats capture - * the time the bus spends in the busy state and are thus only + * the time the layer spends in the busy state and are thus only * relevant when the memory system is in timing mode. */ Stats::Scalar occupancy; @@ -248,27 +242,27 @@ class BaseBus : public MemObject /** cycles of overhead per transaction */ const Cycles headerCycles; - /** the width of the bus in bytes */ + /** the width of the xbar in bytes */ const uint32_t width; - typedef AddrRangeMap<PortID>::iterator PortMapIter; - typedef AddrRangeMap<PortID>::const_iterator PortMapConstIter; AddrRangeMap<PortID> portMap; - /** all contigous ranges seen by this bus */ - AddrRangeList busRanges; + /** all contigous ranges seen by this crossbar */ + AddrRangeList xbarRanges; AddrRange defaultRange; /** - * Function called by the port when the bus is recieving a range change. + * Function called by the port when the crossbar is recieving a + * range change. * * @param master_port_id id of the port that received the change */ void recvRangeChange(PortID master_port_id); - /** Find which port connected to this bus (if any) should be given a packet - * with this address. + /** Find which port connected to this crossbar (if any) should be + * given a packet with this address. + * * @param addr Address to find port for. * @return id of port that the packet should be sent out of. */ @@ -322,7 +316,7 @@ class BaseBus : public MemObject } /** - * Return the address ranges the bus is responsible for. + * Return the address ranges the crossbar is responsible for. * * @return a list of non-overlapping address ranges */ @@ -330,31 +324,25 @@ class BaseBus : public MemObject /** * Calculate the timing parameters for the packet. Updates the - * busFirstWordDelay and busLastWordDelay fields of the packet + * firstWordDelay and lastWordDelay fields of the packet * object with the relative number of ticks required to transmit * the header and the first word, and the last word, respectively. */ void calcPacketTiming(PacketPtr pkt); /** - * Remember for each of the master ports of the bus if we got an - * address range from the connected slave. For convenience, also - * keep track of if we got ranges from all the slave modules or - * not. + * Remember for each of the master ports of the crossbar if we got + * an address range from the connected slave. For convenience, + * also keep track of if we got ranges from all the slave modules + * or not. */ std::vector<bool> gotAddrRanges; bool gotAllAddrRanges; - /** The master and slave ports of the bus */ + /** The master and slave ports of the crossbar */ std::vector<SlavePort*> slavePorts; std::vector<MasterPort*> masterPorts; - /** Convenience typedefs. */ - typedef std::vector<SlavePort*>::iterator SlavePortIter; - typedef std::vector<MasterPort*>::iterator MasterPortIter; - typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter; - typedef std::vector<MasterPort*>::const_iterator MasterPortConstIter; - /** Port that handles requests that don't match any of the interfaces.*/ PortID defaultPortID; @@ -364,29 +352,28 @@ class BaseBus : public MemObject addresses not handled by another port to default device. */ const bool useDefaultRange; - BaseBus(const BaseBusParams *p); + BaseXBar(const BaseXBarParams *p); - virtual ~BaseBus(); + virtual ~BaseXBar(); /** * Stats for transaction distribution and data passing through the - * bus. The transaction distribution is globally counting + * crossbar. The transaction distribution is globally counting * different types of commands. The packet count and total packet - * size are two-dimensional vectors that are indexed by the bus + * size are two-dimensional vectors that are indexed by the * slave port and master port id (thus the neighbouring master and * neighbouring slave), summing up both directions (request and * response). */ - Stats::Formula throughput; Stats::Vector transDist; Stats::Vector2d pktCount; - Stats::Vector2d totPktSize; + Stats::Vector2d pktSize; public: virtual void init(); - /** A function used to return the port associated with this bus object. */ + /** A function used to return the port associated with this object. */ BaseMasterPort& getMasterPort(const std::string& if_name, PortID idx = InvalidPortID); BaseSlavePort& getSlavePort(const std::string& if_name, @@ -398,4 +385,4 @@ class BaseBus : public MemObject }; -#endif //__MEM_BUS_HH__ +#endif //__MEM_XBAR_HH__ diff --git a/src/python/m5/params.py b/src/python/m5/params.py index cf5764530..6c4a61d6a 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -1870,7 +1870,7 @@ class SlavePort(Port): raise TypeError, 'wrong number of arguments' # VectorPort description object. Like Port, but represents a vector -# of connections (e.g., as on a Bus). +# of connections (e.g., as on a XBar). class VectorPort(Port): def __init__(self, *args): self.isVec = True diff --git a/src/python/m5/util/dot_writer.py b/src/python/m5/util/dot_writer.py index ab4687f7f..f54d6a1ab 100644 --- a/src/python/m5/util/dot_writer.py +++ b/src/python/m5/util/dot_writer.py @@ -173,7 +173,7 @@ def dot_create_node(simNode, full_path, label): class NodeType: SYS = 0 CPU = 1 - BUS = 2 + XBAR = 2 MEM = 3 DEV = 4 OTHER = 5 @@ -190,8 +190,8 @@ def get_node_type(simNode): elif 'PioDevice' in dir(m5.objects) and \ isinstance(simNode, m5.objects.PioDevice): return NodeType.DEV - elif isinstance(simNode, m5.objects.BaseBus): - return NodeType.BUS + elif isinstance(simNode, m5.objects.BaseXBar): + return NodeType.XBAR elif isinstance(simNode, m5.objects.AbstractMemory): return NodeType.MEM else: @@ -205,7 +205,7 @@ def get_type_colour(nodeType): return (228, 231, 235) elif nodeType == NodeType.CPU: return (187, 198, 217) - elif nodeType == NodeType.BUS: + elif nodeType == NodeType.XBAR: return (111, 121, 140) elif nodeType == NodeType.MEM: return (94, 89, 88) |