First pass at snooping stuff that compiles and doesn't break.
Still need: -Handle NACK's on the recieve side -Distinguish top level caches -Handle repsonses from caches failing the fast path -Handle BusError and propogate it -Fix the invalidate packet associated with snooping in the cache src/mem/bus.cc: Make sure to snoop on functional accesses src/mem/cache/base_cache.cc: Wait to make a request into a response until it is ready to be issued src/mem/cache/base_cache.hh: Support range changes for snoops Set up snoop responses for cache->cache transfers src/mem/cache/cache_impl.hh: Only access the cache if it wasn't satisfied by cache->cache transfer Handle snoop phases (detect block, then snoop) Fix functional access to work properly (still need to fix snoop path for functional accesses) --HG-- extra : convert_revision : 4c25f11d7a996c1f56f4f7b55dde87a344e5fdf8
This commit is contained in:
parent
868d112578
commit
45f881a4ce
6 changed files with 237 additions and 20 deletions
|
@ -252,6 +252,7 @@ Bus::recvFunctional(Packet *pkt)
|
|||
DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
|
||||
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
|
||||
assert(pkt->getDest() == Packet::Broadcast);
|
||||
atomicSnoop(pkt);
|
||||
findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
|
||||
}
|
||||
|
||||
|
|
4
src/mem/cache/base_cache.cc
vendored
4
src/mem/cache/base_cache.cc
vendored
|
@ -199,7 +199,9 @@ BaseCache::CacheEvent::process()
|
|||
return;
|
||||
}
|
||||
//Response
|
||||
//Know the packet to send, no need to mark in service (must succed)
|
||||
//Know the packet to send
|
||||
pkt->result = Packet::Success;
|
||||
pkt->makeTimingResponse();
|
||||
assert(cachePort->sendTiming(pkt));
|
||||
}
|
||||
|
||||
|
|
42
src/mem/cache/base_cache.hh
vendored
42
src/mem/cache/base_cache.hh
vendored
|
@ -127,6 +127,8 @@ class BaseCache : public MemObject
|
|||
CachePort *cpuSidePort;
|
||||
CachePort *memSidePort;
|
||||
|
||||
bool snoopRangesSent;
|
||||
|
||||
public:
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
|
@ -149,17 +151,22 @@ class BaseCache : public MemObject
|
|||
|
||||
void recvStatusChange(Port::Status status, bool isCpuSide)
|
||||
{
|
||||
if (status == Port::RangeChange)
|
||||
{
|
||||
if (!isCpuSide)
|
||||
{
|
||||
if (status == Port::RangeChange){
|
||||
if (!isCpuSide) {
|
||||
cpuSidePort->sendStatusChange(Port::RangeChange);
|
||||
if (topLevelCache && !snoopRangesSent) {
|
||||
snoopRangesSent = true;
|
||||
memSidePort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
memSidePort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
}
|
||||
else if (status == Port::SnoopSquash) {
|
||||
assert(snoopPhase2);
|
||||
snoopPhase2 = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Packet *getPacket()
|
||||
|
@ -205,6 +212,10 @@ class BaseCache : public MemObject
|
|||
/** True if this cache is connected to the CPU. */
|
||||
bool topLevelCache;
|
||||
|
||||
|
||||
/** True if we are now in phase 2 of the snoop process. */
|
||||
bool snoopPhase2;
|
||||
|
||||
/** Stores time the cache blocked for statistics. */
|
||||
Tick blockedCycle;
|
||||
|
||||
|
@ -332,6 +343,7 @@ class BaseCache : public MemObject
|
|||
//Start ports at null if more than one is created we should panic
|
||||
cpuSidePort = NULL;
|
||||
memSidePort = NULL;
|
||||
snoopRangesSent = false;
|
||||
}
|
||||
|
||||
virtual void init();
|
||||
|
@ -519,8 +531,6 @@ class BaseCache : public MemObject
|
|||
if (!pkt->req->isUncacheable()) {
|
||||
missLatency[pkt->cmdToIndex()][pkt->req->getThreadNum()] += time - pkt->time;
|
||||
}
|
||||
pkt->makeTimingResponse();
|
||||
pkt->result = Packet::Success;
|
||||
CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
|
||||
reqCpu->schedule(time);
|
||||
}
|
||||
|
@ -529,10 +539,12 @@ class BaseCache : public MemObject
|
|||
* Suppliess the data if cache to cache transfers are enabled.
|
||||
* @param pkt The bus transaction to fulfill.
|
||||
*/
|
||||
void respondToSnoop(Packet *pkt)
|
||||
void respondToSnoop(Packet *pkt, Tick time)
|
||||
{
|
||||
assert("Implement\n" && 0);
|
||||
// assert("Implement\n" && 0);
|
||||
// mi->respond(pkt,curTick + hitLatency);
|
||||
CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
|
||||
reqMem->schedule(time);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,6 +563,16 @@ class BaseCache : public MemObject
|
|||
else
|
||||
{
|
||||
//This is where snoops get updated
|
||||
AddrRangeList dummy;
|
||||
if (!topLevelCache)
|
||||
{
|
||||
cpuSidePort->getPeerAddressRanges(dummy, snoop);
|
||||
}
|
||||
else
|
||||
{
|
||||
snoop.push_back(RangeSize(0,-1));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
34
src/mem/cache/cache_impl.hh
vendored
34
src/mem/cache/cache_impl.hh
vendored
|
@ -63,14 +63,26 @@ doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
|
|||
if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
|
||||
pkt->req->setScResult(1);
|
||||
}
|
||||
access(pkt);
|
||||
if (!(pkt->flags & SATISFIED)) {
|
||||
access(pkt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pkt->isResponse())
|
||||
handleResponse(pkt);
|
||||
else
|
||||
snoop(pkt);
|
||||
else {
|
||||
//Check if we are in phase1
|
||||
if (!snoopPhase2) {
|
||||
snoopPhase2 = true;
|
||||
}
|
||||
else {
|
||||
//Check if we should do the snoop
|
||||
if (pkt->flags && SNOOP_COMMIT)
|
||||
snoop(pkt);
|
||||
snoopPhase2 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -117,7 +129,7 @@ doFunctionalAccess(Packet *pkt, bool isCpuSide)
|
|||
assert("Can't handle LL/SC on functional path\n");
|
||||
}
|
||||
|
||||
probe(pkt, true);
|
||||
probe(pkt, false);
|
||||
//TEMP ALWAYS SUCCESFUL FOR NOW
|
||||
pkt->result = Packet::Success;
|
||||
}
|
||||
|
@ -126,7 +138,7 @@ doFunctionalAccess(Packet *pkt, bool isCpuSide)
|
|||
if (pkt->isResponse())
|
||||
handleResponse(pkt);
|
||||
else
|
||||
snoopProbe(pkt, true);
|
||||
snoopProbe(pkt, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,7 +384,7 @@ template<class TagStore, class Buffering, class Coherence>
|
|||
void
|
||||
Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
||||
{
|
||||
|
||||
DPRINTF(Cache, "SNOOPING");
|
||||
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
||||
BlkType *blk = tags->findBlock(pkt);
|
||||
MSHR *mshr = missQueue->findMSHR(blk_addr);
|
||||
|
@ -385,7 +397,10 @@ Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
|||
//If the outstanding request was an invalidate (upgrade,readex,..)
|
||||
//Then we need to ACK the request until we get the data
|
||||
//Also NACK if the outstanding request is not a cachefill (writeback)
|
||||
pkt->flags |= SATISFIED;
|
||||
pkt->flags |= NACKED_LINE;
|
||||
assert("Don't detect these on the other side yet\n");
|
||||
respondToSnoop(pkt, curTick + hitLatency);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
@ -398,6 +413,7 @@ Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
|||
//@todo Make it so that a read to a pending read can't be exclusive now.
|
||||
|
||||
//Set the address so find match works
|
||||
assert("Don't have invalidates yet\n");
|
||||
invalidatePkt->addrOverride(pkt->getAddr());
|
||||
|
||||
//Append the invalidate on
|
||||
|
@ -433,7 +449,7 @@ Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
|||
assert(offset + pkt->getSize() <=blkSize);
|
||||
memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
|
||||
|
||||
respondToSnoop(pkt);
|
||||
respondToSnoop(pkt, curTick + hitLatency);
|
||||
}
|
||||
|
||||
if (pkt->isInvalidate()) {
|
||||
|
@ -449,7 +465,7 @@ Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
|||
bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
|
||||
if (satisfy) {
|
||||
tags->handleSnoop(blk, new_state, pkt);
|
||||
respondToSnoop(pkt);
|
||||
respondToSnoop(pkt, curTick + hitLatency);
|
||||
return;
|
||||
}
|
||||
tags->handleSnoop(blk, new_state);
|
||||
|
@ -517,7 +533,7 @@ Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update)
|
|||
missQueue->findWrites(blk_addr, writes);
|
||||
|
||||
if (!update) {
|
||||
memSidePort->sendFunctional(pkt);
|
||||
memSidePort->sendFunctional(pkt);
|
||||
// Check for data in MSHR and writebuffer.
|
||||
if (mshr) {
|
||||
warn("Found outstanding miss on an non-update probe");
|
||||
|
|
90
tests/configs/o3-timing-mp.py
Normal file
90
tests/configs/o3-timing-mp.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Copyright (c) 2006 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Ron Dreslinski
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
m5.AddToPath('../configs/common')
|
||||
from FullO3Config import *
|
||||
|
||||
# --------------------
|
||||
# Base L1 Cache
|
||||
# ====================
|
||||
|
||||
class L1(BaseCache):
|
||||
latency = 1
|
||||
block_size = 64
|
||||
mshrs = 4
|
||||
tgts_per_mshr = 8
|
||||
protocol = CoherenceProtocol(protocol='moesi')
|
||||
|
||||
# ----------------------
|
||||
# Base L2 Cache
|
||||
# ----------------------
|
||||
|
||||
class L2(BaseCache):
|
||||
block_size = 64
|
||||
latency = 100
|
||||
mshrs = 92
|
||||
tgts_per_mshr = 16
|
||||
write_buffers = 8
|
||||
|
||||
nb_cores = 4
|
||||
cpus = [ DetailedO3CPU() for i in xrange(nb_cores) ]
|
||||
|
||||
# system simulated
|
||||
system = System(cpu = cpus, physmem = PhysicalMemory(), membus =
|
||||
Bus())
|
||||
|
||||
# l2cache & bus
|
||||
system.toL2Bus = Bus()
|
||||
system.l2c = L2(size='4MB', assoc=8)
|
||||
system.l2c.cpu_side = system.toL2Bus.port
|
||||
|
||||
# connect l2c to membus
|
||||
system.l2c.mem_side = system.membus.port
|
||||
|
||||
# add L1 caches
|
||||
for cpu in cpus:
|
||||
cpu.addPrivateSplitL1Caches(L1(size = '32kB', assoc = 1),
|
||||
L1(size = '32kB', assoc = 4))
|
||||
cpu.mem = cpu.dcache
|
||||
# connect cpu level-1 caches to shared level-2 cache
|
||||
cpu.connectMemPorts(system.toL2Bus)
|
||||
|
||||
# connect memory to membus
|
||||
system.physmem.port = system.membus.port
|
||||
|
||||
|
||||
# -----------------------
|
||||
# run simulation
|
||||
# -----------------------
|
||||
|
||||
root = Root( system = system )
|
||||
root.system.mem_mode = 'timing'
|
||||
root.trace.flags="Bus Cache"
|
||||
#root.trace.flags = "BusAddrRanges"
|
86
tests/configs/simple-atomic-mp.py
Normal file
86
tests/configs/simple-atomic-mp.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Copyright (c) 2006 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Ron Dreslinski
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
|
||||
# --------------------
|
||||
# Base L1 Cache
|
||||
# ====================
|
||||
|
||||
class L1(BaseCache):
|
||||
latency = 1
|
||||
block_size = 64
|
||||
mshrs = 4
|
||||
tgts_per_mshr = 8
|
||||
protocol = CoherenceProtocol(protocol='moesi')
|
||||
|
||||
# ----------------------
|
||||
# Base L2 Cache
|
||||
# ----------------------
|
||||
|
||||
class L2(BaseCache):
|
||||
block_size = 64
|
||||
latency = 100
|
||||
mshrs = 92
|
||||
tgts_per_mshr = 16
|
||||
write_buffers = 8
|
||||
|
||||
nb_cores = 4
|
||||
cpus = [ AtomicSimpleCPU() for i in xrange(nb_cores) ]
|
||||
|
||||
# system simulated
|
||||
system = System(cpu = cpus, physmem = PhysicalMemory(), membus =
|
||||
Bus())
|
||||
|
||||
# l2cache & bus
|
||||
system.toL2Bus = Bus()
|
||||
system.l2c = L2(size='4MB', assoc=8)
|
||||
system.l2c.cpu_side = system.toL2Bus.port
|
||||
|
||||
# connect l2c to membus
|
||||
system.l2c.mem_side = system.membus.port
|
||||
|
||||
# add L1 caches
|
||||
for cpu in cpus:
|
||||
cpu.addPrivateSplitL1Caches(L1(size = '32kB', assoc = 1),
|
||||
L1(size = '32kB', assoc = 4))
|
||||
cpu.mem = cpu.dcache
|
||||
# connect cpu level-1 caches to shared level-2 cache
|
||||
cpu.connectMemPorts(system.toL2Bus)
|
||||
|
||||
# connect memory to membus
|
||||
system.physmem.port = system.membus.port
|
||||
|
||||
|
||||
# -----------------------
|
||||
# run simulation
|
||||
# -----------------------
|
||||
|
||||
root = Root( system = system )
|
||||
root.system.mem_mode = 'atomic'
|
Loading…
Reference in a new issue