summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/example/memtest.py100
-rw-r--r--src/base/traceflags.py1
-rw-r--r--src/cpu/memtest/memtest.cc156
-rw-r--r--src/cpu/memtest/memtest.hh16
-rw-r--r--src/mem/bridge.cc17
-rw-r--r--src/mem/bus.cc122
-rw-r--r--src/mem/bus.hh3
-rw-r--r--src/mem/cache/base_cache.cc577
-rw-r--r--src/mem/cache/base_cache.hh641
-rw-r--r--src/mem/cache/cache.cc9
-rw-r--r--src/mem/cache/cache.hh275
-rw-r--r--src/mem/cache/cache_blk.hh25
-rw-r--r--src/mem/cache/cache_builder.cc33
-rw-r--r--src/mem/cache/cache_impl.hh1857
-rw-r--r--src/mem/cache/coherence/SConscript1
-rw-r--r--src/mem/cache/coherence/coherence_protocol.cc46
-rw-r--r--src/mem/cache/coherence/coherence_protocol.hh4
-rw-r--r--src/mem/cache/coherence/simple_coherence.hh21
-rw-r--r--src/mem/cache/coherence/uni_coherence.cc135
-rw-r--r--src/mem/cache/coherence/uni_coherence.hh146
-rw-r--r--src/mem/cache/miss/SConscript3
-rw-r--r--src/mem/cache/miss/blocking_buffer.cc245
-rw-r--r--src/mem/cache/miss/blocking_buffer.hh209
-rw-r--r--src/mem/cache/miss/miss_buffer.cc62
-rw-r--r--src/mem/cache/miss/miss_buffer.hh223
-rw-r--r--src/mem/cache/miss/miss_queue.cc752
-rw-r--r--src/mem/cache/miss/miss_queue.hh327
-rw-r--r--src/mem/cache/miss/mshr.cc78
-rw-r--r--src/mem/cache/miss/mshr.hh95
-rw-r--r--src/mem/cache/miss/mshr_queue.cc98
-rw-r--r--src/mem/cache/miss/mshr_queue.hh140
-rw-r--r--src/mem/cache/prefetch/base_prefetcher.cc9
-rw-r--r--src/mem/cache/tags/fa_lru.cc5
-rw-r--r--src/mem/cache/tags/fa_lru.hh7
-rw-r--r--src/mem/cache/tags/iic.cc32
-rw-r--r--src/mem/cache/tags/iic.hh27
-rw-r--r--src/mem/cache/tags/lru.cc5
-rw-r--r--src/mem/cache/tags/lru.hh15
-rw-r--r--src/mem/cache/tags/split.cc25
-rw-r--r--src/mem/cache/tags/split.hh7
-rw-r--r--src/mem/cache/tags/split_lifo.cc7
-rw-r--r--src/mem/cache/tags/split_lifo.hh15
-rw-r--r--src/mem/cache/tags/split_lru.cc5
-rw-r--r--src/mem/cache/tags/split_lru.hh15
-rw-r--r--src/mem/packet.cc110
-rw-r--r--src/mem/packet.hh199
-rw-r--r--src/mem/physical.cc208
-rw-r--r--src/mem/physical.hh12
-rw-r--r--src/mem/tport.cc13
49 files changed, 2258 insertions, 4875 deletions
diff --git a/configs/example/memtest.py b/configs/example/memtest.py
index c28ffab10..0bc12e7bd 100644
--- a/configs/example/memtest.py
+++ b/configs/example/memtest.py
@@ -33,14 +33,37 @@ m5.AddToPath('../common')
parser = optparse.OptionParser()
-parser.add_option("--caches", action="store_true")
-parser.add_option("-t", "--timing", action="store_true")
-parser.add_option("-m", "--maxtick", type="int")
-parser.add_option("-l", "--maxloads", default = "1000000000000", type="int")
-parser.add_option("-n", "--numtesters", default = "8", type="int")
-parser.add_option("-p", "--protocol",
- default="moesi",
- help="The coherence protocol to use for the L1'a (i.e. MOESI, MOSI)")
+parser.add_option("-c", "--cache-levels", type="int", default=2,
+ metavar="LEVELS",
+ help="Number of cache levels [default: %default]")
+parser.add_option("-a", "--atomic", action="store_true",
+ help="Use atomic (non-timing) mode")
+parser.add_option("-b", "--blocking", action="store_true",
+ help="Use blocking caches")
+parser.add_option("-l", "--maxloads", default="1G", metavar="N",
+ help="Stop after N loads [default: %default]")
+parser.add_option("-m", "--maxtick", type="int", default=m5.MaxTick,
+ metavar="T",
+ help="Stop after T ticks")
+parser.add_option("-n", "--numtesters", type="int", default=8,
+ metavar="N",
+ help="Number of tester pseudo-CPUs [default: %default]")
+parser.add_option("-p", "--protocol", default="moesi",
+ help="Coherence protocol [default: %default]")
+
+parser.add_option("-f", "--functional", type="int", default=0,
+ metavar="PCT",
+ help="Target percentage of functional accesses "
+ "[default: %default]")
+parser.add_option("-u", "--uncacheable", type="int", default=0,
+ metavar="PCT",
+ help="Target percentage of uncacheable accesses "
+ "[default: %default]")
+
+parser.add_option("--progress", type="int", default=1000,
+ metavar="NLOADS",
+ help="Progress message interval "
+ "[default: %default]")
(options, args) = parser.parse_args()
@@ -48,14 +71,29 @@ if args:
print "Error: script doesn't take any positional arguments"
sys.exit(1)
+# Should generalize this someday... would be cool to have a loop that
+# just iterates, adding a level of caching each time.
+#if options.cache_levels != 2 and options.cache_levels != 0:
+# print "Error: number of cache levels must be 0 or 2"
+# sys.exit(1)
+
+if options.blocking:
+ num_l1_mshrs = 1
+ num_l2_mshrs = 1
+else:
+ num_l1_mshrs = 12
+ num_l2_mshrs = 92
+
+block_size = 64
+
# --------------------
# Base L1 Cache
# ====================
class L1(BaseCache):
latency = '1ns'
- block_size = 64
- mshrs = 12
+ block_size = block_size
+ mshrs = num_l1_mshrs
tgts_per_mshr = 8
protocol = CoherenceProtocol(protocol=options.protocol)
@@ -64,28 +102,31 @@ class L1(BaseCache):
# ----------------------
class L2(BaseCache):
- block_size = 64
+ block_size = block_size
latency = '10ns'
- mshrs = 92
+ mshrs = num_l2_mshrs
tgts_per_mshr = 16
write_buffers = 8
+ protocol = CoherenceProtocol(protocol=options.protocol)
-#MAX CORES IS 8 with the false sharing method
-if options.numtesters > 8:
- print "Error: NUmber of testers limited to 8 because of false sharing"
- sys,exit(1)
+if options.numtesters > block_size:
+ print "Error: Number of testers limited to %s because of false sharing" \
+ % (block_size)
+ sys.exit(1)
-cpus = [ MemTest(atomic=not options.timing, max_loads=options.maxloads,
- percent_functional=50, percent_uncacheable=10,
- progress_interval=1000)
+cpus = [ MemTest(atomic=options.atomic, max_loads=options.maxloads,
+ percent_functional=options.functional,
+ percent_uncacheable=options.uncacheable,
+ progress_interval=options.progress)
for i in xrange(options.numtesters) ]
# system simulated
system = System(cpu = cpus, funcmem = PhysicalMemory(),
- physmem = PhysicalMemory(latency = "50ns"), membus = Bus(clock="500MHz", width=16))
+ physmem = PhysicalMemory(latency = "100ns"),
+ membus = Bus(clock="500MHz", width=16))
# l2cache & bus
-if options.caches:
+if options.cache_levels == 2:
system.toL2Bus = Bus(clock="500MHz", width=16)
system.l2c = L2(size='64kB', assoc=8)
system.l2c.cpu_side = system.toL2Bus.port
@@ -95,10 +136,14 @@ if options.caches:
# add L1 caches
for cpu in cpus:
- if options.caches:
+ if options.cache_levels == 2:
cpu.l1c = L1(size = '32kB', assoc = 4)
cpu.test = cpu.l1c.cpu_side
cpu.l1c.mem_side = system.toL2Bus.port
+ elif options.cache_levels == 1:
+ cpu.l1c = L1(size = '32kB', assoc = 4)
+ cpu.test = cpu.l1c.cpu_side
+ cpu.l1c.mem_side = system.membus.port
else:
cpu.test = system.membus.port
system.funcmem.port = cpu.functional
@@ -112,10 +157,10 @@ system.physmem.port = system.membus.port
# -----------------------
root = Root( system = system )
-if options.timing:
- root.system.mem_mode = 'timing'
-else:
+if options.atomic:
root.system.mem_mode = 'atomic'
+else:
+ root.system.mem_mode = 'timing'
# Not much point in this being higher than the L1 latency
m5.ticks.setGlobalFrequency('1ns')
@@ -124,9 +169,6 @@ m5.ticks.setGlobalFrequency('1ns')
m5.instantiate(root)
# simulate until program terminates
-if options.maxtick:
- exit_event = m5.simulate(options.maxtick)
-else:
- exit_event = m5.simulate(10000000000000)
+exit_event = m5.simulate(options.maxtick)
print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
diff --git a/src/base/traceflags.py b/src/base/traceflags.py
index 6b241c410..f4cf7dfd7 100644
--- a/src/base/traceflags.py
+++ b/src/base/traceflags.py
@@ -128,6 +128,7 @@ baseFlags = [
'Mbox',
'MemDepUnit',
'MemoryAccess',
+ 'MemTest',
'O3CPU',
'OzoneCPU',
'OzoneLSQ',
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
index 15774904a..6e8c5d0bf 100644
--- a/src/cpu/memtest/memtest.cc
+++ b/src/cpu/memtest/memtest.cc
@@ -102,7 +102,6 @@ void
MemTest::sendPkt(PacketPtr pkt) {
if (atomic) {
cachePort.sendAtomic(pkt);
- pkt->makeAtomicResponse();
completeRequest(pkt);
}
else if (!cachePort.sendTiming(pkt)) {
@@ -165,8 +164,6 @@ MemTest::MemTest(const string &name,
tickEvent.schedule(0);
id = TESTER_ALLOCATOR++;
- if (TESTER_ALLOCATOR > 8)
- panic("False sharing memtester only allows up to 8 testers");
accessRetry = false;
}
@@ -194,29 +191,25 @@ MemTest::init()
// memory should be 0; no need to initialize them.
}
-static void
-printData(ostream &os, uint8_t *data, int nbytes)
-{
- os << hex << setfill('0');
- // assume little-endian: print bytes from highest address to lowest
- for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) {
- os << setw(2) << (unsigned)*dp;
- }
- os << dec;
-}
void
MemTest::completeRequest(PacketPtr pkt)
{
+ Request *req = pkt->req;
+
+ DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",
+ pkt->isWrite() ? "write" : "read",
+ req->getPaddr(), blockAddr(req->getPaddr()));
+
MemTestSenderState *state =
dynamic_cast<MemTestSenderState *>(pkt->senderState);
uint8_t *data = state->data;
uint8_t *pkt_data = pkt->getPtr<uint8_t>();
- Request *req = pkt->req;
//Remove the address from the list of outstanding
- std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->getPaddr());
+ std::set<unsigned>::iterator removeAddr =
+ outstandingAddrs.find(req->getPaddr());
assert(removeAddr != outstandingAddrs.end());
outstandingAddrs.erase(removeAddr);
@@ -224,15 +217,10 @@ MemTest::completeRequest(PacketPtr pkt)
case MemCmd::ReadResp:
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
- cerr << name() << ": on read of 0x" << hex << req->getPaddr()
- << " (0x" << hex << blockAddr(req->getPaddr()) << ")"
- << "@ cycle " << dec << curTick
- << ", cache returns 0x";
- printData(cerr, pkt_data, pkt->getSize());
- cerr << ", expected 0x";
- printData(cerr, data, pkt->getSize());
- cerr << endl;
- fatal("");
+ panic("%s: read of %x (blk %x) @ cycle %d "
+ "returns %x, expected %x\n", name(),
+ req->getPaddr(), blockAddr(req->getPaddr()), curTick,
+ *pkt_data, *data);
}
numReads++;
@@ -245,39 +233,17 @@ MemTest::completeRequest(PacketPtr pkt)
}
if (numReads >= maxLoads)
- exitSimLoop("Maximum number of loads reached!");
+ exitSimLoop("maximum number of loads reached");
break;
case MemCmd::WriteResp:
numWritesStat++;
break;
-/*
- case Copy:
- //Also remove dest from outstanding list
- removeAddr = outstandingAddrs.find(req->dest);
- assert(removeAddr != outstandingAddrs.end());
- outstandingAddrs.erase(removeAddr);
- numCopiesStat++;
- break;
-*/
+
default:
panic("invalid command %s (%d)", pkt->cmdString(), pkt->cmd.toInt());
}
- if (blockAddr(req->getPaddr()) == traceBlockAddr) {
- cerr << name() << ": completed "
- << (pkt->isWrite() ? "write" : "read")
- << " access of "
- << dec << pkt->getSize() << " bytes at address 0x"
- << hex << req->getPaddr()
- << " (0x" << hex << blockAddr(req->getPaddr()) << ")"
- << ", value = 0x";
- printData(cerr, pkt_data, pkt->getSize());
- cerr << " @ cycle " << dec << curTick;
-
- cerr << endl;
- }
-
noResponseCycles = 0;
delete state;
delete [] data;
@@ -333,7 +299,7 @@ MemTest::tick()
//mem tester
//We can eliminate the lower bits of the offset, and then use the id
//to offset within the blks
- offset &= ~63; //Not the low order bits
+ offset = blockAddr(offset);
offset += id;
access_size = 0;
@@ -359,29 +325,23 @@ MemTest::tick()
if (cmd < percentReads) {
// read
- //For now we only allow one outstanding request per addreess per tester
- //This means we assume CPU does write forwarding to reads that alias something
- //in the cpu store buffer.
+ // For now we only allow one outstanding request per address
+ // per tester This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
delete [] result;
delete req;
return;
}
- else outstandingAddrs.insert(paddr);
+
+ outstandingAddrs.insert(paddr);
// ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
funcPort.readBlob(req->getPaddr(), result, req->getSize());
- if (blockAddr(paddr) == traceBlockAddr) {
- cerr << name()
- << ": initiating read "
- << ((probe) ? "probe of " : "access of ")
- << dec << req->getSize() << " bytes from addr 0x"
- << hex << paddr
- << " (0x" << hex << blockAddr(paddr) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }
+ DPRINTF(MemTest,
+ "initiating read at address %x (blk %x) expecting %x\n",
+ req->getPaddr(), blockAddr(req->getPaddr()), *result);
PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
pkt->dataDynamicArray(new uint8_t[req->getSize()]);
@@ -393,36 +353,25 @@ MemTest::tick()
pkt->makeAtomicResponse();
completeRequest(pkt);
} else {
-// req->completionEvent = new MemCompleteEvent(req, result, this);
sendPkt(pkt);
}
} else {
// write
- //For now we only allow one outstanding request per addreess per tester
- //This means we assume CPU does write forwarding to reads that alias something
- //in the cpu store buffer.
+ // For now we only allow one outstanding request per addreess
+ // per tester. This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
delete [] result;
delete req;
return;
}
- else outstandingAddrs.insert(paddr);
+ outstandingAddrs.insert(paddr);
+
+ DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n",
+ req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff);
-/*
- if (blockAddr(req->getPaddr()) == traceBlockAddr) {
- cerr << name() << ": initiating write "
- << ((probe)?"probe of ":"access of ")
- << dec << req->getSize() << " bytes (value = 0x";
- printData(cerr, data_pkt->getPtr(), req->getSize());
- cerr << ") to addr 0x"
- << hex << req->getPaddr()
- << " (0x" << hex << blockAddr(req->getPaddr()) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }
-*/
PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
uint8_t *pkt_data = new uint8_t[req->getSize()];
pkt->dataDynamicArray(pkt_data);
@@ -437,54 +386,9 @@ MemTest::tick()
pkt->makeAtomicResponse();
completeRequest(pkt);
} else {
-// req->completionEvent = new MemCompleteEvent(req, NULL, this);
sendPkt(pkt);
}
}
-/* else {
- // copy
- unsigned source_align = random() % 100;
- unsigned dest_align = random() % 100;
- unsigned offset2 = random() % size;
-
- Addr source = ((base) ? baseAddr1 : baseAddr2) + offset;
- Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2;
- if (outstandingAddrs.find(source) != outstandingAddrs.end()) return;
- else outstandingAddrs.insert(source);
- if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return;
- else outstandingAddrs.insert(dest);
-
- if (source_align >= percentSourceUnaligned) {
- source = blockAddr(source);
- }
- if (dest_align >= percentDestUnaligned) {
- dest = blockAddr(dest);
- }
- req->cmd = Copy;
- req->flags &= ~UNCACHEABLE;
- req->paddr = source;
- req->dest = dest;
- delete [] req->data;
- req->data = new uint8_t[blockSize];
- req->size = blockSize;
- if (source == traceBlockAddr || dest == traceBlockAddr) {
- cerr << name()
- << ": initiating copy of "
- << dec << req->size << " bytes from addr 0x"
- << hex << source
- << " (0x" << hex << blockAddr(source) << ")"
- << " to addr 0x"
- << hex << dest
- << " (0x" << hex << blockAddr(dest) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }*
- cacheInterface->access(req);
- uint8_t result[blockSize];
- checkMem->access(Read, source, &result, blockSize);
- checkMem->access(Write, dest, &result, blockSize);
- }
-*/
}
void
diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh
index 123ee2a6c..f4713709a 100644
--- a/src/cpu/memtest/memtest.hh
+++ b/src/cpu/memtest/memtest.hh
@@ -35,8 +35,6 @@
#include <set>
#include "base/statistics.hh"
-//#include "mem/functional/functional.hh"
-//#include "mem/mem_interface.hh"
#include "sim/eventq.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
@@ -50,9 +48,6 @@ class MemTest : public MemObject
public:
MemTest(const std::string &name,
-// MemInterface *_cache_interface,
-// PhysicalMemory *main_mem,
-// PhysicalMemory *check_mem,
unsigned _memorySize,
unsigned _percentReads,
unsigned _percentFunctional,
@@ -85,13 +80,13 @@ class MemTest : public MemObject
TickEvent(MemTest *c)
: Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {}
void process() {cpu->tick();}
- virtual const char *description() { return "tick event"; }
+ virtual const char *description() { return "MemTest tick"; }
};
TickEvent tickEvent;
+
class CpuPort : public Port
{
-
MemTest *memtest;
public:
@@ -116,7 +111,7 @@ class MemTest : public MemObject
virtual void getDeviceAddressRanges(AddrRangeList &resp,
bool &snoop)
- { resp.clear(); snoop = true; }
+ { resp.clear(); snoop = false; }
};
CpuPort cachePort;
@@ -136,12 +131,7 @@ class MemTest : public MemObject
uint8_t *data;
};
-// Request *dataReq;
PacketPtr retryPkt;
-// MemInterface *cacheInterface;
-// PhysicalMemory *mainMem;
-// PhysicalMemory *checkMem;
-// SimpleThread *thread;
bool accessRetry;
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index 04b0308e1..fb4574844 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -112,10 +112,6 @@ Bridge::BridgePort::reqQueueFull()
bool
Bridge::BridgePort::recvTiming(PacketPtr pkt)
{
- if (!(pkt->flags & SNOOP_COMMIT))
- return true;
-
-
DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr());
@@ -253,8 +249,6 @@ Bridge::BridgePort::trySend()
PacketPtr pkt = buf->pkt;
- pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
-
// Ugly! @todo When multilevel coherence works this will be removed
if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
pkt->result != Packet::Nacked) {
@@ -345,17 +339,14 @@ void
Bridge::BridgePort::recvFunctional(PacketPtr pkt)
{
std::list<PacketBuffer*>::iterator i;
- bool pktContinue = true;
for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
- if (pkt->intersect((*i)->pkt)) {
- pktContinue &= fixPacket(pkt, (*i)->pkt);
- }
+ if (pkt->checkFunctional((*i)->pkt))
+ return;
}
- if (pktContinue) {
- otherPort->sendFunctional(pkt);
- }
+ // fall through if pkt still not satisfied
+ otherPort->sendFunctional(pkt);
}
/** Function called by the port when the bus is receiving a status change.*/
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index d818a25ea..ffd5e25a7 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -33,7 +33,7 @@
* Definition of a bus object.
*/
-
+#include <algorithm>
#include <limits>
#include "base/misc.hh"
@@ -185,7 +185,8 @@ Bus::recvTiming(PacketPtr pkt)
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
if (tickNextIdle > curTick ||
- (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
+ (retryList.size() && (!inRetry || pktPort != retryList.front())))
+ {
addToRetryList(pktPort);
DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
return false;
@@ -197,31 +198,18 @@ Bus::recvTiming(PacketPtr pkt)
// access has been handled twice.
if (dest == Packet::Broadcast) {
port = findPort(pkt->getAddr(), pkt->getSrc());
- pkt->flags &= ~SNOOP_COMMIT;
- if (timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()])) {
- bool success;
-
- pkt->flags |= SNOOP_COMMIT;
- success = timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
- assert(success);
-
- if (pkt->flags & SATISFIED) {
- //Cache-Cache transfer occuring
- if (inRetry) {
- retryList.front()->onRetryList(false);
- retryList.pop_front();
- inRetry = false;
- }
- occupyBus(pkt);
- DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
- return true;
+ timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+
+ if (pkt->memInhibitAsserted()) {
+ //Cache-Cache transfer occuring
+ if (inRetry) {
+ retryList.front()->onRetryList(false);
+ retryList.pop_front();
+ inRetry = false;
}
- } else {
- //Snoop didn't succeed
- DPRINTF(Bus, "Adding1 a retry to RETRY list %d\n",
- pktPort->getId());
- addToRetryList(pktPort);
- return false;
+ occupyBus(pkt);
+ DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
+ return true;
}
} else {
assert(dest >= 0 && dest < maxId);
@@ -334,27 +322,6 @@ Bus::findPort(Addr addr, int id)
return interfaces[dest_id];
}
-Tick
-Bus::atomicSnoop(PacketPtr pkt, Port *responder)
-{
- Tick response_time = 0;
-
- for (SnoopIter s_iter = snoopPorts.begin();
- s_iter != snoopPorts.end();
- s_iter++) {
- BusPort *p = *s_iter;
- if (p != responder && p->getId() != pkt->getSrc()) {
- Tick response = p->sendAtomic(pkt);
- if (response) {
- assert(!response_time); //Multiple responders
- response_time = response;
- }
- }
- }
-
- return response_time;
-}
-
void
Bus::functionalSnoop(PacketPtr pkt, Port *responder)
{
@@ -402,21 +369,57 @@ Bus::recvAtomic(PacketPtr pkt)
DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
assert(pkt->getDest() == Packet::Broadcast);
- pkt->flags |= SNOOP_COMMIT;
- // Assume one bus cycle in order to get through. This may have
- // some clock skew issues yet again...
- pkt->finishTime = curTick + clock;
+ // Variables for recording original command and snoop response (if
+ // any)... if a snooper respondes, we will need to restore
+ // original command so that additional snoops can take place
+ // properly
+ MemCmd orig_cmd = pkt->cmd;
+ Packet::Result response_result = Packet::Unknown;
+ MemCmd response_cmd = MemCmd::InvalidCmd;
- Port *port = findPort(pkt->getAddr(), pkt->getSrc());
- Tick snoopTime = atomicSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+ Port *target_port = findPort(pkt->getAddr(), pkt->getSrc());
- if (snoopTime)
- return snoopTime; //Snoop satisfies it
- else if (port)
- return port->sendAtomic(pkt);
- else
- return 0;
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+ BusPort *p = *s_iter;
+ // same port should not have both target addresses and snooping
+ assert(p != target_port);
+ if (p->getId() != pkt->getSrc()) {
+ p->sendAtomic(pkt);
+ if (pkt->result != Packet::Unknown) {
+ // response from snoop agent
+ assert(pkt->cmd != orig_cmd);
+ assert(pkt->memInhibitAsserted());
+ assert(pkt->isResponse());
+ // should only happen once
+ assert(response_result == Packet::Unknown);
+ assert(response_cmd == MemCmd::InvalidCmd);
+ // save response state
+ response_result = pkt->result;
+ response_cmd = pkt->cmd;
+ // restore original packet state for remaining snoopers
+ pkt->cmd = orig_cmd;
+ pkt->result = Packet::Unknown;
+ }
+ }
+ }
+
+ Tick response_time = target_port->sendAtomic(pkt);
+
+ // if we got a response from a snooper, restore it here
+ if (response_result != Packet::Unknown) {
+ assert(response_cmd != MemCmd::InvalidCmd);
+ // no one else should have responded
+ assert(pkt->result == Packet::Unknown);
+ assert(pkt->cmd == orig_cmd);
+ pkt->cmd = response_cmd;
+ pkt->result = response_result;
+ }
+
+ // why do we have this packet field and the return value both???
+ pkt->finishTime = std::max(response_time, curTick + clock);
+ return pkt->finishTime;
}
/** Function called by the port when the bus is receiving a Functional
@@ -427,7 +430,6 @@ Bus::recvFunctional(PacketPtr 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);
- pkt->flags |= SNOOP_COMMIT;
Port* port = findPort(pkt->getAddr(), pkt->getSrc());
functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index ee647e20a..bd51337ed 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -182,9 +182,6 @@ class Bus : public MemObject
*/
Port *findPort(Addr addr, int id);
- /** Snoop all relevant ports atomicly. */
- Tick atomicSnoop(PacketPtr pkt, Port* responder);
-
/** Snoop all relevant ports functionally. */
void functionalSnoop(PacketPtr pkt, Port *responder);
diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc
index 8aac02460..1f5182574 100644
--- a/src/mem/cache/base_cache.cc
+++ b/src/mem/cache/base_cache.cc
@@ -40,28 +40,36 @@
using namespace std;
-BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
- bool _isCpuSide)
- : Port(_name, _cache), cache(_cache), isCpuSide(_isCpuSide)
+BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
+ : SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
+ blocked(false), waitingOnRetry(false), mustSendRetry(false),
+ requestCauses(0)
{
- blocked = false;
- waitingOnRetry = false;
- //Start ports at null if more than one is created we should panic
- //cpuSidePort = NULL;
- //memSidePort = NULL;
}
-void
-BaseCache::CachePort::recvStatusChange(Port::Status status)
+BaseCache::BaseCache(const std::string &name, Params &params)
+ : MemObject(name),
+ mshrQueue(params.numMSHRs, 4, MSHRQueue_MSHRs),
+ writeBuffer(params.numWriteBuffers, params.numMSHRs+1000,
+ MSHRQueue_WriteBuffer),
+ blkSize(params.blkSize),
+ hitLatency(params.hitLatency),
+ numTarget(params.numTargets),
+ blocked(0),
+ noTargetMSHR(NULL),
+ missCount(params.maxMisses),
+ drainEvent(NULL)
{
- cache->recvStatusChange(status, isCpuSide);
}
+
void
-BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+BaseCache::CachePort::recvStatusChange(Port::Status status)
{
- cache->getAddressRanges(resp, snoop, isCpuSide);
+ if (status == Port::RangeChange) {
+ otherPort->sendStatusChange(Port::RangeChange);
+ }
}
int
@@ -70,136 +78,25 @@ BaseCache::CachePort::deviceBlockSize()
return cache->getBlockSize();
}
-bool
-BaseCache::CachePort::checkFunctional(PacketPtr pkt)
-{
- //Check storage here first
- list<PacketPtr>::iterator i = drainList.begin();
- list<PacketPtr>::iterator iend = drainList.end();
- bool notDone = true;
- while (i != iend && notDone) {
- PacketPtr target = *i;
- // If the target contains data, and it overlaps the
- // probed request, need to update data
- if (target->intersect(pkt)) {
- DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a drain\n",
- pkt->cmdString(), pkt->getAddr() & ~(cache->getBlockSize() - 1));
- notDone = fixPacket(pkt, target);
- }
- i++;
- }
- //Also check the response not yet ready to be on the list
- std::list<std::pair<Tick,PacketPtr> >::iterator j = transmitList.begin();
- std::list<std::pair<Tick,PacketPtr> >::iterator jend = transmitList.end();
-
- while (j != jend && notDone) {
- PacketPtr target = j->second;
- // If the target contains data, and it overlaps the
- // probed request, need to update data
- if (target->intersect(pkt)) {
- DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a response\n",
- pkt->cmdString(), pkt->getAddr() & ~(cache->getBlockSize() - 1));
- notDone = fixDelayedResponsePacket(pkt, target);
- }
- j++;
- }
- return notDone;
-}
void
BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
{
- bool notDone = checkFunctional(pkt);
- if (notDone)
+ checkFunctional(pkt);
+ if (pkt->result != Packet::Success)
sendFunctional(pkt);
}
-void
-BaseCache::CachePort::recvRetry()
+
+bool
+BaseCache::CachePort::recvRetryCommon()
{
- PacketPtr pkt;
assert(waitingOnRetry);
- if (!drainList.empty()) {
- DPRINTF(CachePort, "%s attempting to send a retry for response (%i waiting)\n"
- , name(), drainList.size());
- //We have some responses to drain first
- pkt = drainList.front();
- drainList.pop_front();
- if (sendTiming(pkt)) {
- DPRINTF(CachePort, "%s sucessful in sending a retry for"
- "response (%i still waiting)\n", name(), drainList.size());
- if (!drainList.empty() ||
- !isCpuSide && cache->doMasterRequest() ||
- isCpuSide && cache->doSlaveRequest()) {
-
- DPRINTF(CachePort, "%s has more responses/requests\n", name());
- new BaseCache::RequestEvent(this, curTick + 1);
- }
- waitingOnRetry = false;
- }
- else {
- drainList.push_front(pkt);
- }
- // Check if we're done draining once this list is empty
- if (drainList.empty())
- cache->checkDrain();
- }
- else if (!isCpuSide)
- {
- DPRINTF(CachePort, "%s attempting to send a retry for MSHR\n", name());
- if (!cache->doMasterRequest()) {
- //This can happen if I am the owner of a block and see an upgrade
- //while the block was in my WB Buffers. I just remove the
- //wb and de-assert the masterRequest
- waitingOnRetry = false;
- return;
- }
- pkt = cache->getPacket();
- MSHR* mshr = (MSHR*) pkt->senderState;
- //Copy the packet, it may be modified/destroyed elsewhere
- PacketPtr copyPkt = new Packet(*pkt);
- copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
- mshr->pkt = copyPkt;
-
- bool success = sendTiming(pkt);
- DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
- pkt->getAddr(), success ? "succesful" : "unsuccesful");
-
- waitingOnRetry = !success;
- if (waitingOnRetry) {
- DPRINTF(CachePort, "%s now waiting on a retry\n", name());
- }
-
- cache->sendResult(pkt, mshr, success);
-
- if (success && cache->doMasterRequest())
- {
- DPRINTF(CachePort, "%s has more requests\n", name());
- //Still more to issue, rerequest in 1 cycle
- new BaseCache::RequestEvent(this, curTick + 1);
- }
- }
- else
- {
- assert(cache->doSlaveRequest());
- //pkt = cache->getCoherencePacket();
- //We save the packet, no reordering on CSHRS
- pkt = cache->getCoherencePacket();
- MSHR* cshr = (MSHR*)pkt->senderState;
- bool success = sendTiming(pkt);
- cache->sendCoherenceResult(pkt, cshr, success);
- waitingOnRetry = !success;
- if (success && cache->doSlaveRequest())
- {
- DPRINTF(CachePort, "%s has more requests\n", name());
- //Still more to issue, rerequest in 1 cycle
- new BaseCache::RequestEvent(this, curTick + 1);
- }
- }
- if (waitingOnRetry) DPRINTF(CachePort, "%s STILL Waiting on retry\n", name());
- else DPRINTF(CachePort, "%s no longer waiting on retry\n", name());
- return;
+ waitingOnRetry = false;
+ return false;
}
+
+
void
BaseCache::CachePort::setBlocked()
{
@@ -224,143 +121,6 @@ BaseCache::CachePort::clearBlocked()
}
}
-BaseCache::RequestEvent::RequestEvent(CachePort *_cachePort, Tick when)
- : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
-{
- this->setFlags(AutoDelete);
- schedule(when);
-}
-
-void
-BaseCache::RequestEvent::process()
-{
- if (cachePort->waitingOnRetry) return;
- //We have some responses to drain first
- if (!cachePort->drainList.empty()) {
- DPRINTF(CachePort, "%s trying to drain a response\n", cachePort->name());
- if (cachePort->sendTiming(cachePort->drainList.front())) {
- DPRINTF(CachePort, "%s drains a response succesfully\n", cachePort->name());
- cachePort->drainList.pop_front();
- if (!cachePort->drainList.empty() ||
- !cachePort->isCpuSide && cachePort->cache->doMasterRequest() ||
- cachePort->isCpuSide && cachePort->cache->doSlaveRequest()) {
-
- DPRINTF(CachePort, "%s still has outstanding bus reqs\n", cachePort->name());
- this->schedule(curTick + 1);
- }
- }
- else {
- cachePort->waitingOnRetry = true;
- DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
- }
- }
- else if (!cachePort->isCpuSide)
- { //MSHR
- DPRINTF(CachePort, "%s trying to send a MSHR request\n", cachePort->name());
- if (!cachePort->cache->doMasterRequest()) {
- //This can happen if I am the owner of a block and see an upgrade
- //while the block was in my WB Buffers. I just remove the
- //wb and de-assert the masterRequest
- return;
- }
-
- PacketPtr pkt = cachePort->cache->getPacket();
- MSHR* mshr = (MSHR*) pkt->senderState;
- //Copy the packet, it may be modified/destroyed elsewhere
- PacketPtr copyPkt = new Packet(*pkt);
- copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
- mshr->pkt = copyPkt;
-
- bool success = cachePort->sendTiming(pkt);
- DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
- pkt->getAddr(), success ? "succesful" : "unsuccesful");
-
- cachePort->waitingOnRetry = !success;
- if (cachePort->waitingOnRetry) {
- DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
- }
-
- cachePort->cache->sendResult(pkt, mshr, success);
- if (success && cachePort->cache->doMasterRequest())
- {
- DPRINTF(CachePort, "%s still more MSHR requests to send\n",
- cachePort->name());
- //Still more to issue, rerequest in 1 cycle
- this->schedule(curTick+1);
- }
- }
- else
- {
- //CSHR
- assert(cachePort->cache->doSlaveRequest());
- PacketPtr pkt = cachePort->cache->getCoherencePacket();
- MSHR* cshr = (MSHR*) pkt->senderState;
- bool success = cachePort->sendTiming(pkt);
- cachePort->cache->sendCoherenceResult(pkt, cshr, success);
- cachePort->waitingOnRetry = !success;
- if (cachePort->waitingOnRetry)
- DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
- if (success && cachePort->cache->doSlaveRequest())
- {
- DPRINTF(CachePort, "%s still more CSHR requests to send\n",
- cachePort->name());
- //Still more to issue, rerequest in 1 cycle
- this->schedule(curTick+1);
- }
- }
-}
-
-const char *
-BaseCache::RequestEvent::description()
-{
- return "Cache request event";
-}
-
-BaseCache::ResponseEvent::ResponseEvent(CachePort *_cachePort)
- : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
-{
-}
-
-void
-BaseCache::ResponseEvent::process()
-{
- assert(cachePort->transmitList.size());
- assert(cachePort->transmitList.front().first <= curTick);
- PacketPtr pkt = cachePort->transmitList.front().second;
- cachePort->transmitList.pop_front();
- if (!cachePort->transmitList.empty()) {
- Tick time = cachePort->transmitList.front().first;
- schedule(time <= curTick ? curTick+1 : time);
- }
-
- if (pkt->flags & NACKED_LINE)
- pkt->result = Packet::Nacked;
- else
- pkt->result = Packet::Success;
- pkt->makeTimingResponse();
- DPRINTF(CachePort, "%s attempting to send a response\n", cachePort->name());
- if (!cachePort->drainList.empty() || cachePort->waitingOnRetry) {
- //Already have a list, just append
- cachePort->drainList.push_back(pkt);
- DPRINTF(CachePort, "%s appending response onto drain list\n", cachePort->name());
- }
- else if (!cachePort->sendTiming(pkt)) {
- //It failed, save it to list of drain events
- DPRINTF(CachePort, "%s now waiting for a retry\n", cachePort->name());
- cachePort->drainList.push_back(pkt);
- cachePort->waitingOnRetry = true;
- }
-
- // Check if we're done draining once this list is empty
- if (cachePort->drainList.empty() && cachePort->transmitList.empty())
- cachePort->cache->checkDrain();
-}
-
-const char *
-BaseCache::ResponseEvent::description()
-{
- return "Cache response event";
-}
void
BaseCache::init()
@@ -370,6 +130,7 @@ BaseCache::init()
cpuSidePort->sendStatusChange(Port::RangeChange);
}
+
void
BaseCache::regStats()
{
@@ -580,17 +341,289 @@ BaseCache::regStats()
.desc("number of cache copies performed")
;
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name() + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+
+ // MSHR statistics
+ // MSHR hit statistics
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshr_hits[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_mshr_hits")
+ .desc("number of " + cstr + " MSHR hits")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrHits
+ .name(name() + ".demand_mshr_hits")
+ .desc("number of demand (read+write) MSHR hits")
+ .flags(total)
+ ;
+ demandMshrHits = mshr_hits[MemCmd::ReadReq] + mshr_hits[MemCmd::WriteReq];
+
+ overallMshrHits
+ .name(name() + ".overall_mshr_hits")
+ .desc("number of overall MSHR hits")
+ .flags(total)
+ ;
+ overallMshrHits = demandMshrHits + mshr_hits[MemCmd::SoftPFReq] +
+ mshr_hits[MemCmd::HardPFReq];
+
+ // MSHR miss statistics
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshr_misses[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_mshr_misses")
+ .desc("number of " + cstr + " MSHR misses")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMisses
+ .name(name() + ".demand_mshr_misses")
+ .desc("number of demand (read+write) MSHR misses")
+ .flags(total)
+ ;
+ demandMshrMisses = mshr_misses[MemCmd::ReadReq] + mshr_misses[MemCmd::WriteReq];
+
+ overallMshrMisses
+ .name(name() + ".overall_mshr_misses")
+ .desc("number of overall MSHR misses")
+ .flags(total)
+ ;
+ overallMshrMisses = demandMshrMisses + mshr_misses[MemCmd::SoftPFReq] +
+ mshr_misses[MemCmd::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshr_miss_latency[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_mshr_miss_latency")
+ .desc("number of " + cstr + " MSHR miss cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMissLatency
+ .name(name() + ".demand_mshr_miss_latency")
+ .desc("number of demand (read+write) MSHR miss cycles")
+ .flags(total)
+ ;
+ demandMshrMissLatency = mshr_miss_latency[MemCmd::ReadReq]
+ + mshr_miss_latency[MemCmd::WriteReq];
+
+ overallMshrMissLatency
+ .name(name() + ".overall_mshr_miss_latency")
+ .desc("number of overall MSHR miss cycles")
+ .flags(total)
+ ;
+ overallMshrMissLatency = demandMshrMissLatency +
+ mshr_miss_latency[MemCmd::SoftPFReq] + mshr_miss_latency[MemCmd::HardPFReq];
+
+ // MSHR uncacheable statistics
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshr_uncacheable[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_mshr_uncacheable")
+ .desc("number of " + cstr + " MSHR uncacheable")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheable
+ .name(name() + ".overall_mshr_uncacheable_misses")
+ .desc("number of overall MSHR uncacheable misses")
+ .flags(total)
+ ;
+ overallMshrUncacheable = mshr_uncacheable[MemCmd::ReadReq]
+ + mshr_uncacheable[MemCmd::WriteReq] + mshr_uncacheable[MemCmd::SoftPFReq]
+ + mshr_uncacheable[MemCmd::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshr_uncacheable_lat[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_mshr_uncacheable_latency")
+ .desc("number of " + cstr + " MSHR uncacheable cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheableLatency
+ .name(name() + ".overall_mshr_uncacheable_latency")
+ .desc("number of overall MSHR uncacheable cycles")
+ .flags(total)
+ ;
+ overallMshrUncacheableLatency = mshr_uncacheable_lat[MemCmd::ReadReq]
+ + mshr_uncacheable_lat[MemCmd::WriteReq]
+ + mshr_uncacheable_lat[MemCmd::SoftPFReq]
+ + mshr_uncacheable_lat[MemCmd::HardPFReq];
+
+#if 0
+ // MSHR access formulas
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshrAccesses[access_idx]
+ .name(name() + "." + cstr + "_mshr_accesses")
+ .desc("number of " + cstr + " mshr accesses(hits+misses)")
+ .flags(total | nozero | nonan)
+ ;
+ mshrAccesses[access_idx] =
+ mshr_hits[access_idx] + mshr_misses[access_idx]
+ + mshr_uncacheable[access_idx];
+ }
+
+ demandMshrAccesses
+ .name(name() + ".demand_mshr_accesses")
+ .desc("number of demand (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ demandMshrAccesses = demandMshrHits + demandMshrMisses;
+
+ overallMshrAccesses
+ .name(name() + ".overall_mshr_accesses")
+ .desc("number of overall (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ overallMshrAccesses = overallMshrHits + overallMshrMisses
+ + overallMshrUncacheable;
+#endif
+
+ // MSHR miss rate formulas
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ mshrMissRate[access_idx]
+ .name(name() + "." + cstr + "_mshr_miss_rate")
+ .desc("mshr miss rate for " + cstr + " accesses")
+ .flags(total | nozero | nonan)
+ ;
+
+ mshrMissRate[access_idx] =
+ mshr_misses[access_idx] / accesses[access_idx];
+ }
+
+ demandMshrMissRate
+ .name(name() + ".demand_mshr_miss_rate")
+ .desc("mshr miss rate for demand accesses")
+ .flags(total)
+ ;
+ demandMshrMissRate = demandMshrMisses / demandAccesses;
+
+ overallMshrMissRate
+ .name(name() + ".overall_mshr_miss_rate")
+ .desc("mshr miss rate for overall accesses")
+ .flags(total)
+ ;
+ overallMshrMissRate = overallMshrMisses / overallAccesses;
+
+ // mshrMiss latency formulas
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ avgMshrMissLatency[access_idx]
+ .name(name() + "." + cstr + "_avg_mshr_miss_latency")
+ .desc("average " + cstr + " mshr miss latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrMissLatency[access_idx] =
+ mshr_miss_latency[access_idx] / mshr_misses[access_idx];
+ }
+
+ demandAvgMshrMissLatency
+ .name(name() + ".demand_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
+
+ overallAvgMshrMissLatency
+ .name(name() + ".overall_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
+
+ // mshrUncacheable latency formulas
+ for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
+ MemCmd cmd(access_idx);
+ const string &cstr = cmd.toString();
+
+ avgMshrUncacheableLatency[access_idx]
+ .name(name() + "." + cstr + "_avg_mshr_uncacheable_latency")
+ .desc("average " + cstr + " mshr uncacheable latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrUncacheableLatency[access_idx] =
+ mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
+ }
+
+ overallAvgMshrUncacheableLatency
+ .name(name() + ".overall_avg_mshr_uncacheable_latency")
+ .desc("average overall mshr uncacheable latency")
+ .flags(total)
+ ;
+ overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
+
+ mshr_cap_events
+ .init(maxThreadsPerCPU)
+ .name(name() + ".mshr_cap_events")
+ .desc("number of times MSHR cap was activated")
+ .flags(total)
+ ;
+
+ //software prefetching stats
+ soft_prefetch_mshr_full
+ .init(maxThreadsPerCPU)
+ .name(name() + ".soft_prefetch_mshr_full")
+ .desc("number of mshr full events for SW prefetching instrutions")
+ .flags(total)
+ ;
+
+ mshr_no_allocate_misses
+ .name(name() +".no_allocate_misses")
+ .desc("Number of misses that were no-allocate")
+ ;
+
}
unsigned int
BaseCache::drain(Event *de)
{
+ int count = memSidePort->drain(de) + cpuSidePort->drain(de);
+
// Set status
- if (!canDrain()) {
+ if (count != 0) {
drainEvent = de;
changeState(SimObject::Draining);
- return 1;
+ return count;
}
changeState(SimObject::Drained);
diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh
index f06a79dc0..27134b2ad 100644
--- a/src/mem/cache/base_cache.hh
+++ b/src/mem/cache/base_cache.hh
@@ -26,6 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Erik Hallnor
+ * Steve Reinhardt
+ * Ron Dreslinski
*/
/**
@@ -44,32 +46,13 @@
#include "base/misc.hh"
#include "base/statistics.hh"
#include "base/trace.hh"
+#include "mem/cache/miss/mshr_queue.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
-#include "mem/port.hh"
+#include "mem/tport.hh"
#include "mem/request.hh"
#include "sim/eventq.hh"
-
-/**
- * Reasons for Caches to be Blocked.
- */
-enum BlockedCause{
- Blocked_NoMSHRs,
- Blocked_NoTargets,
- Blocked_NoWBBuffers,
- Blocked_Coherence,
- NUM_BLOCKED_CAUSES
-};
-
-/**
- * Reasons for cache to request a bus.
- */
-enum RequestCause{
- Request_MSHR,
- Request_WB,
- Request_Coherence,
- Request_PF
-};
+#include "sim/sim_exit.hh"
class MSHR;
/**
@@ -77,121 +60,163 @@ class MSHR;
*/
class BaseCache : public MemObject
{
- class CachePort : public Port
+ /**
+ * Indexes to enumerate the MSHR queues.
+ */
+ enum MSHRQueueIndex {
+ MSHRQueue_MSHRs,
+ MSHRQueue_WriteBuffer
+ };
+
+ /**
+ * Reasons for caches to be blocked.
+ */
+ enum BlockedCause {
+ Blocked_NoMSHRs = MSHRQueue_MSHRs,
+ Blocked_NoWBBuffers = MSHRQueue_WriteBuffer,
+ Blocked_NoTargets,
+ NUM_BLOCKED_CAUSES
+ };
+
+ public:
+ /**
+ * Reasons for cache to request a bus.
+ */
+ enum RequestCause {
+ Request_MSHR = MSHRQueue_MSHRs,
+ Request_WB = MSHRQueue_WriteBuffer,
+ Request_PF,
+ NUM_REQUEST_CAUSES
+ };
+
+ private:
+
+ class CachePort : public SimpleTimingPort
{
public:
BaseCache *cache;
protected:
- CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
- virtual void recvStatusChange(Status status);
+ CachePort(const std::string &_name, BaseCache *_cache);
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop);
+ virtual void recvStatusChange(Status status);
virtual int deviceBlockSize();
- virtual void recvRetry();
+ bool recvRetryCommon();
public:
+ void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; }
+
void setBlocked();
void clearBlocked();
- bool checkFunctional(PacketPtr pkt);
-
void checkAndSendFunctional(PacketPtr pkt);
- bool canDrain() { return drainList.empty() && transmitList.empty(); }
+ CachePort *otherPort;
bool blocked;
- bool mustSendRetry;
-
- bool isCpuSide;
-
bool waitingOnRetry;
- std::list<PacketPtr> drainList;
+ bool mustSendRetry;
- std::list<std::pair<Tick,PacketPtr> > transmitList;
- };
+ /**
+ * Bit vector for the outstanding requests for the master interface.
+ */
+ uint8_t requestCauses;
- struct RequestEvent : public Event
- {
- CachePort *cachePort;
+ bool isBusRequested() { return requestCauses != 0; }
- RequestEvent(CachePort *_cachePort, Tick when);
- void process();
- const char *description();
- };
+ void requestBus(RequestCause cause, Tick time)
+ {
+ DPRINTF(Cache, "Asserting bus request for cause %d\n", cause);
+ if (!isBusRequested() && !waitingOnRetry) {
+ assert(!sendEvent->scheduled());
+ sendEvent->schedule(time);
+ }
+ requestCauses |= (1 << cause);
+ }
- struct ResponseEvent : public Event
- {
- CachePort *cachePort;
+ void deassertBusRequest(RequestCause cause)
+ {
+ DPRINTF(Cache, "Deasserting bus request for cause %d\n", cause);
+ requestCauses &= ~(1 << cause);
+ }
- ResponseEvent(CachePort *_cachePort);
- void process();
- const char *description();
+ void respond(PacketPtr pkt, Tick time) {
+ schedSendTiming(pkt, time);
+ }
};
public: //Made public so coherence can get at it.
CachePort *cpuSidePort;
CachePort *memSidePort;
- ResponseEvent *sendEvent;
- ResponseEvent *memSendEvent;
+ protected:
- private:
- void recvStatusChange(Port::Status status, bool isCpuSide)
+ /** Miss status registers */
+ MSHRQueue mshrQueue;
+
+ /** Write/writeback buffer */
+ MSHRQueue writeBuffer;
+
+ MSHR *allocateBufferInternal(MSHRQueue *mq, Addr addr, int size,
+ PacketPtr pkt, Tick time, bool requestBus)
{
- if (status == Port::RangeChange){
- if (!isCpuSide) {
- cpuSidePort->sendStatusChange(Port::RangeChange);
- }
- else {
- memSidePort->sendStatusChange(Port::RangeChange);
- }
+ MSHR *mshr = mq->allocate(addr, size, pkt);
+ mshr->order = order++;
+
+ if (mq->isFull()) {
+ setBlocked((BlockedCause)mq->index);
}
- }
- virtual PacketPtr getPacket() = 0;
+ if (requestBus) {
+ requestMemSideBus((RequestCause)mq->index, time);
+ }
- virtual PacketPtr getCoherencePacket() = 0;
+ return mshr;
+ }
- virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0;
+ void markInServiceInternal(MSHR *mshr)
+ {
+ MSHRQueue *mq = mshr->queue;
+ bool wasFull = mq->isFull();
+ mq->markInService(mshr);
+ if (!mq->havePending()) {
+ deassertMemSideBusRequest((RequestCause)mq->index);
+ }
+ if (wasFull && !mq->isFull()) {
+ clearBlocked((BlockedCause)mq->index);
+ }
+ }
- virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success) = 0;
+ /** Block size of this cache */
+ const int blkSize;
/**
- * Bit vector of the blocking reasons for the access path.
- * @sa #BlockedCause
+ * The latency of a hit in this device.
*/
- uint8_t blocked;
+ int hitLatency;
- /**
- * Bit vector for the blocking reasons for the snoop path.
- * @sa #BlockedCause
- */
- uint8_t blockedSnoop;
+ /** The number of targets for each MSHR. */
+ const int numTarget;
- /**
- * Bit vector for the outstanding requests for the master interface.
- */
- uint8_t masterRequests;
+ /** Increasing order number assigned to each incoming request. */
+ uint64_t order;
/**
- * Bit vector for the outstanding requests for the slave interface.
+ * Bit vector of the blocking reasons for the access path.
+ * @sa #BlockedCause
*/
- uint8_t slaveRequests;
-
- protected:
+ uint8_t blocked;
/** Stores time the cache blocked for statistics. */
Tick blockedCycle;
- /** Block size of this cache */
- const int blkSize;
+ /** Pointer to the MSHR that has no targets. */
+ MSHR *noTargetMSHR;
/** The number of misses to trigger an exit event. */
Counter missCount;
@@ -265,6 +290,73 @@ class BaseCache : public MemObject
/** The number of cache copies performed. */
Stats::Scalar<> cacheCopies;
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /** Number of misses that hit in the MSHRs per command and thread. */
+ Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS];
+ /** Demand misses that hit in the MSHRs. */
+ Stats::Formula demandMshrHits;
+ /** Total number of misses that hit in the MSHRs. */
+ Stats::Formula overallMshrHits;
+
+ /** Number of misses that miss in the MSHRs, per command and thread. */
+ Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS];
+ /** Demand misses that miss in the MSHRs. */
+ Stats::Formula demandMshrMisses;
+ /** Total number of misses that miss in the MSHRs. */
+ Stats::Formula overallMshrMisses;
+
+ /** Number of misses that miss in the MSHRs, per command and thread. */
+ Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
+ /** Total number of misses that miss in the MSHRs. */
+ Stats::Formula overallMshrUncacheable;
+
+ /** Total cycle latency of each MSHR miss, per command and thread. */
+ Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
+ /** Total cycle latency of demand MSHR misses. */
+ Stats::Formula demandMshrMissLatency;
+ /** Total cycle latency of overall MSHR misses. */
+ Stats::Formula overallMshrMissLatency;
+
+ /** Total cycle latency of each MSHR miss, per command and thread. */
+ Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
+ /** Total cycle latency of overall MSHR misses. */
+ Stats::Formula overallMshrUncacheableLatency;
+
+ /** The total number of MSHR accesses per command and thread. */
+ Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS];
+ /** The total number of demand MSHR accesses. */
+ Stats::Formula demandMshrAccesses;
+ /** The total number of MSHR accesses. */
+ Stats::Formula overallMshrAccesses;
+
+ /** The miss rate in the MSHRs pre command and thread. */
+ Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS];
+ /** The demand miss rate in the MSHRs. */
+ Stats::Formula demandMshrMissRate;
+ /** The overall miss rate in the MSHRs. */
+ Stats::Formula overallMshrMissRate;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrMissLatency[MemCmd::NUM_MEM_CMDS];
+ /** The average latency of a demand MSHR miss. */
+ Stats::Formula demandAvgMshrMissLatency;
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrMissLatency;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrUncacheableLatency[MemCmd::NUM_MEM_CMDS];
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrUncacheableLatency;
+
+ /** The number of times a thread hit its MSHR cap. */
+ Stats::Vector<> mshr_cap_events;
+ /** The number of times software prefetches caused the MSHR to block. */
+ Stats::Vector<> soft_prefetch_mshr_full;
+
+ Stats::Scalar<> mshr_no_allocate_misses;
+
/**
* @}
*/
@@ -279,12 +371,13 @@ class BaseCache : public MemObject
class Params
{
public:
- /** List of address ranges of this cache. */
- std::vector<Range<Addr> > addrRange;
/** The hit latency for this cache. */
int hitLatency;
/** The block size of this cache. */
int blkSize;
+ int numMSHRs;
+ int numTargets;
+ int numWriteBuffers;
/**
* The maximum number of misses this cache should handle before
* ending the simulation.
@@ -294,10 +387,12 @@ class BaseCache : public MemObject
/**
* Construct an instance of this parameter class.
*/
- Params(std::vector<Range<Addr> > addr_range,
- int hit_latency, int _blkSize, Counter max_misses)
- : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
- maxMisses(max_misses)
+ Params(int _hitLatency, int _blkSize,
+ int _numMSHRs, int _numTargets, int _numWriteBuffers,
+ Counter _maxMisses)
+ : hitLatency(_hitLatency), blkSize(_blkSize),
+ numMSHRs(_numMSHRs), numTargets(_numTargets),
+ numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses)
{
}
};
@@ -309,20 +404,10 @@ class BaseCache : public MemObject
* of this cache.
* @param params The parameter object for this BaseCache.
*/
- BaseCache(const std::string &name, Params &params)
- : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
- slaveRequests(0), blkSize(params.blkSize),
- missCount(params.maxMisses), drainEvent(NULL)
- {
- //Start ports at null if more than one is created we should panic
- cpuSidePort = NULL;
- memSidePort = NULL;
- }
+ BaseCache(const std::string &name, Params &params);
~BaseCache()
{
- delete sendEvent;
- delete memSendEvent;
}
virtual void init();
@@ -336,20 +421,41 @@ class BaseCache : public MemObject
return blkSize;
}
- /**
- * Returns true if the cache is blocked for accesses.
- */
- bool isBlocked()
+
+ Addr blockAlign(Addr addr) const { return (addr & ~(blkSize - 1)); }
+
+
+ MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool requestBus)
{
- return blocked != 0;
+ return allocateBufferInternal(&mshrQueue,
+ blockAlign(pkt->getAddr()), blkSize,
+ pkt, time, requestBus);
}
+ MSHR *allocateBuffer(PacketPtr pkt, Tick time, bool requestBus)
+ {
+ MSHRQueue *mq = NULL;
+
+ if (pkt->isWrite() && !pkt->isRead()) {
+ /**
+ * @todo Add write merging here.
+ */
+ mq = &writeBuffer;
+ } else {
+ mq = &mshrQueue;
+ }
+
+ return allocateBufferInternal(mq, pkt->getAddr(), pkt->getSize(),
+ pkt, time, requestBus);
+ }
+
+
/**
- * Returns true if the cache is blocked for snoops.
+ * Returns true if the cache is blocked for accesses.
*/
- bool isBlockedForSnoop()
+ bool isBlocked()
{
- return blockedSnoop != 0;
+ return blocked != 0;
}
/**
@@ -363,32 +469,10 @@ class BaseCache : public MemObject
if (blocked == 0) {
blocked_causes[cause]++;
blockedCycle = curTick;
+ cpuSidePort->setBlocked();
}
- int old_state = blocked;
- if (!(blocked & flag)) {
- //Wasn't already blocked for this cause
- blocked |= flag;
- DPRINTF(Cache,"Blocking for cause %s\n", cause);
- if (!old_state)
- cpuSidePort->setBlocked();
- }
- }
-
- /**
- * Marks the snoop path of the cache as blocked for the given cause. This
- * also sets the blocked flag in the master interface.
- * @param cause The reason to block the snoop path.
- */
- void setBlockedForSnoop(BlockedCause cause)
- {
- uint8_t flag = 1 << cause;
- uint8_t old_state = blockedSnoop;
- if (!(blockedSnoop & flag)) {
- //Wasn't already blocked for this cause
- blockedSnoop |= flag;
- if (!old_state)
- memSidePort->setBlocked();
- }
+ blocked |= flag;
+ DPRINTF(Cache,"Blocking for cause %d, mask=%d\n", cause, blocked);
}
/**
@@ -401,33 +485,21 @@ class BaseCache : public MemObject
void clearBlocked(BlockedCause cause)
{
uint8_t flag = 1 << cause;
- DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
- cause, blocked);
- if (blocked & flag)
- {
- blocked &= ~flag;
- if (!isBlocked()) {
- blocked_cycles[cause] += curTick - blockedCycle;
- DPRINTF(Cache,"Unblocking from all causes\n");
- cpuSidePort->clearBlocked();
- }
- }
- if (blockedSnoop & flag)
- {
- blockedSnoop &= ~flag;
- if (!isBlockedForSnoop()) {
- memSidePort->clearBlocked();
- }
+ blocked &= ~flag;
+ DPRINTF(Cache,"Unblocking for cause %d, mask=%d\n", cause, blocked);
+ if (blocked == 0) {
+ blocked_cycles[cause] += curTick - blockedCycle;
+ cpuSidePort->clearBlocked();
}
}
/**
- * True if the master bus should be requested.
+ * True if the memory-side bus should be requested.
* @return True if there are outstanding requests for the master bus.
*/
- bool doMasterRequest()
+ bool isMemSideBusRequested()
{
- return masterRequests != 0;
+ return memSidePort->isBusRequested();
}
/**
@@ -435,269 +507,38 @@ class BaseCache : public MemObject
* @param cause The reason for the request.
* @param time The time to make the request.
*/
- void setMasterRequest(RequestCause cause, Tick time)
+ void requestMemSideBus(RequestCause cause, Tick time)
{
- if (!doMasterRequest() && !memSidePort->waitingOnRetry)
- {
- new RequestEvent(memSidePort, time);
- }
- uint8_t flag = 1<<cause;
- masterRequests |= flag;
+ memSidePort->requestBus(cause, time);
}
/**
* Clear the master bus request for the given cause.
* @param cause The request reason to clear.
*/
- void clearMasterRequest(RequestCause cause)
- {
- uint8_t flag = 1<<cause;
- masterRequests &= ~flag;
- checkDrain();
- }
-
- /**
- * Return true if the slave bus should be requested.
- * @return True if there are outstanding requests for the slave bus.
- */
- bool doSlaveRequest()
- {
- return slaveRequests != 0;
- }
-
- /**
- * Request the slave bus for the given reason and time.
- * @param cause The reason for the request.
- * @param time The time to make the request.
- */
- void setSlaveRequest(RequestCause cause, Tick time)
- {
- if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry)
- {
- new RequestEvent(cpuSidePort, time);
- }
- uint8_t flag = 1<<cause;
- slaveRequests |= flag;
- }
-
- /**
- * Clear the slave bus request for the given reason.
- * @param cause The request reason to clear.
- */
- void clearSlaveRequest(RequestCause cause)
- {
- uint8_t flag = 1<<cause;
- slaveRequests &= ~flag;
- checkDrain();
- }
-
- /**
- * Send a response to the slave interface.
- * @param pkt The request being responded to.
- * @param time The time the response is ready.
- */
- void respond(PacketPtr pkt, Tick time)
- {
- assert(time >= curTick);
- if (pkt->needsResponse()) {
-/* CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
- reqCpu->schedule(time);
-*/
- if (cpuSidePort->transmitList.empty()) {
- assert(!sendEvent->scheduled());
- sendEvent->schedule(time);
- cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
-
- // something is on the list and this belongs at the end
- if (time >= cpuSidePort->transmitList.back().first) {
- cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
- // Something is on the list and this belongs somewhere else
- std::list<std::pair<Tick,PacketPtr> >::iterator i =
- cpuSidePort->transmitList.begin();
- std::list<std::pair<Tick,PacketPtr> >::iterator end =
- cpuSidePort->transmitList.end();
- bool done = false;
-
- while (i != end && !done) {
- if (time < i->first) {
- if (i == cpuSidePort->transmitList.begin()) {
- //Inserting at begining, reschedule
- sendEvent->reschedule(time);
- }
- cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
- (time,pkt));
- done = true;
- }
- i++;
- }
- }
- else {
- if (pkt->cmd != MemCmd::UpgradeReq)
- {
- delete pkt->req;
- delete pkt;
- }
- }
- }
-
- /**
- * Send a reponse to the slave interface and calculate miss latency.
- * @param pkt The request to respond to.
- * @param time The time the response is ready.
- */
- void respondToMiss(PacketPtr pkt, Tick time)
+ void deassertMemSideBusRequest(RequestCause cause)
{
- assert(time >= curTick);
- if (!pkt->req->isUncacheable()) {
- missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
- time - pkt->time;
- }
- if (pkt->needsResponse()) {
-/* CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
- reqCpu->schedule(time);
-*/
- if (cpuSidePort->transmitList.empty()) {
- assert(!sendEvent->scheduled());
- sendEvent->schedule(time);
- cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
-
- // something is on the list and this belongs at the end
- if (time >= cpuSidePort->transmitList.back().first) {
- cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
- // Something is on the list and this belongs somewhere else
- std::list<std::pair<Tick,PacketPtr> >::iterator i =
- cpuSidePort->transmitList.begin();
- std::list<std::pair<Tick,PacketPtr> >::iterator end =
- cpuSidePort->transmitList.end();
- bool done = false;
-
- while (i != end && !done) {
- if (time < i->first) {
- if (i == cpuSidePort->transmitList.begin()) {
- //Inserting at begining, reschedule
- sendEvent->reschedule(time);
- }
- cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
- (time,pkt));
- done = true;
- }
- i++;
- }
- }
- else {
- if (pkt->cmd != MemCmd::UpgradeReq)
- {
- delete pkt->req;
- delete pkt;
- }
- }
+ memSidePort->deassertBusRequest(cause);
+ // checkDrain();
}
- /**
- * Suppliess the data if cache to cache transfers are enabled.
- * @param pkt The bus transaction to fulfill.
- */
- void respondToSnoop(PacketPtr pkt, Tick time)
- {
- assert(time >= curTick);
- assert (pkt->needsResponse());
-/* CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
- reqMem->schedule(time);
-*/
- if (memSidePort->transmitList.empty()) {
- assert(!memSendEvent->scheduled());
- memSendEvent->schedule(time);
- memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
-
- // something is on the list and this belongs at the end
- if (time >= memSidePort->transmitList.back().first) {
- memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
- (time,pkt));
- return;
- }
- // Something is on the list and this belongs somewhere else
- std::list<std::pair<Tick,PacketPtr> >::iterator i =
- memSidePort->transmitList.begin();
- std::list<std::pair<Tick,PacketPtr> >::iterator end =
- memSidePort->transmitList.end();
- bool done = false;
-
- while (i != end && !done) {
- if (time < i->first) {
- if (i == memSidePort->transmitList.begin()) {
- //Inserting at begining, reschedule
- memSendEvent->reschedule(time);
- }
- memSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
- done = true;
- }
- i++;
- }
- }
-
- /**
- * Notification from master interface that a address range changed. Nothing
- * to do for a cache.
- */
- void rangeChange() {}
+ virtual unsigned int drain(Event *de);
- void getAddressRanges(AddrRangeList &resp, bool &snoop, bool isCpuSide)
- {
- if (isCpuSide)
- {
- bool dummy;
- memSidePort->getPeerAddressRanges(resp, dummy);
- }
- else
- {
- //This is where snoops get updated
- AddrRangeList dummy;
- snoop = true;
- }
- }
+ virtual bool inCache(Addr addr) = 0;
- virtual unsigned int drain(Event *de);
+ virtual bool inMissQueue(Addr addr) = 0;
- void checkDrain()
+ void incMissCount(PacketPtr pkt)
{
- if (drainEvent && canDrain()) {
- drainEvent->process();
- changeState(SimObject::Drained);
- // Clear the drain event
- drainEvent = NULL;
- }
- }
+ misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- bool canDrain()
- {
- if (doMasterRequest() || doSlaveRequest()) {
- return false;
- } else if (memSidePort && !memSidePort->canDrain()) {
- return false;
- } else if (cpuSidePort && !cpuSidePort->canDrain()) {
- return false;
+ if (missCount) {
+ --missCount;
+ if (missCount == 0)
+ exitSimLoop("A cache reached the maximum miss count");
}
- return true;
}
- virtual bool inCache(Addr addr) = 0;
-
- virtual bool inMissQueue(Addr addr) = 0;
};
#endif //__BASE_CACHE_HH__
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index cb4e7f62e..96f9a2e11 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -58,10 +58,6 @@
#include "mem/cache/tags/split_lifo.hh"
#endif
-#include "mem/cache/miss/miss_queue.hh"
-#include "mem/cache/miss/blocking_buffer.hh"
-
-#include "mem/cache/coherence/uni_coherence.hh"
#include "mem/cache/coherence/simple_coherence.hh"
#include "mem/cache/cache_impl.hh"
@@ -72,27 +68,22 @@
#if defined(USE_CACHE_FALRU)
template class Cache<FALRU, SimpleCoherence>;
-template class Cache<FALRU, UniCoherence>;
#endif
#if defined(USE_CACHE_IIC)
template class Cache<IIC, SimpleCoherence>;
-template class Cache<IIC, UniCoherence>;
#endif
#if defined(USE_CACHE_LRU)
template class Cache<LRU, SimpleCoherence>;
-template class Cache<LRU, UniCoherence>;
#endif
#if defined(USE_CACHE_SPLIT)
template class Cache<Split, SimpleCoherence>;
-template class Cache<Split, UniCoherence>;
#endif
#if defined(USE_CACHE_SPLIT_LIFO)
template class Cache<SplitLIFO, SimpleCoherence>;
-template class Cache<SplitLIFO, UniCoherence>;
#endif
#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 3e45c85d2..a93b761ec 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -28,6 +28,7 @@
* Authors: Erik Hallnor
* Dave Greene
* Steve Reinhardt
+ * Ron Dreslinski
*/
/**
@@ -44,10 +45,11 @@
#include "mem/cache/base_cache.hh"
#include "mem/cache/cache_blk.hh"
-#include "mem/cache/miss/miss_buffer.hh"
+#include "mem/cache/miss/mshr.hh"
+
+#include "sim/eventq.hh"
//Forward decleration
-class MSHR;
class BasePrefetcher;
/**
@@ -83,6 +85,9 @@ class Cache : public BaseCache
return static_cast<Cache<TagStore,Coherence> *>(cache);
}
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ bool &snoop);
+
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
@@ -103,17 +108,28 @@ class Cache : public BaseCache
return static_cast<Cache<TagStore,Coherence> *>(cache);
}
+ void sendPacket();
+
+ void processSendEvent();
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ bool &snoop);
+
virtual bool recvTiming(PacketPtr pkt);
+ virtual void recvRetry();
+
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
+
+ typedef EventWrapper<MemSidePort, &MemSidePort::processSendEvent>
+ SendEvent;
};
/** Tag and data Storage */
TagStore *tags;
- /** Miss and Writeback handler */
- MissBuffer *missQueue;
+
/** Coherence protocol. */
Coherence *coherence;
@@ -121,40 +137,6 @@ class Cache : public BaseCache
BasePrefetcher *prefetcher;
/**
- * The clock ratio of the outgoing bus.
- * Used for calculating critical word first.
- */
- int busRatio;
-
- /**
- * The bus width in bytes of the outgoing bus.
- * Used for calculating critical word first.
- */
- int busWidth;
-
- /**
- * The latency of a hit in this device.
- */
- int hitLatency;
-
- /**
- * A permanent mem req to always be used to cause invalidations.
- * Used to append to target list, to cause an invalidation.
- */
- PacketPtr invalidatePkt;
- Request *invalidateReq;
-
- /**
- * Policy class for performing compression.
- */
- CompressionAlgorithm *compressionAlg;
-
- /**
- * The block size of this cache. Set to value in the Tags object.
- */
- const int16_t blkSize;
-
- /**
* Can this cache should allocate a block on a line-sized write miss.
*/
const bool doFastWrites;
@@ -162,57 +144,13 @@ class Cache : public BaseCache
const bool prefetchMiss;
/**
- * Can the data can be stored in a compressed form.
- */
- const bool storeCompressed;
-
- /**
- * Do we need to compress blocks on writebacks (i.e. because
- * writeback bus is compressed but storage is not)?
- */
- const bool compressOnWriteback;
-
- /**
- * The latency of a compression operation.
- */
- const int16_t compLatency;
-
- /**
- * Should we use an adaptive compression scheme.
- */
- const bool adaptiveCompression;
-
- /**
- * Do writebacks need to be compressed (i.e. because writeback bus
- * is compressed), whether or not they're already compressed for
- * storage.
- */
- const bool writebackCompressed;
-
- /**
- * Compare the internal block data to the fast access block data.
- * @param blk The cache block to check.
- * @return True if the data is the same.
- */
- bool verifyData(BlkType *blk);
-
- /**
- * Update the internal data of the block. The data to write is assumed to
- * be in the fast access data.
- * @param blk The block with the data to update.
- * @param writebacks A list to store any generated writebacks.
- * @param compress_block True if we should compress this block
- */
- void updateData(BlkType *blk, PacketList &writebacks, bool compress_block);
-
- /**
* Handle a replacement for the given request.
* @param blk A pointer to the block, usually NULL
* @param pkt The memory request to satisfy.
* @param new_state The new state of the block.
* @param writebacks A list to store any generated writebacks.
*/
- BlkType* doReplacement(BlkType *blk, PacketPtr &pkt,
+ BlkType* doReplacement(BlkType *blk, PacketPtr pkt,
CacheBlk::State new_state, PacketList &writebacks);
/**
@@ -224,59 +162,38 @@ class Cache : public BaseCache
* @return Pointer to the cache block touched by the request. NULL if it
* was a miss.
*/
- BlkType* handleAccess(PacketPtr &pkt, int & lat,
- PacketList & writebacks, bool update = true);
-
+ bool access(PacketPtr pkt, BlkType *&blk, int &lat);
/**
*Handle doing the Compare and Swap function for SPARC.
*/
- void cmpAndSwap(BlkType *blk, PacketPtr &pkt);
-
- /**
- * Populates a cache block and handles all outstanding requests for the
- * satisfied fill request. This version takes an MSHR pointer and uses its
- * request to fill the cache block, while repsonding to its targets.
- * @param blk The cache block if it already exists.
- * @param mshr The MSHR that contains the fill data and targets to satisfy.
- * @param new_state The state of the new cache block.
- * @param writebacks List for any writebacks that need to be performed.
- * @return Pointer to the new cache block.
- */
- BlkType* handleFill(BlkType *blk, MSHR * mshr, CacheBlk::State new_state,
- PacketList & writebacks, PacketPtr pkt);
+ void cmpAndSwap(BlkType *blk, PacketPtr pkt);
/**
* Populates a cache block and handles all outstanding requests for the
* satisfied fill request. This version takes two memory requests. One
* contains the fill data, the other is an optional target to satisfy.
* Used for Cache::probe.
- * @param blk The cache block if it already exists.
* @param pkt The memory request with the fill data.
- * @param new_state The state of the new cache block.
+ * @param blk The cache block if it already exists.
* @param writebacks List for any writebacks that need to be performed.
- * @param target The memory request to perform after the fill.
* @return Pointer to the new cache block.
*/
- BlkType* handleFill(BlkType *blk, PacketPtr &pkt,
- CacheBlk::State new_state,
- PacketList & writebacks, PacketPtr target = NULL);
+ BlkType *handleFill(PacketPtr pkt, BlkType *blk,
+ PacketList &writebacks);
- /**
- * Sets the blk to the new state and handles the given request.
- * @param blk The cache block being snooped.
- * @param new_state The new coherence state for the block.
- * @param pkt The request to satisfy
- */
- void handleSnoop(BlkType *blk, CacheBlk::State new_state,
- PacketPtr &pkt);
+ bool satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk);
+ bool satisfyTarget(MSHR::Target *target, BlkType *blk);
+ bool satisfyMSHR(MSHR *mshr, PacketPtr pkt, BlkType *blk);
+
+ void doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data);
/**
* Sets the blk to the new state.
* @param blk The cache block being snooped.
* @param new_state The new coherence state for the block.
*/
- void handleSnoop(BlkType *blk, CacheBlk::State new_state);
+ void handleSnoop(PacketPtr ptk, BlkType *blk, bool is_timing);
/**
* Create a writeback request for the given block.
@@ -291,44 +208,24 @@ class Cache : public BaseCache
{
public:
TagStore *tags;
- MissBuffer *missQueue;
Coherence *coherence;
BaseCache::Params baseParams;
BasePrefetcher*prefetcher;
bool prefetchAccess;
- int hitLatency;
- CompressionAlgorithm *compressionAlg;
- const int16_t blkSize;
const bool doFastWrites;
const bool prefetchMiss;
- const bool storeCompressed;
- const bool compressOnWriteback;
- const int16_t compLatency;
- const bool adaptiveCompression;
- const bool writebackCompressed;
- Params(TagStore *_tags, MissBuffer *mq, Coherence *coh,
+ Params(TagStore *_tags, Coherence *coh,
BaseCache::Params params,
BasePrefetcher *_prefetcher,
bool prefetch_access, int hit_latency,
bool do_fast_writes,
- bool store_compressed, bool adaptive_compression,
- bool writeback_compressed,
- CompressionAlgorithm *_compressionAlg, int comp_latency,
bool prefetch_miss)
- : tags(_tags), missQueue(mq), coherence(coh),
+ : tags(_tags), coherence(coh),
baseParams(params),
prefetcher(_prefetcher), prefetchAccess(prefetch_access),
- hitLatency(hit_latency),
- compressionAlg(_compressionAlg),
- blkSize(_tags->getBlockSize()),
doFastWrites(do_fast_writes),
- prefetchMiss(prefetch_miss),
- storeCompressed(store_compressed),
- compressOnWriteback(!store_compressed && writeback_compressed),
- compLatency(comp_latency),
- adaptiveCompression(adaptive_compression),
- writebackCompressed(writeback_compressed)
+ prefetchMiss(prefetch_miss)
{
}
};
@@ -339,8 +236,6 @@ class Cache : public BaseCache
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void deletePortRefs(Port *p);
- virtual void recvStatusChange(Port::Status status, bool isCpuSide);
-
void regStats();
/**
@@ -348,98 +243,90 @@ class Cache : public BaseCache
* @param pkt The request to perform.
* @return The result of the access.
*/
- bool access(PacketPtr &pkt);
-
- /**
- * Selects a request to send on the bus.
- * @return The memory request to service.
- */
- virtual PacketPtr getPacket();
+ bool timingAccess(PacketPtr pkt);
/**
- * Was the request was sent successfully?
- * @param pkt The request.
- * @param success True if the request was sent successfully.
+ * Performs the access specified by the request.
+ * @param pkt The request to perform.
+ * @return The result of the access.
*/
- virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success);
+ Tick atomicAccess(PacketPtr pkt);
/**
- * Was the CSHR request was sent successfully?
- * @param pkt The request.
- * @param success True if the request was sent successfully.
+ * Performs the access specified by the request.
+ * @param pkt The request to perform.
+ * @return The result of the access.
*/
- virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* cshr, bool success);
+ void functionalAccess(PacketPtr pkt, CachePort *otherSidePort);
/**
* Handles a response (cache line fill/write ack) from the bus.
* @param pkt The request being responded to.
*/
- void handleResponse(PacketPtr &pkt);
-
- /**
- * Selects a coherence message to forward to lower levels of the hierarchy.
- * @return The coherence message to forward.
- */
- virtual PacketPtr getCoherencePacket();
+ void handleResponse(PacketPtr pkt);
/**
* Snoops bus transactions to maintain coherence.
* @param pkt The current bus transaction.
*/
- void snoop(PacketPtr &pkt);
+ void snoopTiming(PacketPtr pkt);
- void snoopResponse(PacketPtr &pkt);
+ /**
+ * Snoop for the provided request in the cache and return the estimated
+ * time of completion.
+ * @param pkt The memory request to snoop
+ * @return The estimated completion time.
+ */
+ Tick snoopAtomic(PacketPtr pkt);
/**
* Squash all requests associated with specified thread.
* intended for use by I-cache.
* @param threadNum The thread to squash.
*/
- void squash(int threadNum)
- {
- missQueue->squash(threadNum);
- }
+ void squash(int threadNum);
/**
- * Return the number of outstanding misses in a Cache.
- * Default returns 0.
- *
- * @retval unsigned The number of missing still outstanding.
+ * Selects a outstanding request to service.
+ * @return The request to service, NULL if none found.
*/
- unsigned outstandingMisses() const
- {
- return missQueue->getMisses();
- }
+ PacketPtr getBusPacket(PacketPtr cpu_pkt, BlkType *blk,
+ bool needsExclusive);
+ MSHR *getNextMSHR();
+ PacketPtr getTimingPacket();
/**
- * Perform the access specified in the request and return the estimated
- * time of completion. This function can either update the hierarchy state
- * or just perform the access wherever the data is found depending on the
- * state of the update flag.
- * @param pkt The memory request to satisfy
- * @param update If true, update the hierarchy, otherwise just perform the
- * request.
- * @return The estimated completion time.
+ * Marks a request as in service (sent on the bus). This can have side
+ * effect since storage for no response commands is deallocated once they
+ * are successfully sent.
+ * @param pkt The request that was sent on the bus.
*/
- Tick probe(PacketPtr &pkt, bool update, CachePort * otherSidePort);
+ void markInService(MSHR *mshr);
/**
- * Snoop for the provided request in the cache and return the estimated
- * time of completion.
- * @todo Can a snoop probe not change state?
- * @param pkt The memory request to satisfy
- * @param update If true, update the hierarchy, otherwise just perform the
- * request.
- * @return The estimated completion time.
+ * Perform the given writeback request.
+ * @param pkt The writeback request.
*/
- Tick snoopProbe(PacketPtr &pkt);
+ void doWriteback(PacketPtr pkt);
+
+ /**
+ * Return whether there are any outstanding misses.
+ */
+ bool outstandingMisses() const
+ {
+ return mshrQueue.allocated != 0;
+ }
+
+ CacheBlk *findBlock(Addr addr) {
+ return tags->findBlock(addr);
+ }
bool inCache(Addr addr) {
return (tags->findBlock(addr) != 0);
}
bool inMissQueue(Addr addr) {
- return (missQueue->findMSHR(addr) != 0);
+ return (mshrQueue.findMatch(addr) != 0);
}
};
diff --git a/src/mem/cache/cache_blk.hh b/src/mem/cache/cache_blk.hh
index fa00a0f5a..d2aba9480 100644
--- a/src/mem/cache/cache_blk.hh
+++ b/src/mem/cache/cache_blk.hh
@@ -39,6 +39,7 @@
#include "sim/core.hh" // for Tick
#include "arch/isa_traits.hh" // for Addr
+#include "mem/packet.hh"
#include "mem/request.hh"
/**
@@ -51,8 +52,6 @@ enum CacheBlkStatusBits {
BlkWritable = 0x02,
/** dirty (modified) */
BlkDirty = 0x04,
- /** compressed */
- BlkCompressed = 0x08,
/** block was referenced */
BlkReferenced = 0x10,
/** block was a hardware prefetch yet unaccessed*/
@@ -174,21 +173,12 @@ class CacheBlk
* Check to see if a block has been written.
* @return True if the block is dirty.
*/
- bool isModified() const
+ bool isDirty() const
{
return (status & BlkDirty) != 0;
}
/**
- * Check to see if this block contains compressed data.
- * @return True iF the block's data is compressed.
- */
- bool isCompressed() const
- {
- return (status & BlkCompressed) != 0;
- }
-
- /**
* Check if this block has been referenced.
* @return True if the block has been referenced.
*/
@@ -213,10 +203,10 @@ class CacheBlk
* redundant records on the list, but that's OK, as they'll all
* get blown away at the next store.
*/
- void trackLoadLocked(Request *req)
+ void trackLoadLocked(PacketPtr pkt)
{
- assert(req->isLocked());
- lockList.push_front(Lock(req));
+ assert(pkt->isLocked());
+ lockList.push_front(Lock(pkt->req));
}
/**
@@ -230,9 +220,10 @@ class CacheBlk
* @return True if write should proceed, false otherwise. Returns
* false only in the case of a failed store conditional.
*/
- bool checkWrite(Request *req)
+ bool checkWrite(PacketPtr pkt)
{
- if (req->isLocked()) {
+ Request *req = pkt->req;
+ if (pkt->isLocked()) {
// it's a store conditional... have to check for matching
// load locked.
bool success = false;
diff --git a/src/mem/cache/cache_builder.cc b/src/mem/cache/cache_builder.cc
index e887f711e..307c851a2 100644
--- a/src/mem/cache/cache_builder.cc
+++ b/src/mem/cache/cache_builder.cc
@@ -70,12 +70,7 @@
#include "base/compression/null_compression.hh"
#include "base/compression/lzss_compression.hh"
-// MissQueue Templates
-#include "mem/cache/miss/miss_queue.hh"
-#include "mem/cache/miss/blocking_buffer.hh"
-
// Coherence Templates
-#include "mem/cache/coherence/uni_coherence.hh"
#include "mem/cache/coherence/simple_coherence.hh"
//Prefetcher Headers
@@ -208,13 +203,9 @@ END_INIT_SIM_OBJECT_PARAMS(BaseCache)
else { \
BUILD_NULL_PREFETCHER(TAGS); \
} \
- Cache<TAGS, c>::Params params(tags, mq, coh, base_params, \
+ Cache<TAGS, c>::Params params(tags, coh, base_params, \
pf, prefetch_access, latency, \
true, \
- store_compressed, \
- adaptive_compression, \
- compressed_bus, \
- compAlg, compression_latency, \
prefetch_miss); \
Cache<TAGS, c> *retval = \
new Cache<TAGS, c>(getInstanceName(), params); \
@@ -302,13 +293,6 @@ END_INIT_SIM_OBJECT_PARAMS(BaseCache)
} while (0)
#define BUILD_COHERENCE(b) do { \
- if (protocol == NULL) { \
- UniCoherence *coh = new UniCoherence(); \
- BUILD_CACHES(UniCoherence); \
- } else { \
- SimpleCoherence *coh = new SimpleCoherence(protocol); \
- BUILD_CACHES(SimpleCoherence); \
- } \
} while (0)
#if defined(USE_TAGGED)
@@ -375,8 +359,9 @@ CREATE_SIM_OBJECT(BaseCache)
}
// Build BaseCache param object
- BaseCache::Params base_params(addr_range, latency,
- block_size, max_miss_count);
+ BaseCache::Params base_params(latency, block_size,
+ mshrs, tgts_per_mshr, write_buffers,
+ max_miss_count);
//Warnings about prefetcher policy
if (pf_policy == "none" && (prefetch_miss || prefetch_access)) {
@@ -414,14 +399,8 @@ CREATE_SIM_OBJECT(BaseCache)
const void *repl = NULL;
#endif
- if (mshrs == 1 /*|| out_bus->doEvents() == false*/) {
- BlockingBuffer *mq = new BlockingBuffer(true);
- BUILD_COHERENCE(BlockingBuffer);
- } else {
- MissQueue *mq = new MissQueue(mshrs, tgts_per_mshr, write_buffers,
- true, prefetch_miss);
- BUILD_COHERENCE(MissQueue);
- }
+ SimpleCoherence *coh = new SimpleCoherence(protocol);
+ BUILD_CACHES(SimpleCoherence);
return NULL;
}
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 9b094c1e3..0649b5061 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -28,6 +28,8 @@
* Authors: Erik Hallnor
* Dave Greene
* Nathan Binkert
+ * Steve Reinhardt
+ * Ron Dreslinski
*/
/**
@@ -35,17 +37,8 @@
* Cache definitions.
*/
-#include <assert.h>
-#include <math.h>
-
-#include <cassert>
-#include <iostream>
-#include <cstring>
-#include <string>
-
#include "sim/host.hh"
#include "base/misc.hh"
-#include "cpu/smt.hh"
#include "mem/cache/cache.hh"
#include "mem/cache/cache_blk.hh"
@@ -54,43 +47,25 @@
#include "sim/sim_exit.hh" // for SimExitEvent
-bool SIGNAL_NACK_HACK;
-
-template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::
-recvStatusChange(Port::Status status, bool isCpuSide)
-{
-
-}
-
template<class TagStore, class Coherence>
-Cache<TagStore,Coherence>::
-Cache(const std::string &_name,
- Cache<TagStore,Coherence>::Params &params)
+Cache<TagStore,Coherence>::Cache(const std::string &_name,
+ Cache<TagStore,Coherence>::Params &params)
: BaseCache(_name, params.baseParams),
prefetchAccess(params.prefetchAccess),
- tags(params.tags), missQueue(params.missQueue),
+ tags(params.tags),
coherence(params.coherence), prefetcher(params.prefetcher),
- hitLatency(params.hitLatency),
- compressionAlg(params.compressionAlg),
- blkSize(params.blkSize),
doFastWrites(params.doFastWrites),
- prefetchMiss(params.prefetchMiss),
- storeCompressed(params.storeCompressed),
- compressOnWriteback(params.compressOnWriteback),
- compLatency(params.compLatency),
- adaptiveCompression(params.adaptiveCompression),
- writebackCompressed(params.writebackCompressed)
+ prefetchMiss(params.prefetchMiss)
{
+ cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this);
+ memSidePort = new MemSidePort(_name + "-mem_side_port", this);
+ cpuSidePort->setOtherPort(memSidePort);
+ memSidePort->setOtherPort(cpuSidePort);
+
tags->setCache(this);
- missQueue->setCache(this);
- missQueue->setPrefetcher(prefetcher);
coherence->setCache(this);
prefetcher->setCache(this);
- invalidateReq = new Request((Addr) NULL, blkSize, 0);
- invalidatePkt = new Packet(invalidateReq, MemCmd::InvalidateReq, 0);
}
template<class TagStore, class Coherence>
@@ -99,51 +74,154 @@ Cache<TagStore,Coherence>::regStats()
{
BaseCache::regStats();
tags->regStats(name());
- missQueue->regStats(name());
coherence->regStats(name());
prefetcher->regStats(name());
}
template<class TagStore, class Coherence>
-typename Cache<TagStore,Coherence>::BlkType*
-Cache<TagStore,Coherence>::handleAccess(PacketPtr &pkt, int & lat,
- PacketList & writebacks, bool update)
+Port *
+Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx)
{
- // Set the block offset here
- int offset = tags->extractBlkOffset(pkt->getAddr());
-
- BlkType *blk = NULL;
- if (update) {
- blk = tags->findBlock(pkt->getAddr(), lat);
+ if (if_name == "" || if_name == "cpu_side") {
+ return cpuSidePort;
+ } else if (if_name == "mem_side") {
+ return memSidePort;
+ } else if (if_name == "functional") {
+ return new CpuSidePort(name() + "-cpu_side_funcport", this);
} else {
- blk = tags->findBlock(pkt->getAddr());
- lat = 0;
+ panic("Port name %s unrecognized\n", if_name);
}
- if (blk != NULL) {
+}
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::deletePortRefs(Port *p)
+{
+ if (cpuSidePort == p || memSidePort == p)
+ panic("Can only delete functional ports\n");
- if (!update) {
+ delete p;
+}
- if (pkt->isWrite()){
- assert(offset < blkSize);
- assert(pkt->getSize() <= blkSize);
- assert(offset+pkt->getSize() <= blkSize);
- std::memcpy(blk->data + offset, pkt->getPtr<uint8_t>(),
- pkt->getSize());
- } else if (pkt->isReadWrite()) {
- cmpAndSwap(blk, pkt);
- } else if (!(pkt->flags & SATISFIED)) {
- pkt->flags |= SATISFIED;
- pkt->result = Packet::Success;
- assert(offset < blkSize);
- assert(pkt->getSize() <= blkSize);
- assert(offset + pkt->getSize() <=blkSize);
- std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
- pkt->getSize());
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::cmpAndSwap(BlkType *blk, PacketPtr pkt)
+{
+ uint64_t overwrite_val;
+ bool overwrite_mem;
+ uint64_t condition_val64;
+ uint32_t condition_val32;
+
+ int offset = tags->extractBlkOffset(pkt->getAddr());
+ uint8_t *blk_data = blk->data + offset;
+
+ assert(sizeof(uint64_t) >= pkt->getSize());
+
+ overwrite_mem = true;
+ // keep a copy of our possible write value, and copy what is at the
+ // memory address into the packet
+ pkt->writeData((uint8_t *)&overwrite_val);
+ pkt->setData(blk_data);
+
+ if (pkt->req->isCondSwap()) {
+ if (pkt->getSize() == sizeof(uint64_t)) {
+ condition_val64 = pkt->req->getExtraData();
+ overwrite_mem = !std::memcmp(&condition_val64, blk_data,
+ sizeof(uint64_t));
+ } else if (pkt->getSize() == sizeof(uint32_t)) {
+ condition_val32 = (uint32_t)pkt->req->getExtraData();
+ overwrite_mem = !std::memcmp(&condition_val32, blk_data,
+ sizeof(uint32_t));
+ } else
+ panic("Invalid size for conditional read/write\n");
+ }
+
+ if (overwrite_mem)
+ std::memcpy(blk_data, &overwrite_val, pkt->getSize());
+}
+
+
+/////////////////////////////////////////////////////
+//
+// MSHR helper functions
+//
+/////////////////////////////////////////////////////
+
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::markInService(MSHR *mshr)
+{
+ markInServiceInternal(mshr);
+#if 0
+ if (mshr->originalCmd == MemCmd::HardPFReq) {
+ DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n",
+ name());
+ //Also clear pending if need be
+ if (!prefetcher->havePending())
+ {
+ deassertMemSideBusRequest(Request_PF);
}
- return blk;
}
+#endif
+}
+
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::squash(int threadNum)
+{
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (noTargetMSHR && noTargetMSHR->threadNum == threadNum) {
+ noTargetMSHR = NULL;
+ unblock = true;
+ cause = Blocked_NoTargets;
+ }
+ if (mshrQueue.isFull()) {
+ unblock = true;
+ cause = Blocked_NoMSHRs;
+ }
+ mshrQueue.squash(threadNum);
+ if (!mshrQueue.havePending()) {
+ deassertMemSideBusRequest(Request_MSHR);
+ }
+ if (unblock && !mshrQueue.isFull()) {
+ clearBlocked(cause);
+ }
+}
+
+/////////////////////////////////////////////////////
+//
+// Access path: requests coming in from the CPU side
+//
+/////////////////////////////////////////////////////
- // Hit
+template<class TagStore, class Coherence>
+bool
+Cache<TagStore,Coherence>::access(PacketPtr pkt, BlkType *&blk, int &lat)
+{
+ if (pkt->req->isUncacheable()) {
+ blk = NULL;
+ lat = hitLatency;
+ return false;
+ }
+
+ bool satisfied = false; // assume the worst
+ blk = tags->findBlock(pkt->getAddr(), lat);
+
+ if (prefetchAccess) {
+ //We are determining prefetches on access stream, call prefetcher
+ prefetcher->handleMiss(pkt, curTick);
+ }
+
+ DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(), pkt->getAddr(),
+ (blk) ? "hit" : "miss");
+
+ if (blk != NULL) {
+ // HIT
if (blk->isPrefetch()) {
//Signal that this was a hit under prefetch (no need for
//use prefetch (only can get here if true)
@@ -157,652 +235,641 @@ Cache<TagStore,Coherence>::handleAccess(PacketPtr &pkt, int & lat,
}
}
- if ((pkt->isReadWrite() && blk->isWritable()) ||
- (pkt->isWrite() && blk->isWritable()) ||
- (pkt->isRead() && blk->isValid())) {
-
- // We are satisfying the request
- pkt->flags |= SATISFIED;
-
- if (blk->isCompressed()) {
- // If the data is compressed, need to increase the latency
- lat += (compLatency/4);
- }
-
- bool write_data = false;
-
- assert(verifyData(blk));
-
- assert(offset < blkSize);
- assert(pkt->getSize() <= blkSize);
- assert(offset+pkt->getSize() <= blkSize);
+ if (pkt->needsExclusive() ? blk->isWritable() : blk->isValid()) {
+ // OK to satisfy access
+ hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ satisfied = true;
- if (pkt->isWrite()) {
- if (blk->checkWrite(pkt->req)) {
- write_data = true;
+ // Check RMW operations first since both isRead() and
+ // isWrite() will be true for them
+ if (pkt->cmd == MemCmd::SwapReq) {
+ cmpAndSwap(blk, pkt);
+ } else if (pkt->isWrite()) {
+ if (blk->checkWrite(pkt)) {
blk->status |= BlkDirty;
- std::memcpy(blk->data + offset, pkt->getPtr<uint8_t>(),
- pkt->getSize());
+ pkt->writeDataToBlock(blk->data, blkSize);
}
- } else if (pkt->isReadWrite()) {
- cmpAndSwap(blk, pkt);
- } else {
- assert(pkt->isRead());
- if (pkt->req->isLocked()) {
- blk->trackLoadLocked(pkt->req);
+ } else if (pkt->isRead()) {
+ if (pkt->isLocked()) {
+ blk->trackLoadLocked(pkt);
}
- std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
- pkt->getSize());
- }
-
- if (write_data ||
- (adaptiveCompression && blk->isCompressed()))
- {
- // If we wrote data, need to update the internal block
- // data.
- updateData(blk, writebacks,
- !(adaptiveCompression &&
- blk->isReferenced()));
+ pkt->setDataFromBlock(blk->data, blkSize);
+ } else {
+ // Not a read or write... must be an upgrade. it's OK
+ // to just ack those as long as we have an exclusive
+ // copy at this level.
+ assert(pkt->cmd == MemCmd::UpgradeReq);
}
} else {
- // permission violation, treat it as a miss
- blk = NULL;
+ // permission violation... nothing to do here, leave unsatisfied
+ // for statistics purposes this counts like a complete miss
+ incMissCount(pkt);
}
} else {
// complete miss (no matching block)
- if (pkt->req->isLocked() && pkt->isWrite()) {
+ incMissCount(pkt);
+
+ if (pkt->isLocked() && pkt->isWrite()) {
// miss on store conditional... just give up now
pkt->req->setExtraData(0);
- pkt->flags |= SATISFIED;
+ satisfied = true;
}
}
- return blk;
+ return satisfied;
}
-template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::cmpAndSwap(BlkType *blk, PacketPtr &pkt){
- uint64_t overwrite_val;
- bool overwrite_mem;
- uint64_t condition_val64;
- uint32_t condition_val32;
-
- int offset = tags->extractBlkOffset(pkt->getAddr());
-
- assert(sizeof(uint64_t) >= pkt->getSize());
-
- overwrite_mem = true;
- // keep a copy of our possible write value, and copy what is at the
- // memory address into the packet
- std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
- std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
- pkt->getSize());
-
- if (pkt->req->isCondSwap()) {
- if (pkt->getSize() == sizeof(uint64_t)) {
- condition_val64 = pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val64, blk->data + offset,
- sizeof(uint64_t));
- } else if (pkt->getSize() == sizeof(uint32_t)) {
- condition_val32 = (uint32_t)pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val32, blk->data + offset,
- sizeof(uint32_t));
- } else
- panic("Invalid size for conditional read/write\n");
- }
-
- if (overwrite_mem)
- std::memcpy(blk->data + offset,
- &overwrite_val, pkt->getSize());
-
-}
template<class TagStore, class Coherence>
-typename Cache<TagStore,Coherence>::BlkType*
-Cache<TagStore,Coherence>::handleFill(BlkType *blk, PacketPtr &pkt,
- CacheBlk::State new_state,
- PacketList & writebacks,
- PacketPtr target)
+bool
+Cache<TagStore,Coherence>::timingAccess(PacketPtr pkt)
{
-#ifndef NDEBUG
- BlkType *tmp_blk = tags->findBlock(pkt->getAddr());
- assert(tmp_blk == blk);
-#endif
- blk = doReplacement(blk, pkt, new_state, writebacks);
+//@todo Add back in MemDebug Calls
+// MemDebug::cacheAccess(pkt);
+ // we charge hitLatency for doing just about anything here
+ Tick time = curTick + hitLatency;
- if (pkt->isRead()) {
- std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(Cache, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ assert(!pkt->req->isUncacheable());
+ return true;
}
- blk->whenReady = pkt->finishTime;
+ if (pkt->req->isUncacheable()) {
+ allocateBuffer(pkt, time, true);
+ assert(pkt->needsResponse()); // else we should delete it here??
+ return true;
+ }
- // Respond to target, if any
- if (target) {
+ PacketList writebacks;
+ int lat = hitLatency;
+ bool satisfied = false;
- target->flags |= SATISFIED;
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ MSHR *mshr = mshrQueue.findMatch(blk_addr);
+
+ if (!mshr) {
+ // no outstanding access to this block, look up in cache
+ // (otherwise if we allow reads while there's an outstanding
+ // write miss, the read could return stale data out of the
+ // cache block... a more aggressive system could detect the
+ // overlap (if any) and forward data out of the MSHRs, but we
+ // don't do that yet)
+ BlkType *blk = NULL;
+ satisfied = access(pkt, blk, lat);
+ }
- if (target->cmd == MemCmd::InvalidateReq) {
- tags->invalidateBlk(blk);
- blk = NULL;
+#if 0
+ // If this is a block size write/hint (WH64) allocate the block here
+ // if the coherence protocol allows it.
+ /** @todo make the fast write alloc (wh64) work with coherence. */
+ /** @todo Do we want to do fast writes for writebacks as well? */
+ if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
+ (pkt->cmd == MemCmd::WriteReq
+ || pkt->cmd == MemCmd::WriteInvalidateReq) ) {
+ // not outstanding misses, can do this
+ MSHR *outstanding_miss = mshrQueue.findMatch(pkt->getAddr());
+ if (pkt->cmd == MemCmd::WriteInvalidateReq || !outstanding_miss) {
+ if (outstanding_miss) {
+ warn("WriteInv doing a fastallocate"
+ "with an outstanding miss to the same address\n");
+ }
+ blk = handleFill(NULL, pkt, BlkValid | BlkWritable,
+ writebacks);
+ ++fastWrites;
}
+ }
+#endif
- if (blk && ((target->isWrite() || target->isReadWrite()) ?
- blk->isWritable() : blk->isValid())) {
- assert(target->isWrite() || target->isReadWrite() || target->isRead());
- assert(target->getOffset(blkSize) + target->getSize() <= blkSize);
- if (target->isWrite()) {
- if (blk->checkWrite(pkt->req)) {
- blk->status |= BlkDirty;
- std::memcpy(blk->data + target->getOffset(blkSize),
- target->getPtr<uint8_t>(), target->getSize());
- }
- } else if (target->isReadWrite()) {
- cmpAndSwap(blk, target);
- } else {
- if (pkt->req->isLocked()) {
- blk->trackLoadLocked(pkt->req);
- }
- std::memcpy(target->getPtr<uint8_t>(),
- blk->data + target->getOffset(blkSize),
- target->getSize());
+ // copy writebacks to write buffer
+ while (!writebacks.empty()) {
+ PacketPtr wbPkt = writebacks.front();
+ allocateBuffer(wbPkt, time, true);
+ writebacks.pop_front();
+ }
+
+ bool needsResponse = pkt->needsResponse();
+
+ if (satisfied) {
+ assert(needsResponse);
+ pkt->makeTimingResponse();
+ cpuSidePort->respond(pkt, curTick+lat);
+ } else {
+ // miss
+ if (prefetchMiss)
+ prefetcher->handleMiss(pkt, time);
+
+ if (mshr) {
+ // MSHR hit
+ //@todo remove hw_pf here
+ mshr_hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) {
+ mshr->threadNum = -1;
+ }
+ mshr->allocateTarget(pkt, true);
+ if (mshr->getNumTargets() == numTarget) {
+ noTargetMSHR = mshr;
+ setBlocked(Blocked_NoTargets);
+ mshrQueue.moveToFront(mshr);
}
+ } else {
+ // no MSHR
+ mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ // always mark as cache fill for now... if we implement
+ // no-write-allocate or bypass accesses this will have to
+ // be changed.
+ allocateMissBuffer(pkt, time, true);
}
}
- if (blk) {
- // Need to write the data into the block
- updateData(blk, writebacks, !adaptiveCompression || true);
+ if (!needsResponse) {
+ // Need to clean up the packet on a writeback miss, but leave
+ // the request for the next level.
+ delete pkt;
}
- return blk;
+
+ return true;
}
+
template<class TagStore, class Coherence>
-typename Cache<TagStore,Coherence>::BlkType*
-Cache<TagStore,Coherence>::handleFill(BlkType *blk, MSHR * mshr,
- CacheBlk::State new_state,
- PacketList & writebacks, PacketPtr pkt)
+PacketPtr
+Cache<TagStore,Coherence>::getBusPacket(PacketPtr cpu_pkt, BlkType *blk,
+ bool needsExclusive)
{
-/*
-#ifndef NDEBUG
- BlkType *tmp_blk = findBlock(mshr->pkt->getAddr());
- assert(tmp_blk == blk);
-#endif
- PacketPtr pkt = mshr->pkt;*/
- blk = doReplacement(blk, pkt, new_state, writebacks);
+ bool blkValid = blk && blk->isValid();
- if (pkt->isRead()) {
- std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
+ if (cpu_pkt->req->isUncacheable()) {
+ assert(blk == NULL);
+ return NULL;
}
- blk->whenReady = pkt->finishTime;
+ if (!blkValid &&
+ (cpu_pkt->cmd == MemCmd::Writeback ||
+ cpu_pkt->cmd == MemCmd::UpgradeReq)) {
+ // For now, writebacks from upper-level caches that
+ // completely miss in the cache just go through. If we had
+ // "fast write" support (where we could write the whole
+ // block w/o fetching new data) we might want to allocate
+ // on writeback misses instead.
+ return NULL;
+ }
+ assert(cpu_pkt->needsResponse());
- // respond to MSHR targets, if any
+ MemCmd cmd;
+ const bool useUpgrades = true;
+ if (blkValid && useUpgrades) {
+ // only reason to be here is that blk is shared
+ // (read-only) and we need exclusive
+ assert(needsExclusive && !blk->isWritable());
+ cmd = MemCmd::UpgradeReq;
+ } else {
+ // block is invalid
+ cmd = needsExclusive ? MemCmd::ReadExReq : MemCmd::ReadReq;
+ }
+ PacketPtr pkt = new Packet(cpu_pkt->req, cmd, Packet::Broadcast, blkSize);
- // First offset for critical word first calculations
- int initial_offset = 0;
+ pkt->allocate();
+ return pkt;
+}
- if (mshr->hasTargets()) {
- initial_offset = mshr->getTarget()->getOffset(blkSize);
+
+template<class TagStore, class Coherence>
+Tick
+Cache<TagStore,Coherence>::atomicAccess(PacketPtr pkt)
+{
+ int lat = hitLatency;
+
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(Cache, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ assert(!pkt->req->isUncacheable());
+ return lat;
}
- while (mshr->hasTargets()) {
- PacketPtr target = mshr->getTarget();
+ // should assert here that there are no outstanding MSHRs or
+ // writebacks... that would mean that someone used an atomic
+ // access in timing mode
- target->flags |= SATISFIED;
+ BlkType *blk = NULL;
- // How many bytes pass the first request is this one
- int transfer_offset = target->getOffset(blkSize) - initial_offset;
- if (transfer_offset < 0) {
- transfer_offset += blkSize;
+ if (!access(pkt, blk, lat)) {
+ // MISS
+ PacketPtr busPkt = getBusPacket(pkt, blk, pkt->needsExclusive());
+
+ bool isCacheFill = (busPkt != NULL);
+
+ if (busPkt == NULL) {
+ // just forwarding the same request to the next level
+ // no local cache operation involved
+ busPkt = pkt;
}
- // If critical word (no offset) return first word time
- Tick completion_time = tags->getHitLatency() +
- transfer_offset ? pkt->finishTime : pkt->firstWordTime;
+ DPRINTF(Cache, "Sending an atomic %s for %x\n",
+ busPkt->cmdString(), busPkt->getAddr());
- if (target->cmd == MemCmd::InvalidateReq) {
- //Mark the blk as invalid now, if it hasn't been already
- if (blk) {
- tags->invalidateBlk(blk);
- blk = NULL;
- }
+#if TRACING_ON
+ CacheBlk::State old_state = blk ? blk->status : 0;
+#endif
- //Also get rid of the invalidate
- mshr->popTarget();
+ lat += memSidePort->sendAtomic(busPkt);
- DPRINTF(Cache, "Popping off a Invalidate for addr %x\n",
- pkt->getAddr());
+ DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
+ busPkt->cmdString(), busPkt->getAddr(), old_state);
- continue;
- }
+ if (isCacheFill) {
+ PacketList writebacks;
+ blk = handleFill(busPkt, blk, writebacks);
+ bool status = satisfyCpuSideRequest(pkt, blk);
+ assert(status);
+ delete busPkt;
- if (blk && ((target->isWrite() || target->isReadWrite()) ?
- blk->isWritable() : blk->isValid())) {
- assert(target->isWrite() || target->isRead() || target->isReadWrite() );
- assert(target->getOffset(blkSize) + target->getSize() <= blkSize);
- if (target->isWrite()) {
- if (blk->checkWrite(pkt->req)) {
- blk->status |= BlkDirty;
- std::memcpy(blk->data + target->getOffset(blkSize),
- target->getPtr<uint8_t>(), target->getSize());
- }
- } else if (target->isReadWrite()) {
- cmpAndSwap(blk, target);
- } else {
- if (target->req->isLocked()) {
- blk->trackLoadLocked(target->req);
- }
- std::memcpy(target->getPtr<uint8_t>(),
- blk->data + target->getOffset(blkSize),
- target->getSize());
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ PacketPtr wbPkt = writebacks.front();
+ memSidePort->sendAtomic(wbPkt);
+ writebacks.pop_front();
+ delete wbPkt;
}
- } else {
- // Invalid access, need to do another request
- // can occur if block is invalidated, or not correct
- // permissions
-// mshr->pkt = pkt;
- break;
}
- respondToMiss(target, completion_time);
- mshr->popTarget();
}
- if (blk) {
- // Need to write the data into the block
- updateData(blk, writebacks, !adaptiveCompression || true);
+ // We now have the block one way or another (hit or completed miss)
+
+ if (pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
+ pkt->result = Packet::Success;
}
- return blk;
+ return lat;
}
template<class TagStore, class Coherence>
void
-Cache<TagStore,Coherence>::handleSnoop(BlkType *blk,
- CacheBlk::State new_state,
- PacketPtr &pkt)
+Cache<TagStore,Coherence>::functionalAccess(PacketPtr pkt,
+ CachePort *otherSidePort)
{
- //Must have the block to supply
- assert(blk);
- // Can only supply data, and if it hasn't already been supllied
- assert(pkt->isRead());
- assert(!(pkt->flags & SATISFIED));
- pkt->flags |= SATISFIED;
- Addr offset = pkt->getOffset(blkSize);
- assert(offset < blkSize);
- assert(pkt->getSize() <= blkSize);
- assert(offset + pkt->getSize() <=blkSize);
- std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset, pkt->getSize());
-
- handleSnoop(blk, new_state);
-}
+ Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
+ BlkType *blk = tags->findBlock(pkt->getAddr());
-template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::handleSnoop(BlkType *blk,
- CacheBlk::State new_state)
-{
- if (blk && blk->status != new_state) {
- if ((new_state && BlkValid) == 0) {
- tags->invalidateBlk(blk);
- } else {
- assert(new_state >= 0 && new_state < 128);
- blk->status = new_state;
+ if (blk && pkt->checkFunctional(blk_addr, blkSize, blk->data)) {
+ // request satisfied from block
+ return;
+ }
+
+ // Need to check for outstanding misses and writes
+
+ // There can only be one matching outstanding miss.
+ MSHR *mshr = mshrQueue.findMatch(blk_addr);
+ if (mshr) {
+ MSHR::TargetList *targets = mshr->getTargetList();
+ MSHR::TargetList::iterator i = targets->begin();
+ MSHR::TargetList::iterator end = targets->end();
+ for (; i != end; ++i) {
+ PacketPtr targetPkt = i->pkt;
+ if (pkt->checkFunctional(targetPkt))
+ return;
}
}
-}
-template<class TagStore, class Coherence>
-PacketPtr
-Cache<TagStore,Coherence>::writebackBlk(BlkType *blk)
-{
- assert(blk && blk->isValid() && blk->isModified());
- int data_size = blkSize;
- data_size = blk->size;
- if (compressOnWriteback) {
- // not already compressed
- // need to compress to ship it
- assert(data_size == blkSize);
- uint8_t *tmp_data = new uint8_t[blkSize];
- data_size = compressionAlg->compress(tmp_data,blk->data,
- data_size);
- delete [] tmp_data;
+ // There can be many matching outstanding writes.
+ std::vector<MSHR*> writes;
+ writeBuffer.findMatches(blk_addr, writes);
+ for (int i = 0; i < writes.size(); ++i) {
+ MSHR *mshr = writes[i];
+ if (pkt->checkFunctional(mshr->addr, mshr->size, mshr->writeData))
+ return;
}
-/* PacketPtr writeback =
- buildWritebackReq(tags->regenerateBlkAddr(blk->tag, blk->set),
- blk->asid, blkSize,
- blk->data, data_size);
-*/
+ otherSidePort->checkAndSendFunctional(pkt);
+}
- Request *writebackReq =
- new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0);
- PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback, -1);
- writeback->allocate();
- std::memcpy(writeback->getPtr<uint8_t>(),blk->data,blkSize);
- blk->status &= ~BlkDirty;
- return writeback;
-}
+/////////////////////////////////////////////////////
+//
+// Response handling: responses from the memory side
+//
+/////////////////////////////////////////////////////
template<class TagStore, class Coherence>
bool
-Cache<TagStore,Coherence>::verifyData(BlkType *blk)
+Cache<TagStore,Coherence>::satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk)
{
- bool retval;
- // The data stored in the blk
- uint8_t *blk_data = new uint8_t[blkSize];
- tags->readData(blk, blk_data);
- // Pointer for uncompressed data, assumed uncompressed
- uint8_t *tmp_data = blk_data;
- // The size of the data being stored, assumed uncompressed
- int data_size = blkSize;
-
- // If the block is compressed need to uncompress to access
- if (blk->isCompressed()){
- // Allocate new storage for the data
- tmp_data = new uint8_t[blkSize];
- data_size = compressionAlg->uncompress(tmp_data,blk_data, blk->size);
- assert(data_size == blkSize);
- // Don't need to keep blk_data around
- delete [] blk_data;
+ if (blk && (pkt->needsExclusive() ? blk->isWritable() : blk->isValid())) {
+ assert(pkt->isWrite() || pkt->isReadWrite() || pkt->isRead());
+ assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize);
+
+ if (pkt->isWrite()) {
+ if (blk->checkWrite(pkt)) {
+ blk->status |= BlkDirty;
+ pkt->writeDataToBlock(blk->data, blkSize);
+ }
+ } else if (pkt->isReadWrite()) {
+ cmpAndSwap(blk, pkt);
+ } else {
+ if (pkt->isLocked()) {
+ blk->trackLoadLocked(pkt);
+ }
+ pkt->setDataFromBlock(blk->data, blkSize);
+ }
+
+ return true;
} else {
- assert(blkSize == blk->size);
+ return false;
}
-
- retval = std::memcmp(tmp_data, blk->data, blkSize) == 0;
- delete [] tmp_data;
- return retval;
}
+
template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::updateData(BlkType *blk, PacketList &writebacks,
- bool compress_block)
+bool
+Cache<TagStore,Coherence>::satisfyTarget(MSHR::Target *target, BlkType *blk)
{
- if (storeCompressed && compress_block) {
- uint8_t *comp_data = new uint8_t[blkSize];
- int new_size = compressionAlg->compress(comp_data, blk->data, blkSize);
- if (new_size > (blkSize - tags->getSubBlockSize())){
- // no benefit to storing it compressed
- blk->status &= ~BlkCompressed;
- tags->writeData(blk, blk->data, blkSize,
- writebacks);
- } else {
- // Store the data compressed
- blk->status |= BlkCompressed;
- tags->writeData(blk, comp_data, new_size,
- writebacks);
- }
- delete [] comp_data;
- } else {
- blk->status &= ~BlkCompressed;
- tags->writeData(blk, blk->data, blkSize, writebacks);
- }
+ assert(target != NULL);
+ assert(target->isCpuSide());
+ return satisfyCpuSideRequest(target->pkt, blk);
}
template<class TagStore, class Coherence>
-typename Cache<TagStore,Coherence>::BlkType*
-Cache<TagStore,Coherence>::doReplacement(BlkType *blk, PacketPtr &pkt,
- CacheBlk::State new_state,
- PacketList &writebacks)
+bool
+Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
+ BlkType *blk)
{
- if (blk == NULL) {
- // need to do a replacement
- BlkList compress_list;
- blk = tags->findReplacement(pkt, writebacks, compress_list);
- while (adaptiveCompression && !compress_list.empty()) {
- updateData(compress_list.front(), writebacks, true);
- compress_list.pop_front();
+ // respond to MSHR targets, if any
+
+ // First offset for critical word first calculations
+ int initial_offset = 0;
+
+ if (mshr->hasTargets()) {
+ initial_offset = mshr->getTarget()->pkt->getOffset(blkSize);
+ }
+
+ while (mshr->hasTargets()) {
+ MSHR::Target *target = mshr->getTarget();
+
+ if (!satisfyTarget(target, blk)) {
+ // Invalid access, need to do another request
+ // can occur if block is invalidated, or not correct
+ // permissions
+ MSHRQueue *mq = mshr->queue;
+ mq->markPending(mshr);
+ mshr->order = order++;
+ requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
+ return false;
}
- if (blk->isValid()) {
- DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
- tags->regenerateBlkAddr(blk->tag,blk->set), pkt->getAddr(),
- (blk->isModified()) ? "writeback" : "clean");
- if (blk->isModified()) {
- // Need to write the data back
- writebacks.push_back(writebackBlk(blk));
- }
+
+ // How many bytes pass the first request is this one
+ int transfer_offset = target->pkt->getOffset(blkSize) - initial_offset;
+ if (transfer_offset < 0) {
+ transfer_offset += blkSize;
}
- blk->tag = tags->extractTag(pkt->getAddr(), blk);
- } else {
- // must be a status change
- // assert(blk->status != new_state);
- if (blk->status == new_state) warn("Changing state to same value\n");
+
+ // If critical word (no offset) return first word time
+ Tick completion_time = tags->getHitLatency() +
+ transfer_offset ? pkt->finishTime : pkt->firstWordTime;
+
+ if (!target->pkt->req->isUncacheable()) {
+ missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
+ completion_time - target->time;
+ }
+ target->pkt->makeTimingResponse();
+ cpuSidePort->respond(target->pkt, completion_time);
+ mshr->popTarget();
}
- blk->status = new_state;
- return blk;
+ return true;
}
template<class TagStore, class Coherence>
-bool
-Cache<TagStore,Coherence>::access(PacketPtr &pkt)
+void
+Cache<TagStore,Coherence>::handleResponse(PacketPtr pkt)
{
-//@todo Add back in MemDebug Calls
-// MemDebug::cacheAccess(pkt);
- BlkType *blk = NULL;
- PacketList writebacks;
- int size = blkSize;
- int lat = hitLatency;
- if (prefetchAccess) {
- //We are determining prefetches on access stream, call prefetcher
- prefetcher->handleMiss(pkt, curTick);
+ Tick time = curTick + hitLatency;
+ MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
+ assert(mshr);
+ if (pkt->result == Packet::Nacked) {
+ //pkt->reinitFromRequest();
+ warn("NACKs from devices not connected to the same bus "
+ "not implemented\n");
+ return;
}
+ assert(pkt->result != Packet::BadAddress);
+ assert(pkt->result == Packet::Success);
+ DPRINTF(Cache, "Handling reponse to %x\n", pkt->getAddr());
- Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ MSHRQueue *mq = mshr->queue;
+ bool wasFull = mq->isFull();
- if (!pkt->req->isUncacheable()) {
- if (!missQueue->findMSHR(blk_addr)) {
- blk = handleAccess(pkt, lat, writebacks);
- }
- } else {
- size = pkt->getSize();
- }
- // If this is a block size write/hint (WH64) allocate the block here
- // if the coherence protocol allows it.
- /** @todo make the fast write alloc (wh64) work with coherence. */
- /** @todo Do we want to do fast writes for writebacks as well? */
- if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
- (pkt->cmd == MemCmd::WriteReq
- || pkt->cmd == MemCmd::WriteInvalidateReq) ) {
- // not outstanding misses, can do this
- MSHR* outstanding_miss = missQueue->findMSHR(pkt->getAddr());
- if (pkt->cmd == MemCmd::WriteInvalidateReq || !outstanding_miss) {
- if (outstanding_miss) {
- warn("WriteInv doing a fastallocate"
- "with an outstanding miss to the same address\n");
- }
- blk = handleFill(NULL, pkt, BlkValid | BlkWritable,
- writebacks);
- ++fastWrites;
- }
- }
- while (!writebacks.empty()) {
- PacketPtr wbPkt = writebacks.front();
- missQueue->doWriteback(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
+ if (mshr == noTargetMSHR) {
+ // we always clear at least one target
+ clearBlocked(Blocked_NoTargets);
+ noTargetMSHR = NULL;
}
- DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(), pkt->getAddr(),
- (blk) ? "hit" : "miss");
+ // Can we deallocate MSHR when done?
+ bool deallocate = false;
- if (blk) {
- // Hit
- hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- // clear dirty bit if write through
- respond(pkt, curTick+lat);
- return true;
- }
+ if (mshr->isCacheFill) {
+#if 0
+ mshr_miss_latency[mshr->originalCmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
+ curTick - pkt->time;
+#endif
+ DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
+ pkt->getAddr());
+ BlkType *blk = tags->findBlock(pkt->getAddr());
+ PacketList writebacks;
+ blk = handleFill(pkt, blk, writebacks);
+ deallocate = satisfyMSHR(mshr, pkt, blk);
+ // copy writebacks to write buffer
+ while (!writebacks.empty()) {
+ PacketPtr wbPkt = writebacks.front();
+ allocateBuffer(wbPkt, time, true);
+ writebacks.pop_front();
+ }
+ } else {
+ if (pkt->req->isUncacheable()) {
+ mshr_uncacheable_lat[pkt->cmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
+ curTick - pkt->time;
+ }
- // Miss
- if (!pkt->req->isUncacheable()) {
- misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- /** @todo Move miss count code into BaseCache */
- if (missCount) {
- --missCount;
- if (missCount == 0)
- exitSimLoop("A cache reached the maximum miss count");
+ while (mshr->hasTargets()) {
+ MSHR::Target *target = mshr->getTarget();
+ assert(target->isCpuSide());
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ target->pkt->setData(pkt->getPtr<uint8_t>());
+ }
+ cpuSidePort->respond(target->pkt, time);
}
+ assert(!mshr->hasTargets());
+ deallocate = true;
}
- if (pkt->flags & SATISFIED) {
- // happens when a store conditional fails because it missed
- // the cache completely
- respond(pkt, curTick+lat);
- } else {
- missQueue->handleMiss(pkt, size, curTick + hitLatency);
+ if (deallocate) {
+ mq->deallocate(mshr);
+ if (wasFull && !mq->isFull()) {
+ clearBlocked((BlockedCause)mq->index);
+ }
}
+}
- if (!pkt->needsResponse()) {
- //Need to clean up the packet on a writeback miss, but leave the request
- //for the next level.
- delete pkt;
- }
- return true;
-}
template<class TagStore, class Coherence>
PacketPtr
-Cache<TagStore,Coherence>::getPacket()
+Cache<TagStore,Coherence>::writebackBlk(BlkType *blk)
{
- assert(missQueue->havePending());
- PacketPtr pkt = missQueue->getPacket();
- if (pkt) {
- if (!pkt->req->isUncacheable()) {
- if (pkt->cmd == MemCmd::HardPFReq)
- misses[MemCmd::HardPFReq][0/*pkt->req->getThreadNum()*/]++;
- BlkType *blk = tags->findBlock(pkt->getAddr());
- MemCmd cmd =
- coherence->getBusCmd(pkt->cmd, (blk) ? blk->status : 0);
- missQueue->setBusCmd(pkt, cmd);
- }
- }
+ assert(blk && blk->isValid() && blk->isDirty());
- assert(!doMasterRequest() || missQueue->havePending());
- assert(!pkt || pkt->time <= curTick);
- SIGNAL_NACK_HACK = false;
- return pkt;
+ writebacks[0/*pkt->req->getThreadNum()*/]++;
+
+ Request *writebackReq =
+ new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0);
+ PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback, -1);
+ writeback->allocate();
+ std::memcpy(writeback->getPtr<uint8_t>(), blk->data, blkSize);
+
+ blk->status &= ~BlkDirty;
+ return writeback;
}
+
+// Note that the reason we return a list of writebacks rather than
+// inserting them directly in the write buffer is that this function
+// is called by both atomic and timing-mode accesses, and in atomic
+// mode we don't mess with the write buffer (we just perform the
+// writebacks atomically once the original request is complete).
template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::sendResult(PacketPtr &pkt, MSHR* mshr,
- bool success)
+typename Cache<TagStore,Coherence>::BlkType*
+Cache<TagStore,Coherence>::handleFill(PacketPtr pkt, BlkType *blk,
+ PacketList &writebacks)
{
- if (success && !(SIGNAL_NACK_HACK)) {
- //Remember if it was an upgrade because writeback MSHR's are removed
- //in Mark in Service
- bool upgrade = (mshr->pkt && mshr->pkt->cmd == MemCmd::UpgradeReq);
-
- missQueue->markInService(mshr->pkt, mshr);
-
- //Temp Hack for UPGRADES
- if (upgrade) {
- assert(pkt); //Upgrades need to be fixed
- pkt->flags &= ~CACHE_LINE_FILL;
- BlkType *blk = tags->findBlock(pkt->getAddr());
- CacheBlk::State old_state = (blk) ? blk->status : 0;
- CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
- if (old_state != new_state)
- DPRINTF(Cache, "Block for blk addr %x moving from state "
- "%i to %i\n", pkt->getAddr(), old_state, new_state);
- //Set the state on the upgrade
- std::memcpy(pkt->getPtr<uint8_t>(), blk->data, blkSize);
- PacketList writebacks;
- handleFill(blk, mshr, new_state, writebacks, pkt);
- assert(writebacks.empty());
- missQueue->handleResponse(pkt, curTick + hitLatency);
- }
- } else if (pkt && !pkt->req->isUncacheable()) {
- pkt->flags &= ~NACKED_LINE;
- SIGNAL_NACK_HACK = false;
- pkt->flags &= ~SATISFIED;
- pkt->flags &= ~SNOOP_COMMIT;
+ Addr addr = pkt->getAddr();
-//Rmove copy from mshr
- delete mshr->pkt;
- mshr->pkt = pkt;
+ if (blk == NULL) {
+ // better have read new data
+ assert(pkt->isRead());
- missQueue->restoreOrigCmd(pkt);
- }
-}
+ // need to do a replacement
+ blk = tags->findReplacement(addr, writebacks);
+ if (blk->isValid()) {
+ DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
+ tags->regenerateBlkAddr(blk->tag, blk->set), addr,
+ blk->isDirty() ? "writeback" : "clean");
-template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::handleResponse(PacketPtr &pkt)
-{
- BlkType *blk = NULL;
- if (pkt->senderState) {
- //Delete temp copy in MSHR, restore it.
- delete ((MSHR*)pkt->senderState)->pkt;
- ((MSHR*)pkt->senderState)->pkt = pkt;
- if (pkt->result == Packet::Nacked) {
- //pkt->reinitFromRequest();
- warn("NACKs from devices not connected to the same bus "
- "not implemented\n");
- return;
- }
- if (pkt->result == Packet::BadAddress) {
- //Make the response a Bad address and send it
- }
-// MemDebug::cacheResponse(pkt);
- DPRINTF(Cache, "Handling reponse to %x\n", pkt->getAddr());
-
- if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
- DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
- pkt->getAddr());
- blk = tags->findBlock(pkt->getAddr());
- CacheBlk::State old_state = (blk) ? blk->status : 0;
- PacketList writebacks;
- CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
- if (old_state != new_state)
- DPRINTF(Cache, "Block for blk addr %x moving from "
- "state %i to %i\n",
- pkt->getAddr(),
- old_state, new_state);
- blk = handleFill(blk, (MSHR*)pkt->senderState,
- new_state, writebacks, pkt);
- while (!writebacks.empty()) {
- PacketPtr wbPkt = writebacks.front();
- missQueue->doWriteback(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
+ if (blk->isDirty()) {
+ // Save writeback packet for handling by caller
+ writebacks.push_back(writebackBlk(blk));
}
}
- missQueue->handleResponse(pkt, curTick + hitLatency);
+
+ blk->tag = tags->extractTag(addr);
+ blk->status = coherence->getNewState(pkt);
+ } else {
+ // existing block... probably an upgrade
+ assert(blk->tag == tags->extractTag(addr));
+ // either we're getting new data or the block should already be valid
+ assert(pkt->isRead() || blk->isValid());
+ CacheBlk::State old_state = blk->status;
+ blk->status = coherence->getNewState(pkt, old_state);
+ if (blk->status != old_state)
+ DPRINTF(Cache, "Block addr %x moving from state %i to %i\n",
+ addr, old_state, blk->status);
+ else
+ warn("Changing state to same value\n");
}
+
+ // if we got new data, copy it in
+ if (pkt->isRead()) {
+ std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
+ }
+
+ blk->whenReady = pkt->finishTime;
+
+ return blk;
}
+
+/////////////////////////////////////////////////////
+//
+// Snoop path: requests coming in from the memory side
+//
+/////////////////////////////////////////////////////
+
template<class TagStore, class Coherence>
-PacketPtr
-Cache<TagStore,Coherence>::getCoherencePacket()
+void
+Cache<TagStore,Coherence>::doTimingSupplyResponse(PacketPtr req_pkt,
+ uint8_t *blk_data)
{
- return coherence->getPacket();
+ // timing-mode snoop responses require a new packet
+ PacketPtr pkt = new Packet(req_pkt);
+ pkt->allocate();
+ pkt->makeTimingResponse();
+ pkt->setDataFromBlock(blk_data, blkSize);
+ memSidePort->respond(pkt, curTick + hitLatency);
}
template<class TagStore, class Coherence>
void
-Cache<TagStore,Coherence>::sendCoherenceResult(PacketPtr &pkt,
- MSHR *cshr,
- bool success)
+Cache<TagStore,Coherence>::handleSnoop(PacketPtr pkt, BlkType *blk,
+ bool is_timing)
{
- coherence->sendResult(pkt, cshr, success);
+ if (!blk || !blk->isValid()) {
+ return;
+ }
+
+ // we may end up modifying both the block state and the packet (if
+ // we respond in atomic mode), so just figure out what to do now
+ // and then do it later
+ bool supply = blk->isDirty() && pkt->isRead();
+ bool invalidate = pkt->isInvalidate();
+
+ if (pkt->isRead() && !pkt->isInvalidate()) {
+ assert(!pkt->needsExclusive());
+ pkt->assertShared();
+ int bits_to_clear = BlkWritable;
+ const bool haveOwnershipState = true; // for now
+ if (!haveOwnershipState) {
+ // if we don't support pure ownership (dirty && !writable),
+ // have to clear dirty bit here, assume memory snarfs data
+ // on cache-to-cache xfer
+ bits_to_clear |= BlkDirty;
+ }
+ blk->status &= ~bits_to_clear;
+ }
+
+ if (supply) {
+ pkt->assertMemInhibit();
+ if (is_timing) {
+ doTimingSupplyResponse(pkt, blk->data);
+ } else {
+ pkt->makeAtomicResponse();
+ pkt->setDataFromBlock(blk->data, blkSize);
+ }
+ }
+
+ // Do this last in case it deallocates block data or something
+ // like that
+ if (invalidate) {
+ tags->invalidateBlk(blk);
+ }
+
+ DPRINTF(Cache, "snooped a %s request for addr %x, %snew state is %i\n",
+ pkt->cmdString(), blockAlign(pkt->getAddr()),
+ supply ? "supplying data, " : "", blk->status);
}
template<class TagStore, class Coherence>
void
-Cache<TagStore,Coherence>::snoop(PacketPtr &pkt)
+Cache<TagStore,Coherence>::snoopTiming(PacketPtr pkt)
{
if (pkt->req->isUncacheable()) {
//Can't get a hit on an uncacheable address
@@ -810,373 +877,201 @@ Cache<TagStore,Coherence>::snoop(PacketPtr &pkt)
return;
}
- //Send a timing (true) invalidate up if the protocol calls for it
- if (coherence->propogateInvalidate(pkt, true)) {
- //Temp hack, we had a functional read hit in the L1, mark as success
- pkt->flags |= SATISFIED;
- pkt->result = Packet::Success;
- respondToSnoop(pkt, curTick + hitLatency);
- return;
- }
+ BlkType *blk = tags->findBlock(pkt->getAddr());
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
- BlkType *blk = tags->findBlock(pkt->getAddr());
- MSHR *mshr = missQueue->findMSHR(blk_addr);
- if (coherence->hasProtocol() || pkt->isInvalidate()) {
- //@todo Move this into handle bus req
- //If we find an mshr, and it is in service, we need to NACK or
- //invalidate
- if (mshr) {
- if (mshr->inService) {
- if ((mshr->pkt->isInvalidate() || !mshr->pkt->isCacheFill())
- && (pkt->cmd != MemCmd::InvalidateReq
- && pkt->cmd != MemCmd::WriteInvalidateReq)) {
- //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)
- assert(!(pkt->flags & SATISFIED));
- pkt->flags |= SATISFIED;
- pkt->flags |= NACKED_LINE;
- SIGNAL_NACK_HACK = true;
- ///@todo NACK's from other levels
- //warn("NACKs from devices not connected to the same bus "
- //"not implemented\n");
- //respondToSnoop(pkt, curTick + hitLatency);
- return;
- }
- else {
- //The supplier will be someone else, because we are
- //waiting for the data. This should cause this cache to
- //be forced to go to the shared state, not the exclusive
- //even though the shared line won't be asserted. But for
- //now we will just invlidate ourselves and allow the other
- //cache to go into the exclusive state. @todo Make it so
- //a read to a pending read doesn't invalidate. @todo Make
- //it so that a read to a pending read can't be exclusive
- //now.
-
- //Set the address so find match works
- //panic("Don't have invalidates yet\n");
- invalidatePkt->addrOverride(pkt->getAddr());
-
- //Append the invalidate on
- missQueue->addTarget(mshr,invalidatePkt);
- DPRINTF(Cache, "Appending Invalidate to addr: %x\n",
- pkt->getAddr());
- return;
+ MSHR *mshr = mshrQueue.findMatch(blk_addr);
+ // better not be snooping a request that conflicts with something
+ // we have outstanding...
+ assert(!mshr || !mshr->inService);
+
+ //We also need to check the writeback buffers and handle those
+ std::vector<MSHR *> writebacks;
+ if (writeBuffer.findMatches(blk_addr, writebacks)) {
+ DPRINTF(Cache, "Snoop hit in writeback to addr: %x\n",
+ pkt->getAddr());
+
+ //Look through writebacks for any non-uncachable writes, use that
+ for (int i=0; i<writebacks.size(); i++) {
+ mshr = writebacks[i];
+ assert(!mshr->isUncacheable());
+
+ if (pkt->isRead()) {
+ pkt->assertMemInhibit();
+ if (!pkt->needsExclusive()) {
+ pkt->assertShared();
+ } else {
+ // if we're not asserting the shared line, we need to
+ // invalidate our copy. we'll do that below as long as
+ // the packet's invalidate flag is set...
+ assert(pkt->isInvalidate());
}
+ doTimingSupplyResponse(pkt, mshr->writeData);
}
- }
- //We also need to check the writeback buffers and handle those
- std::vector<MSHR *> writebacks;
- if (missQueue->findWrites(blk_addr, writebacks)) {
- DPRINTF(Cache, "Snoop hit in writeback to addr: %x\n",
- pkt->getAddr());
-
- //Look through writebacks for any non-uncachable writes, use that
- for (int i=0; i<writebacks.size(); i++) {
- mshr = writebacks[i];
-
- if (!mshr->pkt->req->isUncacheable()) {
- if (pkt->isRead()) {
- //Only Upgrades don't get here
- //Supply the data
- assert(!(pkt->flags & SATISFIED));
- pkt->flags |= SATISFIED;
-
- //If we are in an exclusive protocol, make it ask again
- //to get write permissions (upgrade), signal shared
- pkt->flags |= SHARED_LINE;
-
- assert(pkt->isRead());
- Addr offset = pkt->getAddr() & (blkSize - 1);
- assert(offset < blkSize);
- assert(pkt->getSize() <= blkSize);
- assert(offset + pkt->getSize() <=blkSize);
- std::memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
-
- respondToSnoop(pkt, curTick + hitLatency);
- }
-
- if (pkt->isInvalidate()) {
- //This must be an upgrade or other cache will take
- //ownership
- missQueue->markInService(mshr->pkt, mshr);
- }
- return;
- }
+
+ if (pkt->isInvalidate()) {
+ // Invalidation trumps our writeback... discard here
+ assert(0);
+ markInService(mshr);
}
+ return;
}
}
- CacheBlk::State new_state;
- bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
-
- if (blk && mshr && !mshr->inService && new_state == 0) {
- //There was a outstanding write to a shared block, not need ReadEx
- //not update, so change No Allocate param in MSHR
- mshr->pkt->flags &= ~NO_ALLOCATE;
- }
- if (satisfy) {
- DPRINTF(Cache, "Cache snooped a %s request for addr %x and "
- "now supplying data, new state is %i\n",
- pkt->cmdString(), blk_addr, new_state);
-
- handleSnoop(blk, new_state, pkt);
- respondToSnoop(pkt, curTick + hitLatency);
- return;
- }
- if (blk)
- DPRINTF(Cache, "Cache snooped a %s request for addr %x, "
- "new state is %i\n", pkt->cmdString(), blk_addr, new_state);
-
- handleSnoop(blk, new_state);
+ handleSnoop(pkt, blk, true);
}
+
template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::snoopResponse(PacketPtr &pkt)
+Tick
+Cache<TagStore,Coherence>::snoopAtomic(PacketPtr pkt)
{
- //Need to handle the response, if NACKED
- if (pkt->flags & NACKED_LINE) {
- //Need to mark it as not in service, and retry for bus
- assert(0); //Yeah, we saw a NACK come through
-
- //For now this should never get called, we return false when we see a
- //NACK instead, by doing this we allow the bus_blocked mechanism to
- //handle the retry For now it retrys in just 2 cycles, need to figure
- //out how to change that Eventually we will want to also have success
- //come in as a parameter Need to make sure that we handle the
- //functionality that happens on successufl return of the sendAddr
- //function
+ if (pkt->req->isUncacheable()) {
+ // Can't get a hit on an uncacheable address
+ // Revisit this for multi level coherence
+ return hitLatency;
}
+
+ BlkType *blk = tags->findBlock(pkt->getAddr());
+ handleSnoop(pkt, blk, false);
+ return hitLatency;
}
-/**
- * @todo Fix to not assume write allocate
- */
template<class TagStore, class Coherence>
-Tick
-Cache<TagStore,Coherence>::probe(PacketPtr &pkt, bool update,
- CachePort* otherSidePort)
+MSHR *
+Cache<TagStore,Coherence>::getNextMSHR()
{
-// MemDebug::cacheProbe(pkt);
- if (!pkt->req->isUncacheable()) {
- if (pkt->isInvalidate() && !pkt->isRead() && !pkt->isWrite()) {
- //Upgrade or Invalidate, satisfy it, don't forward
- DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr());
- pkt->flags |= SATISFIED;
- return 0;
- }
- }
+ // Check both MSHR queue and write buffer for potential requests
+ MSHR *miss_mshr = mshrQueue.getNextMSHR();
+ MSHR *write_mshr = writeBuffer.getNextMSHR();
- if (!update && (otherSidePort == cpuSidePort)) {
- // Still need to change data in all locations.
- otherSidePort->checkAndSendFunctional(pkt);
- if (pkt->isRead() && pkt->result == Packet::Success)
- return 0;
+ // Now figure out which one to send... some cases are easy
+ if (miss_mshr && !write_mshr) {
+ return miss_mshr;
+ }
+ if (write_mshr && !miss_mshr) {
+ return write_mshr;
}
- PacketList writebacks;
- int lat;
-
- BlkType *blk = handleAccess(pkt, lat, writebacks, update);
-
- DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(),
- pkt->getAddr(), (blk) ? "hit" : "miss");
-
-
- // Need to check for outstanding misses and writes
- Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
-
- // There can only be one matching outstanding miss.
- MSHR* mshr = missQueue->findMSHR(blk_addr);
-
- // There can be many matching outstanding writes.
- std::vector<MSHR*> writes;
- missQueue->findWrites(blk_addr, writes);
-
- if (!update) {
- bool notDone = !(pkt->flags & SATISFIED); //Hit in cache (was a block)
- // Check for data in MSHR and writebuffer.
- if (mshr) {
- MSHR::TargetList *targets = mshr->getTargetList();
- MSHR::TargetList::iterator i = targets->begin();
- MSHR::TargetList::iterator end = targets->end();
- for (; i != end && notDone; ++i) {
- PacketPtr target = *i;
- // If the target contains data, and it overlaps the
- // probed request, need to update data
- if (target->intersect(pkt)) {
- DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a MSHR\n",
- pkt->cmdString(), blk_addr);
- notDone = fixPacket(pkt, target);
- }
- }
- }
- for (int i = 0; i < writes.size() && notDone; ++i) {
- PacketPtr write = writes[i]->pkt;
- if (write->intersect(pkt)) {
- DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a writeback\n",
- pkt->cmdString(), blk_addr);
- notDone = fixPacket(pkt, write);
+ if (miss_mshr && write_mshr) {
+ // We have one of each... normally we favor the miss request
+ // unless the write buffer is full
+ if (writeBuffer.isFull() && writeBuffer.inServiceEntries == 0) {
+ // Write buffer is full, so we'd like to issue a write;
+ // need to search MSHR queue for conflicting earlier miss.
+ MSHR *conflict_mshr =
+ mshrQueue.findPending(write_mshr->addr, write_mshr->size);
+
+ if (conflict_mshr && conflict_mshr->order < write_mshr->order) {
+ // Service misses in order until conflict is cleared.
+ return conflict_mshr;
}
- }
- if (notDone && otherSidePort == memSidePort) {
- otherSidePort->checkAndSendFunctional(pkt);
- assert(pkt->result == Packet::Success);
- }
- return 0;
- } else if (!blk && !(pkt->flags & SATISFIED)) {
- // update the cache state and statistics
- if (mshr || !writes.empty()){
- // Can't handle it, return request unsatisfied.
- panic("Atomic access ran into outstanding MSHR's or WB's!");
- }
- if (!pkt->req->isUncacheable() /*Uncacheables just go through*/
- && (pkt->cmd != MemCmd::Writeback)/*Writebacks on miss fall through*/) {
- // Fetch the cache block to fill
- BlkType *blk = tags->findBlock(pkt->getAddr());
- MemCmd temp_cmd =
- coherence->getBusCmd(pkt->cmd, (blk) ? blk->status : 0);
-
- PacketPtr busPkt = new Packet(pkt->req,temp_cmd, -1, blkSize);
- busPkt->allocate();
-
- busPkt->time = curTick;
+ // No conflicts; issue write
+ return write_mshr;
+ }
- DPRINTF(Cache, "Sending a atomic %s for %x\n",
- busPkt->cmdString(), busPkt->getAddr());
+ // Write buffer isn't full, but need to check it for
+ // conflicting earlier writeback
+ MSHR *conflict_mshr =
+ writeBuffer.findPending(miss_mshr->addr, miss_mshr->size);
+ if (conflict_mshr) {
+ // not sure why we don't check order here... it was in the
+ // original code but commented out.
+
+ // The only way this happens is if we are
+ // doing a write and we didn't have permissions
+ // then subsequently saw a writeback (owned got evicted)
+ // We need to make sure to perform the writeback first
+ // To preserve the dirty data, then we can issue the write
+
+ // should we return write_mshr here instead? I.e. do we
+ // have to flush writes in order? I don't think so... not
+ // for Alpha anyway. Maybe for x86?
+ return conflict_mshr;
+ }
- lat = memSidePort->sendAtomic(busPkt);
+ // No conclifts; issue read
+ return miss_mshr;
+ }
- //Be sure to flip the response to a request for coherence
- if (busPkt->needsResponse()) {
- busPkt->makeAtomicResponse();
- }
+ // fall through... no pending requests. Try a prefetch.
+ assert(!miss_mshr && !write_mshr);
+ if (!mshrQueue.isFull()) {
+ // If we have a miss queue slot, we can try a prefetch
+ PacketPtr pkt = prefetcher->getPacket();
+ if (pkt) {
+ // Update statistic on number of prefetches issued
+ // (hwpf_mshr_misses)
+ mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ // Don't request bus, since we already have it
+ return allocateMissBuffer(pkt, curTick, false);
+ }
+ }
-/* if (!(busPkt->flags & SATISFIED)) {
-// blocked at a higher level, just return
-return 0;
+ return NULL;
}
-*/ misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- CacheBlk::State old_state = (blk) ? blk->status : 0;
- CacheBlk::State new_state =
- coherence->getNewState(busPkt, old_state);
- DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
- busPkt->cmdString(), busPkt->getAddr(), old_state);
- if (old_state != new_state)
- DPRINTF(Cache, "Block for blk addr %x moving from state "
- "%i to %i\n", busPkt->getAddr(), old_state, new_state);
+template<class TagStore, class Coherence>
+PacketPtr
+Cache<TagStore,Coherence>::getTimingPacket()
+{
+ MSHR *mshr = getNextMSHR();
- handleFill(blk, busPkt, new_state, writebacks, pkt);
- //Free the packet
- delete busPkt;
+ if (mshr == NULL) {
+ return NULL;
+ }
- // Handle writebacks if needed
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
- }
- return lat + hitLatency;
- } else {
- return memSidePort->sendAtomic(pkt);
- }
+ // use request from 1st target
+ PacketPtr tgt_pkt = mshr->getTarget()->pkt;
+ PacketPtr pkt = NULL;
+
+ if (mshr->isSimpleForward()) {
+ // no response expected, just forward packet as it is
+ assert(tags->findBlock(mshr->addr) == NULL);
+ pkt = tgt_pkt;
} else {
- if (blk) {
- // There was a cache hit.
- // Handle writebacks if needed
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
+ BlkType *blk = tags->findBlock(mshr->addr);
+ pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive);
+
+ mshr->isCacheFill = (pkt != NULL);
+
+ if (pkt == NULL) {
+ // not a cache block request, but a response is expected
+ assert(!mshr->isSimpleForward());
+ // make copy of current packet to forward, keep current
+ // copy for response handling
+ pkt = new Packet(tgt_pkt);
+ pkt->allocate();
+ if (pkt->isWrite()) {
+ pkt->setData(tgt_pkt->getPtr<uint8_t>());
}
-
- hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
}
-
- return hitLatency;
}
- return 0;
+ assert(pkt != NULL);
+ pkt->senderState = mshr;
+ return pkt;
}
-template<class TagStore, class Coherence>
-Tick
-Cache<TagStore,Coherence>::snoopProbe(PacketPtr &pkt)
-{
- //Send a atomic (false) invalidate up if the protocol calls for it
- if (coherence->propogateInvalidate(pkt, false)) {
- //Temp hack, we had a functional read hit in the L1, mark as success
- pkt->flags |= SATISFIED;
- pkt->result = Packet::Success;
- return hitLatency;
- }
-
- Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
- BlkType *blk = tags->findBlock(pkt->getAddr());
- MSHR *mshr = missQueue->findMSHR(blk_addr);
- CacheBlk::State new_state = 0;
- bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
- if (satisfy) {
- DPRINTF(Cache, "Cache snooped a %s request for addr %x and "
- "now supplying data, new state is %i\n",
- pkt->cmdString(), blk_addr, new_state);
-
- handleSnoop(blk, new_state, pkt);
- return hitLatency;
- }
- if (blk)
- DPRINTF(Cache, "Cache snooped a %s request for addr %x, "
- "new state is %i\n",
- pkt->cmdString(), blk_addr, new_state);
- handleSnoop(blk, new_state);
- return 0;
-}
-template<class TagStore, class Coherence>
-Port *
-Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx)
-{
- if (if_name == "" || if_name == "cpu_side")
- {
- if (cpuSidePort == NULL) {
- cpuSidePort = new CpuSidePort(name() + "-cpu_side_port", this);
- sendEvent = new ResponseEvent(cpuSidePort);
- }
- return cpuSidePort;
- }
- else if (if_name == "functional")
- {
- return new CpuSidePort(name() + "-cpu_side_funcport", this);
- }
- else if (if_name == "mem_side")
- {
- if (memSidePort != NULL)
- panic("Already have a mem side for this cache\n");
- memSidePort = new MemSidePort(name() + "-mem_side_port", this);
- memSendEvent = new ResponseEvent(memSidePort);
- return memSidePort;
- }
- else panic("Port name %s unrecognized\n", if_name);
-}
+///////////////
+//
+// CpuSidePort
+//
+///////////////
template<class TagStore, class Coherence>
void
-Cache<TagStore,Coherence>::deletePortRefs(Port *p)
+Cache<TagStore,Coherence>::CpuSidePort::
+getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
{
- if (cpuSidePort == p || memSidePort == p)
- panic("Can only delete functional ports\n");
-
- delete p;
+ // CPU side port doesn't snoop; it's a target only.
+ bool dummy;
+ otherPort->getPeerAddressRanges(resp, dummy);
+ snoop = false;
}
@@ -1184,58 +1079,58 @@ template<class TagStore, class Coherence>
bool
Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt)
{
- assert(pkt->result != Packet::Nacked);
-
- if (!pkt->req->isUncacheable()
- && pkt->isInvalidate()
- && !pkt->isRead() && !pkt->isWrite()) {
- //Upgrade or Invalidate
- //Look into what happens if two slave caches on bus
- DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr());
-
- assert(!(pkt->flags & SATISFIED));
- pkt->flags |= SATISFIED;
- //Invalidates/Upgrades need no response if they get the bus
- return true;
- }
-
- if (pkt->isRequest() && blocked)
- {
+ if (pkt->isRequest() && blocked) {
DPRINTF(Cache,"Scheduling a retry while blocked\n");
mustSendRetry = true;
return false;
}
- if (pkt->isWrite() && (pkt->req->isLocked())) {
- pkt->req->setExtraData(1);
- }
- myCache()->access(pkt);
+ myCache()->timingAccess(pkt);
return true;
}
+
template<class TagStore, class Coherence>
Tick
Cache<TagStore,Coherence>::CpuSidePort::recvAtomic(PacketPtr pkt)
{
- myCache()->probe(pkt, true, NULL);
- //TEMP ALWAYS SUCCES FOR NOW
- pkt->result = Packet::Success;
- //Fix this timing info
- return myCache()->hitLatency;
+ return myCache()->atomicAccess(pkt);
}
+
template<class TagStore, class Coherence>
void
Cache<TagStore,Coherence>::CpuSidePort::recvFunctional(PacketPtr pkt)
{
- if (checkFunctional(pkt)) {
- //TEMP USE CPU?THREAD 0 0
- pkt->req->setThreadContext(0,0);
+ checkFunctional(pkt);
+ if (pkt->result != Packet::Success)
+ myCache()->functionalAccess(pkt, cache->memSidePort);
+}
- myCache()->probe(pkt, false, cache->memSidePort);
- //TEMP ALWAYS SUCCESFUL FOR NOW
- pkt->result = Packet::Success;
- }
+
+template<class TagStore, class Coherence>
+Cache<TagStore,Coherence>::
+CpuSidePort::CpuSidePort(const std::string &_name,
+ Cache<TagStore,Coherence> *_cache)
+ : BaseCache::CachePort(_name, _cache)
+{
+}
+
+///////////////
+//
+// MemSidePort
+//
+///////////////
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::MemSidePort::
+getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+{
+ otherPort->getPeerAddressRanges(resp, snoop);
+ // Memory-side port always snoops, so unconditionally set flag for
+ // caller.
+ snoop = true;
}
@@ -1249,58 +1144,124 @@ Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt)
if (pkt->result == Packet::Nacked)
panic("Need to implement cache resending nacked packets!\n");
- if (pkt->isRequest() && blocked)
- {
+ if (pkt->isRequest() && blocked) {
DPRINTF(Cache,"Scheduling a retry while blocked\n");
mustSendRetry = true;
return false;
}
- if (pkt->isResponse())
+ if (pkt->isResponse()) {
myCache()->handleResponse(pkt);
- else {
- //Check if we should do the snoop
- if (pkt->flags & SNOOP_COMMIT)
- myCache()->snoop(pkt);
+ } else {
+ myCache()->snoopTiming(pkt);
}
return true;
}
+
template<class TagStore, class Coherence>
Tick
Cache<TagStore,Coherence>::MemSidePort::recvAtomic(PacketPtr pkt)
{
- if (pkt->isResponse())
- myCache()->handleResponse(pkt);
- else
- return myCache()->snoopProbe(pkt);
- //Fix this timing info
- return myCache()->hitLatency;
+ // in atomic mode, responses go back to the sender via the
+ // function return from sendAtomic(), not via a separate
+ // sendAtomic() from the responder. Thus we should never see a
+ // response packet in recvAtomic() (anywhere, not just here).
+ assert(!pkt->isResponse());
+ return myCache()->snoopAtomic(pkt);
}
+
template<class TagStore, class Coherence>
void
Cache<TagStore,Coherence>::MemSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->probe(pkt, false, cache->cpuSidePort);
+ checkFunctional(pkt);
if (pkt->result != Packet::Success)
- checkFunctional(pkt);
+ myCache()->functionalAccess(pkt, cache->cpuSidePort);
}
+
template<class TagStore, class Coherence>
-Cache<TagStore,Coherence>::
-CpuSidePort::CpuSidePort(const std::string &_name,
- Cache<TagStore,Coherence> *_cache)
- : BaseCache::CachePort(_name, _cache, true)
+void
+Cache<TagStore,Coherence>::MemSidePort::sendPacket()
+{
+ // if we have responses that are ready, they take precedence
+ if (deferredPacketReady()) {
+ bool success = sendTiming(transmitList.front().pkt);
+
+ if (success) {
+ //send successful, remove packet
+ transmitList.pop_front();
+ }
+
+ waitingOnRetry = !success;
+ } else {
+ // check for non-response packets (requests & writebacks)
+ PacketPtr pkt = myCache()->getTimingPacket();
+ MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
+
+ bool success = sendTiming(pkt);
+ DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
+ pkt->getAddr(), success ? "successful" : "unsuccessful");
+
+ waitingOnRetry = !success;
+ if (waitingOnRetry) {
+ DPRINTF(CachePort, "%s now waiting on a retry\n", name());
+ } else {
+ myCache()->markInService(mshr);
+ }
+ }
+
+
+ // tried to send packet... if it was successful (no retry), see if
+ // we need to rerequest bus or not
+ if (!waitingOnRetry) {
+ if (isBusRequested()) {
+ // more requests/writebacks: rerequest ASAP
+ DPRINTF(CachePort, "%s still more MSHR requests to send\n",
+ name());
+ sendEvent->schedule(curTick+1);
+ } else if (!transmitList.empty()) {
+ // deferred packets: rerequest bus, but possibly not until later
+ Tick time = transmitList.front().tick;
+ sendEvent->schedule(time <= curTick ? curTick+1 : time);
+ } else {
+ // no more to send right now: if we're draining, we may be done
+ if (drainEvent) {
+ drainEvent->process();
+ drainEvent = NULL;
+ }
+ }
+ }
+}
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::MemSidePort::recvRetry()
{
+ assert(waitingOnRetry);
+ sendPacket();
}
+
+template<class TagStore, class Coherence>
+void
+Cache<TagStore,Coherence>::MemSidePort::processSendEvent()
+{
+ assert(!waitingOnRetry);
+ sendPacket();
+}
+
+
template<class TagStore, class Coherence>
Cache<TagStore,Coherence>::
MemSidePort::MemSidePort(const std::string &_name,
Cache<TagStore,Coherence> *_cache)
- : BaseCache::CachePort(_name, _cache, false)
+ : BaseCache::CachePort(_name, _cache)
{
+ // override default send event from SimpleTimingPort
+ delete sendEvent;
+ sendEvent = new SendEvent(this);
}
-
diff --git a/src/mem/cache/coherence/SConscript b/src/mem/cache/coherence/SConscript
index 4f5966140..91720b20e 100644
--- a/src/mem/cache/coherence/SConscript
+++ b/src/mem/cache/coherence/SConscript
@@ -33,5 +33,4 @@ Import('*')
SimObject('CoherenceProtocol.py')
Source('coherence_protocol.cc')
-Source('uni_coherence.cc')
diff --git a/src/mem/cache/coherence/coherence_protocol.cc b/src/mem/cache/coherence/coherence_protocol.cc
index 33a8a4e63..47d2b469f 100644
--- a/src/mem/cache/coherence/coherence_protocol.cc
+++ b/src/mem/cache/coherence/coherence_protocol.cc
@@ -139,31 +139,6 @@ CoherenceProtocol::regStats()
.desc("readEx snoops on exclusive blocks")
;
- snoopCount[Shared][MemCmd::InvalidateReq]
- .name(name() + ".snoop_inv_shared")
- .desc("Invalidate snoops on shared blocks")
- ;
-
- snoopCount[Owned][MemCmd::InvalidateReq]
- .name(name() + ".snoop_inv_owned")
- .desc("Invalidate snoops on owned blocks")
- ;
-
- snoopCount[Exclusive][MemCmd::InvalidateReq]
- .name(name() + ".snoop_inv_exclusive")
- .desc("Invalidate snoops on exclusive blocks")
- ;
-
- snoopCount[Modified][MemCmd::InvalidateReq]
- .name(name() + ".snoop_inv_modified")
- .desc("Invalidate snoops on modified blocks")
- ;
-
- snoopCount[Invalid][MemCmd::InvalidateReq]
- .name(name() + ".snoop_inv_invalid")
- .desc("Invalidate snoops on invalid blocks")
- ;
-
snoopCount[Shared][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_shared")
.desc("WriteInvalidate snoops on shared blocks")
@@ -219,7 +194,7 @@ CoherenceProtocol::supplyAndGotoSharedTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Shared;
- pkt->flags |= SHARED_LINE;
+ pkt->assertShared();
return supplyTrans(cache, pkt, blk, mshr, new_state);
}
@@ -231,7 +206,7 @@ CoherenceProtocol::supplyAndGotoOwnedTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Owned;
- pkt->flags |= SHARED_LINE;
+ pkt->assertShared();
return supplyTrans(cache, pkt, blk, mshr, new_state);
}
@@ -253,7 +228,7 @@ CoherenceProtocol::assertShared(BaseCache *cache, PacketPtr &pkt,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Shared;
- pkt->flags |= SHARED_LINE;
+ pkt->assertShared();
return false;
}
@@ -284,7 +259,7 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
MC::Command writeToSharedCmd =
doUpgrades ? MC::UpgradeReq : MC::ReadExReq;
MC::Command writeToSharedResp =
- doUpgrades ? MC::UpgradeReq : MC::ReadExResp;
+ doUpgrades ? MC::UpgradeResp : MC::ReadExResp;
// Note that all transitions by default cause a panic.
// Override the valid transitions with the appropriate actions here.
@@ -295,11 +270,15 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
tt[Invalid][MC::ReadReq].onRequest(MC::ReadReq);
// we only support write allocate right now
tt[Invalid][MC::WriteReq].onRequest(MC::ReadExReq);
+ tt[Invalid][MC::ReadExReq].onRequest(MC::ReadExReq);
tt[Invalid][MC::SwapReq].onRequest(MC::ReadExReq);
+ tt[Invalid][MC::UpgradeReq].onRequest(MC::UpgradeReq);
tt[Shared][MC::WriteReq].onRequest(writeToSharedCmd);
+ tt[Shared][MC::ReadExReq].onRequest(MC::ReadExReq);
tt[Shared][MC::SwapReq].onRequest(writeToSharedCmd);
if (hasOwned) {
tt[Owned][MC::WriteReq].onRequest(writeToSharedCmd);
+ tt[Owned][MC::ReadExReq].onRequest(MC::ReadExReq);
tt[Owned][MC::SwapReq].onRequest(writeToSharedCmd);
}
@@ -333,12 +312,10 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
//
tt[Invalid][MC::ReadReq].onSnoop(nullTransition);
tt[Invalid][MC::ReadExReq].onSnoop(nullTransition);
- tt[Invalid][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Invalid][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
tt[Shared][MC::ReadReq].onSnoop(hasExclusive
? assertShared : nullTransition);
tt[Shared][MC::ReadExReq].onSnoop(invalidateTrans);
- tt[Shared][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Shared][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
if (doUpgrades) {
tt[Invalid][MC::UpgradeReq].onSnoop(nullTransition);
@@ -348,13 +325,11 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
tt[Modified][MC::ReadReq].onSnoop(hasOwned
? supplyAndGotoOwnedTrans
: supplyAndGotoSharedTrans);
- tt[Modified][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Modified][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
if (hasExclusive) {
tt[Exclusive][MC::ReadReq].onSnoop(assertShared);
tt[Exclusive][MC::ReadExReq].onSnoop(invalidateTrans);
- tt[Exclusive][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Exclusive][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
}
@@ -362,7 +337,6 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
tt[Owned][MC::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
tt[Owned][MC::ReadExReq].onSnoop(supplyAndInvalidateTrans);
tt[Owned][MC::UpgradeReq].onSnoop(invalidateTrans);
- tt[Owned][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Owned][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
}
@@ -391,7 +365,7 @@ CoherenceProtocol::getBusCmd(MemCmd cmdIn, CacheBlk::State state,
CacheBlk::State
-CoherenceProtocol::getNewState(PacketPtr &pkt, CacheBlk::State oldState)
+CoherenceProtocol::getNewState(PacketPtr pkt, CacheBlk::State oldState)
{
CacheBlk::State state = oldState & stateMask;
int cmd_idx = pkt->cmdToIndex();
@@ -403,7 +377,7 @@ CoherenceProtocol::getNewState(PacketPtr &pkt, CacheBlk::State oldState)
//Check if it's exclusive and the shared line was asserted,
//then goto shared instead
- if (newState == Exclusive && (pkt->flags & SHARED_LINE)) {
+ if (newState == Exclusive && pkt->sharedAsserted()) {
newState = Shared;
}
diff --git a/src/mem/cache/coherence/coherence_protocol.hh b/src/mem/cache/coherence/coherence_protocol.hh
index 775bc807a..4b8024582 100644
--- a/src/mem/cache/coherence/coherence_protocol.hh
+++ b/src/mem/cache/coherence/coherence_protocol.hh
@@ -89,8 +89,8 @@ class CoherenceProtocol : public SimObject
* @param oldState The current block state.
* @return The new state.
*/
- CacheBlk::State getNewState(PacketPtr &pkt,
- CacheBlk::State oldState);
+ CacheBlk::State getNewState(PacketPtr pkt,
+ CacheBlk::State oldState = 0);
/**
* Handle snooped bus requests.
diff --git a/src/mem/cache/coherence/simple_coherence.hh b/src/mem/cache/coherence/simple_coherence.hh
index 1c89c703a..214828ca7 100644
--- a/src/mem/cache/coherence/simple_coherence.hh
+++ b/src/mem/cache/coherence/simple_coherence.hh
@@ -95,24 +95,13 @@ class SimpleCoherence
}
/**
- * Was the CSHR request was sent successfully?
- * @param pkt The request.
- * @param success True if the request was sent successfully.
- */
- void sendResult(PacketPtr &pkt, MSHR* cshr, bool success)
- {
- //Don't do coherence
- return;
- }
-
-
- /**
* Return the proper state given the current state and the bus response.
* @param pkt The bus response.
* @param current The current block state.
* @return The new state.
*/
- CacheBlk::State getNewState(PacketPtr &pkt, CacheBlk::State current)
+ CacheBlk::State getNewState(PacketPtr pkt,
+ CacheBlk::State current = 0)
{
return protocol->getNewState(pkt, current);
}
@@ -161,12 +150,6 @@ class SimpleCoherence
bool allowFastWrites() { return false; }
bool hasProtocol() { return true; }
-
- bool propogateInvalidate(PacketPtr pkt, bool isTiming)
- {
- //For now we do nothing, asssumes simple coherence is top level of cache
- return false;
- }
};
#endif //__SIMPLE_COHERENCE_HH__
diff --git a/src/mem/cache/coherence/uni_coherence.cc b/src/mem/cache/coherence/uni_coherence.cc
deleted file mode 100644
index 6061c89c3..000000000
--- a/src/mem/cache/coherence/uni_coherence.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- */
-
-#include "mem/cache/coherence/uni_coherence.hh"
-#include "mem/cache/base_cache.hh"
-
-#include "base/trace.hh"
-
-using namespace std;
-
-UniCoherence::UniCoherence()
- : cshrs(50)
-{
-}
-
-PacketPtr
-UniCoherence::getPacket()
-{
- PacketPtr pkt = cshrs.getReq();
- return pkt;
-}
-
-void
-UniCoherence::sendResult(PacketPtr &pkt, MSHR* cshr, bool success)
-{
- if (success)
- {
- bool unblock = cshrs.isFull();
-// cshrs.markInService(cshr);
- delete pkt->req;
- cshrs.deallocate(cshr);
- if (!cshrs.havePending()) {
- cache->clearSlaveRequest(Request_Coherence);
- }
- if (unblock) {
- //since CSHRs are always used as buffers, should always get rid of one
- assert(!cshrs.isFull());
- cache->clearBlocked(Blocked_Coherence);
- }
- }
-}
-
-
-/**
- * @todo add support for returning slave requests, not doing them here.
- */
-bool
-UniCoherence::handleBusRequest(PacketPtr &pkt, CacheBlk *blk, MSHR *mshr,
- CacheBlk::State &new_state)
-{
- new_state = 0;
- if (pkt->isInvalidate()) {
- DPRINTF(Cache, "snoop inval on blk %x (blk ptr %x)\n",
- pkt->getAddr(), blk);
- }
- else if (blk) {
- new_state = blk->status;
- if (pkt->isRead()) {
- DPRINTF(Cache, "Uni-coherence snoops a read that hit in itself"
- ". Should satisfy the packet\n");
- return true; //Satisfy Reads if we can
- }
- }
- return false;
-}
-
-bool
-UniCoherence::propogateInvalidate(PacketPtr pkt, bool isTiming)
-{
- if (pkt->isInvalidate()) {
-/* Temp Fix for now, forward all invalidates up as functional accesses */
- if (isTiming) {
- // Forward to other caches
- Request* req = new Request(pkt->req->getPaddr(), pkt->getSize(), 0);
- PacketPtr tmp = new Packet(req, MemCmd::InvalidateReq, -1);
- cshrs.allocate(tmp);
- cache->setSlaveRequest(Request_Coherence, curTick);
- if (cshrs.isFull())
- cache->setBlockedForSnoop(Blocked_Coherence);
- }
- else {
- PacketPtr tmp = new Packet(pkt->req, MemCmd::InvalidateReq, -1);
- cache->cpuSidePort->sendAtomic(tmp);
- delete tmp;
- }
-/**/
-/* PacketPtr tmp = new Packet(pkt->req, MemCmd::InvalidateReq, -1);
- cache->cpuSidePort->sendFunctional(tmp);
- delete tmp;
-*/
- }
- if (pkt->isRead()) {
- /*For now we will see if someone above us has the data by
- doing a functional access on reads. Fix this later */
- PacketPtr tmp = new Packet(pkt->req, MemCmd::ReadReq, -1);
- tmp->allocate();
- cache->cpuSidePort->sendFunctional(tmp);
- bool hit = (tmp->result == Packet::Success);
- if (hit) {
- memcpy(pkt->getPtr<uint8_t>(), tmp->getPtr<uint8_t>(),
- pkt->getSize());
- DPRINTF(Cache, "Uni-coherence snoops a read that hit in L1\n");
- }
- delete tmp;
- return hit;
- }
- return false;
-}
diff --git a/src/mem/cache/coherence/uni_coherence.hh b/src/mem/cache/coherence/uni_coherence.hh
deleted file mode 100644
index 9efb4e192..000000000
--- a/src/mem/cache/coherence/uni_coherence.hh
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- */
-
-#ifndef __UNI_COHERENCE_HH__
-#define __UNI_COHERENCE_HH__
-
-#include "base/trace.hh"
-#include "base/misc.hh"
-#include "mem/cache/cache_blk.hh"
-#include "mem/cache/miss/mshr_queue.hh"
-#include "mem/packet.hh"
-
-class BaseCache;
-
-class UniCoherence
-{
- protected:
- /** Buffers to hold forwarded invalidates. */
- MSHRQueue cshrs;
- /** Pointer to the parent cache. */
- BaseCache *cache;
-
- public:
- /**
- * Construct and initialize this coherence policy.
- */
- UniCoherence();
-
- /**
- * Set the pointer to the parent cache.
- * @param _cache The parent cache.
- */
- void setCache(BaseCache *_cache)
- {
- cache = _cache;
- }
-
- /**
- * Register statistics.
- * @param name The name to prepend to stat descriptions.
- */
- void regStats(const std::string &name)
- {
- }
-
- /**
- * Return Read.
- * @param cmd The request's command.
- * @param state The current state of the cache block.
- * @return The proper bus command, as determined by the protocol.
- * @todo Make changes so writebacks don't get here.
- */
- MemCmd getBusCmd(MemCmd cmd, CacheBlk::State state)
- {
- if (cmd == MemCmd::HardPFReq && state)
- warn("Trying to issue a prefetch to a block we already have\n");
- if (cmd == MemCmd::Writeback)
- return MemCmd::Writeback;
- return MemCmd::ReadReq;
- }
-
- /**
- * Just return readable and writeable.
- * @param pkt The bus response.
- * @param current The current block state.
- * @return The new state.
- */
- CacheBlk::State getNewState(PacketPtr &pkt, CacheBlk::State current)
- {
- if (pkt->senderState) //Blocking Buffers don't get mshrs
- {
- if (((MSHR *)(pkt->senderState))->originalCmd == MemCmd::HardPFReq) {
- DPRINTF(HWPrefetch, "Marking a hardware prefetch as such in the state\n");
- return BlkHWPrefetched | BlkValid | BlkWritable;
- }
- else {
- return BlkValid | BlkWritable;
- }
- }
- //@todo What about prefetching with blocking buffers
- else
- return BlkValid | BlkWritable;
- }
-
- /**
- * Return outstanding invalidate to forward.
- * @return The next invalidate to forward to lower levels of cache.
- */
- PacketPtr getPacket();
-
- /**
- * Was the CSHR request was sent successfully?
- * @param pkt The request.
- * @param success True if the request was sent successfully.
- */
- void sendResult(PacketPtr &pkt, MSHR* cshr, bool success);
-
- /**
- * Handle snooped bus requests.
- * @param pkt The snooped bus request.
- * @param blk The cache block corresponding to the request, if any.
- * @param mshr The MSHR corresponding to the request, if any.
- * @param new_state The new coherence state of the block.
- * @return True if the request should be satisfied locally.
- */
- bool handleBusRequest(PacketPtr &pkt, CacheBlk *blk, MSHR *mshr,
- CacheBlk::State &new_state);
-
- /**
- * Return true if this coherence policy can handle fast cache writes.
- */
- bool allowFastWrites() { return true; }
-
- bool hasProtocol() { return false; }
-
- bool propogateInvalidate(PacketPtr pkt, bool isTiming);
-};
-
-#endif //__UNI_COHERENCE_HH__
diff --git a/src/mem/cache/miss/SConscript b/src/mem/cache/miss/SConscript
index 0f81a2570..376d670cd 100644
--- a/src/mem/cache/miss/SConscript
+++ b/src/mem/cache/miss/SConscript
@@ -30,8 +30,5 @@
Import('*')
-Source('blocking_buffer.cc')
-Source('miss_buffer.cc')
-Source('miss_queue.cc')
Source('mshr.cc')
Source('mshr_queue.cc')
diff --git a/src/mem/cache/miss/blocking_buffer.cc b/src/mem/cache/miss/blocking_buffer.cc
deleted file mode 100644
index e8ff26880..000000000
--- a/src/mem/cache/miss/blocking_buffer.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- */
-
-/**
- * @file
- * Definitions of a simple buffer for a blocking cache.
- */
-#include <cstring>
-
-#include "mem/cache/base_cache.hh"
-#include "mem/cache/miss/blocking_buffer.hh"
-#include "mem/cache/prefetch/base_prefetcher.hh"
-#include "mem/request.hh"
-
-/**
- * @todo Move writebacks into shared BaseBuffer class.
- */
-void
-BlockingBuffer::regStats(const std::string &name)
-{
- MissBuffer::regStats(name);
-}
-
-
-void
-BlockingBuffer::handleMiss(PacketPtr &pkt, int blk_size, Tick time)
-{
- Addr blk_addr = pkt->getAddr() & ~(Addr)(blk_size - 1);
- if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
- !pkt->needsResponse())) {
- if (!pkt->needsResponse()) {
- wb.allocateAsBuffer(pkt);
- } else {
- wb.allocate(pkt->cmd, blk_addr, blk_size, pkt);
- }
-
- std::memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), blk_size);
-
- cache->setBlocked(Blocked_NoWBBuffers);
- cache->setMasterRequest(Request_WB, time);
- return;
- }
-
- if (!pkt->needsResponse()) {
- miss.allocateAsBuffer(pkt);
- } else {
- miss.allocate(pkt->cmd, blk_addr, blk_size, pkt);
- }
- if (!pkt->req->isUncacheable()) {
- miss.pkt->flags |= CACHE_LINE_FILL;
- }
- cache->setBlocked(Blocked_NoMSHRs);
- cache->setMasterRequest(Request_MSHR, time);
-}
-
-PacketPtr
-BlockingBuffer::getPacket()
-{
- if (miss.pkt && !miss.inService) {
- return miss.pkt;
- }
- return wb.pkt;
-}
-
-void
-BlockingBuffer::setBusCmd(PacketPtr &pkt, MemCmd cmd)
-{
- MSHR *mshr = (MSHR*) pkt->senderState;
- mshr->originalCmd = pkt->cmd;
- if (pkt->isCacheFill())
- pkt->cmdOverride(cmd);
-}
-
-void
-BlockingBuffer::restoreOrigCmd(PacketPtr &pkt)
-{
- pkt->cmdOverride(((MSHR*)(pkt->senderState))->originalCmd);
-}
-
-void
-BlockingBuffer::markInService(PacketPtr &pkt, MSHR* mshr)
-{
- if (!pkt->isCacheFill() && pkt->isWrite()) {
- // Forwarding a write/ writeback, don't need to change
- // the command
- assert(mshr == &wb);
- cache->clearMasterRequest(Request_WB);
- if (!pkt->needsResponse()) {
- assert(wb.getNumTargets() == 0);
- wb.deallocate();
- cache->clearBlocked(Blocked_NoWBBuffers);
- } else {
- wb.inService = true;
- }
- } else {
- assert(mshr == &miss);
- cache->clearMasterRequest(Request_MSHR);
- if (!pkt->needsResponse()) {
- assert(miss.getNumTargets() == 0);
- miss.deallocate();
- cache->clearBlocked(Blocked_NoMSHRs);
- } else {
- //mark in service
- miss.inService = true;
- }
- }
-}
-
-void
-BlockingBuffer::handleResponse(PacketPtr &pkt, Tick time)
-{
- if (pkt->isCacheFill()) {
- // targets were handled in the cache tags
- assert((MSHR*)pkt->senderState == &miss);
- miss.deallocate();
- cache->clearBlocked(Blocked_NoMSHRs);
- } else {
- if (((MSHR*)(pkt->senderState))->hasTargets()) {
- // Should only have 1 target if we had any
- assert(((MSHR*)(pkt->senderState))->getNumTargets() == 1);
- PacketPtr target = ((MSHR*)(pkt->senderState))->getTarget();
- ((MSHR*)(pkt->senderState))->popTarget();
- if (pkt->isRead()) {
- std::memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), target->getSize());
- }
- cache->respond(target, time);
- assert(!((MSHR*)(pkt->senderState))->hasTargets());
- }
-
- if (pkt->isWrite()) {
- assert(((MSHR*)(pkt->senderState)) == &wb);
- wb.deallocate();
- cache->clearBlocked(Blocked_NoWBBuffers);
- } else {
- miss.deallocate();
- cache->clearBlocked(Blocked_NoMSHRs);
- }
- }
-}
-
-void
-BlockingBuffer::squash(int threadNum)
-{
- if (miss.threadNum == threadNum) {
- PacketPtr target = miss.getTarget();
- miss.popTarget();
- assert(0/*target->req->getThreadNum()*/ == threadNum);
- target = NULL;
- assert(!miss.hasTargets());
- miss.ntargets=0;
- if (!miss.inService) {
- miss.deallocate();
- cache->clearBlocked(Blocked_NoMSHRs);
- cache->clearMasterRequest(Request_MSHR);
- }
- }
-}
-
-void
-BlockingBuffer::doWriteback(Addr addr,
- int size, uint8_t *data, bool compressed)
-{
- // Generate request
- Request * req = new Request(addr, size, 0);
- PacketPtr pkt = new Packet(req, MemCmd::Writeback, -1);
- pkt->allocate();
- if (data) {
- std::memcpy(pkt->getPtr<uint8_t>(), data, size);
- }
-
- if (compressed) {
- pkt->flags |= COMPRESSED;
- }
-
- ///All writebacks charged to same thread @todo figure this out
- writebacks[0/*pkt->req->getThreadNum()*/]++;
-
- wb.allocateAsBuffer(pkt);
- cache->setMasterRequest(Request_WB, curTick);
- cache->setBlocked(Blocked_NoWBBuffers);
-}
-
-
-
-void
-BlockingBuffer::doWriteback(PacketPtr &pkt)
-{
- writebacks[0/*pkt->req->getThreadNum()*/]++;
-
- wb.allocateAsBuffer(pkt);
-
- // Since allocate as buffer copies the request,
- // need to copy data here.
- std::memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
-
- cache->setBlocked(Blocked_NoWBBuffers);
- cache->setMasterRequest(Request_WB, curTick);
-}
-
-
-MSHR *
-BlockingBuffer::findMSHR(Addr addr)
-{
- if (miss.addr == addr && miss.pkt)
- return &miss;
- return NULL;
-}
-
-
-bool
-BlockingBuffer::findWrites(Addr addr, std::vector<MSHR*>& writes)
-{
- if (wb.addr == addr && wb.pkt) {
- writes.push_back(&wb);
- return true;
- }
- return false;
-}
diff --git a/src/mem/cache/miss/blocking_buffer.hh b/src/mem/cache/miss/blocking_buffer.hh
deleted file mode 100644
index 86b24d539..000000000
--- a/src/mem/cache/miss/blocking_buffer.hh
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- */
-
-/**
- * @file
- * Declaration of a simple buffer for a blocking cache.
- */
-
-#ifndef __BLOCKING_BUFFER_HH__
-#define __BLOCKING_BUFFER_HH__
-
-#include <vector>
-
-#include "base/misc.hh" // for fatal()
-#include "mem/cache/miss/miss_buffer.hh"
-#include "mem/cache/miss/mshr.hh"
-
-/**
- * Miss and writeback storage for a blocking cache.
- */
-class BlockingBuffer : public MissBuffer
-{
-protected:
- /** Miss storage. */
- MSHR miss;
- /** WB storage. */
- MSHR wb;
-
-public:
- /**
- * Builds and initializes this buffer.
- * @param write_allocate If true, treat write misses the same as reads.
- */
- BlockingBuffer(bool write_allocate)
- : MissBuffer(write_allocate)
- {
- }
-
- /**
- * Register statistics for this object.
- * @param name The name of the parent cache.
- */
- void regStats(const std::string &name);
-
- /**
- * Handle a cache miss properly. Requests the bus and marks the cache as
- * blocked.
- * @param pkt The request that missed in the cache.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- */
- void handleMiss(PacketPtr &pkt, int blk_size, Tick time);
-
- /**
- * Fetch the block for the given address and buffer the given target.
- * @param addr The address to fetch.
- * @param asid The address space of the address.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- * @param target The target for the fetch.
- */
- MSHR* fetchBlock(Addr addr, int blk_size, Tick time,
- PacketPtr &target)
- {
- fatal("Unimplemented");
- M5_DUMMY_RETURN
- }
-
- /**
- * Selects a outstanding request to service.
- * @return The request to service, NULL if none found.
- */
- PacketPtr getPacket();
-
- /**
- * Set the command to the given bus command.
- * @param pkt The request to update.
- * @param cmd The bus command to use.
- */
- void setBusCmd(PacketPtr &pkt, MemCmd cmd);
-
- /**
- * Restore the original command in case of a bus transmission error.
- * @param pkt The request to reset.
- */
- void restoreOrigCmd(PacketPtr &pkt);
-
- /**
- * Marks a request as in service (sent on the bus). This can have side
- * effect since storage for no response commands is deallocated once they
- * are successfully sent.
- * @param pkt The request that was sent on the bus.
- */
- void markInService(PacketPtr &pkt, MSHR* mshr);
-
- /**
- * Frees the resources of the request and unblock the cache.
- * @param pkt The request that has been satisfied.
- * @param time The time when the request is satisfied.
- */
- void handleResponse(PacketPtr &pkt, Tick time);
-
- /**
- * Removes all outstanding requests for a given thread number. If a request
- * has been sent to the bus, this function removes all of its targets.
- * @param threadNum The thread number of the requests to squash.
- */
- void squash(int threadNum);
-
- /**
- * Return the current number of outstanding misses.
- * @return the number of outstanding misses.
- */
- int getMisses()
- {
- return miss.getNumTargets();
- }
-
- /**
- * Searches for the supplied address in the miss "queue".
- * @param addr The address to look for.
- * @param asid The address space id.
- * @return A pointer to miss if it matches.
- */
- MSHR* findMSHR(Addr addr);
-
- /**
- * Searches for the supplied address in the write buffer.
- * @param addr The address to look for.
- * @param asid The address space id.
- * @param writes List of pointers to the matching writes.
- * @return True if there is a matching write.
- */
- bool findWrites(Addr addr, std::vector<MSHR*>& writes);
-
- /**
- * Perform a writeback of dirty data to the given address.
- * @param addr The address to write to.
- * @param asid The address space id.
- * @param size The number of bytes to write.
- * @param data The data to write, can be NULL.
- * @param compressed True if the data is compressed.
- */
- void doWriteback(Addr addr,
- int size, uint8_t *data, bool compressed);
-
- /**
- * Perform a writeback request.
- * @param pkt The writeback request.
- */
- void doWriteback(PacketPtr &pkt);
-
- /**
- * Returns true if there are outstanding requests.
- * @return True if there are outstanding requests.
- */
- bool havePending()
- {
- return !miss.inService || !wb.inService;
- }
-
- /**
- * Add a target to the given MSHR. This assumes it is in the miss queue.
- * @param mshr The mshr to add a target to.
- * @param pkt The target to add.
- */
- void addTarget(MSHR *mshr, PacketPtr &pkt)
- {
- fatal("Shouldn't call this on a blocking buffer.");
- }
-
- /**
- * Dummy implmentation.
- */
- MSHR* allocateTargetList(Addr addr)
- {
- fatal("Unimplemented");
- M5_DUMMY_RETURN
- }
-};
-
-#endif // __BLOCKING_BUFFER_HH__
diff --git a/src/mem/cache/miss/miss_buffer.cc b/src/mem/cache/miss/miss_buffer.cc
deleted file mode 100644
index 4d9cd0958..000000000
--- a/src/mem/cache/miss/miss_buffer.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2003-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: Erik Hallnor
- */
-
-#include "cpu/smt.hh" //for maxThreadsPerCPU
-#include "mem/cache/base_cache.hh"
-#include "mem/cache/miss/miss_buffer.hh"
-#include "mem/cache/prefetch/base_prefetcher.hh"
-
-/**
- * @todo Move writebacks into shared BaseBuffer class.
- */
-void
-MissBuffer::regStats(const std::string &name)
-{
- using namespace Stats;
- writebacks
- .init(maxThreadsPerCPU)
- .name(name + ".writebacks")
- .desc("number of writebacks")
- .flags(total)
- ;
-}
-
-void
-MissBuffer::setCache(BaseCache *_cache)
-{
- cache = _cache;
- blkSize = cache->getBlockSize();
-}
-
-void
-MissBuffer::setPrefetcher(BasePrefetcher *_prefetcher)
-{
- prefetcher = _prefetcher;
-}
diff --git a/src/mem/cache/miss/miss_buffer.hh b/src/mem/cache/miss/miss_buffer.hh
deleted file mode 100644
index 9a86db304..000000000
--- a/src/mem/cache/miss/miss_buffer.hh
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2003-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: Steve Reinhardt
- */
-
-/**
- * @file
- * MissBuffer declaration.
- */
-
-#ifndef __MISS_BUFFER_HH__
-#define __MISS_BUFFER_HH__
-
-class BaseCache;
-class BasePrefetcher;
-class MSHR;
-
-/**
- * Abstract base class for cache miss buffering.
- */
-class MissBuffer
-{
- protected:
- /** True if the cache should allocate on a write miss. */
- const bool writeAllocate;
-
- /** Pointer to the parent cache. */
- BaseCache *cache;
-
- /** The Prefetcher */
- BasePrefetcher *prefetcher;
-
- /** Block size of the parent cache. */
- int blkSize;
-
- // Statistics
- /**
- * @addtogroup CacheStatistics
- * @{
- */
- /** Number of blocks written back per thread. */
- Stats::Vector<> writebacks;
-
- /**
- * @}
- */
-
- public:
- MissBuffer(bool write_allocate)
- : writeAllocate(write_allocate)
- {
- }
-
- virtual ~MissBuffer() {}
-
- /**
- * Called by the parent cache to set the back pointer.
- * @param _cache A pointer to the parent cache.
- */
- void setCache(BaseCache *_cache);
-
- void setPrefetcher(BasePrefetcher *_prefetcher);
-
- /**
- * Register statistics for this object.
- * @param name The name of the parent cache.
- */
- virtual void regStats(const std::string &name);
-
- /**
- * Handle a cache miss properly. Either allocate an MSHR for the request,
- * or forward it through the write buffer.
- * @param pkt The request that missed in the cache.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- */
- virtual void handleMiss(PacketPtr &pkt, int blk_size, Tick time) = 0;
-
- /**
- * Fetch the block for the given address and buffer the given target.
- * @param addr The address to fetch.
- * @param asid The address space of the address.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- * @param target The target for the fetch.
- */
- virtual MSHR *fetchBlock(Addr addr, int blk_size, Tick time,
- PacketPtr &target) = 0;
-
- /**
- * Selects a outstanding request to service.
- * @return The request to service, NULL if none found.
- */
- virtual PacketPtr getPacket() = 0;
-
- /**
- * Set the command to the given bus command.
- * @param pkt The request to update.
- * @param cmd The bus command to use.
- */
- virtual void setBusCmd(PacketPtr &pkt, MemCmd cmd) = 0;
-
- /**
- * Restore the original command in case of a bus transmission error.
- * @param pkt The request to reset.
- */
- virtual void restoreOrigCmd(PacketPtr &pkt) = 0;
-
- /**
- * Marks a request as in service (sent on the bus). This can have side
- * effect since storage for no response commands is deallocated once they
- * are successfully sent.
- * @param pkt The request that was sent on the bus.
- */
- virtual void markInService(PacketPtr &pkt, MSHR* mshr) = 0;
-
- /**
- * Collect statistics and free resources of a satisfied request.
- * @param pkt The request that has been satisfied.
- * @param time The time when the request is satisfied.
- */
- virtual void handleResponse(PacketPtr &pkt, Tick time) = 0;
-
- /**
- * Removes all outstanding requests for a given thread number. If a request
- * has been sent to the bus, this function removes all of its targets.
- * @param threadNum The thread number of the requests to squash.
- */
- virtual void squash(int threadNum) = 0;
-
- /**
- * Return the current number of outstanding misses.
- * @return the number of outstanding misses.
- */
- virtual int getMisses() = 0;
-
- /**
- * Searches for the supplied address in the miss queue.
- * @param addr The address to look for.
- * @param asid The address space id.
- * @return The MSHR that contains the address, NULL if not found.
- * @warning Currently only searches the miss queue. If non write allocate
- * might need to search the write buffer for coherence.
- */
- virtual MSHR* findMSHR(Addr addr) = 0;
-
- /**
- * Searches for the supplied address in the write buffer.
- * @param addr The address to look for.
- * @param asid The address space id.
- * @param writes The list of writes that match the address.
- * @return True if any writes are found
- */
- virtual bool findWrites(Addr addr, std::vector<MSHR*>& writes) = 0;
-
- /**
- * Perform a writeback of dirty data to the given address.
- * @param addr The address to write to.
- * @param asid The address space id.
- * @param xc The execution context of the address space.
- * @param size The number of bytes to write.
- * @param data The data to write, can be NULL.
- * @param compressed True if the data is compressed.
- */
- virtual void doWriteback(Addr addr, int size, uint8_t *data,
- bool compressed) = 0;
-
- /**
- * Perform the given writeback request.
- * @param pkt The writeback request.
- */
- virtual void doWriteback(PacketPtr &pkt) = 0;
-
- /**
- * Returns true if there are outstanding requests.
- * @return True if there are outstanding requests.
- */
- virtual bool havePending() = 0;
-
- /**
- * Add a target to the given MSHR. This assumes it is in the miss queue.
- * @param mshr The mshr to add a target to.
- * @param pkt The target to add.
- */
- virtual void addTarget(MSHR *mshr, PacketPtr &pkt) = 0;
-
- /**
- * Allocate a MSHR to hold a list of targets to a block involved in a copy.
- * If the block is marked done then the MSHR already holds the data to
- * fill the block. Otherwise the block needs to be fetched.
- * @param addr The address to buffer.
- * @param asid The address space ID.
- * @return A pointer to the allocated MSHR.
- */
- virtual MSHR* allocateTargetList(Addr addr) = 0;
-};
-
-#endif //__MISS_BUFFER_HH__
diff --git a/src/mem/cache/miss/miss_queue.cc b/src/mem/cache/miss/miss_queue.cc
deleted file mode 100644
index 24ca9cfa2..000000000
--- a/src/mem/cache/miss/miss_queue.cc
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- * Ron Dreslinski
- */
-
-/**
- * @file
- * Miss and writeback queue definitions.
- */
-
-#include "cpu/smt.hh" //for maxThreadsPerCPU
-#include "mem/cache/base_cache.hh"
-#include "mem/cache/miss/miss_queue.hh"
-#include "mem/cache/prefetch/base_prefetcher.hh"
-
-using namespace std;
-
-// simple constructor
-/**
- * @todo Remove the +16 from the write buffer constructor once we handle
- * stalling on writebacks do to compression writes.
- */
-MissQueue::MissQueue(int numMSHRs, int numTargets, int write_buffers,
- bool write_allocate, bool prefetch_miss)
- : MissBuffer(write_allocate),
- mq(numMSHRs, 4), wb(write_buffers,numMSHRs+1000), numMSHR(numMSHRs),
- numTarget(numTargets), writeBuffers(write_buffers),
- order(0), prefetchMiss(prefetch_miss)
-{
- noTargetMSHR = NULL;
-}
-
-
-MissQueue::~MissQueue()
-{
-}
-
-
-void
-MissQueue::regStats(const string &name)
-{
- MissBuffer::regStats(name);
-
- using namespace Stats;
-
- // MSHR hit statistics
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshr_hits[access_idx]
- .init(maxThreadsPerCPU)
- .name(name + "." + cstr + "_mshr_hits")
- .desc("number of " + cstr + " MSHR hits")
- .flags(total | nozero | nonan)
- ;
- }
-
- demandMshrHits
- .name(name + ".demand_mshr_hits")
- .desc("number of demand (read+write) MSHR hits")
- .flags(total)
- ;
- demandMshrHits = mshr_hits[MemCmd::ReadReq] + mshr_hits[MemCmd::WriteReq];
-
- overallMshrHits
- .name(name + ".overall_mshr_hits")
- .desc("number of overall MSHR hits")
- .flags(total)
- ;
- overallMshrHits = demandMshrHits + mshr_hits[MemCmd::SoftPFReq] +
- mshr_hits[MemCmd::HardPFReq];
-
- // MSHR miss statistics
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshr_misses[access_idx]
- .init(maxThreadsPerCPU)
- .name(name + "." + cstr + "_mshr_misses")
- .desc("number of " + cstr + " MSHR misses")
- .flags(total | nozero | nonan)
- ;
- }
-
- demandMshrMisses
- .name(name + ".demand_mshr_misses")
- .desc("number of demand (read+write) MSHR misses")
- .flags(total)
- ;
- demandMshrMisses = mshr_misses[MemCmd::ReadReq] + mshr_misses[MemCmd::WriteReq];
-
- overallMshrMisses
- .name(name + ".overall_mshr_misses")
- .desc("number of overall MSHR misses")
- .flags(total)
- ;
- overallMshrMisses = demandMshrMisses + mshr_misses[MemCmd::SoftPFReq] +
- mshr_misses[MemCmd::HardPFReq];
-
- // MSHR miss latency statistics
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshr_miss_latency[access_idx]
- .init(maxThreadsPerCPU)
- .name(name + "." + cstr + "_mshr_miss_latency")
- .desc("number of " + cstr + " MSHR miss cycles")
- .flags(total | nozero | nonan)
- ;
- }
-
- demandMshrMissLatency
- .name(name + ".demand_mshr_miss_latency")
- .desc("number of demand (read+write) MSHR miss cycles")
- .flags(total)
- ;
- demandMshrMissLatency = mshr_miss_latency[MemCmd::ReadReq]
- + mshr_miss_latency[MemCmd::WriteReq];
-
- overallMshrMissLatency
- .name(name + ".overall_mshr_miss_latency")
- .desc("number of overall MSHR miss cycles")
- .flags(total)
- ;
- overallMshrMissLatency = demandMshrMissLatency +
- mshr_miss_latency[MemCmd::SoftPFReq] + mshr_miss_latency[MemCmd::HardPFReq];
-
- // MSHR uncacheable statistics
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshr_uncacheable[access_idx]
- .init(maxThreadsPerCPU)
- .name(name + "." + cstr + "_mshr_uncacheable")
- .desc("number of " + cstr + " MSHR uncacheable")
- .flags(total | nozero | nonan)
- ;
- }
-
- overallMshrUncacheable
- .name(name + ".overall_mshr_uncacheable_misses")
- .desc("number of overall MSHR uncacheable misses")
- .flags(total)
- ;
- overallMshrUncacheable = mshr_uncacheable[MemCmd::ReadReq]
- + mshr_uncacheable[MemCmd::WriteReq] + mshr_uncacheable[MemCmd::SoftPFReq]
- + mshr_uncacheable[MemCmd::HardPFReq];
-
- // MSHR miss latency statistics
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshr_uncacheable_lat[access_idx]
- .init(maxThreadsPerCPU)
- .name(name + "." + cstr + "_mshr_uncacheable_latency")
- .desc("number of " + cstr + " MSHR uncacheable cycles")
- .flags(total | nozero | nonan)
- ;
- }
-
- overallMshrUncacheableLatency
- .name(name + ".overall_mshr_uncacheable_latency")
- .desc("number of overall MSHR uncacheable cycles")
- .flags(total)
- ;
- overallMshrUncacheableLatency = mshr_uncacheable_lat[MemCmd::ReadReq]
- + mshr_uncacheable_lat[MemCmd::WriteReq]
- + mshr_uncacheable_lat[MemCmd::SoftPFReq]
- + mshr_uncacheable_lat[MemCmd::HardPFReq];
-
-#if 0
- // MSHR access formulas
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshrAccesses[access_idx]
- .name(name + "." + cstr + "_mshr_accesses")
- .desc("number of " + cstr + " mshr accesses(hits+misses)")
- .flags(total | nozero | nonan)
- ;
- mshrAccesses[access_idx] =
- mshr_hits[access_idx] + mshr_misses[access_idx]
- + mshr_uncacheable[access_idx];
- }
-
- demandMshrAccesses
- .name(name + ".demand_mshr_accesses")
- .desc("number of demand (read+write) mshr accesses")
- .flags(total | nozero | nonan)
- ;
- demandMshrAccesses = demandMshrHits + demandMshrMisses;
-
- overallMshrAccesses
- .name(name + ".overall_mshr_accesses")
- .desc("number of overall (read+write) mshr accesses")
- .flags(total | nozero | nonan)
- ;
- overallMshrAccesses = overallMshrHits + overallMshrMisses
- + overallMshrUncacheable;
-#endif
-
- // MSHR miss rate formulas
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- mshrMissRate[access_idx]
- .name(name + "." + cstr + "_mshr_miss_rate")
- .desc("mshr miss rate for " + cstr + " accesses")
- .flags(total | nozero | nonan)
- ;
-
- mshrMissRate[access_idx] =
- mshr_misses[access_idx] / cache->accesses[access_idx];
- }
-
- demandMshrMissRate
- .name(name + ".demand_mshr_miss_rate")
- .desc("mshr miss rate for demand accesses")
- .flags(total)
- ;
- demandMshrMissRate = demandMshrMisses / cache->demandAccesses;
-
- overallMshrMissRate
- .name(name + ".overall_mshr_miss_rate")
- .desc("mshr miss rate for overall accesses")
- .flags(total)
- ;
- overallMshrMissRate = overallMshrMisses / cache->overallAccesses;
-
- // mshrMiss latency formulas
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- avgMshrMissLatency[access_idx]
- .name(name + "." + cstr + "_avg_mshr_miss_latency")
- .desc("average " + cstr + " mshr miss latency")
- .flags(total | nozero | nonan)
- ;
-
- avgMshrMissLatency[access_idx] =
- mshr_miss_latency[access_idx] / mshr_misses[access_idx];
- }
-
- demandAvgMshrMissLatency
- .name(name + ".demand_avg_mshr_miss_latency")
- .desc("average overall mshr miss latency")
- .flags(total)
- ;
- demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
-
- overallAvgMshrMissLatency
- .name(name + ".overall_avg_mshr_miss_latency")
- .desc("average overall mshr miss latency")
- .flags(total)
- ;
- overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
-
- // mshrUncacheable latency formulas
- for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
- MemCmd cmd(access_idx);
- const string &cstr = cmd.toString();
-
- avgMshrUncacheableLatency[access_idx]
- .name(name + "." + cstr + "_avg_mshr_uncacheable_latency")
- .desc("average " + cstr + " mshr uncacheable latency")
- .flags(total | nozero | nonan)
- ;
-
- avgMshrUncacheableLatency[access_idx] =
- mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
- }
-
- overallAvgMshrUncacheableLatency
- .name(name + ".overall_avg_mshr_uncacheable_latency")
- .desc("average overall mshr uncacheable latency")
- .flags(total)
- ;
- overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
-
- mshr_cap_events
- .init(maxThreadsPerCPU)
- .name(name + ".mshr_cap_events")
- .desc("number of times MSHR cap was activated")
- .flags(total)
- ;
-
- //software prefetching stats
- soft_prefetch_mshr_full
- .init(maxThreadsPerCPU)
- .name(name + ".soft_prefetch_mshr_full")
- .desc("number of mshr full events for SW prefetching instrutions")
- .flags(total)
- ;
-
- mshr_no_allocate_misses
- .name(name +".no_allocate_misses")
- .desc("Number of misses that were no-allocate")
- ;
-
-}
-
-
-MSHR*
-MissQueue::allocateMiss(PacketPtr &pkt, int size, Tick time)
-{
- MSHR* mshr = mq.allocate(pkt, size);
- mshr->order = order++;
- if (!pkt->req->isUncacheable() ){//&& !pkt->isNoAllocate()) {
- // Mark this as a cache line fill
- mshr->pkt->flags |= CACHE_LINE_FILL;
- }
- if (mq.isFull()) {
- cache->setBlocked(Blocked_NoMSHRs);
- }
- if (pkt->cmd != MemCmd::HardPFReq) {
- //If we need to request the bus (not on HW prefetch), do so
- cache->setMasterRequest(Request_MSHR, time);
- }
- return mshr;
-}
-
-
-MSHR*
-MissQueue::allocateWrite(PacketPtr &pkt, int size, Tick time)
-{
- MSHR* mshr = wb.allocate(pkt,size);
- mshr->order = order++;
-
-//REMOVING COMPRESSION FOR NOW
-#if 0
- if (pkt->isCompressed()) {
- mshr->pkt->deleteData();
- mshr->pkt->actualSize = pkt->actualSize;
- mshr->pkt->data = new uint8_t[pkt->actualSize];
- memcpy(mshr->pkt->data, pkt->data, pkt->actualSize);
- } else {
-#endif
- memcpy(mshr->pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
- //{
-
- if (wb.isFull()) {
- cache->setBlocked(Blocked_NoWBBuffers);
- }
-
- cache->setMasterRequest(Request_WB, time);
-
- return mshr;
-}
-
-
-/**
- * @todo Remove SW prefetches on mshr hits.
- */
-void
-MissQueue::handleMiss(PacketPtr &pkt, int blkSize, Tick time)
-{
-// if (!cache->isTopLevel())
- if (prefetchMiss) prefetcher->handleMiss(pkt, time);
-
- int size = blkSize;
- Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
- MSHR* mshr = NULL;
- if (!pkt->req->isUncacheable()) {
- mshr = mq.findMatch(blkAddr);
- if (mshr) {
- //@todo remove hw_pf here
- mshr_hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) {
- mshr->threadNum = -1;
- }
- mq.allocateTarget(mshr, pkt);
- if (mshr->pkt->isNoAllocate() && !pkt->isNoAllocate()) {
- //We are adding an allocate after a no-allocate
- mshr->pkt->flags &= ~NO_ALLOCATE;
- }
- if (mshr->getNumTargets() == numTarget) {
- noTargetMSHR = mshr;
- cache->setBlocked(Blocked_NoTargets);
- mq.moveToFront(mshr);
- }
- return;
- }
- if (pkt->isNoAllocate()) {
- //Count no-allocate requests differently
- mshr_no_allocate_misses++;
- }
- else {
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- }
- } else {
- //Count uncacheable accesses
- mshr_uncacheable[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- size = pkt->getSize();
- }
- if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
- !pkt->needsResponse())) {
- /**
- * @todo Add write merging here.
- */
- mshr = allocateWrite(pkt, pkt->getSize(), time);
- return;
- }
-
- mshr = allocateMiss(pkt, blkSize, time);
-}
-
-MSHR*
-MissQueue::fetchBlock(Addr addr, int blk_size, Tick time,
- PacketPtr &target)
-{
- Addr blkAddr = addr & ~(Addr)(blk_size - 1);
- assert(mq.findMatch(addr) == NULL);
- MSHR *mshr = mq.allocateFetch(blkAddr, blk_size, target);
- mshr->order = order++;
- mshr->pkt->flags |= CACHE_LINE_FILL;
- if (mq.isFull()) {
- cache->setBlocked(Blocked_NoMSHRs);
- }
- cache->setMasterRequest(Request_MSHR, time);
- return mshr;
-}
-
-PacketPtr
-MissQueue::getPacket()
-{
- PacketPtr pkt = mq.getReq();
- if (((wb.isFull() && wb.inServiceMSHRs == 0) || !pkt ||
- pkt->time > curTick) && wb.havePending()) {
- pkt = wb.getReq();
- // Need to search for earlier miss.
- MSHR *mshr = mq.findPending(pkt);
- if (mshr && mshr->order < ((MSHR*)(pkt->senderState))->order) {
- // Service misses in order until conflict is cleared.
- return mq.getReq();
- }
- }
- if (pkt) {
- MSHR* mshr = wb.findPending(pkt);
- if (mshr /*&& mshr->order < pkt->senderState->order*/) {
- // The only way this happens is if we are
- // doing a write and we didn't have permissions
- // then subsequently saw a writeback(owned got evicted)
- // We need to make sure to perform the writeback first
- // To preserve the dirty data, then we can issue the write
- return wb.getReq();
- }
- }
- else if (!mq.isFull()){
- //If we have a miss queue slot, we can try a prefetch
- pkt = prefetcher->getPacket();
- if (pkt) {
- //Update statistic on number of prefetches issued (hwpf_mshr_misses)
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- //It will request the bus for the future, but should clear that immedieatley
- allocateMiss(pkt, pkt->getSize(), curTick);
- pkt = mq.getReq();
- assert(pkt); //We should get back a req b/c we just put one in
- }
- }
- return pkt;
-}
-
-void
-MissQueue::setBusCmd(PacketPtr &pkt, MemCmd cmd)
-{
- assert(pkt->senderState != 0);
- MSHR * mshr = (MSHR*)pkt->senderState;
- mshr->originalCmd = pkt->cmd;
- if (cmd == MemCmd::UpgradeReq || cmd == MemCmd::InvalidateReq) {
- pkt->flags |= NO_ALLOCATE;
- pkt->flags &= ~CACHE_LINE_FILL;
- }
- else if (!pkt->req->isUncacheable() && !pkt->isNoAllocate() &&
- cmd.needsResponse()) {
- pkt->flags |= CACHE_LINE_FILL;
- }
- if (pkt->isCacheFill() || pkt->isNoAllocate())
- pkt->cmd = cmd;
-}
-
-void
-MissQueue::restoreOrigCmd(PacketPtr &pkt)
-{
- pkt->cmd = ((MSHR*)(pkt->senderState))->originalCmd;
-}
-
-void
-MissQueue::markInService(PacketPtr &pkt, MSHR* mshr)
-{
- bool unblock = false;
- BlockedCause cause = NUM_BLOCKED_CAUSES;
-
- /**
- * @todo Should include MSHRQueue pointer in MSHR to select the correct
- * one.
- */
- if ((!pkt->isCacheFill() && pkt->isWrite())) {
- // Forwarding a write/ writeback, don't need to change
- // the command
- unblock = wb.isFull();
- wb.markInService(mshr);
- if (!wb.havePending()){
- cache->clearMasterRequest(Request_WB);
- }
- if (unblock) {
- // Do we really unblock?
- unblock = !wb.isFull();
- cause = Blocked_NoWBBuffers;
- }
- } else {
- unblock = mq.isFull();
- mq.markInService(mshr);
- if (!mq.havePending()){
- cache->clearMasterRequest(Request_MSHR);
- }
- if (mshr->originalCmd == MemCmd::HardPFReq) {
- DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n",
- cache->name());
- //Also clear pending if need be
- if (!prefetcher->havePending())
- {
- cache->clearMasterRequest(Request_PF);
- }
- }
- if (unblock) {
- unblock = !mq.isFull();
- cause = Blocked_NoMSHRs;
- }
- }
- if (unblock) {
- cache->clearBlocked(cause);
- }
-}
-
-
-void
-MissQueue::handleResponse(PacketPtr &pkt, Tick time)
-{
- MSHR* mshr = (MSHR*)pkt->senderState;
- if (((MSHR*)(pkt->senderState))->originalCmd == MemCmd::HardPFReq) {
- DPRINTF(HWPrefetch, "%s:Handling the response to a HW_PF\n",
- cache->name());
- }
-#ifndef NDEBUG
- int num_targets = mshr->getNumTargets();
-#endif
-
- bool unblock = false;
- bool unblock_target = false;
- BlockedCause cause = NUM_BLOCKED_CAUSES;
-
- if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
- mshr_miss_latency[mshr->originalCmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
- curTick - pkt->time;
- // targets were handled in the cache tags
- if (mshr == noTargetMSHR) {
- // we always clear at least one target
- unblock_target = true;
- cause = Blocked_NoTargets;
- noTargetMSHR = NULL;
- }
-
- if (mshr->hasTargets()) {
- // Didn't satisfy all the targets, need to resend
- MemCmd cmd = mshr->getTarget()->cmd;
- mshr->pkt->setDest(Packet::Broadcast);
- mshr->pkt->result = Packet::Unknown;
- mshr->pkt->req = mshr->getTarget()->req;
- mq.markPending(mshr, cmd);
- mshr->order = order++;
- cache->setMasterRequest(Request_MSHR, time);
- }
- else {
- unblock = mq.isFull();
- mq.deallocate(mshr);
- if (unblock) {
- unblock = !mq.isFull();
- cause = Blocked_NoMSHRs;
- }
- }
- } else {
- if (pkt->req->isUncacheable()) {
- mshr_uncacheable_lat[pkt->cmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
- curTick - pkt->time;
- }
- if (mshr->hasTargets() && pkt->req->isUncacheable()) {
- // Should only have 1 target if we had any
- assert(num_targets == 1);
- PacketPtr target = mshr->getTarget();
- mshr->popTarget();
- if (pkt->isRead()) {
- memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
- target->getSize());
- }
- cache->respond(target, time);
- assert(!mshr->hasTargets());
- }
- else if (mshr->hasTargets()) {
- //Must be a no_allocate with possibly more than one target
- assert(mshr->pkt->isNoAllocate());
- while (mshr->hasTargets()) {
- PacketPtr target = mshr->getTarget();
- mshr->popTarget();
- if (pkt->isRead()) {
- memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
- target->getSize());
- }
- cache->respond(target, time);
- }
- }
-
- if (pkt->isWrite()) {
- // If the wrtie buffer is full, we might unblock now
- unblock = wb.isFull();
- wb.deallocate(mshr);
- if (unblock) {
- // Did we really unblock?
- unblock = !wb.isFull();
- cause = Blocked_NoWBBuffers;
- }
- } else {
- unblock = mq.isFull();
- mq.deallocate(mshr);
- if (unblock) {
- unblock = !mq.isFull();
- cause = Blocked_NoMSHRs;
- }
- }
- }
- if (unblock || unblock_target) {
- cache->clearBlocked(cause);
- }
-}
-
-void
-MissQueue::squash(int threadNum)
-{
- bool unblock = false;
- BlockedCause cause = NUM_BLOCKED_CAUSES;
-
- if (noTargetMSHR && noTargetMSHR->threadNum == threadNum) {
- noTargetMSHR = NULL;
- unblock = true;
- cause = Blocked_NoTargets;
- }
- if (mq.isFull()) {
- unblock = true;
- cause = Blocked_NoMSHRs;
- }
- mq.squash(threadNum);
- if (!mq.havePending()) {
- cache->clearMasterRequest(Request_MSHR);
- }
- if (unblock && !mq.isFull()) {
- cache->clearBlocked(cause);
- }
-
-}
-
-MSHR*
-MissQueue::findMSHR(Addr addr)
-{
- return mq.findMatch(addr);
-}
-
-bool
-MissQueue::findWrites(Addr addr, vector<MSHR*> &writes)
-{
- return wb.findMatches(addr,writes);
-}
-
-void
-MissQueue::doWriteback(Addr addr,
- int size, uint8_t *data, bool compressed)
-{
- // Generate request
- Request * req = new Request(addr, size, 0);
- PacketPtr pkt = new Packet(req, MemCmd::Writeback, -1);
- pkt->allocate();
- if (data) {
- memcpy(pkt->getPtr<uint8_t>(), data, size);
- }
-
- if (compressed) {
- pkt->flags |= COMPRESSED;
- }
-
- ///All writebacks charged to same thread @todo figure this out
- writebacks[0/*pkt->req->getThreadNum()*/]++;
-
- allocateWrite(pkt, 0, curTick);
-}
-
-
-void
-MissQueue::doWriteback(PacketPtr &pkt)
-{
- writebacks[0/*pkt->req->getThreadNum()*/]++;
- allocateWrite(pkt, 0, curTick);
-}
-
-
-MSHR*
-MissQueue::allocateTargetList(Addr addr)
-{
- MSHR* mshr = mq.allocateTargetList(addr, blkSize);
- mshr->pkt->flags |= CACHE_LINE_FILL;
- if (mq.isFull()) {
- cache->setBlocked(Blocked_NoMSHRs);
- }
- return mshr;
-}
-
-bool
-MissQueue::havePending()
-{
- return mq.havePending() || wb.havePending() || prefetcher->havePending();
-}
diff --git a/src/mem/cache/miss/miss_queue.hh b/src/mem/cache/miss/miss_queue.hh
deleted file mode 100644
index d3560ff36..000000000
--- a/src/mem/cache/miss/miss_queue.hh
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Erik Hallnor
- */
-
-/**
- * @file
- * Miss and writeback queue declarations.
- */
-
-#ifndef __MISS_QUEUE_HH__
-#define __MISS_QUEUE_HH__
-
-#include <vector>
-
-#include "mem/cache/miss/miss_buffer.hh"
-#include "mem/cache/miss/mshr.hh"
-#include "mem/cache/miss/mshr_queue.hh"
-#include "base/statistics.hh"
-
-/**
- * Manages cache misses and writebacks. Contains MSHRs to store miss data
- * and the writebuffer for writes/writebacks.
- * @todo need to handle data on writes better (encapsulate).
- * @todo need to make replacements/writebacks happen in Cache::access
- */
-class MissQueue : public MissBuffer
-{
- protected:
- /** The MSHRs. */
- MSHRQueue mq;
- /** Write Buffer. */
- MSHRQueue wb;
-
- // PARAMTERS
-
- /** The number of MSHRs in the miss queue. */
- const int numMSHR;
- /** The number of targets for each MSHR. */
- const int numTarget;
- /** The number of write buffers. */
- const int writeBuffers;
-
- /** Increasing order number assigned to each incoming request. */
- uint64_t order;
-
- bool prefetchMiss;
-
- // Statistics
- /**
- * @addtogroup CacheStatistics
- * @{
- */
- /** Number of misses that hit in the MSHRs per command and thread. */
- Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS];
- /** Demand misses that hit in the MSHRs. */
- Stats::Formula demandMshrHits;
- /** Total number of misses that hit in the MSHRs. */
- Stats::Formula overallMshrHits;
-
- /** Number of misses that miss in the MSHRs, per command and thread. */
- Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS];
- /** Demand misses that miss in the MSHRs. */
- Stats::Formula demandMshrMisses;
- /** Total number of misses that miss in the MSHRs. */
- Stats::Formula overallMshrMisses;
-
- /** Number of misses that miss in the MSHRs, per command and thread. */
- Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
- /** Total number of misses that miss in the MSHRs. */
- Stats::Formula overallMshrUncacheable;
-
- /** Total cycle latency of each MSHR miss, per command and thread. */
- Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
- /** Total cycle latency of demand MSHR misses. */
- Stats::Formula demandMshrMissLatency;
- /** Total cycle latency of overall MSHR misses. */
- Stats::Formula overallMshrMissLatency;
-
- /** Total cycle latency of each MSHR miss, per command and thread. */
- Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
- /** Total cycle latency of overall MSHR misses. */
- Stats::Formula overallMshrUncacheableLatency;
-
- /** The total number of MSHR accesses per command and thread. */
- Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS];
- /** The total number of demand MSHR accesses. */
- Stats::Formula demandMshrAccesses;
- /** The total number of MSHR accesses. */
- Stats::Formula overallMshrAccesses;
-
- /** The miss rate in the MSHRs pre command and thread. */
- Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS];
- /** The demand miss rate in the MSHRs. */
- Stats::Formula demandMshrMissRate;
- /** The overall miss rate in the MSHRs. */
- Stats::Formula overallMshrMissRate;
-
- /** The average latency of an MSHR miss, per command and thread. */
- Stats::Formula avgMshrMissLatency[MemCmd::NUM_MEM_CMDS];
- /** The average latency of a demand MSHR miss. */
- Stats::Formula demandAvgMshrMissLatency;
- /** The average overall latency of an MSHR miss. */
- Stats::Formula overallAvgMshrMissLatency;
-
- /** The average latency of an MSHR miss, per command and thread. */
- Stats::Formula avgMshrUncacheableLatency[MemCmd::NUM_MEM_CMDS];
- /** The average overall latency of an MSHR miss. */
- Stats::Formula overallAvgMshrUncacheableLatency;
-
- /** The number of times a thread hit its MSHR cap. */
- Stats::Vector<> mshr_cap_events;
- /** The number of times software prefetches caused the MSHR to block. */
- Stats::Vector<> soft_prefetch_mshr_full;
-
- Stats::Scalar<> mshr_no_allocate_misses;
-
- /**
- * @}
- */
-
- private:
- /** Pointer to the MSHR that has no targets. */
- MSHR* noTargetMSHR;
-
- /**
- * Allocate a new MSHR to handle the provided miss.
- * @param pkt The miss to buffer.
- * @param size The number of bytes to fetch.
- * @param time The time the miss occurs.
- * @return A pointer to the new MSHR.
- */
- MSHR* allocateMiss(PacketPtr &pkt, int size, Tick time);
-
- /**
- * Allocate a new WriteBuffer to handle the provided write.
- * @param pkt The write to handle.
- * @param size The number of bytes to write.
- * @param time The time the write occurs.
- * @return A pointer to the new write buffer.
- */
- MSHR* allocateWrite(PacketPtr &pkt, int size, Tick time);
-
- public:
- /**
- * Simple Constructor. Initializes all needed internal storage and sets
- * parameters.
- * @param numMSHRs The number of outstanding misses to handle.
- * @param numTargets The number of outstanding targets to each miss.
- * @param write_buffers The number of outstanding writes to handle.
- * @param write_allocate If true, treat write misses the same as reads.
- */
- MissQueue(int numMSHRs, int numTargets, int write_buffers,
- bool write_allocate, bool prefetch_miss);
-
- /**
- * Deletes all allocated internal storage.
- */
- ~MissQueue();
-
- /**
- * Register statistics for this object.
- * @param name The name of the parent cache.
- */
- void regStats(const std::string &name);
-
- /**
- * Handle a cache miss properly. Either allocate an MSHR for the request,
- * or forward it through the write buffer.
- * @param pkt The request that missed in the cache.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- */
- void handleMiss(PacketPtr &pkt, int blk_size, Tick time);
-
- /**
- * Fetch the block for the given address and buffer the given target.
- * @param addr The address to fetch.
- * @param asid The address space of the address.
- * @param blk_size The block size of the cache.
- * @param time The time the miss is detected.
- * @param target The target for the fetch.
- */
- MSHR* fetchBlock(Addr addr, int blk_size, Tick time,
- PacketPtr &target);
-
- /**
- * Selects a outstanding request to service.
- * @return The request to service, NULL if none found.
- */
- PacketPtr getPacket();
-
- /**
- * Set the command to the given bus command.
- * @param pkt The request to update.
- * @param cmd The bus command to use.
- */
- void setBusCmd(PacketPtr &pkt, MemCmd cmd);
-
- /**
- * Restore the original command in case of a bus transmission error.
- * @param pkt The request to reset.
- */
- void restoreOrigCmd(PacketPtr &pkt);
-
- /**
- * Marks a request as in service (sent on the bus). This can have side
- * effect since storage for no response commands is deallocated once they
- * are successfully sent.
- * @param pkt The request that was sent on the bus.
- */
- void markInService(PacketPtr &pkt, MSHR* mshr);
-
- /**
- * Collect statistics and free resources of a satisfied request.
- * @param pkt The request that has been satisfied.
- * @param time The time when the request is satisfied.
- */
- void handleResponse(PacketPtr &pkt, Tick time);
-
- /**
- * Removes all outstanding requests for a given thread number. If a request
- * has been sent to the bus, this function removes all of its targets.
- * @param threadNum The thread number of the requests to squash.
- */
- void squash(int threadNum);
-
- /**
- * Return the current number of outstanding misses.
- * @return the number of outstanding misses.
- */
- int getMisses()
- {
- return mq.getAllocatedTargets();
- }
-
- /**
- * Searches for the supplied address in the miss queue.
- * @param addr The address to look for.
- * @param asid The address space id.
- * @return The MSHR that contains the address, NULL if not found.
- * @warning Currently only searches the miss queue. If non write allocate
- * might need to search the write buffer for coherence.
- */
- MSHR* findMSHR(Addr addr);
-
- /**
- * Searches for the supplied address in the write buffer.
- * @param addr The address to look for.
- * @param asid The address space id.
- * @param writes The list of writes that match the address.
- * @return True if any writes are found
- */
- bool findWrites(Addr addr, std::vector<MSHR*>& writes);
-
- /**
- * Perform a writeback of dirty data to the given address.
- * @param addr The address to write to.
- * @param asid The address space id.
- * @param xc The execution context of the address space.
- * @param size The number of bytes to write.
- * @param data The data to write, can be NULL.
- * @param compressed True if the data is compressed.
- */
- void doWriteback(Addr addr,
- int size, uint8_t *data, bool compressed);
-
- /**
- * Perform the given writeback request.
- * @param pkt The writeback request.
- */
- void doWriteback(PacketPtr &pkt);
-
- /**
- * Returns true if there are outstanding requests.
- * @return True if there are outstanding requests.
- */
- bool havePending();
-
- /**
- * Add a target to the given MSHR. This assumes it is in the miss queue.
- * @param mshr The mshr to add a target to.
- * @param pkt The target to add.
- */
- void addTarget(MSHR *mshr, PacketPtr &pkt)
- {
- mq.allocateTarget(mshr, pkt);
- }
-
- /**
- * Allocate a MSHR to hold a list of targets to a block involved in a copy.
- * If the block is marked done then the MSHR already holds the data to
- * fill the block. Otherwise the block needs to be fetched.
- * @param addr The address to buffer.
- * @param asid The address space ID.
- * @return A pointer to the allocated MSHR.
- */
- MSHR* allocateTargetList(Addr addr);
-
-};
-
-#endif //__MISS_QUEUE_HH__
diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc
index 74dad658b..1f2c05a6e 100644
--- a/src/mem/cache/miss/mshr.cc
+++ b/src/mem/cache/miss/mshr.cc
@@ -54,45 +54,20 @@ MSHR::MSHR()
}
void
-MSHR::allocate(MemCmd cmd, Addr _addr, int size,
- PacketPtr &target)
+MSHR::allocate(Addr _addr, int _size, PacketPtr target)
{
addr = _addr;
- if (target)
- {
- //Have a request, just use it
- pkt = new Packet(target->req, cmd, Packet::Broadcast, size);
- pkt->time = curTick;
- pkt->allocate();
- pkt->senderState = (Packet::SenderState *)this;
- allocateTarget(target);
- }
- else
- {
- //need a request first
- Request * req = new Request();
- req->setPhys(addr, size, 0);
- //Thread context??
- pkt = new Packet(req, cmd, Packet::Broadcast, size);
- pkt->time = curTick;
- pkt->allocate();
- pkt->senderState = (Packet::SenderState *)this;
- }
-}
-
-// Since we aren't sure if data is being used, don't copy here.
-/**
- * @todo When we have a "global" data flag, might want to copy data here.
- */
-void
-MSHR::allocateAsBuffer(PacketPtr &target)
-{
- addr = target->getAddr();
- threadNum = 0/*target->req->getThreadNum()*/;
- pkt = new Packet(target->req, target->cmd, -1);
- pkt->allocate();
- pkt->senderState = (Packet::SenderState*)this;
- pkt->time = curTick;
+ size = _size;
+ assert(target);
+ isCacheFill = false;
+ needsExclusive = target->needsExclusive();
+ _isUncacheable = target->req->isUncacheable();
+ inService = false;
+ threadNum = 0;
+ ntargets = 1;
+ // Don't know of a case where we would allocate a new MSHR for a
+ // snoop (mem0-side request), so set cpuSide to true here.
+ targets.push_back(Target(target, true));
}
void
@@ -100,8 +75,6 @@ MSHR::deallocate()
{
assert(targets.empty());
assert(ntargets == 0);
- delete pkt;
- pkt = NULL;
inService = false;
//allocIter = NULL;
//readyIter = NULL;
@@ -111,16 +84,17 @@ MSHR::deallocate()
* Adds a target to an MSHR
*/
void
-MSHR::allocateTarget(PacketPtr &target)
+MSHR::allocateTarget(PacketPtr target, bool cpuSide)
{
//If we append an invalidate and we issued a read to the bus,
//but now have some pending writes, we need to move
//the invalidate to before the first non-read
- if (inService && pkt->isRead() && target->isInvalidate()) {
- std::list<PacketPtr> temp;
+ if (inService && !inServiceForExclusive && needsExclusive
+ && !cpuSide && target->isInvalidate()) {
+ std::list<Target> temp;
while (!targets.empty()) {
- if (!targets.front()->isRead()) break;
+ if (targets.front().pkt->needsExclusive()) break;
//Place on top of temp stack
temp.push_front(targets.front());
//Remove from targets
@@ -129,7 +103,7 @@ MSHR::allocateTarget(PacketPtr &target)
//Now that we have all the reads off until first non-read, we can
//place the invalidate on
- targets.push_front(target);
+ targets.push_front(Target(target, cpuSide));
//Now we pop off the temp_stack and put them back
while (!temp.empty()) {
@@ -138,22 +112,16 @@ MSHR::allocateTarget(PacketPtr &target)
}
}
else {
- targets.push_back(target);
+ targets.push_back(Target(target, cpuSide));
}
++ntargets;
assert(targets.size() == ntargets);
- /**
- * @todo really prioritize the target commands.
- */
- if (!inService && target->isWrite()) {
- pkt->cmd = MemCmd::WriteReq;
- }
+ needsExclusive = needsExclusive || target->needsExclusive();
}
-
void
MSHR::dump()
{
@@ -167,8 +135,8 @@ MSHR::dump()
for (int i = 0; i < ntargets; i++) {
assert(tar_it != targets.end());
- ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n",
- i, (*tar_it)->getAddr(), (*tar_it)->cmdToIndex());
+ ccprintf(cerr, "\t%d: Addr: %x cmd: %s\n",
+ i, tar_it->pkt->getAddr(), tar_it->pkt->cmdString());
tar_it++;
}
@@ -177,6 +145,4 @@ MSHR::dump()
MSHR::~MSHR()
{
- if (pkt)
- pkt = NULL;
}
diff --git a/src/mem/cache/miss/mshr.hh b/src/mem/cache/miss/mshr.hh
index d0410acda..195438e46 100644
--- a/src/mem/cache/miss/mshr.hh
+++ b/src/mem/cache/miss/mshr.hh
@@ -36,22 +36,39 @@
#ifndef __MSHR_HH__
#define __MSHR_HH__
-#include "mem/packet.hh"
#include <list>
-#include <deque>
-class MSHR;
+#include "mem/packet.hh"
+
+class CacheBlk;
+class MSHRQueue;
/**
* Miss Status and handling Register. This class keeps all the information
* needed to handle a cache miss including a list of target requests.
*/
-class MSHR {
+class MSHR : public Packet::SenderState
+{
+
public:
+
+ class Target {
+ public:
+ Tick time; //!< Time when request was received (for stats)
+ PacketPtr pkt; //!< Pending request packet.
+ bool cpuSide; //!< Did request come from cpu side or mem side?
+
+ bool isCpuSide() { return cpuSide; }
+
+ Target(PacketPtr _pkt, bool _cpuSide, Tick _time = curTick)
+ : time(_time), pkt(_pkt), cpuSide(_cpuSide)
+ {}
+ };
+
/** Defines the Data structure of the MSHR targetlist. */
- typedef std::list<PacketPtr> TargetList;
+ typedef std::list<Target> TargetList;
/** Target list iterator. */
- typedef std::list<PacketPtr>::iterator TargetListIterator;
+ typedef std::list<Target>::iterator TargetListIterator;
/** A list of MSHRs. */
typedef std::list<MSHR *> List;
/** MSHR list iterator. */
@@ -59,20 +76,35 @@ class MSHR {
/** MSHR list const_iterator. */
typedef List::const_iterator ConstIterator;
- /** Address of the miss. */
+ /** Pointer to queue containing this MSHR. */
+ MSHRQueue *queue;
+
+ /** Address of the request. */
Addr addr;
- /** Adress space id of the miss. */
- short asid;
+
+ /** Size of the request. */
+ int size;
+
+ /** Data associated with the request (if a write). */
+ uint8_t *writeData;
+
/** True if the request has been sent to the bus. */
bool inService;
+
+ /** True if we will be putting the returned block in the cache */
+ bool isCacheFill;
+ /** True if we need to get an exclusive copy of the block. */
+ bool needsExclusive;
+ /** True if the request is uncacheable */
+ bool _isUncacheable;
+
+ /** True if the request that has been sent to the bus is for en
+ * exclusive copy. */
+ bool inServiceForExclusive;
/** Thread number of the miss. */
- int threadNum;
- /** The request that is forwarded to the next level of the hierarchy. */
- PacketPtr pkt;
+ short threadNum;
/** The number of currently allocated targets. */
short ntargets;
- /** The original requesting command. */
- MemCmd originalCmd;
/** Order number of assigned by the miss queue. */
uint64_t order;
@@ -81,6 +113,7 @@ class MSHR {
* @sa MissQueue, MSHRQueue::readyList
*/
Iterator readyIter;
+
/**
* Pointer to this MSHR on the allocated list.
* @sa MissQueue, MSHRQueue::allocatedList
@@ -92,6 +125,9 @@ private:
TargetList targets;
public:
+
+ bool isUncacheable() { return _isUncacheable; }
+
/**
* Allocate a miss to this MSHR.
* @param cmd The requesting command.
@@ -100,14 +136,13 @@ public:
* @param size The number of bytes to request.
* @param pkt The original miss.
*/
- void allocate(MemCmd cmd, Addr addr, int size,
- PacketPtr &pkt);
+ void allocate(Addr addr, int size, PacketPtr pkt);
/**
* Allocate this MSHR as a buffer for the given request.
* @param target The memory request to buffer.
*/
- void allocateAsBuffer(PacketPtr &target);
+ void allocateAsBuffer(PacketPtr target);
/**
* Mark this MSHR as free.
@@ -118,7 +153,7 @@ public:
* Add a request to the list of targets.
* @param target The target.
*/
- void allocateTarget(PacketPtr &target);
+ void allocateTarget(PacketPtr target, bool cpuSide);
/** A simple constructor. */
MSHR();
@@ -129,28 +164,19 @@ public:
* Returns the current number of allocated targets.
* @return The current number of allocated targets.
*/
- int getNumTargets()
- {
- return(ntargets);
- }
+ int getNumTargets() { return ntargets; }
/**
* Returns a pointer to the target list.
* @return a pointer to the target list.
*/
- TargetList* getTargetList()
- {
- return &targets;
- }
+ TargetList* getTargetList() { return &targets; }
/**
* Returns a reference to the first target.
* @return A pointer to the first target.
*/
- PacketPtr getTarget()
- {
- return targets.front();
- }
+ Target *getTarget() { return &targets.front(); }
/**
* Pop first target.
@@ -165,9 +191,14 @@ public:
* Returns true if there are targets left.
* @return true if there are targets
*/
- bool hasTargets()
+ bool hasTargets() { return !targets.empty(); }
+
+ bool isSimpleForward()
{
- return !targets.empty();
+ if (getNumTargets() != 1)
+ return false;
+ Target *tgt = getTarget();
+ return tgt->isCpuSide() && !tgt->pkt->needsResponse();
}
/**
diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc
index add11dfe7..3407e2588 100644
--- a/src/mem/cache/miss/mshr_queue.cc
+++ b/src/mem/cache/miss/mshr_queue.cc
@@ -29,22 +29,22 @@
*/
/** @file
- * Definition of the MSHRQueue.
+ * Definition of MSHRQueue class functions.
*/
#include "mem/cache/miss/mshr_queue.hh"
-#include "sim/eventq.hh"
using namespace std;
-MSHRQueue::MSHRQueue(int num_mshrs, int reserve)
- : numMSHRs(num_mshrs + reserve - 1), numReserve(reserve)
+MSHRQueue::MSHRQueue(int num_entries, int reserve, int _index)
+ : numEntries(num_entries + reserve - 1), numReserve(reserve),
+ index(_index)
{
allocated = 0;
- inServiceMSHRs = 0;
- allocatedTargets = 0;
- registers = new MSHR[numMSHRs];
- for (int i = 0; i < numMSHRs; ++i) {
+ inServiceEntries = 0;
+ registers = new MSHR[numEntries];
+ for (int i = 0; i < numEntries; ++i) {
+ registers[i].queue = this;
freeList.push_back(&registers[i]);
}
}
@@ -54,7 +54,7 @@ MSHRQueue::~MSHRQueue()
delete [] registers;
}
-MSHR*
+MSHR *
MSHRQueue::findMatch(Addr addr) const
{
MSHR::ConstIterator i = allocatedList.begin();
@@ -87,19 +87,19 @@ MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const
}
-MSHR*
-MSHRQueue::findPending(PacketPtr &pkt) const
+MSHR *
+MSHRQueue::findPending(Addr addr, int size) const
{
MSHR::ConstIterator i = pendingList.begin();
MSHR::ConstIterator end = pendingList.end();
for (; i != end; ++i) {
MSHR *mshr = *i;
- if (mshr->addr < pkt->getAddr()) {
- if (mshr->addr + mshr->pkt->getSize() > pkt->getAddr()) {
+ if (mshr->addr < addr) {
+ if (mshr->addr + mshr->size > addr) {
return mshr;
}
} else {
- if (pkt->getAddr() + pkt->getSize() > mshr->addr) {
+ if (addr + size > mshr->addr) {
return mshr;
}
}
@@ -107,22 +107,15 @@ MSHRQueue::findPending(PacketPtr &pkt) const
return NULL;
}
-MSHR*
-MSHRQueue::allocate(PacketPtr &pkt, int size)
+MSHR *
+MSHRQueue::allocate(Addr addr, int size, PacketPtr &pkt)
{
- Addr aligned_addr = pkt->getAddr() & ~((Addr)size - 1);
assert(!freeList.empty());
MSHR *mshr = freeList.front();
assert(mshr->getNumTargets() == 0);
freeList.pop_front();
- if (!pkt->needsResponse()) {
- mshr->allocateAsBuffer(pkt);
- } else {
- assert(size !=0);
- mshr->allocate(pkt->cmd, aligned_addr, size, pkt);
- allocatedTargets += 1;
- }
+ mshr->allocate(addr, size, pkt);
mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
@@ -130,51 +123,21 @@ MSHRQueue::allocate(PacketPtr &pkt, int size)
return mshr;
}
-MSHR*
-MSHRQueue::allocateFetch(Addr addr, int size, PacketPtr &target)
-{
- MSHR *mshr = freeList.front();
- assert(mshr->getNumTargets() == 0);
- freeList.pop_front();
- mshr->allocate(MemCmd::ReadReq, addr, size, target);
- mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
- mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
-
- allocated += 1;
- return mshr;
-}
-
-MSHR*
-MSHRQueue::allocateTargetList(Addr addr, int size)
-{
- MSHR *mshr = freeList.front();
- assert(mshr->getNumTargets() == 0);
- freeList.pop_front();
- PacketPtr dummy;
- mshr->allocate(MemCmd::ReadReq, addr, size, dummy);
- mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
- mshr->inService = true;
- ++inServiceMSHRs;
- ++allocated;
- return mshr;
-}
-
void
-MSHRQueue::deallocate(MSHR* mshr)
+MSHRQueue::deallocate(MSHR *mshr)
{
deallocateOne(mshr);
}
MSHR::Iterator
-MSHRQueue::deallocateOne(MSHR* mshr)
+MSHRQueue::deallocateOne(MSHR *mshr)
{
MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
freeList.push_front(mshr);
allocated--;
- allocatedTargets -= mshr->getNumTargets();
if (mshr->inService) {
- inServiceMSHRs--;
+ inServiceEntries--;
} else {
pendingList.erase(mshr->readyIter);
}
@@ -193,29 +156,29 @@ MSHRQueue::moveToFront(MSHR *mshr)
}
void
-MSHRQueue::markInService(MSHR* mshr)
+MSHRQueue::markInService(MSHR *mshr)
{
- //assert(mshr == pendingList.front());
- if (!mshr->pkt->needsResponse() && !(mshr->pkt->cmd == MemCmd::UpgradeReq)) {
- assert(mshr->getNumTargets() == 0);
+ if (mshr->isSimpleForward()) {
+ // we just forwarded the request packet & don't expect a
+ // response, so get rid of it
+ assert(mshr->getNumTargets() == 1);
+ mshr->popTarget();
deallocate(mshr);
return;
}
mshr->inService = true;
pendingList.erase(mshr->readyIter);
//mshr->readyIter = NULL;
- inServiceMSHRs += 1;
+ inServiceEntries += 1;
//pendingList.pop_front();
}
void
-MSHRQueue::markPending(MSHR* mshr, MemCmd cmd)
+MSHRQueue::markPending(MSHR *mshr)
{
//assert(mshr->readyIter == NULL);
- mshr->pkt->cmd = cmd;
- mshr->pkt->flags &= ~SATISFIED;
mshr->inService = false;
- --inServiceMSHRs;
+ --inServiceEntries;
/**
* @ todo might want to add rerequests to front of pending list for
* performance.
@@ -232,11 +195,8 @@ MSHRQueue::squash(int threadNum)
MSHR *mshr = *i;
if (mshr->threadNum == threadNum) {
while (mshr->hasTargets()) {
- PacketPtr target = mshr->getTarget();
mshr->popTarget();
-
assert(0/*target->req->getThreadNum()*/ == threadNum);
- target = NULL;
}
assert(!mshr->hasTargets());
assert(mshr->ntargets==0);
diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh
index 5069db661..806aa9c64 100644
--- a/src/mem/cache/miss/mshr_queue.hh
+++ b/src/mem/cache/miss/mshr_queue.hh
@@ -32,71 +32,74 @@
* Declaration of a structure to manage MSHRs.
*/
-#ifndef __MSHR_QUEUE_HH__
-#define __MSHR_QUEUE_HH__
+#ifndef __MEM__CACHE__MISS__MSHR_QUEUE_HH__
+#define __MEM__CACHE__MISS__MSHR_QUEUE_HH__
#include <vector>
+
+#include "mem/packet.hh"
#include "mem/cache/miss/mshr.hh"
/**
* A Class for maintaining a list of pending and allocated memory requests.
*/
-class MSHRQueue {
+class MSHRQueue
+{
private:
/** MSHR storage. */
- MSHR* registers;
- /** Holds pointers to all allocated MSHRs. */
+ MSHR *registers;
+ /** Holds pointers to all allocated entries. */
MSHR::List allocatedList;
- /** Holds pointers to MSHRs that haven't been sent to the bus. */
+ /** Holds pointers to entries that haven't been sent to the bus. */
MSHR::List pendingList;
- /** Holds non allocated MSHRs. */
+ /** Holds non allocated entries. */
MSHR::List freeList;
// Parameters
/**
- * The total number of MSHRs in this queue. This number is set as the
- * number of MSHRs requested plus (numReserve - 1). This allows for
- * the same number of effective MSHRs while still maintaining the reserve.
+ * The total number of entries in this queue. This number is set as the
+ * number of entries requested plus (numReserve - 1). This allows for
+ * the same number of effective entries while still maintaining the reserve.
*/
- const int numMSHRs;
+ const int numEntries;
/**
- * The number of MSHRs to hold in reserve. This is needed because copy
- * operations can allocate upto 4 MSHRs at one time.
+ * The number of entries to hold in reserve. This is needed because copy
+ * operations can allocate upto 4 entries at one time.
*/
const int numReserve;
public:
- /** The number of allocated MSHRs. */
+ /** The number of allocated entries. */
int allocated;
- /** The number of MSHRs that have been forwarded to the bus. */
- int inServiceMSHRs;
- /** The number of targets waiting for response. */
- int allocatedTargets;
+ /** The number of entries that have been forwarded to the bus. */
+ int inServiceEntries;
+ /** The index of this queue within the cache (MSHR queue vs. write
+ * buffer). */
+ const int index;
/**
- * Create a queue with a given number of MSHRs.
- * @param num_mshrs The number of MSHRs in this queue.
- * @param reserve The minimum number of MSHRs needed to satisfy any access.
+ * Create a queue with a given number of entries.
+ * @param num_entrys The number of entries in this queue.
+ * @param reserve The minimum number of entries needed to satisfy
+ * any access.
*/
- MSHRQueue(int num_mshrs, int reserve = 1);
+ MSHRQueue(int num_entries, int reserve, int index);
/** Destructor */
~MSHRQueue();
/**
- * Find the first MSHR that matches the provide address and asid.
+ * Find the first MSHR that matches the provided address.
* @param addr The address to find.
- * @param asid The address space id.
* @return Pointer to the matching MSHR, null if not found.
*/
- MSHR* findMatch(Addr addr) const;
+ MSHR *findMatch(Addr addr) const;
/**
- * Find and return all the matching MSHRs in the provided vector.
+ * Find and return all the matching entries in the provided vector.
* @param addr The address to find.
- * @param asid The address space ID.
- * @param matches The vector to return pointers to the matching MSHRs.
+ * @param matches The vector to return pointers to the matching entries.
* @return True if any matches are found, false otherwise.
* @todo Typedef the vector??
*/
@@ -107,7 +110,7 @@ class MSHRQueue {
* @param pkt The request to find.
* @return A pointer to the earliest matching MSHR.
*/
- MSHR* findPending(PacketPtr &pkt) const;
+ MSHR *findPending(Addr addr, int size) const;
/**
* Allocates a new MSHR for the request and size. This places the request
@@ -116,60 +119,29 @@ class MSHRQueue {
* @param size The number in bytes to fetch from memory.
* @return The a pointer to the MSHR allocated.
*
- * @pre There are free MSHRs.
+ * @pre There are free entries.
*/
- MSHR* allocate(PacketPtr &pkt, int size = 0);
-
- /**
- * Allocate a read request for the given address, and places the given
- * target on the target list.
- * @param addr The address to fetch.
- * @param asid The address space for the fetch.
- * @param size The number of bytes to request.
- * @param target The first target for the request.
- * @return Pointer to the new MSHR.
- */
- MSHR* allocateFetch(Addr addr, int size, PacketPtr &target);
-
- /**
- * Allocate a target list for the given address.
- * @param addr The address to fetch.
- * @param asid The address space for the fetch.
- * @param size The number of bytes to request.
- * @return Pointer to the new MSHR.
- */
- MSHR* allocateTargetList(Addr addr, int size);
+ MSHR *allocate(Addr addr, int size, PacketPtr &pkt);
/**
* Removes the given MSHR from the queue. This places the MSHR on the
* free list.
* @param mshr
*/
- void deallocate(MSHR* mshr);
-
- /**
- * Allocates a target to the given MSHR. Used to keep track of the number
- * of outstanding targets.
- * @param mshr The MSHR to allocate the target to.
- * @param pkt The target request.
- */
- void allocateTarget(MSHR* mshr, PacketPtr &pkt)
- {
- mshr->allocateTarget(pkt);
- allocatedTargets += 1;
- }
+ void deallocate(MSHR *mshr);
/**
- * Remove a MSHR from the queue. Returns an iterator into the allocatedList
- * for faster squash implementation.
+ * Remove a MSHR from the queue. Returns an iterator into the
+ * allocatedList for faster squash implementation.
* @param mshr The MSHR to remove.
* @return An iterator to the next entry in the allocatedList.
*/
- MSHR::Iterator deallocateOne(MSHR* mshr);
+ MSHR::Iterator deallocateOne(MSHR *mshr);
/**
- * Moves the MSHR to the front of the pending list if it is not in service.
- * @param mshr The mshr to move.
+ * Moves the MSHR to the front of the pending list if it is not
+ * in service.
+ * @param mshr The entry to move.
*/
void moveToFront(MSHR *mshr);
@@ -178,14 +150,13 @@ class MSHRQueue {
* pendingList. Deallocates the MSHR if it does not expect a response.
* @param mshr The MSHR to mark in service.
*/
- void markInService(MSHR* mshr);
+ void markInService(MSHR *mshr);
/**
- * Mark an in service mshr as pending, used to resend a request.
+ * Mark an in service entry as pending, used to resend a request.
* @param mshr The MSHR to resend.
- * @param cmd The command to resend.
*/
- void markPending(MSHR* mshr, MemCmd cmd);
+ void markPending(MSHR *mshr);
/**
* Squash outstanding requests with the given thread number. If a request
@@ -204,36 +175,25 @@ class MSHRQueue {
}
/**
- * Returns true if there are no free MSHRs.
+ * Returns true if there are no free entries.
* @return True if this queue is full.
*/
bool isFull() const
{
- return (allocated > numMSHRs - numReserve);
+ return (allocated > numEntries - numReserve);
}
/**
- * Returns the request at the head of the pendingList.
+ * Returns the MSHR at the head of the pendingList.
* @return The next request to service.
*/
- PacketPtr getReq() const
+ MSHR *getNextMSHR() const
{
if (pendingList.empty()) {
return NULL;
}
- MSHR* mshr = pendingList.front();
- return mshr->pkt;
+ return pendingList.front();
}
-
- /**
- * Returns the number of outstanding targets.
- * @return the number of allocated targets.
- */
- int getAllocatedTargets() const
- {
- return allocatedTargets;
- }
-
};
-#endif //__MSHR_QUEUE_HH__
+#endif //__MEM__CACHE__MISS__MSHR_QUEUE_HH__
diff --git a/src/mem/cache/prefetch/base_prefetcher.cc b/src/mem/cache/prefetch/base_prefetcher.cc
index 44daf75e1..378363665 100644
--- a/src/mem/cache/prefetch/base_prefetcher.cc
+++ b/src/mem/cache/prefetch/base_prefetcher.cc
@@ -141,7 +141,7 @@ BasePrefetcher::getPacket()
keepTrying = cache->inCache(pkt->getAddr());
}
if (pf.empty()) {
- cache->clearMasterRequest(Request_PF);
+ cache->deassertMemSideBusRequest(BaseCache::Request_PF);
if (keepTrying) return NULL; //None left, all were in cache
}
} while (keepTrying);
@@ -165,7 +165,7 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
pfRemovedMSHR++;
pf.erase(iter);
if (pf.empty())
- cache->clearMasterRequest(Request_PF);
+ cache->deassertMemSideBusRequest(BaseCache::Request_PF);
}
//Remove anything in queue with delay older than time
@@ -182,7 +182,7 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
iter--;
}
if (pf.empty())
- cache->clearMasterRequest(Request_PF);
+ cache->deassertMemSideBusRequest(BaseCache::Request_PF);
}
@@ -241,10 +241,9 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
}
pf.push_back(prefetch);
- prefetch->flags |= CACHE_LINE_FILL;
//Make sure to request the bus, with proper delay
- cache->setMasterRequest(Request_PF, prefetch->time);
+ cache->requestMemSideBus(BaseCache::Request_PF, prefetch->time);
//Increment through the list
addr++;
diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
index 42a1fe34f..607e89a75 100644
--- a/src/mem/cache/tags/fa_lru.cc
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -215,14 +215,13 @@ FALRU::findBlock(Addr addr) const
}
FALRUBlk*
-FALRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+FALRU::findReplacement(Addr addr, PacketList &writebacks)
{
FALRUBlk * blk = tail;
assert(blk->inCache == 0);
moveToHead(blk);
tagHash.erase(blk->tag);
- tagHash[blkAlign(pkt->getAddr())] = blk;
+ tagHash[blkAlign(addr)] = blk;
if (blk->isValid()) {
replacements[0]++;
} else {
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
index dabbda740..8cbc79813 100644
--- a/src/mem/cache/tags/fa_lru.hh
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -201,11 +201,9 @@ public:
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- FALRUBlk* findReplacement(PacketPtr &pkt, PacketList & writebacks,
- BlkList &compress_blocks);
+ FALRUBlk* findReplacement(Addr addr, PacketList & writebacks);
/**
* Return the hit latency of this cache.
@@ -248,10 +246,9 @@ public:
* Generate the tag from the addres. For fully associative this is just the
* block address.
* @param addr The address to get the tag from.
- * @param blk ignored here
* @return The tag.
*/
- Addr extractTag(Addr addr, FALRUBlk *blk) const
+ Addr extractTag(Addr addr) const
{
return blkAlign(addr);
}
diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc
index 9c802d0dc..2f95cdb0f 100644
--- a/src/mem/cache/tags/iic.cc
+++ b/src/mem/cache/tags/iic.cc
@@ -303,11 +303,10 @@ IIC::findBlock(Addr addr) const
IICTag*
-IIC::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+IIC::findReplacement(Addr addr, PacketList &writebacks)
{
- DPRINTF(IIC, "Finding Replacement for %x\n", pkt->getAddr());
- unsigned set = hash(pkt->getAddr());
+ DPRINTF(IIC, "Finding Replacement for %x\n", addr);
+ unsigned set = hash(addr);
IICTag *tag_ptr;
unsigned long *tmp_data = new unsigned long[numSub];
@@ -332,12 +331,14 @@ IIC::findReplacement(PacketPtr &pkt, PacketList &writebacks,
list<unsigned long> tag_indexes;
repl->doAdvance(tag_indexes);
+/*
while (!tag_indexes.empty()) {
if (!tagStore[tag_indexes.front()].isCompressed()) {
compress_blocks.push_back(&tagStore[tag_indexes.front()]);
}
tag_indexes.pop_front();
}
+*/
tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
@@ -355,7 +356,7 @@ IIC::freeReplacementBlock(PacketList & writebacks)
DPRINTF(Cache, "Replacing %x in IIC: %s\n",
regenerateBlkAddr(tag_ptr->tag,0),
- tag_ptr->isModified() ? "writeback" : "clean");
+ tag_ptr->isDirty() ? "writeback" : "clean");
/* write back replaced block data */
if (tag_ptr && (tag_ptr->isValid())) {
replacements[0]++;
@@ -363,7 +364,7 @@ IIC::freeReplacementBlock(PacketList & writebacks)
++sampledRefs;
tag_ptr->refCount = 0;
- if (tag_ptr->isModified()) {
+ if (tag_ptr->isDirty()) {
/* PacketPtr writeback =
buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
tag_ptr->req->asid, tag_ptr->xc, blkSize,
@@ -619,24 +620,6 @@ IIC::secondaryChain(Addr tag, unsigned long chain_ptr,
}
void
-IIC::decompressBlock(unsigned long index)
-{
- IICTag *tag_ptr = &tagStore[index];
- if (tag_ptr->isCompressed()) {
- // decompress the data here.
- }
-}
-
-void
-IIC::compressBlock(unsigned long index)
-{
- IICTag *tag_ptr = &tagStore[index];
- if (!tag_ptr->isCompressed()) {
- // Compress the data here.
- }
-}
-
-void
IIC::invalidateBlk(IIC::BlkType *tag_ptr)
{
if (tag_ptr) {
@@ -672,7 +655,6 @@ void
IIC::writeData(IICTag *blk, uint8_t *write_data, int size,
PacketList & writebacks)
{
- assert(size < blkSize || !blk->isCompressed());
DPRINTF(IIC, "Writing %d bytes to %x\n", size,
blk->tag<<tagShift);
// Find the number of subblocks needed, (round up)
diff --git a/src/mem/cache/tags/iic.hh b/src/mem/cache/tags/iic.hh
index d0663d330..082b3d15e 100644
--- a/src/mem/cache/tags/iic.hh
+++ b/src/mem/cache/tags/iic.hh
@@ -345,17 +345,6 @@ class IIC : public BaseTags
return hitLatency;
}
- /**
- * Generate the tag from the address.
- * @param addr The address to a get a tag for.
- * @param blk Ignored here.
- * @return the tag.
- */
- Addr extractTag(Addr addr, IICTag *blk) const
- {
- return (addr >> tagShift);
- }
-
/**
* Generate the tag from the address.
* @param addr The address to a get a tag for.
@@ -423,18 +412,6 @@ class IIC : public BaseTags
}
/**
- * Decompress a block if it is compressed.
- * @param index The tag store index for the block to uncompress.
- */
- void decompressBlock(unsigned long index);
-
- /**
- * Try and compress a block if it is not already compressed.
- * @param index The tag store index for the block to compress.
- */
- void compressBlock(unsigned long index);
-
- /**
* Invalidate a block.
* @param blk The block to invalidate.
*/
@@ -462,11 +439,9 @@ class IIC : public BaseTags
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- IICTag* findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks);
+ IICTag* findReplacement(Addr addr, PacketList &writebacks);
/**
* Read the data from the internal storage of the given cache block.
diff --git a/src/mem/cache/tags/lru.cc b/src/mem/cache/tags/lru.cc
index 8e8779774..334312aaf 100644
--- a/src/mem/cache/tags/lru.cc
+++ b/src/mem/cache/tags/lru.cc
@@ -194,10 +194,9 @@ LRU::findBlock(Addr addr) const
}
LRUBlk*
-LRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+LRU::findReplacement(Addr addr, PacketList &writebacks)
{
- unsigned set = extractSet(pkt->getAddr());
+ unsigned set = extractSet(addr);
// grab a replacement candidate
LRUBlk *blk = sets[set].blks[assoc-1];
sets[set].moveToHead(blk);
diff --git a/src/mem/cache/tags/lru.hh b/src/mem/cache/tags/lru.hh
index 75272544c..26038d709 100644
--- a/src/mem/cache/tags/lru.hh
+++ b/src/mem/cache/tags/lru.hh
@@ -189,11 +189,9 @@ public:
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- LRUBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks);
+ LRUBlk* findReplacement(Addr addr, PacketList &writebacks);
/**
* Generate the tag from the given address.
@@ -205,17 +203,6 @@ public:
return (addr >> tagShift);
}
- /**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @param blk Ignored.
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr, LRUBlk *blk) const
- {
- return (addr >> tagShift);
- }
-
/**
* Calculate the set index from the address.
* @param addr The address to get the set from.
diff --git a/src/mem/cache/tags/split.cc b/src/mem/cache/tags/split.cc
index 5ac87eaba..e22ccbb96 100644
--- a/src/mem/cache/tags/split.cc
+++ b/src/mem/cache/tags/split.cc
@@ -298,27 +298,25 @@ Split::findBlock(Addr addr) const
}
SplitBlk*
-Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+Split::findReplacement(Addr addr, PacketList &writebacks)
{
SplitBlk *blk;
+ assert(0);
+#if 0
if (pkt->nic_pkt()) {
DPRINTF(Split, "finding a replacement for nic_req\n");
nic_repl++;
if (lifo && lifo_net)
- blk = lifo_net->findReplacement(pkt, writebacks,
- compress_blocks);
+ blk = lifo_net->findReplacement(addr, writebacks);
else if (lru_net)
- blk = lru_net->findReplacement(pkt, writebacks,
- compress_blocks);
+ blk = lru_net->findReplacement(addr, writebacks);
// in this case, this is an LRU only cache, it's non partitioned
else
- blk = lru->findReplacement(pkt, writebacks, compress_blocks);
+ blk = lru->findReplacement(addr, writebacks);
} else {
DPRINTF(Split, "finding replacement for cpu_req\n");
- blk = lru->findReplacement(pkt, writebacks,
- compress_blocks);
+ blk = lru->findReplacement(addr, writebacks);
cpu_repl++;
}
@@ -346,6 +344,7 @@ Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
// blk attributes for the new blk coming IN
blk->ts = curTick;
blk->isNIC = (pkt->nic_pkt()) ? true : false;
+#endif
return blk;
}
@@ -400,8 +399,13 @@ Split::regenerateBlkAddr(Addr tag, int set) const
}
Addr
-Split::extractTag(Addr addr, SplitBlk *blk) const
+Split::extractTag(Addr addr) const
{
+ // need to fix this if we want to use it... old interface of
+ // passing in blk was too weird
+ assert(0);
+ return 0;
+/*
if (blk->part == 2) {
if (lifo_net)
return lifo_net->extractTag(addr);
@@ -411,5 +415,6 @@ Split::extractTag(Addr addr, SplitBlk *blk) const
panic("this shouldn't happen");
} else
return lru->extractTag(addr);
+*/
}
diff --git a/src/mem/cache/tags/split.hh b/src/mem/cache/tags/split.hh
index 840b68940..ab48ce769 100644
--- a/src/mem/cache/tags/split.hh
+++ b/src/mem/cache/tags/split.hh
@@ -212,20 +212,17 @@ class Split : public BaseTags
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks);
+ SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
/**
* Generate the tag from the given address.
* @param addr The address to get the tag from.
- * @param blk The block to find the partition it's in
* @return The tag of the address.
*/
- Addr extractTag(Addr addr, SplitBlk *blk) const;
+ Addr extractTag(Addr addr) const;
/**
* Calculate the set index from the address.
diff --git a/src/mem/cache/tags/split_lifo.cc b/src/mem/cache/tags/split_lifo.cc
index d71d1a3ef..4ee2473a4 100644
--- a/src/mem/cache/tags/split_lifo.cc
+++ b/src/mem/cache/tags/split_lifo.cc
@@ -266,10 +266,9 @@ SplitLIFO::findBlock(Addr addr) const
}
SplitBlk*
-SplitLIFO::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+SplitLIFO::findReplacement(Addr addr, PacketList &writebacks)
{
- unsigned set = extractSet(pkt->getAddr());
+ unsigned set = extractSet(addr);
SplitBlk *firstIn = sets[set].firstIn;
SplitBlk *lastIn = sets[set].lastIn;
@@ -289,7 +288,7 @@ SplitLIFO::findReplacement(PacketPtr &pkt, PacketList &writebacks,
}
DPRINTF(Split, "just assigned %#x addr into LIFO, replacing %#x status %#x\n",
- pkt->getAddr(), regenerateBlkAddr(blk->tag, set), blk->status);
+ addr, regenerateBlkAddr(blk->tag, set), blk->status);
if (blk->isValid()) {
replacements[0]++;
totalRefs += blk->refCount;
diff --git a/src/mem/cache/tags/split_lifo.hh b/src/mem/cache/tags/split_lifo.hh
index 0f8adf18d..13ccf7ef4 100644
--- a/src/mem/cache/tags/split_lifo.hh
+++ b/src/mem/cache/tags/split_lifo.hh
@@ -212,11 +212,9 @@ public:
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks);
+ SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
/**
* Generate the tag from the given address.
@@ -228,17 +226,6 @@ public:
return (addr >> tagShift);
}
- /**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @param blk Ignored
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr, SplitBlk *blk) const
- {
- return (addr >> tagShift);
- }
-
/**
* Calculate the set index from the address.
* @param addr The address to get the set from.
diff --git a/src/mem/cache/tags/split_lru.cc b/src/mem/cache/tags/split_lru.cc
index 7227fb5c1..4d271a92a 100644
--- a/src/mem/cache/tags/split_lru.cc
+++ b/src/mem/cache/tags/split_lru.cc
@@ -213,10 +213,9 @@ SplitLRU::findBlock(Addr addr) const
}
SplitBlk*
-SplitLRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks)
+SplitLRU::findReplacement(Addr addr, PacketList &writebacks)
{
- unsigned set = extractSet(pkt->getAddr());
+ unsigned set = extractSet(addr);
// grab a replacement candidate
SplitBlk *blk = sets[set].blks[assoc-1];
sets[set].moveToHead(blk);
diff --git a/src/mem/cache/tags/split_lru.hh b/src/mem/cache/tags/split_lru.hh
index eb65445ea..a708ef740 100644
--- a/src/mem/cache/tags/split_lru.hh
+++ b/src/mem/cache/tags/split_lru.hh
@@ -195,11 +195,9 @@ public:
* Find a replacement block for the address provided.
* @param pkt The request to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @param compress_blocks List of blocks to compress, for adaptive comp.
* @return The block to place the replacement in.
*/
- SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
- BlkList &compress_blocks);
+ SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
/**
* Generate the tag from the given address.
@@ -212,17 +210,6 @@ public:
}
/**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @param blk Ignored.
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr, SplitBlk *blk) const
- {
- return (addr >> tagShift);
- }
-
- /**
* Calculate the set index from the address.
* @param addr The address to get the set from.
* @return The set index of the address.
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index f70c0cec3..cd0ed8a2e 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -56,17 +56,16 @@ MemCmd::commandInfo[] =
{ 0, InvalidCmd, "InvalidCmd" },
/* ReadReq */
{ SET3(IsRead, IsRequest, NeedsResponse), ReadResp, "ReadReq" },
- /* WriteReq */
- { SET4(IsWrite, IsRequest, NeedsResponse, HasData),
- WriteResp, "WriteReq" },
- /* WriteReqNoAck */
- { SET3(IsWrite, IsRequest, HasData), InvalidCmd, "WriteReqNoAck" },
/* ReadResp */
{ SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
+ /* WriteReq */
+ { SET5(IsWrite, NeedsExclusive, IsRequest, NeedsResponse, HasData),
+ WriteResp, "WriteReq" },
/* WriteResp */
- { SET2(IsWrite, IsResponse), InvalidCmd, "WriteResp" },
+ { SET3(IsWrite, NeedsExclusive, IsResponse), InvalidCmd, "WriteResp" },
/* Writeback */
- { SET3(IsWrite, IsRequest, HasData), InvalidCmd, "Writeback" },
+ { SET4(IsWrite, NeedsExclusive, IsRequest, HasData),
+ InvalidCmd, "Writeback" },
/* SoftPFReq */
{ SET4(IsRead, IsRequest, IsSWPrefetch, NeedsResponse),
SoftPFResp, "SoftPFReq" },
@@ -79,27 +78,43 @@ MemCmd::commandInfo[] =
/* HardPFResp */
{ SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
InvalidCmd, "HardPFResp" },
- /* InvalidateReq */
- { SET2(IsInvalidate, IsRequest), InvalidCmd, "InvalidateReq" },
/* WriteInvalidateReq */
- { SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse),
+ { SET6(IsWrite, NeedsExclusive, IsInvalidate,
+ IsRequest, HasData, NeedsResponse),
WriteInvalidateResp, "WriteInvalidateReq" },
/* WriteInvalidateResp */
- { SET3(IsWrite, IsInvalidate, IsResponse),
+ { SET4(IsWrite, NeedsExclusive, IsInvalidate, IsResponse),
InvalidCmd, "WriteInvalidateResp" },
/* UpgradeReq */
- { SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" },
+ { SET4(IsInvalidate, NeedsExclusive, IsRequest, NeedsResponse),
+ UpgradeResp, "UpgradeReq" },
+ /* UpgradeResp */
+ { SET3(IsInvalidate, NeedsExclusive, IsResponse),
+ InvalidCmd, "UpgradeResp" },
/* ReadExReq */
- { SET4(IsRead, IsInvalidate, IsRequest, NeedsResponse),
+ { SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
ReadExResp, "ReadExReq" },
/* ReadExResp */
- { SET4(IsRead, IsInvalidate, IsResponse, HasData),
+ { SET5(IsRead, NeedsExclusive, IsInvalidate, IsResponse, HasData),
InvalidCmd, "ReadExResp" },
+ /* LoadLockedReq */
+ { SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
+ ReadResp, "LoadLockedReq" },
+ /* LoadLockedResp */
+ { SET4(IsRead, IsLocked, IsResponse, HasData),
+ InvalidCmd, "LoadLockedResp" },
+ /* StoreCondReq */
+ { SET6(IsWrite, NeedsExclusive, IsLocked,
+ IsRequest, NeedsResponse, HasData),
+ StoreCondResp, "StoreCondReq" },
+ /* StoreCondResp */
+ { SET4(IsWrite, NeedsExclusive, IsLocked, IsResponse),
+ InvalidCmd, "StoreCondResp" },
/* SwapReq -- for Swap ldstub type operations */
- { SET4(IsReadWrite, IsRequest, HasData, NeedsResponse),
+ { SET6(IsRead, IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
SwapResp, "SwapReq" },
/* SwapResp -- for Swap ldstub type operations */
- { SET3(IsReadWrite, IsResponse, HasData),
+ { SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
InvalidCmd, "SwapResp" }
};
@@ -170,27 +185,28 @@ fixDelayedResponsePacket(PacketPtr func, PacketPtr timing)
}
bool
-fixPacket(PacketPtr func, PacketPtr timing)
+Packet::checkFunctional(Addr addr, int size, uint8_t *data)
{
- Addr funcStart = func->getAddr();
- Addr funcEnd = func->getAddr() + func->getSize() - 1;
- Addr timingStart = timing->getAddr();
- Addr timingEnd = timing->getAddr() + timing->getSize() - 1;
+ Addr func_start = getAddr();
+ Addr func_end = getAddr() + getSize() - 1;
+ Addr val_start = addr;
+ Addr val_end = val_start + size - 1;
- assert(!(funcStart > timingEnd || timingStart > funcEnd));
+ if (func_start > val_end || val_start > func_end) {
+ // no intersection
+ return false;
+ }
- // this packet can't solve our problem, continue on
- if (!timing->hasData())
- return true;
+ // offset of functional request into supplied value (could be
+ // negative if partial overlap)
+ int offset = func_start - val_start;
- if (func->isRead()) {
- if (funcStart >= timingStart && funcEnd <= timingEnd) {
- func->allocate();
- std::memcpy(func->getPtr<uint8_t>(), timing->getPtr<uint8_t>() +
- funcStart - timingStart, func->getSize());
- func->result = Packet::Success;
- func->flags |= SATISFIED;
- return false;
+ if (isRead()) {
+ if (func_start >= val_start && func_end <= val_end) {
+ allocate();
+ std::memcpy(getPtr<uint8_t>(), data + offset, getSize());
+ result = Packet::Success;
+ return true;
} else {
// In this case the timing packet only partially satisfies
// the request, so we would need more information to make
@@ -198,25 +214,21 @@ fixPacket(PacketPtr func, PacketPtr timing)
// something, so the request could continue and get this
// bit of possibly newer data along with the older data
// not written to yet.
- panic("Timing packet only partially satisfies the functional"
- "request. Now what?");
+ panic("Memory value only partially satisfies the functional "
+ "request. Now what?");
}
- } else if (func->isWrite()) {
- if (funcStart >= timingStart) {
- std::memcpy(timing->getPtr<uint8_t>() + (funcStart - timingStart),
- func->getPtr<uint8_t>(),
- (std::min(funcEnd, timingEnd) - funcStart) + 1);
- } else { // timingStart > funcStart
- std::memcpy(timing->getPtr<uint8_t>(),
- func->getPtr<uint8_t>() + (timingStart - funcStart),
- (std::min(funcEnd, timingEnd) - timingStart) + 1);
+ } else if (isWrite()) {
+ if (offset >= 0) {
+ std::memcpy(data + offset, getPtr<uint8_t>(),
+ (std::min(func_end, val_end) - func_start) + 1);
+ } else { // val_start > func_start
+ std::memcpy(data, getPtr<uint8_t>() - offset,
+ (std::min(func_end, val_end) - val_start) + 1);
}
// we always want to keep going with a write
- return true;
+ return false;
} else
- panic("Don't know how to handle command type %#x\n",
- func->cmdToIndex());
-
+ panic("Don't know how to handle command %s\n", cmdString());
}
@@ -246,8 +258,6 @@ operator<<(std::ostream &o, const Packet &p)
o << "Read ";
if (p.isWrite())
o << "Write ";
- if (p.isReadWrite())
- o << "Read/Write ";
if (p.isInvalidate())
o << "Invalidate ";
if (p.isRequest())
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index fb077901e..80da045ef 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -55,16 +55,6 @@ typedef Packet *PacketPtr;
typedef uint8_t* PacketDataPtr;
typedef std::list<PacketPtr> PacketList;
-//Coherence Flags
-#define NACKED_LINE (1 << 0)
-#define SATISFIED (1 << 1)
-#define SHARED_LINE (1 << 2)
-#define CACHE_LINE_FILL (1 << 3)
-#define COMPRESSED (1 << 4)
-#define NO_ALLOCATE (1 << 5)
-#define SNOOP_COMMIT (1 << 6)
-
-
class MemCmd
{
public:
@@ -74,21 +64,24 @@ class MemCmd
{
InvalidCmd,
ReadReq,
- WriteReq,
- WriteReqNoAck,
ReadResp,
+ WriteReq,
WriteResp,
Writeback,
SoftPFReq,
HardPFReq,
SoftPFResp,
HardPFResp,
- InvalidateReq,
WriteInvalidateReq,
WriteInvalidateResp,
UpgradeReq,
+ UpgradeResp,
ReadExReq,
ReadExResp,
+ LoadLockedReq,
+ LoadLockedResp,
+ StoreCondReq,
+ StoreCondResp,
SwapReq,
SwapResp,
NUM_MEM_CMDS
@@ -98,18 +91,18 @@ class MemCmd
/** List of command attributes. */
enum Attribute
{
- IsRead,
- IsWrite,
- IsPrefetch,
+ IsRead, //!< Data flows from responder to requester
+ IsWrite, //!< Data flows from requester to responder
+ IsPrefetch, //!< Not a demand access
IsInvalidate,
- IsRequest,
- IsResponse,
- NeedsResponse,
+ NeedsExclusive, //!< Requires exclusive copy to complete in-cache
+ IsRequest, //!< Issued by requester
+ IsResponse, //!< Issue by responder
+ NeedsResponse, //!< Requester needs response from target
IsSWPrefetch,
IsHWPrefetch,
- IsUpgrade,
- HasData,
- IsReadWrite,
+ IsLocked, //!< Alpha/MIPS LL or SC access
+ HasData, //!< There is an associated payload
NUM_COMMAND_ATTRIBUTES
};
@@ -142,10 +135,12 @@ class MemCmd
bool isWrite() const { return testCmdAttrib(IsWrite); }
bool isRequest() const { return testCmdAttrib(IsRequest); }
bool isResponse() const { return testCmdAttrib(IsResponse); }
+ bool needsExclusive() const { return testCmdAttrib(NeedsExclusive); }
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
bool isInvalidate() const { return testCmdAttrib(IsInvalidate); }
bool hasData() const { return testCmdAttrib(HasData); }
- bool isReadWrite() const { return testCmdAttrib(IsReadWrite); }
+ bool isReadWrite() const { return isRead() && isWrite(); }
+ bool isLocked() const { return testCmdAttrib(IsLocked); }
const Command responseCommand() const {
return commandInfo[cmd].response;
@@ -189,9 +184,6 @@ class Packet : public FastAlloc
typedef MemCmd::Command Command;
- /** Temporary FLAGS field until cache gets working, this should be in coherence/sender state. */
- uint64_t flags;
-
private:
/** A pointer to the data being transfered. It can be differnt
* sizes at each level of the heirarchy so it belongs in the
@@ -236,6 +228,14 @@ class Packet : public FastAlloc
/** Is the 'src' field valid? */
bool srcValid;
+ enum SnoopFlag {
+ MemInhibit,
+ Shared,
+ NUM_SNOOP_FLAGS
+ };
+
+ /** Coherence snoopFlags for snooping */
+ std::bitset<NUM_SNOOP_FLAGS> snoopFlags;
public:
@@ -302,14 +302,17 @@ class Packet : public FastAlloc
bool isWrite() const { return cmd.isWrite(); }
bool isRequest() const { return cmd.isRequest(); }
bool isResponse() const { return cmd.isResponse(); }
+ bool needsExclusive() const { return cmd.needsExclusive(); }
bool needsResponse() const { return cmd.needsResponse(); }
bool isInvalidate() const { return cmd.isInvalidate(); }
bool hasData() const { return cmd.hasData(); }
bool isReadWrite() const { return cmd.isReadWrite(); }
+ bool isLocked() const { return cmd.isLocked(); }
- bool isCacheFill() const { return (flags & CACHE_LINE_FILL) != 0; }
- bool isNoAllocate() const { return (flags & NO_ALLOCATE) != 0; }
- bool isCompressed() const { return (flags & COMPRESSED) != 0; }
+ void assertMemInhibit() { snoopFlags[MemInhibit] = true; }
+ void assertShared() { snoopFlags[Shared] = true; }
+ bool memInhibitAsserted() { return snoopFlags[MemInhibit]; }
+ bool sharedAsserted() { return snoopFlags[Shared]; }
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
@@ -328,6 +331,8 @@ class Packet : public FastAlloc
/** Accessor function that returns the source index of the packet. */
short getSrc() const { assert(srcValid); return src; }
void setSrc(short _src) { src = _src; srcValid = true; }
+ /** Reset source field, e.g. to retransmit packet on different bus. */
+ void clearSrc() { srcValid = false; }
/** Accessor function that returns the destination index of
the packet. */
@@ -348,13 +353,12 @@ class Packet : public FastAlloc
Packet(Request *_req, MemCmd _cmd, short _dest)
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
addr(_req->paddr), size(_req->size), dest(_dest),
- addrSizeValid(_req->validPaddr),
- srcValid(false),
+ addrSizeValid(_req->validPaddr), srcValid(false),
+ snoopFlags(0),
+ time(curTick),
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
result(Unknown)
{
- flags = 0;
- time = curTick;
}
/** Alternate constructor if you are trying to create a packet with
@@ -362,14 +366,32 @@ class Packet : public FastAlloc
* this allows for overriding the size/addr of the req.*/
Packet(Request *_req, MemCmd _cmd, short _dest, int _blkSize)
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
- addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize),
- dest(_dest),
+ addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize), dest(_dest),
addrSizeValid(_req->validPaddr), srcValid(false),
+ snoopFlags(0),
+ time(curTick),
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
result(Unknown)
{
- flags = 0;
- time = curTick;
+ }
+
+ /** Alternate constructor for copying a packet. Copy all fields
+ * *except* set data allocation as static... even if the original
+ * packet's data was dynamic, we don't want to free it when the
+ * new packet is deallocated. Note that if original packet used
+ * dynamic data, user must guarantee that the new packet's
+ * lifetime is less than that of the original packet. */
+ Packet(Packet *origPkt)
+ : data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ addr(origPkt->addr), size(origPkt->size),
+ dest(origPkt->dest),
+ addrSizeValid(origPkt->addrSizeValid), srcValid(origPkt->srcValid),
+ snoopFlags(origPkt->snoopFlags),
+ time(curTick),
+ req(origPkt->req), coherence(origPkt->coherence),
+ senderState(origPkt->senderState), cmd(origPkt->cmd),
+ result(origPkt->result)
+ {
}
/** Destructor. */
@@ -383,7 +405,7 @@ class Packet : public FastAlloc
* multiple transactions. */
void reinitFromRequest() {
assert(req->validPaddr);
- flags = 0;
+ snoopFlags = 0;
addr = req->paddr;
size = req->size;
time = req->time;
@@ -396,29 +418,40 @@ class Packet : public FastAlloc
}
}
- /** Take a request packet and modify it in place to be suitable
- * for returning as a response to that request. Used for timing
- * accesses only. For atomic and functional accesses, the
- * request packet is always implicitly passed back *without*
- * modifying the destination fields, so this function
- * should not be called. */
- void makeTimingResponse() {
+ /**
+ * Take a request packet and modify it in place to be suitable for
+ * returning as a response to that request. The source and
+ * destination fields are *not* modified, as is appropriate for
+ * atomic accesses.
+ */
+ void makeAtomicResponse()
+ {
assert(needsResponse());
assert(isRequest());
+ assert(result == Unknown);
cmd = cmd.responseCommand();
+ result = Success;
+ }
+
+ /**
+ * Perform the additional work required for timing responses above
+ * and beyond atomic responses; i.e., change the destination to
+ * point back to the requester and clear the source field.
+ */
+ void convertAtomicToTimingResponse()
+ {
dest = src;
srcValid = false;
}
/**
* Take a request packet and modify it in place to be suitable for
- * returning as a response to that request.
+ * returning as a response to a timing request.
*/
- void makeAtomicResponse()
+ void makeTimingResponse()
{
- assert(needsResponse());
- assert(isRequest());
- cmd = cmd.responseCommand();
+ makeAtomicResponse();
+ convertAtomicToTimingResponse();
}
/**
@@ -495,6 +528,40 @@ class Packet : public FastAlloc
void set(T v);
/**
+ * Copy data into the packet from the provided pointer.
+ */
+ void setData(uint8_t *p)
+ {
+ std::memcpy(getPtr<uint8_t>(), p, getSize());
+ }
+
+ /**
+ * Copy data into the packet from the provided block pointer,
+ * which is aligned to the given block size.
+ */
+ void setDataFromBlock(uint8_t *blk_data, int blkSize)
+ {
+ setData(blk_data + getOffset(blkSize));
+ }
+
+ /**
+ * Copy data from the packet to the provided block pointer, which
+ * is aligned to the given block size.
+ */
+ void writeData(uint8_t *p)
+ {
+ std::memcpy(p, getPtr<uint8_t>(), getSize());
+ }
+
+ /**
+ * Copy data from the packet to the memory at the provided pointer.
+ */
+ void writeDataToBlock(uint8_t *blk_data, int blkSize)
+ {
+ writeData(blk_data + getOffset(blkSize));
+ }
+
+ /**
* delete the data pointed to in the data pointer. Ok to call to
* matter how data was allocted.
*/
@@ -505,15 +572,35 @@ class Packet : public FastAlloc
/** Do the packet modify the same addresses. */
bool intersect(PacketPtr p);
+
+ /**
+ * Check a functional request against a memory value represented
+ * by a base/size pair and an associated data array. If the
+ * functional request is a read, it may be satisfied by the memory
+ * value. If the functional request is a write, it may update the
+ * memory value.
+ */
+ bool checkFunctional(Addr base, int size, uint8_t *data);
+
+ /**
+ * Check a functional request against a memory value stored in
+ * another packet (i.e. an in-transit request or response).
+ */
+ bool checkFunctional(PacketPtr otherPkt) {
+ return (otherPkt->hasData() &&
+ checkFunctional(otherPkt->getAddr(), otherPkt->getSize(),
+ otherPkt->getPtr<uint8_t>()));
+ }
};
-/** This function given a functional packet and a timing packet either
- * satisfies the timing packet, or updates the timing packet to
- * reflect the updated state in the timing packet. It returns if the
- * functional packet should continue to traverse the memory hierarchy
- * or not.
+
+
+/** Temporary for backwards compatibility.
*/
-bool fixPacket(PacketPtr func, PacketPtr timing);
+inline
+bool fixPacket(PacketPtr func, PacketPtr timing) {
+ return !func->checkFunctional(timing);
+}
/** This function is a wrapper for the fixPacket field that toggles
* the hasData bit it is used when a response is waiting in the
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index 9d840fe69..93cba96c4 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -58,8 +58,9 @@ PhysicalMemory::PhysicalMemory(Params *p)
panic("Memory Size not divisible by page size\n");
int map_flags = MAP_ANON | MAP_PRIVATE;
- pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
- map_flags, -1, 0);
+ pmemAddr =
+ (uint8_t *)mmap(NULL, params()->addrRange.size(),
+ PROT_READ | PROT_WRITE, map_flags, -1, 0);
if (pmemAddr == (void *)MAP_FAILED) {
perror("mmap");
@@ -121,8 +122,9 @@ PhysicalMemory::calculateLatency(PacketPtr pkt)
// Add load-locked to tracking list. Should only be called if the
// operation is a load and the LOCKED flag is set.
void
-PhysicalMemory::trackLoadLocked(Request *req)
+PhysicalMemory::trackLoadLocked(PacketPtr pkt)
{
+ Request *req = pkt->req;
Addr paddr = LockedAddr::mask(req->getPaddr());
// first we check if we already have a locked addr for this
@@ -151,10 +153,11 @@ PhysicalMemory::trackLoadLocked(Request *req)
// conflict with locked addresses, and for success/failure of store
// conditionals.
bool
-PhysicalMemory::checkLockedAddrList(Request *req)
+PhysicalMemory::checkLockedAddrList(PacketPtr pkt)
{
+ Request *req = pkt->req;
Addr paddr = LockedAddr::mask(req->getPaddr());
- bool isLocked = req->isLocked();
+ bool isLocked = pkt->isLocked();
// Initialize return value. Non-conditional stores always
// succeed. Assume conditional stores will fail until proven
@@ -198,74 +201,50 @@ PhysicalMemory::checkLockedAddrList(Request *req)
return success;
}
-void
-PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
+
+#if TRACING_ON
+
+#define CASE(A, T) \
+ case sizeof(T): \
+ DPRINTF(MemoryAccess, A " of size %i on address 0x%x data 0x%x\n", \
+ pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \
+ break
+
+
+#define TRACE_PACKET(A) \
+ do { \
+ switch (pkt->getSize()) { \
+ CASE(A, uint64_t); \
+ CASE(A, uint32_t); \
+ CASE(A, uint16_t); \
+ CASE(A, uint8_t); \
+ default: \
+ DPRINTF(MemoryAccess, A " of size %i on address 0x%x\n", \
+ pkt->getSize(), pkt->getAddr()); \
+ } \
+ } while (0)
+
+#else
+
+#define TRACE_PACKET(A)
+
+#endif
+
+Tick
+PhysicalMemory::doAtomicAccess(PacketPtr pkt)
{
assert(pkt->getAddr() >= start() &&
pkt->getAddr() + pkt->getSize() <= start() + size());
- if (pkt->isRead()) {
- if (pkt->req->isLocked()) {
- trackLoadLocked(pkt->req);
- }
- memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
- pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- break;
- default:
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
- }
-#endif
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ return 0;
}
- else if (pkt->isWrite()) {
- if (writeOK(pkt->req)) {
- memcpy(pmemAddr + pkt->getAddr() - start(), pkt->getPtr<uint8_t>(),
- pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- break;
- default:
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
- }
-#endif
- }
- } else if (pkt->isInvalidate()) {
- //upgrade or invalidate
- pkt->flags |= SATISFIED;
- } else if (pkt->isReadWrite()) {
+
+ uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
+
+ if (pkt->cmd == MemCmd::SwapReq) {
IntReg overwrite_val;
bool overwrite_mem;
uint64_t condition_val64;
@@ -277,66 +256,76 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
// keep a copy of our possible write value, and copy what is at the
// memory address into the packet
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
- std::memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
- pkt->getSize());
+ std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
if (pkt->req->isCondSwap()) {
if (pkt->getSize() == sizeof(uint64_t)) {
condition_val64 = pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val64, pmemAddr +
- pkt->getAddr() - start(), sizeof(uint64_t));
+ overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
+ sizeof(uint64_t));
} else if (pkt->getSize() == sizeof(uint32_t)) {
condition_val32 = (uint32_t)pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val32, pmemAddr +
- pkt->getAddr() - start(), sizeof(uint32_t));
+ overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
+ sizeof(uint32_t));
} else
panic("Invalid size for conditional read/write\n");
}
if (overwrite_mem)
- std::memcpy(pmemAddr + pkt->getAddr() - start(),
- &overwrite_val, pkt->getSize());
+ std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
- overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
- condition_val64, overwrite_mem ? "happened" : "didn't happen");
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
- overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
- condition_val32, overwrite_mem ? "happened" : "didn't happen");
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
- overwrite_mem);
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
- overwrite_mem);
- break;
- default:
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
+ TRACE_PACKET("Read/Write");
+ } else if (pkt->isRead()) {
+ assert(!pkt->isWrite());
+ if (pkt->isLocked()) {
+ trackLoadLocked(pkt);
+ }
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ TRACE_PACKET("Read");
+ } else if (pkt->isWrite()) {
+ if (writeOK(pkt)) {
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ TRACE_PACKET("Write");
+ }
+ } else if (pkt->isInvalidate()) {
+ //upgrade or invalidate
+ if (pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
}
-#endif
} else {
panic("unimplemented");
}
+ if (pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
+ }
+ return calculateLatency(pkt);
+}
+
+
+void
+PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
+{
+ assert(pkt->getAddr() >= start() &&
+ pkt->getAddr() + pkt->getSize() <= start() + size());
+
+ uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
+
+ if (pkt->cmd == MemCmd::ReadReq) {
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ TRACE_PACKET("Read");
+ } else if (pkt->cmd == MemCmd::WriteReq) {
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ TRACE_PACKET("Write");
+ } else {
+ panic("PhysicalMemory: unimplemented functional command %s",
+ pkt->cmdString());
+ }
+
pkt->result = Packet::Success;
}
+
Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
{
@@ -407,8 +396,7 @@ PhysicalMemory::MemoryPort::deviceBlockSize()
Tick
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
{
- memory->doFunctionalAccess(pkt);
- return memory->calculateLatency(pkt);
+ return memory->doAtomicAccess(pkt);
}
void
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index b9af5d334..8b13d32c1 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -112,12 +112,12 @@ class PhysicalMemory : public MemObject
// inline a quick check for an empty locked addr list (hopefully
// the common case), and do the full list search (if necessary) in
// this out-of-line function
- bool checkLockedAddrList(Request *req);
+ bool checkLockedAddrList(PacketPtr pkt);
// Record the address of a load-locked operation so that we can
// clear the execution context's lock flag if a matching store is
// performed
- void trackLoadLocked(Request *req);
+ void trackLoadLocked(PacketPtr pkt);
// Compare a store address with any locked addresses so we can
// clear the lock flag appropriately. Return value set to 'false'
@@ -126,17 +126,18 @@ class PhysicalMemory : public MemObject
// requesting execution context), 'true' otherwise. Note that
// this method must be called on *all* stores since even
// non-conditional stores must clear any matching lock addresses.
- bool writeOK(Request *req) {
+ bool writeOK(PacketPtr pkt) {
+ Request *req = pkt->req;
if (lockedAddrList.empty()) {
// no locked addrs: nothing to check, store_conditional fails
- bool isLocked = req->isLocked();
+ bool isLocked = pkt->isLocked();
if (isLocked) {
req->setExtraData(0);
}
return !isLocked; // only do write if not an sc
} else {
// iterate over list...
- return checkLockedAddrList(req);
+ return checkLockedAddrList(pkt);
}
}
@@ -175,6 +176,7 @@ class PhysicalMemory : public MemObject
unsigned int drain(Event *de);
protected:
+ Tick doAtomicAccess(PacketPtr pkt);
void doFunctionalAccess(PacketPtr pkt);
virtual Tick calculateLatency(PacketPtr pkt);
void recvStatusChange(Port::Status status);
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
index ed4c0c172..2644a504c 100644
--- a/src/mem/tport.cc
+++ b/src/mem/tport.cc
@@ -67,14 +67,17 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
// code to hanldle nacks here, but I'm pretty sure it didn't work
// correctly with the drain code, so that would need to be fixed
// if we ever added it back.
- assert(pkt->result != Packet::Nacked);
+ assert(pkt->isRequest());
+ assert(pkt->result == Packet::Unknown);
+ bool needsResponse = pkt->needsResponse();
Tick latency = recvAtomic(pkt);
// turn packet around to go back to requester if response expected
- if (pkt->needsResponse()) {
- pkt->makeTimingResponse();
+ if (needsResponse) {
+ // recvAtomic() should already have turned packet into atomic response
+ assert(pkt->isResponse());
+ pkt->convertAtomicToTimingResponse();
schedSendTiming(pkt, curTick + latency);
- }
- else if (pkt->cmd != MemCmd::UpgradeReq) {
+ } else {
delete pkt->req;
delete pkt;
}