More major reorg of cache. Seems to work for atomic mode now,
timing mode still broken. configs/example/memtest.py: Revamp options. src/cpu/memtest/memtest.cc: No need for memory initialization. No need to make atomic response... memory system should do that now. src/cpu/memtest/memtest.hh: MemTest really doesn't want to snoop. src/mem/bridge.cc: checkFunctional() cleanup. src/mem/bus.cc: src/mem/bus.hh: src/mem/cache/base_cache.cc: src/mem/cache/base_cache.hh: src/mem/cache/cache.cc: src/mem/cache/cache.hh: src/mem/cache/cache_blk.hh: src/mem/cache/cache_builder.cc: src/mem/cache/cache_impl.hh: src/mem/cache/coherence/coherence_protocol.cc: src/mem/cache/coherence/coherence_protocol.hh: src/mem/cache/coherence/simple_coherence.hh: src/mem/cache/miss/SConscript: src/mem/cache/miss/mshr.cc: src/mem/cache/miss/mshr.hh: src/mem/cache/miss/mshr_queue.cc: src/mem/cache/miss/mshr_queue.hh: src/mem/cache/prefetch/base_prefetcher.cc: src/mem/cache/tags/fa_lru.cc: src/mem/cache/tags/fa_lru.hh: src/mem/cache/tags/iic.cc: src/mem/cache/tags/iic.hh: src/mem/cache/tags/lru.cc: src/mem/cache/tags/lru.hh: src/mem/cache/tags/split.cc: src/mem/cache/tags/split.hh: src/mem/cache/tags/split_lifo.cc: src/mem/cache/tags/split_lifo.hh: src/mem/cache/tags/split_lru.cc: src/mem/cache/tags/split_lru.hh: src/mem/packet.cc: src/mem/packet.hh: src/mem/physical.cc: src/mem/physical.hh: src/mem/tport.cc: More major reorg. Seems to work for atomic mode now, timing mode still broken. --HG-- extra : convert_revision : 7e70dfc4a752393b911880ff028271433855ae87
This commit is contained in:
parent
a9b7c558fd
commit
35cf19d441
|
@ -33,14 +33,32 @@ m5.AddToPath('../common')
|
||||||
|
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
|
|
||||||
parser.add_option("--caches", action="store_true")
|
parser.add_option("-c", "--cache-levels", type="int", default=2,
|
||||||
parser.add_option("-t", "--timing", action="store_true")
|
metavar="LEVELS",
|
||||||
parser.add_option("-m", "--maxtick", type="int")
|
help="Number of cache levels [default: %default]")
|
||||||
parser.add_option("-l", "--maxloads", default = "1000000000000", type="int")
|
parser.add_option("-a", "--atomic", action="store_true",
|
||||||
parser.add_option("-n", "--numtesters", default = "8", type="int")
|
help="Use atomic (non-timing) mode")
|
||||||
parser.add_option("-p", "--protocol",
|
parser.add_option("-b", "--blocking", action="store_true",
|
||||||
default="moesi",
|
help="Use blocking caches")
|
||||||
help="The coherence protocol to use for the L1'a (i.e. MOESI, MOSI)")
|
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]")
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
@ -48,14 +66,29 @@ if args:
|
||||||
print "Error: script doesn't take any positional arguments"
|
print "Error: script doesn't take any positional arguments"
|
||||||
sys.exit(1)
|
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
|
# Base L1 Cache
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
class L1(BaseCache):
|
class L1(BaseCache):
|
||||||
latency = '1ns'
|
latency = '1ns'
|
||||||
block_size = 64
|
block_size = block_size
|
||||||
mshrs = 12
|
mshrs = num_l1_mshrs
|
||||||
tgts_per_mshr = 8
|
tgts_per_mshr = 8
|
||||||
protocol = CoherenceProtocol(protocol=options.protocol)
|
protocol = CoherenceProtocol(protocol=options.protocol)
|
||||||
|
|
||||||
|
@ -64,29 +97,31 @@ class L1(BaseCache):
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class L2(BaseCache):
|
class L2(BaseCache):
|
||||||
block_size = 64
|
block_size = block_size
|
||||||
latency = '10ns'
|
latency = '10ns'
|
||||||
mshrs = 92
|
mshrs = num_l2_mshrs
|
||||||
tgts_per_mshr = 16
|
tgts_per_mshr = 16
|
||||||
write_buffers = 8
|
write_buffers = 8
|
||||||
|
protocol = CoherenceProtocol(protocol=options.protocol)
|
||||||
|
|
||||||
#MAX CORES IS 8 with the false sharing method
|
if options.numtesters > block_size:
|
||||||
if options.numtesters > 8:
|
print "Error: Number of testers limited to %s because of false sharing" \
|
||||||
print "Error: NUmber of testers limited to 8 because of false sharing"
|
% (block_size)
|
||||||
sys,exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
cpus = [ MemTest(atomic=not options.timing, max_loads=options.maxloads,
|
cpus = [ MemTest(atomic=options.atomic, max_loads=options.maxloads,
|
||||||
percent_functional=50, percent_uncacheable=10,
|
percent_functional=options.functional,
|
||||||
|
percent_uncacheable=options.uncacheable,
|
||||||
progress_interval=1000)
|
progress_interval=1000)
|
||||||
for i in xrange(options.numtesters) ]
|
for i in xrange(options.numtesters) ]
|
||||||
|
|
||||||
# system simulated
|
# system simulated
|
||||||
system = System(cpu = cpus, funcmem = PhysicalMemory(),
|
system = System(cpu = cpus, funcmem = PhysicalMemory(),
|
||||||
physmem = PhysicalMemory(latency = "50ps"),
|
physmem = PhysicalMemory(latency = "100ns"),
|
||||||
membus = Bus(clock="500MHz", width=16))
|
membus = Bus(clock="500MHz", width=16))
|
||||||
|
|
||||||
# l2cache & bus
|
# l2cache & bus
|
||||||
if options.caches:
|
if options.cache_levels == 2:
|
||||||
system.toL2Bus = Bus(clock="500MHz", width=16)
|
system.toL2Bus = Bus(clock="500MHz", width=16)
|
||||||
system.l2c = L2(size='64kB', assoc=8)
|
system.l2c = L2(size='64kB', assoc=8)
|
||||||
system.l2c.cpu_side = system.toL2Bus.port
|
system.l2c.cpu_side = system.toL2Bus.port
|
||||||
|
@ -96,10 +131,14 @@ if options.caches:
|
||||||
|
|
||||||
# add L1 caches
|
# add L1 caches
|
||||||
for cpu in cpus:
|
for cpu in cpus:
|
||||||
if options.caches:
|
if options.cache_levels == 2:
|
||||||
cpu.l1c = L1(size = '32kB', assoc = 4)
|
cpu.l1c = L1(size = '32kB', assoc = 4)
|
||||||
cpu.test = cpu.l1c.cpu_side
|
cpu.test = cpu.l1c.cpu_side
|
||||||
cpu.l1c.mem_side = system.toL2Bus.port
|
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:
|
else:
|
||||||
cpu.test = system.membus.port
|
cpu.test = system.membus.port
|
||||||
system.funcmem.port = cpu.functional
|
system.funcmem.port = cpu.functional
|
||||||
|
@ -113,10 +152,10 @@ system.physmem.port = system.membus.port
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
|
||||||
root = Root( system = system )
|
root = Root( system = system )
|
||||||
if options.timing:
|
if options.atomic:
|
||||||
root.system.mem_mode = 'timing'
|
|
||||||
else:
|
|
||||||
root.system.mem_mode = 'atomic'
|
root.system.mem_mode = 'atomic'
|
||||||
|
else:
|
||||||
|
root.system.mem_mode = 'timing'
|
||||||
|
|
||||||
# Not much point in this being higher than the L1 latency
|
# Not much point in this being higher than the L1 latency
|
||||||
m5.ticks.setGlobalFrequency('1ns')
|
m5.ticks.setGlobalFrequency('1ns')
|
||||||
|
@ -125,9 +164,6 @@ m5.ticks.setGlobalFrequency('1ns')
|
||||||
m5.instantiate(root)
|
m5.instantiate(root)
|
||||||
|
|
||||||
# simulate until program terminates
|
# simulate until program terminates
|
||||||
if options.maxtick:
|
exit_event = m5.simulate(options.maxtick)
|
||||||
exit_event = m5.simulate(options.maxtick)
|
|
||||||
else:
|
|
||||||
exit_event = m5.simulate(10000000000000)
|
|
||||||
|
|
||||||
print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
|
print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
|
||||||
|
|
|
@ -102,7 +102,6 @@ void
|
||||||
MemTest::sendPkt(PacketPtr pkt) {
|
MemTest::sendPkt(PacketPtr pkt) {
|
||||||
if (atomic) {
|
if (atomic) {
|
||||||
cachePort.sendAtomic(pkt);
|
cachePort.sendAtomic(pkt);
|
||||||
pkt->makeAtomicResponse();
|
|
||||||
completeRequest(pkt);
|
completeRequest(pkt);
|
||||||
}
|
}
|
||||||
else if (!cachePort.sendTiming(pkt)) {
|
else if (!cachePort.sendTiming(pkt)) {
|
||||||
|
@ -165,8 +164,6 @@ MemTest::MemTest(const string &name,
|
||||||
tickEvent.schedule(0);
|
tickEvent.schedule(0);
|
||||||
|
|
||||||
id = TESTER_ALLOCATOR++;
|
id = TESTER_ALLOCATOR++;
|
||||||
if (TESTER_ALLOCATOR > 8)
|
|
||||||
panic("False sharing memtester only allows up to 8 testers");
|
|
||||||
|
|
||||||
accessRetry = false;
|
accessRetry = false;
|
||||||
}
|
}
|
||||||
|
@ -190,14 +187,8 @@ MemTest::init()
|
||||||
blockAddrMask = blockSize - 1;
|
blockAddrMask = blockSize - 1;
|
||||||
traceBlockAddr = blockAddr(traceBlockAddr);
|
traceBlockAddr = blockAddr(traceBlockAddr);
|
||||||
|
|
||||||
// set up intial memory contents here
|
// initial memory contents for both physical memory and functional
|
||||||
|
// memory should be 0; no need to initialize them.
|
||||||
cachePort.memsetBlob(baseAddr1, 1, size);
|
|
||||||
funcPort.memsetBlob(baseAddr1, 1, size);
|
|
||||||
cachePort.memsetBlob(baseAddr2, 2, size);
|
|
||||||
funcPort.memsetBlob(baseAddr2, 2, size);
|
|
||||||
cachePort.memsetBlob(uncacheAddr, 3, size);
|
|
||||||
funcPort.memsetBlob(uncacheAddr, 3, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -230,15 +221,10 @@ MemTest::completeRequest(PacketPtr pkt)
|
||||||
case MemCmd::ReadResp:
|
case MemCmd::ReadResp:
|
||||||
|
|
||||||
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
|
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
|
||||||
cerr << name() << ": on read of 0x" << hex << req->getPaddr()
|
panic("%s: read of %x (blk %x) @ cycle %d "
|
||||||
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
"returns %x, expected %x\n", name(),
|
||||||
<< "@ cycle " << dec << curTick
|
req->getPaddr(), blockAddr(req->getPaddr()), curTick,
|
||||||
<< ", cache returns 0x";
|
*pkt_data, *data);
|
||||||
printData(cerr, pkt_data, pkt->getSize());
|
|
||||||
cerr << ", expected 0x";
|
|
||||||
printData(cerr, data, pkt->getSize());
|
|
||||||
cerr << endl;
|
|
||||||
fatal("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
numReads++;
|
numReads++;
|
||||||
|
@ -267,7 +253,7 @@ MemTest::completeRequest(PacketPtr pkt)
|
||||||
break;
|
break;
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
panic("invalid command");
|
panic("invalid command %s (%d)", pkt->cmdString(), pkt->cmd.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ class MemTest : public MemObject
|
||||||
|
|
||||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
||||||
bool &snoop)
|
bool &snoop)
|
||||||
{ resp.clear(); snoop = true; }
|
{ resp.clear(); snoop = false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
CpuPort cachePort;
|
CpuPort cachePort;
|
||||||
|
|
|
@ -339,17 +339,14 @@ void
|
||||||
Bridge::BridgePort::recvFunctional(PacketPtr pkt)
|
Bridge::BridgePort::recvFunctional(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
std::list<PacketBuffer*>::iterator i;
|
std::list<PacketBuffer*>::iterator i;
|
||||||
bool pktContinue = true;
|
|
||||||
|
|
||||||
for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
|
for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
|
||||||
if (pkt->intersect((*i)->pkt)) {
|
if (pkt->checkFunctional((*i)->pkt))
|
||||||
pktContinue &= fixPacket(pkt, (*i)->pkt);
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pktContinue) {
|
// fall through if pkt still not satisfied
|
||||||
otherPort->sendFunctional(pkt);
|
otherPort->sendFunctional(pkt);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Function called by the port when the bus is receiving a status change.*/
|
/** Function called by the port when the bus is receiving a status change.*/
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
* Definition of a bus object.
|
* Definition of a bus object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
|
@ -182,8 +182,7 @@ Bus::recvTiming(PacketPtr pkt)
|
||||||
|
|
||||||
// If the bus is busy, or other devices are in line ahead of the current
|
// If the bus is busy, or other devices are in line ahead of the current
|
||||||
// one, put this device on the retry list.
|
// one, put this device on the retry list.
|
||||||
if (!(pkt->flags & EXPRESS_SNOOP) &&
|
if (tickNextIdle > curTick ||
|
||||||
tickNextIdle > curTick ||
|
|
||||||
(retryList.size() && (!inRetry || pktPort != retryList.front())))
|
(retryList.size() && (!inRetry || pktPort != retryList.front())))
|
||||||
{
|
{
|
||||||
addToRetryList(pktPort);
|
addToRetryList(pktPort);
|
||||||
|
@ -199,7 +198,7 @@ Bus::recvTiming(PacketPtr pkt)
|
||||||
port = findPort(pkt->getAddr(), pkt->getSrc());
|
port = findPort(pkt->getAddr(), pkt->getSrc());
|
||||||
timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
|
timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
|
||||||
|
|
||||||
if (pkt->flags & SATISFIED) {
|
if (pkt->memInhibitAsserted()) {
|
||||||
//Cache-Cache transfer occuring
|
//Cache-Cache transfer occuring
|
||||||
if (inRetry) {
|
if (inRetry) {
|
||||||
retryList.front()->onRetryList(false);
|
retryList.front()->onRetryList(false);
|
||||||
|
@ -321,27 +320,6 @@ Bus::findPort(Addr addr, int id)
|
||||||
return interfaces[dest_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
|
void
|
||||||
Bus::functionalSnoop(PacketPtr pkt, Port *responder)
|
Bus::functionalSnoop(PacketPtr pkt, Port *responder)
|
||||||
{
|
{
|
||||||
|
@ -390,19 +368,56 @@ Bus::recvAtomic(PacketPtr pkt)
|
||||||
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
|
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
|
||||||
assert(pkt->getDest() == Packet::Broadcast);
|
assert(pkt->getDest() == Packet::Broadcast);
|
||||||
|
|
||||||
// Assume one bus cycle in order to get through. This may have
|
// Variables for recording original command and snoop response (if
|
||||||
// some clock skew issues yet again...
|
// any)... if a snooper respondes, we will need to restore
|
||||||
pkt->finishTime = curTick + clock;
|
// 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());
|
Port *target_port = findPort(pkt->getAddr(), pkt->getSrc());
|
||||||
Tick snoopTime = atomicSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
|
|
||||||
|
|
||||||
if (snoopTime)
|
SnoopIter s_end = snoopPorts.end();
|
||||||
return snoopTime; //Snoop satisfies it
|
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
|
||||||
else if (port)
|
BusPort *p = *s_iter;
|
||||||
return port->sendAtomic(pkt);
|
// same port should not have both target addresses and snooping
|
||||||
else
|
assert(p != target_port);
|
||||||
return 0;
|
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
|
/** Function called by the port when the bus is receiving a Functional
|
||||||
|
|
|
@ -182,9 +182,6 @@ class Bus : public MemObject
|
||||||
*/
|
*/
|
||||||
Port *findPort(Addr addr, int id);
|
Port *findPort(Addr addr, int id);
|
||||||
|
|
||||||
/** Snoop all relevant ports atomicly. */
|
|
||||||
Tick atomicSnoop(PacketPtr pkt, Port* responder);
|
|
||||||
|
|
||||||
/** Snoop all relevant ports functionally. */
|
/** Snoop all relevant ports functionally. */
|
||||||
void functionalSnoop(PacketPtr pkt, Port *responder);
|
void functionalSnoop(PacketPtr pkt, Port *responder);
|
||||||
|
|
||||||
|
|
413
src/mem/cache/base_cache.cc
vendored
413
src/mem/cache/base_cache.cc
vendored
|
@ -41,18 +41,23 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
|
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
|
||||||
: Port(_name, _cache), cache(_cache), otherPort(NULL)
|
: SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
|
||||||
|
blocked(false), waitingOnRetry(false), mustSendRetry(false),
|
||||||
|
requestCauses(0)
|
||||||
{
|
{
|
||||||
blocked = false;
|
|
||||||
waitingOnRetry = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BaseCache::BaseCache(const std::string &name, Params ¶ms)
|
BaseCache::BaseCache(const std::string &name, Params ¶ms)
|
||||||
: MemObject(name),
|
: MemObject(name),
|
||||||
blocked(0), blockedSnoop(0),
|
mshrQueue(params.numMSHRs, 4),
|
||||||
|
writeBuffer(params.numWriteBuffers, params.numMSHRs+1000),
|
||||||
blkSize(params.blkSize),
|
blkSize(params.blkSize),
|
||||||
missCount(params.maxMisses), drainEvent(NULL)
|
numTarget(params.numTargets),
|
||||||
|
blocked(0),
|
||||||
|
noTargetMSHR(NULL),
|
||||||
|
missCount(params.maxMisses),
|
||||||
|
drainEvent(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,139 +76,21 @@ BaseCache::CachePort::deviceBlockSize()
|
||||||
return cache->getBlockSize();
|
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
|
void
|
||||||
BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
|
BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
bool notDone = checkFunctional(pkt);
|
checkFunctional(pkt);
|
||||||
if (notDone)
|
if (pkt->result != Packet::Success)
|
||||||
sendFunctional(pkt);
|
sendFunctional(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
BaseCache::CachePort::respond(PacketPtr pkt, Tick time)
|
|
||||||
{
|
|
||||||
assert(time >= curTick);
|
|
||||||
if (pkt->needsResponse()) {
|
|
||||||
if (transmitList.empty()) {
|
|
||||||
assert(!responseEvent->scheduled());
|
|
||||||
responseEvent->schedule(time);
|
|
||||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time,pkt));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// something is on the list and this belongs at the end
|
|
||||||
if (time >= transmitList.back().first) {
|
|
||||||
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 =
|
|
||||||
transmitList.begin();
|
|
||||||
std::list<std::pair<Tick,PacketPtr> >::iterator end =
|
|
||||||
transmitList.end();
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
while (i != end && !done) {
|
|
||||||
if (time < i->first) {
|
|
||||||
if (i == transmitList.begin()) {
|
|
||||||
//Inserting at begining, reschedule
|
|
||||||
responseEvent->reschedule(time);
|
|
||||||
}
|
|
||||||
transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(0);
|
|
||||||
// this code was on the cpuSidePort only... do we still need it?
|
|
||||||
if (pkt->cmd != MemCmd::UpgradeReq)
|
|
||||||
{
|
|
||||||
delete pkt->req;
|
|
||||||
delete pkt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
BaseCache::CachePort::drainResponse()
|
|
||||||
{
|
|
||||||
DPRINTF(CachePort,
|
|
||||||
"%s attempting to send a retry for response (%i waiting)\n",
|
|
||||||
name(), drainList.size());
|
|
||||||
//We have some responses to drain first
|
|
||||||
PacketPtr pkt = drainList.front();
|
|
||||||
if (sendTiming(pkt)) {
|
|
||||||
drainList.pop_front();
|
|
||||||
DPRINTF(CachePort, "%s sucessful in sending a retry for"
|
|
||||||
"response (%i still waiting)\n", name(), drainList.size());
|
|
||||||
if (!drainList.empty() || isBusRequested()) {
|
|
||||||
|
|
||||||
DPRINTF(CachePort, "%s has more responses/requests\n", name());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingOnRetry = true;
|
|
||||||
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BaseCache::CachePort::recvRetryCommon()
|
BaseCache::CachePort::recvRetryCommon()
|
||||||
{
|
{
|
||||||
assert(waitingOnRetry);
|
assert(waitingOnRetry);
|
||||||
waitingOnRetry = false;
|
waitingOnRetry = false;
|
||||||
if (!drainList.empty()) {
|
|
||||||
if (!drainResponse()) {
|
|
||||||
// more responses to drain... re-request bus
|
|
||||||
scheduleRequestEvent(curTick + 1);
|
|
||||||
}
|
|
||||||
// Check if we're done draining once this list is empty
|
|
||||||
if (drainList.empty()) {
|
|
||||||
cache->checkDrain();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,17 +338,289 @@ BaseCache::regStats()
|
||||||
.desc("number of cache copies performed")
|
.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
|
unsigned int
|
||||||
BaseCache::drain(Event *de)
|
BaseCache::drain(Event *de)
|
||||||
{
|
{
|
||||||
|
int count = memSidePort->drain(de) + cpuSidePort->drain(de);
|
||||||
|
|
||||||
// Set status
|
// Set status
|
||||||
if (!canDrain()) {
|
if (count != 0) {
|
||||||
drainEvent = de;
|
drainEvent = de;
|
||||||
|
|
||||||
changeState(SimObject::Draining);
|
changeState(SimObject::Draining);
|
||||||
return 1;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeState(SimObject::Drained);
|
changeState(SimObject::Drained);
|
||||||
|
|
236
src/mem/cache/base_cache.hh
vendored
236
src/mem/cache/base_cache.hh
vendored
|
@ -46,11 +46,13 @@
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
|
#include "mem/cache/miss/mshr_queue.hh"
|
||||||
#include "mem/mem_object.hh"
|
#include "mem/mem_object.hh"
|
||||||
#include "mem/packet.hh"
|
#include "mem/packet.hh"
|
||||||
#include "mem/port.hh"
|
#include "mem/tport.hh"
|
||||||
#include "mem/request.hh"
|
#include "mem/request.hh"
|
||||||
#include "sim/eventq.hh"
|
#include "sim/eventq.hh"
|
||||||
|
#include "sim/sim_exit.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reasons for Caches to be Blocked.
|
* Reasons for Caches to be Blocked.
|
||||||
|
@ -79,7 +81,7 @@ class MSHR;
|
||||||
*/
|
*/
|
||||||
class BaseCache : public MemObject
|
class BaseCache : public MemObject
|
||||||
{
|
{
|
||||||
class CachePort : public Port
|
class CachePort : public SimpleTimingPort
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BaseCache *cache;
|
BaseCache *cache;
|
||||||
|
@ -102,77 +104,76 @@ class BaseCache : public MemObject
|
||||||
|
|
||||||
void clearBlocked();
|
void clearBlocked();
|
||||||
|
|
||||||
bool checkFunctional(PacketPtr pkt);
|
|
||||||
|
|
||||||
void checkAndSendFunctional(PacketPtr pkt);
|
void checkAndSendFunctional(PacketPtr pkt);
|
||||||
|
|
||||||
bool canDrain() { return drainList.empty() && transmitList.empty(); }
|
|
||||||
|
|
||||||
bool drainResponse();
|
|
||||||
|
|
||||||
CachePort *otherPort;
|
CachePort *otherPort;
|
||||||
|
|
||||||
bool blocked;
|
bool blocked;
|
||||||
|
|
||||||
bool mustSendRetry;
|
|
||||||
|
|
||||||
bool waitingOnRetry;
|
bool waitingOnRetry;
|
||||||
|
|
||||||
|
bool mustSendRetry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit vector for the outstanding requests for the master interface.
|
* Bit vector for the outstanding requests for the master interface.
|
||||||
*/
|
*/
|
||||||
uint8_t requestCauses;
|
uint8_t requestCauses;
|
||||||
|
|
||||||
std::list<PacketPtr> drainList;
|
|
||||||
|
|
||||||
std::list<std::pair<Tick,PacketPtr> > transmitList;
|
|
||||||
|
|
||||||
bool isBusRequested() { return requestCauses != 0; }
|
bool isBusRequested() { return requestCauses != 0; }
|
||||||
|
|
||||||
// These need to be virtual since the Event objects depend on
|
|
||||||
// cache template parameters.
|
|
||||||
virtual void scheduleRequestEvent(Tick t) = 0;
|
|
||||||
|
|
||||||
void requestBus(RequestCause cause, Tick time)
|
void requestBus(RequestCause cause, Tick time)
|
||||||
{
|
{
|
||||||
|
DPRINTF(Cache, "Asserting bus request for cause %d\n", cause);
|
||||||
if (!isBusRequested() && !waitingOnRetry) {
|
if (!isBusRequested() && !waitingOnRetry) {
|
||||||
scheduleRequestEvent(time);
|
assert(!sendEvent->scheduled());
|
||||||
|
sendEvent->schedule(time);
|
||||||
}
|
}
|
||||||
requestCauses |= (1 << cause);
|
requestCauses |= (1 << cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deassertBusRequest(RequestCause cause)
|
void deassertBusRequest(RequestCause cause)
|
||||||
{
|
{
|
||||||
|
DPRINTF(Cache, "Deasserting bus request for cause %d\n", cause);
|
||||||
requestCauses &= ~(1 << cause);
|
requestCauses &= ~(1 << cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
void respond(PacketPtr pkt, Tick time);
|
void respond(PacketPtr pkt, Tick time) {
|
||||||
|
schedSendTiming(pkt, time);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public: //Made public so coherence can get at it.
|
public: //Made public so coherence can get at it.
|
||||||
CachePort *cpuSidePort;
|
CachePort *cpuSidePort;
|
||||||
CachePort *memSidePort;
|
CachePort *memSidePort;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
|
/** Miss status registers */
|
||||||
|
MSHRQueue mshrQueue;
|
||||||
|
|
||||||
|
/** Write/writeback buffer */
|
||||||
|
MSHRQueue writeBuffer;
|
||||||
|
|
||||||
|
/** Block size of this cache */
|
||||||
|
const int blkSize;
|
||||||
|
|
||||||
|
/** The number of targets for each MSHR. */
|
||||||
|
const int numTarget;
|
||||||
|
|
||||||
|
/** Increasing order number assigned to each incoming request. */
|
||||||
|
uint64_t order;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit vector of the blocking reasons for the access path.
|
* Bit vector of the blocking reasons for the access path.
|
||||||
* @sa #BlockedCause
|
* @sa #BlockedCause
|
||||||
*/
|
*/
|
||||||
uint8_t blocked;
|
uint8_t blocked;
|
||||||
|
|
||||||
/**
|
|
||||||
* Bit vector for the blocking reasons for the snoop path.
|
|
||||||
* @sa #BlockedCause
|
|
||||||
*/
|
|
||||||
uint8_t blockedSnoop;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/** Stores time the cache blocked for statistics. */
|
/** Stores time the cache blocked for statistics. */
|
||||||
Tick blockedCycle;
|
Tick blockedCycle;
|
||||||
|
|
||||||
/** Block size of this cache */
|
/** Pointer to the MSHR that has no targets. */
|
||||||
const int blkSize;
|
MSHR *noTargetMSHR;
|
||||||
|
|
||||||
/** The number of misses to trigger an exit event. */
|
/** The number of misses to trigger an exit event. */
|
||||||
Counter missCount;
|
Counter missCount;
|
||||||
|
@ -246,6 +247,73 @@ class BaseCache : public MemObject
|
||||||
/** The number of cache copies performed. */
|
/** The number of cache copies performed. */
|
||||||
Stats::Scalar<> cacheCopies;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -260,12 +328,13 @@ class BaseCache : public MemObject
|
||||||
class Params
|
class Params
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** List of address ranges of this cache. */
|
|
||||||
std::vector<Range<Addr> > addrRange;
|
|
||||||
/** The hit latency for this cache. */
|
/** The hit latency for this cache. */
|
||||||
int hitLatency;
|
int hitLatency;
|
||||||
/** The block size of this cache. */
|
/** The block size of this cache. */
|
||||||
int blkSize;
|
int blkSize;
|
||||||
|
int numMSHRs;
|
||||||
|
int numTargets;
|
||||||
|
int numWriteBuffers;
|
||||||
/**
|
/**
|
||||||
* The maximum number of misses this cache should handle before
|
* The maximum number of misses this cache should handle before
|
||||||
* ending the simulation.
|
* ending the simulation.
|
||||||
|
@ -275,10 +344,12 @@ class BaseCache : public MemObject
|
||||||
/**
|
/**
|
||||||
* Construct an instance of this parameter class.
|
* Construct an instance of this parameter class.
|
||||||
*/
|
*/
|
||||||
Params(std::vector<Range<Addr> > addr_range,
|
Params(int _hitLatency, int _blkSize,
|
||||||
int hit_latency, int _blkSize, Counter max_misses)
|
int _numMSHRs, int _numTargets, int _numWriteBuffers,
|
||||||
: addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
|
Counter _maxMisses)
|
||||||
maxMisses(max_misses)
|
: hitLatency(_hitLatency), blkSize(_blkSize),
|
||||||
|
numMSHRs(_numMSHRs), numTargets(_numTargets),
|
||||||
|
numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -307,6 +378,10 @@ class BaseCache : public MemObject
|
||||||
return blkSize;
|
return blkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Addr blockAlign(Addr addr) const { return (addr & ~(blkSize - 1)); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the cache is blocked for accesses.
|
* Returns true if the cache is blocked for accesses.
|
||||||
*/
|
*/
|
||||||
|
@ -315,14 +390,6 @@ class BaseCache : public MemObject
|
||||||
return blocked != 0;
|
return blocked != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the cache is blocked for snoops.
|
|
||||||
*/
|
|
||||||
bool isBlockedForSnoop()
|
|
||||||
{
|
|
||||||
return blockedSnoop != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the access path of the cache as blocked for the given cause. This
|
* Marks the access path of the cache as blocked for the given cause. This
|
||||||
* also sets the blocked flag in the slave interface.
|
* also sets the blocked flag in the slave interface.
|
||||||
|
@ -345,23 +412,6 @@ class BaseCache : public MemObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the cache as unblocked for the given cause. This also clears the
|
* Marks the cache as unblocked for the given cause. This also clears the
|
||||||
* blocked flags in the appropriate interfaces.
|
* blocked flags in the appropriate interfaces.
|
||||||
|
@ -383,13 +433,6 @@ class BaseCache : public MemObject
|
||||||
cpuSidePort->clearBlocked();
|
cpuSidePort->clearBlocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blockedSnoop & flag)
|
|
||||||
{
|
|
||||||
blockedSnoop &= ~flag;
|
|
||||||
if (!isBlockedForSnoop()) {
|
|
||||||
memSidePort->clearBlocked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -418,55 +461,26 @@ class BaseCache : public MemObject
|
||||||
void deassertMemSideBusRequest(RequestCause cause)
|
void deassertMemSideBusRequest(RequestCause cause)
|
||||||
{
|
{
|
||||||
memSidePort->deassertBusRequest(cause);
|
memSidePort->deassertBusRequest(cause);
|
||||||
checkDrain();
|
// 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)
|
|
||||||
{
|
|
||||||
cpuSidePort->respond(pkt, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suppliess the data if cache to cache transfers are enabled.
|
|
||||||
* @param pkt The bus transaction to fulfill.
|
|
||||||
*/
|
|
||||||
void respondToSnoop(PacketPtr pkt, Tick time)
|
|
||||||
{
|
|
||||||
memSidePort->respond(pkt, time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned int drain(Event *de);
|
virtual unsigned int drain(Event *de);
|
||||||
|
|
||||||
void checkDrain()
|
|
||||||
{
|
|
||||||
if (drainEvent && canDrain()) {
|
|
||||||
drainEvent->process();
|
|
||||||
changeState(SimObject::Drained);
|
|
||||||
// Clear the drain event
|
|
||||||
drainEvent = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canDrain()
|
|
||||||
{
|
|
||||||
if (isMemSideBusRequested()) {
|
|
||||||
return false;
|
|
||||||
} else if (memSidePort && !memSidePort->canDrain()) {
|
|
||||||
return false;
|
|
||||||
} else if (cpuSidePort && !cpuSidePort->canDrain()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool inCache(Addr addr) = 0;
|
virtual bool inCache(Addr addr) = 0;
|
||||||
|
|
||||||
virtual bool inMissQueue(Addr addr) = 0;
|
virtual bool inMissQueue(Addr addr) = 0;
|
||||||
|
|
||||||
|
void incMissCount(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
||||||
|
|
||||||
|
if (missCount) {
|
||||||
|
--missCount;
|
||||||
|
if (missCount == 0)
|
||||||
|
exitSimLoop("A cache reached the maximum miss count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__BASE_CACHE_HH__
|
#endif //__BASE_CACHE_HH__
|
||||||
|
|
3
src/mem/cache/cache.cc
vendored
3
src/mem/cache/cache.cc
vendored
|
@ -58,9 +58,6 @@
|
||||||
#include "mem/cache/tags/split_lifo.hh"
|
#include "mem/cache/tags/split_lifo.hh"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mem/cache/miss/miss_queue.hh"
|
|
||||||
#include "mem/cache/miss/blocking_buffer.hh"
|
|
||||||
|
|
||||||
#include "mem/cache/coherence/simple_coherence.hh"
|
#include "mem/cache/coherence/simple_coherence.hh"
|
||||||
|
|
||||||
#include "mem/cache/cache_impl.hh"
|
#include "mem/cache/cache_impl.hh"
|
||||||
|
|
281
src/mem/cache/cache.hh
vendored
281
src/mem/cache/cache.hh
vendored
|
@ -45,12 +45,11 @@
|
||||||
|
|
||||||
#include "mem/cache/base_cache.hh"
|
#include "mem/cache/base_cache.hh"
|
||||||
#include "mem/cache/cache_blk.hh"
|
#include "mem/cache/cache_blk.hh"
|
||||||
#include "mem/cache/miss/miss_buffer.hh"
|
#include "mem/cache/miss/mshr.hh"
|
||||||
|
|
||||||
#include "sim/eventq.hh"
|
#include "sim/eventq.hh"
|
||||||
|
|
||||||
//Forward decleration
|
//Forward decleration
|
||||||
class MSHR;
|
|
||||||
class BasePrefetcher;
|
class BasePrefetcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,29 +85,14 @@ class Cache : public BaseCache
|
||||||
return static_cast<Cache<TagStore,Coherence> *>(cache);
|
return static_cast<Cache<TagStore,Coherence> *>(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processRequestEvent();
|
|
||||||
void processResponseEvent();
|
|
||||||
|
|
||||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
||||||
bool &snoop);
|
bool &snoop);
|
||||||
|
|
||||||
virtual bool recvTiming(PacketPtr pkt);
|
virtual bool recvTiming(PacketPtr pkt);
|
||||||
|
|
||||||
virtual void recvRetry();
|
|
||||||
|
|
||||||
virtual Tick recvAtomic(PacketPtr pkt);
|
virtual Tick recvAtomic(PacketPtr pkt);
|
||||||
|
|
||||||
virtual void recvFunctional(PacketPtr pkt);
|
virtual void recvFunctional(PacketPtr pkt);
|
||||||
|
|
||||||
typedef EventWrapper<CpuSidePort, &CpuSidePort::processResponseEvent>
|
|
||||||
ResponseEvent;
|
|
||||||
|
|
||||||
typedef EventWrapper<CpuSidePort, &CpuSidePort::processRequestEvent>
|
|
||||||
RequestEvent;
|
|
||||||
|
|
||||||
virtual void scheduleRequestEvent(Tick t) {
|
|
||||||
new RequestEvent(this, t);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MemSidePort : public CachePort
|
class MemSidePort : public CachePort
|
||||||
|
@ -124,8 +108,9 @@ class Cache : public BaseCache
|
||||||
return static_cast<Cache<TagStore,Coherence> *>(cache);
|
return static_cast<Cache<TagStore,Coherence> *>(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processRequestEvent();
|
void sendPacket();
|
||||||
void processResponseEvent();
|
|
||||||
|
void processSendEvent();
|
||||||
|
|
||||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
||||||
bool &snoop);
|
bool &snoop);
|
||||||
|
@ -138,21 +123,13 @@ class Cache : public BaseCache
|
||||||
|
|
||||||
virtual void recvFunctional(PacketPtr pkt);
|
virtual void recvFunctional(PacketPtr pkt);
|
||||||
|
|
||||||
typedef EventWrapper<MemSidePort, &MemSidePort::processResponseEvent>
|
typedef EventWrapper<MemSidePort, &MemSidePort::processSendEvent>
|
||||||
ResponseEvent;
|
SendEvent;
|
||||||
|
|
||||||
typedef EventWrapper<MemSidePort, &MemSidePort::processRequestEvent>
|
|
||||||
RequestEvent;
|
|
||||||
|
|
||||||
virtual void scheduleRequestEvent(Tick t) {
|
|
||||||
new RequestEvent(this, t);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Tag and data Storage */
|
/** Tag and data Storage */
|
||||||
TagStore *tags;
|
TagStore *tags;
|
||||||
/** Miss and Writeback handler */
|
|
||||||
MissBuffer *missQueue;
|
|
||||||
/** Coherence protocol. */
|
/** Coherence protocol. */
|
||||||
Coherence *coherence;
|
Coherence *coherence;
|
||||||
|
|
||||||
|
@ -176,23 +153,6 @@ class Cache : public BaseCache
|
||||||
*/
|
*/
|
||||||
int hitLatency;
|
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.
|
* Can this cache should allocate a block on a line-sized write miss.
|
||||||
*/
|
*/
|
||||||
|
@ -200,50 +160,6 @@ class Cache : public BaseCache
|
||||||
|
|
||||||
const bool prefetchMiss;
|
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.
|
* Handle a replacement for the given request.
|
||||||
* @param blk A pointer to the block, usually NULL
|
* @param blk A pointer to the block, usually NULL
|
||||||
|
@ -251,7 +167,7 @@ class Cache : public BaseCache
|
||||||
* @param new_state The new state of the block.
|
* @param new_state The new state of the block.
|
||||||
* @param writebacks A list to store any generated writebacks.
|
* @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);
|
CacheBlk::State new_state, PacketList &writebacks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,59 +179,38 @@ class Cache : public BaseCache
|
||||||
* @return Pointer to the cache block touched by the request. NULL if it
|
* @return Pointer to the cache block touched by the request. NULL if it
|
||||||
* was a miss.
|
* was a miss.
|
||||||
*/
|
*/
|
||||||
BlkType* handleAccess(PacketPtr &pkt, int & lat,
|
bool access(PacketPtr pkt, BlkType *blk, int & lat);
|
||||||
PacketList & writebacks, bool update = true);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Handle doing the Compare and Swap function for SPARC.
|
*Handle doing the Compare and Swap function for SPARC.
|
||||||
*/
|
*/
|
||||||
void cmpAndSwap(BlkType *blk, 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 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates a cache block and handles all outstanding requests for the
|
* Populates a cache block and handles all outstanding requests for the
|
||||||
* satisfied fill request. This version takes two memory requests. One
|
* satisfied fill request. This version takes two memory requests. One
|
||||||
* contains the fill data, the other is an optional target to satisfy.
|
* contains the fill data, the other is an optional target to satisfy.
|
||||||
* Used for Cache::probe.
|
* Used for Cache::probe.
|
||||||
* @param blk The cache block if it already exists.
|
|
||||||
* @param pkt The memory request with the fill data.
|
* @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 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.
|
* @return Pointer to the new cache block.
|
||||||
*/
|
*/
|
||||||
BlkType* handleFill(BlkType *blk, PacketPtr &pkt,
|
BlkType *handleFill(PacketPtr pkt, BlkType *blk,
|
||||||
CacheBlk::State new_state,
|
PacketList &writebacks);
|
||||||
PacketList & writebacks, PacketPtr target = NULL);
|
|
||||||
|
|
||||||
/**
|
bool satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk);
|
||||||
* Sets the blk to the new state and handles the given request.
|
bool satisfyTarget(MSHR::Target *target, BlkType *blk);
|
||||||
* @param blk The cache block being snooped.
|
void satisfyMSHR(MSHR *mshr, PacketPtr pkt, BlkType *blk);
|
||||||
* @param new_state The new coherence state for the block.
|
|
||||||
* @param pkt The request to satisfy
|
void doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data);
|
||||||
*/
|
|
||||||
void handleSnoop(BlkType *blk, CacheBlk::State new_state,
|
|
||||||
PacketPtr &pkt);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the blk to the new state.
|
* Sets the blk to the new state.
|
||||||
* @param blk The cache block being snooped.
|
* @param blk The cache block being snooped.
|
||||||
* @param new_state The new coherence state for the block.
|
* @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.
|
* Create a writeback request for the given block.
|
||||||
|
@ -330,44 +225,24 @@ class Cache : public BaseCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TagStore *tags;
|
TagStore *tags;
|
||||||
MissBuffer *missQueue;
|
|
||||||
Coherence *coherence;
|
Coherence *coherence;
|
||||||
BaseCache::Params baseParams;
|
BaseCache::Params baseParams;
|
||||||
BasePrefetcher*prefetcher;
|
BasePrefetcher*prefetcher;
|
||||||
bool prefetchAccess;
|
bool prefetchAccess;
|
||||||
int hitLatency;
|
|
||||||
CompressionAlgorithm *compressionAlg;
|
|
||||||
const int16_t blkSize;
|
|
||||||
const bool doFastWrites;
|
const bool doFastWrites;
|
||||||
const bool prefetchMiss;
|
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,
|
BaseCache::Params params,
|
||||||
BasePrefetcher *_prefetcher,
|
BasePrefetcher *_prefetcher,
|
||||||
bool prefetch_access, int hit_latency,
|
bool prefetch_access, int hit_latency,
|
||||||
bool do_fast_writes,
|
bool do_fast_writes,
|
||||||
bool store_compressed, bool adaptive_compression,
|
|
||||||
bool writeback_compressed,
|
|
||||||
CompressionAlgorithm *_compressionAlg, int comp_latency,
|
|
||||||
bool prefetch_miss)
|
bool prefetch_miss)
|
||||||
: tags(_tags), missQueue(mq), coherence(coh),
|
: tags(_tags), coherence(coh),
|
||||||
baseParams(params),
|
baseParams(params),
|
||||||
prefetcher(_prefetcher), prefetchAccess(prefetch_access),
|
prefetcher(_prefetcher), prefetchAccess(prefetch_access),
|
||||||
hitLatency(hit_latency),
|
|
||||||
compressionAlg(_compressionAlg),
|
|
||||||
blkSize(_tags->getBlockSize()),
|
|
||||||
doFastWrites(do_fast_writes),
|
doFastWrites(do_fast_writes),
|
||||||
prefetchMiss(prefetch_miss),
|
prefetchMiss(prefetch_miss)
|
||||||
storeCompressed(store_compressed),
|
|
||||||
compressOnWriteback(!store_compressed && writeback_compressed),
|
|
||||||
compLatency(comp_latency),
|
|
||||||
adaptiveCompression(adaptive_compression),
|
|
||||||
writebackCompressed(writeback_compressed)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -385,85 +260,105 @@ class Cache : public BaseCache
|
||||||
* @param pkt The request to perform.
|
* @param pkt The request to perform.
|
||||||
* @return The result of the access.
|
* @return The result of the access.
|
||||||
*/
|
*/
|
||||||
bool access(PacketPtr &pkt);
|
bool timingAccess(PacketPtr pkt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects a request to send on the bus.
|
* Performs the access specified by the request.
|
||||||
* @return The memory request to service.
|
* @param pkt The request to perform.
|
||||||
|
* @return The result of the access.
|
||||||
*/
|
*/
|
||||||
PacketPtr getPacket();
|
Tick atomicAccess(PacketPtr pkt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Was the request was sent successfully?
|
* Performs the access specified by the request.
|
||||||
* @param pkt The request.
|
* @param pkt The request to perform.
|
||||||
* @param success True if the request was sent successfully.
|
* @return The result of the access.
|
||||||
*/
|
*/
|
||||||
void sendResult(PacketPtr &pkt, MSHR* mshr, bool success);
|
void functionalAccess(PacketPtr pkt, CachePort *otherSidePort);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a response (cache line fill/write ack) from the bus.
|
* Handles a response (cache line fill/write ack) from the bus.
|
||||||
* @param pkt The request being responded to.
|
* @param pkt The request being responded to.
|
||||||
*/
|
*/
|
||||||
void handleResponse(PacketPtr &pkt);
|
void handleResponse(PacketPtr pkt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snoops bus transactions to maintain coherence.
|
* Snoops bus transactions to maintain coherence.
|
||||||
* @param pkt The current bus transaction.
|
* @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.
|
* Squash all requests associated with specified thread.
|
||||||
* intended for use by I-cache.
|
* intended for use by I-cache.
|
||||||
* @param threadNum The thread to squash.
|
* @param threadNum The thread to squash.
|
||||||
*/
|
*/
|
||||||
void squash(int threadNum)
|
void squash(int threadNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new MSHR or write buffer to handle a miss.
|
||||||
|
* @param pkt The access that missed.
|
||||||
|
* @param time The time to continue processing the miss.
|
||||||
|
* @param isFill Whether to fetch & allocate a block
|
||||||
|
* or just forward the request.
|
||||||
|
*/
|
||||||
|
MSHR *allocateBuffer(PacketPtr pkt, Tick time, bool isFill,
|
||||||
|
bool requestBus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects a outstanding request to service.
|
||||||
|
* @return The request to service, NULL if none found.
|
||||||
|
*/
|
||||||
|
MSHR *getNextMSHR();
|
||||||
|
PacketPtr getPacket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the given writeback request.
|
||||||
|
* @param pkt The writeback request.
|
||||||
|
*/
|
||||||
|
void doWriteback(PacketPtr pkt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether there are any outstanding misses.
|
||||||
|
*/
|
||||||
|
bool outstandingMisses() const
|
||||||
{
|
{
|
||||||
missQueue->squash(threadNum);
|
return mshrQueue.allocated != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
CacheBlk *findBlock(Addr addr) {
|
||||||
* Return the number of outstanding misses in a Cache.
|
return tags->findBlock(addr);
|
||||||
* Default returns 0.
|
|
||||||
*
|
|
||||||
* @retval unsigned The number of missing still outstanding.
|
|
||||||
*/
|
|
||||||
unsigned outstandingMisses() const
|
|
||||||
{
|
|
||||||
return missQueue->getMisses();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
Tick probe(PacketPtr &pkt, bool update, CachePort * otherSidePort);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
Tick snoopProbe(PacketPtr &pkt);
|
|
||||||
|
|
||||||
bool inCache(Addr addr) {
|
bool inCache(Addr addr) {
|
||||||
return (tags->findBlock(addr) != 0);
|
return (tags->findBlock(addr) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inMissQueue(Addr addr) {
|
bool inMissQueue(Addr addr) {
|
||||||
return (missQueue->findMSHR(addr) != 0);
|
return (mshrQueue.findMatch(addr) != 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
25
src/mem/cache/cache_blk.hh
vendored
25
src/mem/cache/cache_blk.hh
vendored
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "sim/core.hh" // for Tick
|
#include "sim/core.hh" // for Tick
|
||||||
#include "arch/isa_traits.hh" // for Addr
|
#include "arch/isa_traits.hh" // for Addr
|
||||||
|
#include "mem/packet.hh"
|
||||||
#include "mem/request.hh"
|
#include "mem/request.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,8 +52,6 @@ enum CacheBlkStatusBits {
|
||||||
BlkWritable = 0x02,
|
BlkWritable = 0x02,
|
||||||
/** dirty (modified) */
|
/** dirty (modified) */
|
||||||
BlkDirty = 0x04,
|
BlkDirty = 0x04,
|
||||||
/** compressed */
|
|
||||||
BlkCompressed = 0x08,
|
|
||||||
/** block was referenced */
|
/** block was referenced */
|
||||||
BlkReferenced = 0x10,
|
BlkReferenced = 0x10,
|
||||||
/** block was a hardware prefetch yet unaccessed*/
|
/** block was a hardware prefetch yet unaccessed*/
|
||||||
|
@ -174,20 +173,11 @@ class CacheBlk
|
||||||
* Check to see if a block has been written.
|
* Check to see if a block has been written.
|
||||||
* @return True if the block is dirty.
|
* @return True if the block is dirty.
|
||||||
*/
|
*/
|
||||||
bool isModified() const
|
bool isDirty() const
|
||||||
{
|
{
|
||||||
return (status & BlkDirty) != 0;
|
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.
|
* Check if this block has been referenced.
|
||||||
* @return True if the 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
|
* redundant records on the list, but that's OK, as they'll all
|
||||||
* get blown away at the next store.
|
* get blown away at the next store.
|
||||||
*/
|
*/
|
||||||
void trackLoadLocked(Request *req)
|
void trackLoadLocked(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
assert(req->isLocked());
|
assert(pkt->isLocked());
|
||||||
lockList.push_front(Lock(req));
|
lockList.push_front(Lock(pkt->req));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,9 +220,10 @@ class CacheBlk
|
||||||
* @return True if write should proceed, false otherwise. Returns
|
* @return True if write should proceed, false otherwise. Returns
|
||||||
* false only in the case of a failed store conditional.
|
* 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
|
// it's a store conditional... have to check for matching
|
||||||
// load locked.
|
// load locked.
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
27
src/mem/cache/cache_builder.cc
vendored
27
src/mem/cache/cache_builder.cc
vendored
|
@ -70,10 +70,6 @@
|
||||||
#include "base/compression/null_compression.hh"
|
#include "base/compression/null_compression.hh"
|
||||||
#include "base/compression/lzss_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
|
// Coherence Templates
|
||||||
#include "mem/cache/coherence/simple_coherence.hh"
|
#include "mem/cache/coherence/simple_coherence.hh"
|
||||||
|
|
||||||
|
@ -207,13 +203,9 @@ END_INIT_SIM_OBJECT_PARAMS(BaseCache)
|
||||||
else { \
|
else { \
|
||||||
BUILD_NULL_PREFETCHER(TAGS); \
|
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, \
|
pf, prefetch_access, latency, \
|
||||||
true, \
|
true, \
|
||||||
store_compressed, \
|
|
||||||
adaptive_compression, \
|
|
||||||
compressed_bus, \
|
|
||||||
compAlg, compression_latency, \
|
|
||||||
prefetch_miss); \
|
prefetch_miss); \
|
||||||
Cache<TAGS, c> *retval = \
|
Cache<TAGS, c> *retval = \
|
||||||
new Cache<TAGS, c>(getInstanceName(), params); \
|
new Cache<TAGS, c>(getInstanceName(), params); \
|
||||||
|
@ -301,8 +293,6 @@ END_INIT_SIM_OBJECT_PARAMS(BaseCache)
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define BUILD_COHERENCE(b) do { \
|
#define BUILD_COHERENCE(b) do { \
|
||||||
SimpleCoherence *coh = new SimpleCoherence(protocol); \
|
|
||||||
BUILD_CACHES(SimpleCoherence); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#if defined(USE_TAGGED)
|
#if defined(USE_TAGGED)
|
||||||
|
@ -369,8 +359,9 @@ CREATE_SIM_OBJECT(BaseCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build BaseCache param object
|
// Build BaseCache param object
|
||||||
BaseCache::Params base_params(addr_range, latency,
|
BaseCache::Params base_params(latency, block_size,
|
||||||
block_size, max_miss_count);
|
mshrs, tgts_per_mshr, write_buffers,
|
||||||
|
max_miss_count);
|
||||||
|
|
||||||
//Warnings about prefetcher policy
|
//Warnings about prefetcher policy
|
||||||
if (pf_policy == "none" && (prefetch_miss || prefetch_access)) {
|
if (pf_policy == "none" && (prefetch_miss || prefetch_access)) {
|
||||||
|
@ -408,14 +399,8 @@ CREATE_SIM_OBJECT(BaseCache)
|
||||||
const void *repl = NULL;
|
const void *repl = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mshrs == 1 /*|| out_bus->doEvents() == false*/) {
|
SimpleCoherence *coh = new SimpleCoherence(protocol);
|
||||||
BlockingBuffer *mq = new BlockingBuffer(true);
|
BUILD_CACHES(SimpleCoherence);
|
||||||
BUILD_COHERENCE(BlockingBuffer);
|
|
||||||
} else {
|
|
||||||
MissQueue *mq = new MissQueue(mshrs, tgts_per_mshr, write_buffers,
|
|
||||||
true, prefetch_miss);
|
|
||||||
BUILD_COHERENCE(MissQueue);
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2390
src/mem/cache/cache_impl.hh
vendored
2390
src/mem/cache/cache_impl.hh
vendored
File diff suppressed because it is too large
Load diff
40
src/mem/cache/coherence/coherence_protocol.cc
vendored
40
src/mem/cache/coherence/coherence_protocol.cc
vendored
|
@ -139,31 +139,6 @@ CoherenceProtocol::regStats()
|
||||||
.desc("readEx snoops on exclusive blocks")
|
.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]
|
snoopCount[Shared][MemCmd::WriteInvalidateReq]
|
||||||
.name(name() + ".snoop_writeinv_shared")
|
.name(name() + ".snoop_writeinv_shared")
|
||||||
.desc("WriteInvalidate snoops on shared blocks")
|
.desc("WriteInvalidate snoops on shared blocks")
|
||||||
|
@ -219,7 +194,7 @@ CoherenceProtocol::supplyAndGotoSharedTrans(BaseCache *cache, PacketPtr &pkt,
|
||||||
CacheBlk::State & new_state)
|
CacheBlk::State & new_state)
|
||||||
{
|
{
|
||||||
new_state = (blk->status & ~stateMask) | Shared;
|
new_state = (blk->status & ~stateMask) | Shared;
|
||||||
pkt->flags |= SHARED_LINE;
|
pkt->assertShared();
|
||||||
return supplyTrans(cache, pkt, blk, mshr, new_state);
|
return supplyTrans(cache, pkt, blk, mshr, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +206,7 @@ CoherenceProtocol::supplyAndGotoOwnedTrans(BaseCache *cache, PacketPtr &pkt,
|
||||||
CacheBlk::State & new_state)
|
CacheBlk::State & new_state)
|
||||||
{
|
{
|
||||||
new_state = (blk->status & ~stateMask) | Owned;
|
new_state = (blk->status & ~stateMask) | Owned;
|
||||||
pkt->flags |= SHARED_LINE;
|
pkt->assertShared();
|
||||||
return supplyTrans(cache, pkt, blk, mshr, new_state);
|
return supplyTrans(cache, pkt, blk, mshr, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +228,7 @@ CoherenceProtocol::assertShared(BaseCache *cache, PacketPtr &pkt,
|
||||||
CacheBlk::State & new_state)
|
CacheBlk::State & new_state)
|
||||||
{
|
{
|
||||||
new_state = (blk->status & ~stateMask) | Shared;
|
new_state = (blk->status & ~stateMask) | Shared;
|
||||||
pkt->flags |= SHARED_LINE;
|
pkt->assertShared();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,12 +311,10 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
|
||||||
//
|
//
|
||||||
tt[Invalid][MC::ReadReq].onSnoop(nullTransition);
|
tt[Invalid][MC::ReadReq].onSnoop(nullTransition);
|
||||||
tt[Invalid][MC::ReadExReq].onSnoop(nullTransition);
|
tt[Invalid][MC::ReadExReq].onSnoop(nullTransition);
|
||||||
tt[Invalid][MC::InvalidateReq].onSnoop(invalidateTrans);
|
|
||||||
tt[Invalid][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
tt[Invalid][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
||||||
tt[Shared][MC::ReadReq].onSnoop(hasExclusive
|
tt[Shared][MC::ReadReq].onSnoop(hasExclusive
|
||||||
? assertShared : nullTransition);
|
? assertShared : nullTransition);
|
||||||
tt[Shared][MC::ReadExReq].onSnoop(invalidateTrans);
|
tt[Shared][MC::ReadExReq].onSnoop(invalidateTrans);
|
||||||
tt[Shared][MC::InvalidateReq].onSnoop(invalidateTrans);
|
|
||||||
tt[Shared][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
tt[Shared][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
||||||
if (doUpgrades) {
|
if (doUpgrades) {
|
||||||
tt[Invalid][MC::UpgradeReq].onSnoop(nullTransition);
|
tt[Invalid][MC::UpgradeReq].onSnoop(nullTransition);
|
||||||
|
@ -351,13 +324,11 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
|
||||||
tt[Modified][MC::ReadReq].onSnoop(hasOwned
|
tt[Modified][MC::ReadReq].onSnoop(hasOwned
|
||||||
? supplyAndGotoOwnedTrans
|
? supplyAndGotoOwnedTrans
|
||||||
: supplyAndGotoSharedTrans);
|
: supplyAndGotoSharedTrans);
|
||||||
tt[Modified][MC::InvalidateReq].onSnoop(invalidateTrans);
|
|
||||||
tt[Modified][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
tt[Modified][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
||||||
|
|
||||||
if (hasExclusive) {
|
if (hasExclusive) {
|
||||||
tt[Exclusive][MC::ReadReq].onSnoop(assertShared);
|
tt[Exclusive][MC::ReadReq].onSnoop(assertShared);
|
||||||
tt[Exclusive][MC::ReadExReq].onSnoop(invalidateTrans);
|
tt[Exclusive][MC::ReadExReq].onSnoop(invalidateTrans);
|
||||||
tt[Exclusive][MC::InvalidateReq].onSnoop(invalidateTrans);
|
|
||||||
tt[Exclusive][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
tt[Exclusive][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +336,6 @@ CoherenceProtocol::CoherenceProtocol(const string &name,
|
||||||
tt[Owned][MC::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
|
tt[Owned][MC::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
|
||||||
tt[Owned][MC::ReadExReq].onSnoop(supplyAndInvalidateTrans);
|
tt[Owned][MC::ReadExReq].onSnoop(supplyAndInvalidateTrans);
|
||||||
tt[Owned][MC::UpgradeReq].onSnoop(invalidateTrans);
|
tt[Owned][MC::UpgradeReq].onSnoop(invalidateTrans);
|
||||||
tt[Owned][MC::InvalidateReq].onSnoop(invalidateTrans);
|
|
||||||
tt[Owned][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
tt[Owned][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +364,7 @@ CoherenceProtocol::getBusCmd(MemCmd cmdIn, CacheBlk::State state,
|
||||||
|
|
||||||
|
|
||||||
CacheBlk::State
|
CacheBlk::State
|
||||||
CoherenceProtocol::getNewState(PacketPtr &pkt, CacheBlk::State oldState)
|
CoherenceProtocol::getNewState(PacketPtr pkt, CacheBlk::State oldState)
|
||||||
{
|
{
|
||||||
CacheBlk::State state = oldState & stateMask;
|
CacheBlk::State state = oldState & stateMask;
|
||||||
int cmd_idx = pkt->cmdToIndex();
|
int cmd_idx = pkt->cmdToIndex();
|
||||||
|
@ -406,7 +376,7 @@ CoherenceProtocol::getNewState(PacketPtr &pkt, CacheBlk::State oldState)
|
||||||
|
|
||||||
//Check if it's exclusive and the shared line was asserted,
|
//Check if it's exclusive and the shared line was asserted,
|
||||||
//then goto shared instead
|
//then goto shared instead
|
||||||
if (newState == Exclusive && (pkt->flags & SHARED_LINE)) {
|
if (newState == Exclusive && pkt->sharedAsserted()) {
|
||||||
newState = Shared;
|
newState = Shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,8 @@ class CoherenceProtocol : public SimObject
|
||||||
* @param oldState The current block state.
|
* @param oldState The current block state.
|
||||||
* @return The new state.
|
* @return The new state.
|
||||||
*/
|
*/
|
||||||
CacheBlk::State getNewState(PacketPtr &pkt,
|
CacheBlk::State getNewState(PacketPtr pkt,
|
||||||
CacheBlk::State oldState);
|
CacheBlk::State oldState = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle snooped bus requests.
|
* Handle snooped bus requests.
|
||||||
|
|
15
src/mem/cache/coherence/simple_coherence.hh
vendored
15
src/mem/cache/coherence/simple_coherence.hh
vendored
|
@ -94,25 +94,14 @@ class SimpleCoherence
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Return the proper state given the current state and the bus response.
|
||||||
* @param pkt The bus response.
|
* @param pkt The bus response.
|
||||||
* @param current The current block state.
|
* @param current The current block state.
|
||||||
* @return The new 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);
|
return protocol->getNewState(pkt, current);
|
||||||
}
|
}
|
||||||
|
|
3
src/mem/cache/miss/SConscript
vendored
3
src/mem/cache/miss/SConscript
vendored
|
@ -30,8 +30,5 @@
|
||||||
|
|
||||||
Import('*')
|
Import('*')
|
||||||
|
|
||||||
Source('blocking_buffer.cc')
|
|
||||||
Source('miss_buffer.cc')
|
|
||||||
Source('miss_queue.cc')
|
|
||||||
Source('mshr.cc')
|
Source('mshr.cc')
|
||||||
Source('mshr_queue.cc')
|
Source('mshr_queue.cc')
|
||||||
|
|
245
src/mem/cache/miss/blocking_buffer.cc
vendored
245
src/mem/cache/miss/blocking_buffer.cc
vendored
|
@ -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->requestMemSideBus(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->requestMemSideBus(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->deassertMemSideBusRequest(Request_WB);
|
|
||||||
if (!pkt->needsResponse()) {
|
|
||||||
assert(wb.getNumTargets() == 0);
|
|
||||||
wb.deallocate();
|
|
||||||
cache->clearBlocked(Blocked_NoWBBuffers);
|
|
||||||
} else {
|
|
||||||
wb.inService = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(mshr == &miss);
|
|
||||||
cache->deassertMemSideBusRequest(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->deassertMemSideBusRequest(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->requestMemSideBus(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->requestMemSideBus(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;
|
|
||||||
}
|
|
209
src/mem/cache/miss/blocking_buffer.hh
vendored
209
src/mem/cache/miss/blocking_buffer.hh
vendored
|
@ -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__
|
|
62
src/mem/cache/miss/miss_buffer.cc
vendored
62
src/mem/cache/miss/miss_buffer.cc
vendored
|
@ -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;
|
|
||||||
}
|
|
223
src/mem/cache/miss/miss_buffer.hh
vendored
223
src/mem/cache/miss/miss_buffer.hh
vendored
|
@ -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__
|
|
752
src/mem/cache/miss/miss_queue.cc
vendored
752
src/mem/cache/miss/miss_queue.cc
vendored
|
@ -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->requestMemSideBus(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->requestMemSideBus(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->requestMemSideBus(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->deassertMemSideBusRequest(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->deassertMemSideBusRequest(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->deassertMemSideBusRequest(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->requestMemSideBus(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->deassertMemSideBusRequest(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();
|
|
||||||
}
|
|
327
src/mem/cache/miss/miss_queue.hh
vendored
327
src/mem/cache/miss/miss_queue.hh
vendored
|
@ -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__
|
|
78
src/mem/cache/miss/mshr.cc
vendored
78
src/mem/cache/miss/mshr.cc
vendored
|
@ -54,45 +54,20 @@ MSHR::MSHR()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSHR::allocate(MemCmd cmd, Addr _addr, int size,
|
MSHR::allocate(Addr _addr, int _size, PacketPtr target, bool cacheFill)
|
||||||
PacketPtr &target)
|
|
||||||
{
|
{
|
||||||
addr = _addr;
|
addr = _addr;
|
||||||
if (target)
|
size = _size;
|
||||||
{
|
assert(target);
|
||||||
//Have a request, just use it
|
isCacheFill = cacheFill;
|
||||||
pkt = new Packet(target->req, cmd, Packet::Broadcast, size);
|
needsExclusive = target->needsExclusive();
|
||||||
pkt->time = curTick;
|
_isUncacheable = target->req->isUncacheable();
|
||||||
pkt->allocate();
|
inService = false;
|
||||||
pkt->senderState = (Packet::SenderState *)this;
|
threadNum = 0;
|
||||||
allocateTarget(target);
|
ntargets = 1;
|
||||||
}
|
// Don't know of a case where we would allocate a new MSHR for a
|
||||||
else
|
// snoop (mem0-side request), so set cpuSide to true here.
|
||||||
{
|
targets.push_back(Target(target, true));
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -100,8 +75,6 @@ MSHR::deallocate()
|
||||||
{
|
{
|
||||||
assert(targets.empty());
|
assert(targets.empty());
|
||||||
assert(ntargets == 0);
|
assert(ntargets == 0);
|
||||||
delete pkt;
|
|
||||||
pkt = NULL;
|
|
||||||
inService = false;
|
inService = false;
|
||||||
//allocIter = NULL;
|
//allocIter = NULL;
|
||||||
//readyIter = NULL;
|
//readyIter = NULL;
|
||||||
|
@ -111,16 +84,17 @@ MSHR::deallocate()
|
||||||
* Adds a target to an MSHR
|
* Adds a target to an MSHR
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MSHR::allocateTarget(PacketPtr &target)
|
MSHR::allocateTarget(PacketPtr target, bool cpuSide)
|
||||||
{
|
{
|
||||||
//If we append an invalidate and we issued a read to the bus,
|
//If we append an invalidate and we issued a read to the bus,
|
||||||
//but now have some pending writes, we need to move
|
//but now have some pending writes, we need to move
|
||||||
//the invalidate to before the first non-read
|
//the invalidate to before the first non-read
|
||||||
if (inService && pkt->isRead() && target->isInvalidate()) {
|
if (inService && !inServiceForExclusive && needsExclusive
|
||||||
std::list<PacketPtr> temp;
|
&& !cpuSide && target->isInvalidate()) {
|
||||||
|
std::list<Target> temp;
|
||||||
|
|
||||||
while (!targets.empty()) {
|
while (!targets.empty()) {
|
||||||
if (!targets.front()->isRead()) break;
|
if (targets.front().pkt->needsExclusive()) break;
|
||||||
//Place on top of temp stack
|
//Place on top of temp stack
|
||||||
temp.push_front(targets.front());
|
temp.push_front(targets.front());
|
||||||
//Remove from targets
|
//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
|
//Now that we have all the reads off until first non-read, we can
|
||||||
//place the invalidate on
|
//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
|
//Now we pop off the temp_stack and put them back
|
||||||
while (!temp.empty()) {
|
while (!temp.empty()) {
|
||||||
|
@ -138,22 +112,16 @@ MSHR::allocateTarget(PacketPtr &target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targets.push_back(target);
|
targets.push_back(Target(target, cpuSide));
|
||||||
}
|
}
|
||||||
|
|
||||||
++ntargets;
|
++ntargets;
|
||||||
assert(targets.size() == ntargets);
|
assert(targets.size() == ntargets);
|
||||||
/**
|
|
||||||
* @todo really prioritize the target commands.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!inService && target->isWrite()) {
|
needsExclusive = needsExclusive || target->needsExclusive();
|
||||||
pkt->cmd = MemCmd::WriteReq;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MSHR::dump()
|
MSHR::dump()
|
||||||
{
|
{
|
||||||
|
@ -167,8 +135,8 @@ MSHR::dump()
|
||||||
for (int i = 0; i < ntargets; i++) {
|
for (int i = 0; i < ntargets; i++) {
|
||||||
assert(tar_it != targets.end());
|
assert(tar_it != targets.end());
|
||||||
|
|
||||||
ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n",
|
ccprintf(cerr, "\t%d: Addr: %x cmd: %s\n",
|
||||||
i, (*tar_it)->getAddr(), (*tar_it)->cmdToIndex());
|
i, tar_it->pkt->getAddr(), tar_it->pkt->cmdString());
|
||||||
|
|
||||||
tar_it++;
|
tar_it++;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +145,4 @@ MSHR::dump()
|
||||||
|
|
||||||
MSHR::~MSHR()
|
MSHR::~MSHR()
|
||||||
{
|
{
|
||||||
if (pkt)
|
|
||||||
pkt = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
77
src/mem/cache/miss/mshr.hh
vendored
77
src/mem/cache/miss/mshr.hh
vendored
|
@ -36,22 +36,39 @@
|
||||||
#ifndef __MSHR_HH__
|
#ifndef __MSHR_HH__
|
||||||
#define __MSHR_HH__
|
#define __MSHR_HH__
|
||||||
|
|
||||||
#include "mem/packet.hh"
|
|
||||||
#include <list>
|
#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
|
* Miss Status and handling Register. This class keeps all the information
|
||||||
* needed to handle a cache miss including a list of target requests.
|
* needed to handle a cache miss including a list of target requests.
|
||||||
*/
|
*/
|
||||||
class MSHR {
|
class MSHR : public Packet::SenderState
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
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. */
|
/** Defines the Data structure of the MSHR targetlist. */
|
||||||
typedef std::list<PacketPtr> TargetList;
|
typedef std::list<Target> TargetList;
|
||||||
/** Target list iterator. */
|
/** Target list iterator. */
|
||||||
typedef std::list<PacketPtr>::iterator TargetListIterator;
|
typedef std::list<Target>::iterator TargetListIterator;
|
||||||
/** A list of MSHRs. */
|
/** A list of MSHRs. */
|
||||||
typedef std::list<MSHR *> List;
|
typedef std::list<MSHR *> List;
|
||||||
/** MSHR list iterator. */
|
/** MSHR list iterator. */
|
||||||
|
@ -59,20 +76,35 @@ class MSHR {
|
||||||
/** MSHR list const_iterator. */
|
/** MSHR list const_iterator. */
|
||||||
typedef List::const_iterator ConstIterator;
|
typedef List::const_iterator ConstIterator;
|
||||||
|
|
||||||
/** Address of the miss. */
|
/** Pointer to queue containing this MSHR. */
|
||||||
|
MSHRQueue *queue;
|
||||||
|
|
||||||
|
/** Address of the request. */
|
||||||
Addr addr;
|
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. */
|
/** True if the request has been sent to the bus. */
|
||||||
bool inService;
|
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. */
|
/** Thread number of the miss. */
|
||||||
int threadNum;
|
short threadNum;
|
||||||
/** The request that is forwarded to the next level of the hierarchy. */
|
|
||||||
PacketPtr pkt;
|
|
||||||
/** The number of currently allocated targets. */
|
/** The number of currently allocated targets. */
|
||||||
short ntargets;
|
short ntargets;
|
||||||
/** The original requesting command. */
|
|
||||||
MemCmd originalCmd;
|
|
||||||
/** Order number of assigned by the miss queue. */
|
/** Order number of assigned by the miss queue. */
|
||||||
uint64_t order;
|
uint64_t order;
|
||||||
|
|
||||||
|
@ -81,6 +113,7 @@ class MSHR {
|
||||||
* @sa MissQueue, MSHRQueue::readyList
|
* @sa MissQueue, MSHRQueue::readyList
|
||||||
*/
|
*/
|
||||||
Iterator readyIter;
|
Iterator readyIter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to this MSHR on the allocated list.
|
* Pointer to this MSHR on the allocated list.
|
||||||
* @sa MissQueue, MSHRQueue::allocatedList
|
* @sa MissQueue, MSHRQueue::allocatedList
|
||||||
|
@ -92,6 +125,9 @@ private:
|
||||||
TargetList targets;
|
TargetList targets;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
bool isUncacheable() { return _isUncacheable; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a miss to this MSHR.
|
* Allocate a miss to this MSHR.
|
||||||
* @param cmd The requesting command.
|
* @param cmd The requesting command.
|
||||||
|
@ -100,14 +136,13 @@ public:
|
||||||
* @param size The number of bytes to request.
|
* @param size The number of bytes to request.
|
||||||
* @param pkt The original miss.
|
* @param pkt The original miss.
|
||||||
*/
|
*/
|
||||||
void allocate(MemCmd cmd, Addr addr, int size,
|
void allocate(Addr addr, int size, PacketPtr pkt, bool isFill);
|
||||||
PacketPtr &pkt);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate this MSHR as a buffer for the given request.
|
* Allocate this MSHR as a buffer for the given request.
|
||||||
* @param target The memory request to buffer.
|
* @param target The memory request to buffer.
|
||||||
*/
|
*/
|
||||||
void allocateAsBuffer(PacketPtr &target);
|
void allocateAsBuffer(PacketPtr target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark this MSHR as free.
|
* Mark this MSHR as free.
|
||||||
|
@ -118,7 +153,7 @@ public:
|
||||||
* Add a request to the list of targets.
|
* Add a request to the list of targets.
|
||||||
* @param target The target.
|
* @param target The target.
|
||||||
*/
|
*/
|
||||||
void allocateTarget(PacketPtr &target);
|
void allocateTarget(PacketPtr target, bool cpuSide);
|
||||||
|
|
||||||
/** A simple constructor. */
|
/** A simple constructor. */
|
||||||
MSHR();
|
MSHR();
|
||||||
|
@ -131,7 +166,7 @@ public:
|
||||||
*/
|
*/
|
||||||
int getNumTargets()
|
int getNumTargets()
|
||||||
{
|
{
|
||||||
return(ntargets);
|
return ntargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -147,9 +182,9 @@ public:
|
||||||
* Returns a reference to the first target.
|
* Returns a reference to the first target.
|
||||||
* @return A pointer to the first target.
|
* @return A pointer to the first target.
|
||||||
*/
|
*/
|
||||||
PacketPtr getTarget()
|
Target *getTarget()
|
||||||
{
|
{
|
||||||
return targets.front();
|
return &targets.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
90
src/mem/cache/miss/mshr_queue.cc
vendored
90
src/mem/cache/miss/mshr_queue.cc
vendored
|
@ -29,22 +29,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* Definition of the MSHRQueue.
|
* Definition of MSHRQueue class functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mem/cache/miss/mshr_queue.hh"
|
#include "mem/cache/miss/mshr_queue.hh"
|
||||||
#include "sim/eventq.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
MSHRQueue::MSHRQueue(int num_mshrs, int reserve)
|
MSHRQueue::MSHRQueue(int num_entries, int reserve)
|
||||||
: numMSHRs(num_mshrs + reserve - 1), numReserve(reserve)
|
: numEntries(num_entries + reserve - 1), numReserve(reserve)
|
||||||
{
|
{
|
||||||
allocated = 0;
|
allocated = 0;
|
||||||
inServiceMSHRs = 0;
|
inServiceEntries = 0;
|
||||||
allocatedTargets = 0;
|
registers = new MSHR[numEntries];
|
||||||
registers = new MSHR[numMSHRs];
|
for (int i = 0; i < numEntries; ++i) {
|
||||||
for (int i = 0; i < numMSHRs; ++i) {
|
registers[i].queue = this;
|
||||||
freeList.push_back(®isters[i]);
|
freeList.push_back(®isters[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +53,7 @@ MSHRQueue::~MSHRQueue()
|
||||||
delete [] registers;
|
delete [] registers;
|
||||||
}
|
}
|
||||||
|
|
||||||
MSHR*
|
MSHR *
|
||||||
MSHRQueue::findMatch(Addr addr) const
|
MSHRQueue::findMatch(Addr addr) const
|
||||||
{
|
{
|
||||||
MSHR::ConstIterator i = allocatedList.begin();
|
MSHR::ConstIterator i = allocatedList.begin();
|
||||||
|
@ -87,19 +86,19 @@ MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MSHR*
|
MSHR *
|
||||||
MSHRQueue::findPending(PacketPtr &pkt) const
|
MSHRQueue::findPending(Addr addr, int size) const
|
||||||
{
|
{
|
||||||
MSHR::ConstIterator i = pendingList.begin();
|
MSHR::ConstIterator i = pendingList.begin();
|
||||||
MSHR::ConstIterator end = pendingList.end();
|
MSHR::ConstIterator end = pendingList.end();
|
||||||
for (; i != end; ++i) {
|
for (; i != end; ++i) {
|
||||||
MSHR *mshr = *i;
|
MSHR *mshr = *i;
|
||||||
if (mshr->addr < pkt->getAddr()) {
|
if (mshr->addr < addr) {
|
||||||
if (mshr->addr + mshr->pkt->getSize() > pkt->getAddr()) {
|
if (mshr->addr + mshr->size > addr) {
|
||||||
return mshr;
|
return mshr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pkt->getAddr() + pkt->getSize() > mshr->addr) {
|
if (addr + size > mshr->addr) {
|
||||||
return mshr;
|
return mshr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,21 +106,15 @@ MSHRQueue::findPending(PacketPtr &pkt) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MSHR*
|
MSHR *
|
||||||
MSHRQueue::allocate(PacketPtr &pkt, int size)
|
MSHRQueue::allocate(Addr addr, int size, PacketPtr &pkt, bool isFill)
|
||||||
{
|
{
|
||||||
Addr aligned_addr = pkt->getAddr() & ~((Addr)size - 1);
|
|
||||||
assert(!freeList.empty());
|
assert(!freeList.empty());
|
||||||
MSHR *mshr = freeList.front();
|
MSHR *mshr = freeList.front();
|
||||||
assert(mshr->getNumTargets() == 0);
|
assert(mshr->getNumTargets() == 0);
|
||||||
freeList.pop_front();
|
freeList.pop_front();
|
||||||
|
|
||||||
if (!pkt->needsResponse()) {
|
mshr->allocate(addr, size, pkt, isFill);
|
||||||
mshr->allocateAsBuffer(pkt);
|
|
||||||
} else {
|
|
||||||
mshr->allocate(pkt->cmd, aligned_addr, size, pkt);
|
|
||||||
allocatedTargets += 1;
|
|
||||||
}
|
|
||||||
mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
|
mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
|
||||||
mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
|
mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
|
||||||
|
|
||||||
|
@ -129,51 +122,21 @@ MSHRQueue::allocate(PacketPtr &pkt, int size)
|
||||||
return mshr;
|
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
|
void
|
||||||
MSHRQueue::deallocate(MSHR* mshr)
|
MSHRQueue::deallocate(MSHR *mshr)
|
||||||
{
|
{
|
||||||
deallocateOne(mshr);
|
deallocateOne(mshr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MSHR::Iterator
|
MSHR::Iterator
|
||||||
MSHRQueue::deallocateOne(MSHR* mshr)
|
MSHRQueue::deallocateOne(MSHR *mshr)
|
||||||
{
|
{
|
||||||
MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
|
MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
|
||||||
freeList.push_front(mshr);
|
freeList.push_front(mshr);
|
||||||
allocated--;
|
allocated--;
|
||||||
allocatedTargets -= mshr->getNumTargets();
|
|
||||||
if (mshr->inService) {
|
if (mshr->inService) {
|
||||||
inServiceMSHRs--;
|
inServiceEntries--;
|
||||||
} else {
|
} else {
|
||||||
pendingList.erase(mshr->readyIter);
|
pendingList.erase(mshr->readyIter);
|
||||||
}
|
}
|
||||||
|
@ -192,29 +155,29 @@ MSHRQueue::moveToFront(MSHR *mshr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSHRQueue::markInService(MSHR* mshr)
|
MSHRQueue::markInService(MSHR *mshr)
|
||||||
{
|
{
|
||||||
//assert(mshr == pendingList.front());
|
//assert(mshr == pendingList.front());
|
||||||
|
#if 0
|
||||||
if (!mshr->pkt->needsResponse() && !(mshr->pkt->cmd == MemCmd::UpgradeReq)) {
|
if (!mshr->pkt->needsResponse() && !(mshr->pkt->cmd == MemCmd::UpgradeReq)) {
|
||||||
assert(mshr->getNumTargets() == 0);
|
assert(mshr->getNumTargets() == 0);
|
||||||
deallocate(mshr);
|
deallocate(mshr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
mshr->inService = true;
|
mshr->inService = true;
|
||||||
pendingList.erase(mshr->readyIter);
|
pendingList.erase(mshr->readyIter);
|
||||||
//mshr->readyIter = NULL;
|
//mshr->readyIter = NULL;
|
||||||
inServiceMSHRs += 1;
|
inServiceEntries += 1;
|
||||||
//pendingList.pop_front();
|
//pendingList.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSHRQueue::markPending(MSHR* mshr, MemCmd cmd)
|
MSHRQueue::markPending(MSHR *mshr)
|
||||||
{
|
{
|
||||||
//assert(mshr->readyIter == NULL);
|
//assert(mshr->readyIter == NULL);
|
||||||
mshr->pkt->cmd = cmd;
|
|
||||||
mshr->pkt->flags &= ~SATISFIED;
|
|
||||||
mshr->inService = false;
|
mshr->inService = false;
|
||||||
--inServiceMSHRs;
|
--inServiceEntries;
|
||||||
/**
|
/**
|
||||||
* @ todo might want to add rerequests to front of pending list for
|
* @ todo might want to add rerequests to front of pending list for
|
||||||
* performance.
|
* performance.
|
||||||
|
@ -231,11 +194,8 @@ MSHRQueue::squash(int threadNum)
|
||||||
MSHR *mshr = *i;
|
MSHR *mshr = *i;
|
||||||
if (mshr->threadNum == threadNum) {
|
if (mshr->threadNum == threadNum) {
|
||||||
while (mshr->hasTargets()) {
|
while (mshr->hasTargets()) {
|
||||||
PacketPtr target = mshr->getTarget();
|
|
||||||
mshr->popTarget();
|
mshr->popTarget();
|
||||||
|
|
||||||
assert(0/*target->req->getThreadNum()*/ == threadNum);
|
assert(0/*target->req->getThreadNum()*/ == threadNum);
|
||||||
target = NULL;
|
|
||||||
}
|
}
|
||||||
assert(!mshr->hasTargets());
|
assert(!mshr->hasTargets());
|
||||||
assert(mshr->ntargets==0);
|
assert(mshr->ntargets==0);
|
||||||
|
|
137
src/mem/cache/miss/mshr_queue.hh
vendored
137
src/mem/cache/miss/mshr_queue.hh
vendored
|
@ -32,71 +32,71 @@
|
||||||
* Declaration of a structure to manage MSHRs.
|
* Declaration of a structure to manage MSHRs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MSHR_QUEUE_HH__
|
#ifndef __MEM__CACHE__MISS__MSHR_QUEUE_HH__
|
||||||
#define __MSHR_QUEUE_HH__
|
#define __MEM__CACHE__MISS__MSHR_QUEUE_HH__
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mem/packet.hh"
|
||||||
#include "mem/cache/miss/mshr.hh"
|
#include "mem/cache/miss/mshr.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class for maintaining a list of pending and allocated memory requests.
|
* A Class for maintaining a list of pending and allocated memory requests.
|
||||||
*/
|
*/
|
||||||
class MSHRQueue {
|
class MSHRQueue
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
/** MSHR storage. */
|
/** MSHR storage. */
|
||||||
MSHR* registers;
|
MSHR *registers;
|
||||||
/** Holds pointers to all allocated MSHRs. */
|
/** Holds pointers to all allocated entries. */
|
||||||
MSHR::List allocatedList;
|
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;
|
MSHR::List pendingList;
|
||||||
/** Holds non allocated MSHRs. */
|
/** Holds non allocated entries. */
|
||||||
MSHR::List freeList;
|
MSHR::List freeList;
|
||||||
|
|
||||||
// Parameters
|
// Parameters
|
||||||
/**
|
/**
|
||||||
* The total number of MSHRs in this queue. This number is set as the
|
* The total number of entries in this queue. This number is set as the
|
||||||
* number of MSHRs requested plus (numReserve - 1). This allows for
|
* number of entries requested plus (numReserve - 1). This allows for
|
||||||
* the same number of effective MSHRs while still maintaining the reserve.
|
* 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
|
* The number of entries to hold in reserve. This is needed because copy
|
||||||
* operations can allocate upto 4 MSHRs at one time.
|
* operations can allocate upto 4 entries at one time.
|
||||||
*/
|
*/
|
||||||
const int numReserve;
|
const int numReserve;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** The number of allocated MSHRs. */
|
/** The number of allocated entries. */
|
||||||
int allocated;
|
int allocated;
|
||||||
/** The number of MSHRs that have been forwarded to the bus. */
|
/** The number of entries that have been forwarded to the bus. */
|
||||||
int inServiceMSHRs;
|
int inServiceEntries;
|
||||||
/** The number of targets waiting for response. */
|
|
||||||
int allocatedTargets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a queue with a given number of MSHRs.
|
* Create a queue with a given number of entries.
|
||||||
* @param num_mshrs The number of MSHRs in this queue.
|
* @param num_entrys The number of entries in this queue.
|
||||||
* @param reserve The minimum number of MSHRs needed to satisfy any access.
|
* @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 = 1);
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~MSHRQueue();
|
~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 addr The address to find.
|
||||||
* @param asid The address space id.
|
|
||||||
* @return Pointer to the matching MSHR, null if not found.
|
* @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 addr The address to find.
|
||||||
* @param asid The address space ID.
|
* @param matches The vector to return pointers to the matching entries.
|
||||||
* @param matches The vector to return pointers to the matching MSHRs.
|
|
||||||
* @return True if any matches are found, false otherwise.
|
* @return True if any matches are found, false otherwise.
|
||||||
* @todo Typedef the vector??
|
* @todo Typedef the vector??
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +107,7 @@ class MSHRQueue {
|
||||||
* @param pkt The request to find.
|
* @param pkt The request to find.
|
||||||
* @return A pointer to the earliest matching MSHR.
|
* @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
|
* Allocates a new MSHR for the request and size. This places the request
|
||||||
|
@ -116,60 +116,29 @@ class MSHRQueue {
|
||||||
* @param size The number in bytes to fetch from memory.
|
* @param size The number in bytes to fetch from memory.
|
||||||
* @return The a pointer to the MSHR allocated.
|
* @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);
|
MSHR *allocate(Addr addr, int size, PacketPtr &pkt, bool isFill);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given MSHR from the queue. This places the MSHR on the
|
* Removes the given MSHR from the queue. This places the MSHR on the
|
||||||
* free list.
|
* free list.
|
||||||
* @param mshr
|
* @param mshr
|
||||||
*/
|
*/
|
||||||
void deallocate(MSHR* mshr);
|
void deallocate(MSHR *mshr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a target to the given MSHR. Used to keep track of the number
|
* Remove a MSHR from the queue. Returns an iterator into the
|
||||||
* of outstanding targets.
|
* allocatedList for faster squash implementation.
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a MSHR from the queue. Returns an iterator into the allocatedList
|
|
||||||
* for faster squash implementation.
|
|
||||||
* @param mshr The MSHR to remove.
|
* @param mshr The MSHR to remove.
|
||||||
* @return An iterator to the next entry in the allocatedList.
|
* @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.
|
* Moves the MSHR to the front of the pending list if it is not
|
||||||
* @param mshr The mshr to move.
|
* in service.
|
||||||
|
* @param mshr The entry to move.
|
||||||
*/
|
*/
|
||||||
void moveToFront(MSHR *mshr);
|
void moveToFront(MSHR *mshr);
|
||||||
|
|
||||||
|
@ -178,14 +147,13 @@ class MSHRQueue {
|
||||||
* pendingList. Deallocates the MSHR if it does not expect a response.
|
* pendingList. Deallocates the MSHR if it does not expect a response.
|
||||||
* @param mshr The MSHR to mark in service.
|
* @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 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
|
* Squash outstanding requests with the given thread number. If a request
|
||||||
|
@ -204,36 +172,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.
|
* @return True if this queue is full.
|
||||||
*/
|
*/
|
||||||
bool isFull() const
|
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.
|
* @return The next request to service.
|
||||||
*/
|
*/
|
||||||
PacketPtr getReq() const
|
MSHR *getNextMSHR() const
|
||||||
{
|
{
|
||||||
if (pendingList.empty()) {
|
if (pendingList.empty()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
MSHR* mshr = pendingList.front();
|
return pendingList.front();
|
||||||
return mshr->pkt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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__
|
||||||
|
|
1
src/mem/cache/prefetch/base_prefetcher.cc
vendored
1
src/mem/cache/prefetch/base_prefetcher.cc
vendored
|
@ -241,7 +241,6 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
|
||||||
}
|
}
|
||||||
|
|
||||||
pf.push_back(prefetch);
|
pf.push_back(prefetch);
|
||||||
prefetch->flags |= CACHE_LINE_FILL;
|
|
||||||
|
|
||||||
//Make sure to request the bus, with proper delay
|
//Make sure to request the bus, with proper delay
|
||||||
cache->requestMemSideBus(Request_PF, prefetch->time);
|
cache->requestMemSideBus(Request_PF, prefetch->time);
|
||||||
|
|
5
src/mem/cache/tags/fa_lru.cc
vendored
5
src/mem/cache/tags/fa_lru.cc
vendored
|
@ -215,14 +215,13 @@ FALRU::findBlock(Addr addr) const
|
||||||
}
|
}
|
||||||
|
|
||||||
FALRUBlk*
|
FALRUBlk*
|
||||||
FALRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
FALRU::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
FALRUBlk * blk = tail;
|
FALRUBlk * blk = tail;
|
||||||
assert(blk->inCache == 0);
|
assert(blk->inCache == 0);
|
||||||
moveToHead(blk);
|
moveToHead(blk);
|
||||||
tagHash.erase(blk->tag);
|
tagHash.erase(blk->tag);
|
||||||
tagHash[blkAlign(pkt->getAddr())] = blk;
|
tagHash[blkAlign(addr)] = blk;
|
||||||
if (blk->isValid()) {
|
if (blk->isValid()) {
|
||||||
replacements[0]++;
|
replacements[0]++;
|
||||||
} else {
|
} else {
|
||||||
|
|
7
src/mem/cache/tags/fa_lru.hh
vendored
7
src/mem/cache/tags/fa_lru.hh
vendored
|
@ -201,11 +201,9 @@ public:
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
FALRUBlk* findReplacement(PacketPtr &pkt, PacketList & writebacks,
|
FALRUBlk* findReplacement(Addr addr, PacketList & writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the hit latency of this cache.
|
* 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
|
* Generate the tag from the addres. For fully associative this is just the
|
||||||
* block address.
|
* block address.
|
||||||
* @param addr The address to get the tag from.
|
* @param addr The address to get the tag from.
|
||||||
* @param blk ignored here
|
|
||||||
* @return The tag.
|
* @return The tag.
|
||||||
*/
|
*/
|
||||||
Addr extractTag(Addr addr, FALRUBlk *blk) const
|
Addr extractTag(Addr addr) const
|
||||||
{
|
{
|
||||||
return blkAlign(addr);
|
return blkAlign(addr);
|
||||||
}
|
}
|
||||||
|
|
32
src/mem/cache/tags/iic.cc
vendored
32
src/mem/cache/tags/iic.cc
vendored
|
@ -303,11 +303,10 @@ IIC::findBlock(Addr addr) const
|
||||||
|
|
||||||
|
|
||||||
IICTag*
|
IICTag*
|
||||||
IIC::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
IIC::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
DPRINTF(IIC, "Finding Replacement for %x\n", pkt->getAddr());
|
DPRINTF(IIC, "Finding Replacement for %x\n", addr);
|
||||||
unsigned set = hash(pkt->getAddr());
|
unsigned set = hash(addr);
|
||||||
IICTag *tag_ptr;
|
IICTag *tag_ptr;
|
||||||
unsigned long *tmp_data = new unsigned long[numSub];
|
unsigned long *tmp_data = new unsigned long[numSub];
|
||||||
|
|
||||||
|
@ -332,12 +331,14 @@ IIC::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
||||||
|
|
||||||
list<unsigned long> tag_indexes;
|
list<unsigned long> tag_indexes;
|
||||||
repl->doAdvance(tag_indexes);
|
repl->doAdvance(tag_indexes);
|
||||||
|
/*
|
||||||
while (!tag_indexes.empty()) {
|
while (!tag_indexes.empty()) {
|
||||||
if (!tagStore[tag_indexes.front()].isCompressed()) {
|
if (!tagStore[tag_indexes.front()].isCompressed()) {
|
||||||
compress_blocks.push_back(&tagStore[tag_indexes.front()]);
|
compress_blocks.push_back(&tagStore[tag_indexes.front()]);
|
||||||
}
|
}
|
||||||
tag_indexes.pop_front();
|
tag_indexes.pop_front();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
|
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",
|
DPRINTF(Cache, "Replacing %x in IIC: %s\n",
|
||||||
regenerateBlkAddr(tag_ptr->tag,0),
|
regenerateBlkAddr(tag_ptr->tag,0),
|
||||||
tag_ptr->isModified() ? "writeback" : "clean");
|
tag_ptr->isDirty() ? "writeback" : "clean");
|
||||||
/* write back replaced block data */
|
/* write back replaced block data */
|
||||||
if (tag_ptr && (tag_ptr->isValid())) {
|
if (tag_ptr && (tag_ptr->isValid())) {
|
||||||
replacements[0]++;
|
replacements[0]++;
|
||||||
|
@ -363,7 +364,7 @@ IIC::freeReplacementBlock(PacketList & writebacks)
|
||||||
++sampledRefs;
|
++sampledRefs;
|
||||||
tag_ptr->refCount = 0;
|
tag_ptr->refCount = 0;
|
||||||
|
|
||||||
if (tag_ptr->isModified()) {
|
if (tag_ptr->isDirty()) {
|
||||||
/* PacketPtr writeback =
|
/* PacketPtr writeback =
|
||||||
buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
|
buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
|
||||||
tag_ptr->req->asid, tag_ptr->xc, blkSize,
|
tag_ptr->req->asid, tag_ptr->xc, blkSize,
|
||||||
|
@ -618,24 +619,6 @@ IIC::secondaryChain(Addr tag, unsigned long chain_ptr,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
void
|
||||||
IIC::invalidateBlk(IIC::BlkType *tag_ptr)
|
IIC::invalidateBlk(IIC::BlkType *tag_ptr)
|
||||||
{
|
{
|
||||||
|
@ -672,7 +655,6 @@ void
|
||||||
IIC::writeData(IICTag *blk, uint8_t *write_data, int size,
|
IIC::writeData(IICTag *blk, uint8_t *write_data, int size,
|
||||||
PacketList & writebacks)
|
PacketList & writebacks)
|
||||||
{
|
{
|
||||||
assert(size < blkSize || !blk->isCompressed());
|
|
||||||
DPRINTF(IIC, "Writing %d bytes to %x\n", size,
|
DPRINTF(IIC, "Writing %d bytes to %x\n", size,
|
||||||
blk->tag<<tagShift);
|
blk->tag<<tagShift);
|
||||||
// Find the number of subblocks needed, (round up)
|
// Find the number of subblocks needed, (round up)
|
||||||
|
|
27
src/mem/cache/tags/iic.hh
vendored
27
src/mem/cache/tags/iic.hh
vendored
|
@ -345,17 +345,6 @@ class IIC : public BaseTags
|
||||||
return hitLatency;
|
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.
|
* Generate the tag from the address.
|
||||||
* @param addr The address to a get a tag for.
|
* @param addr The address to a get a tag for.
|
||||||
|
@ -422,18 +411,6 @@ class IIC : public BaseTags
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Invalidate a block.
|
||||||
* @param blk The block to invalidate.
|
* @param blk The block to invalidate.
|
||||||
|
@ -462,11 +439,9 @@ class IIC : public BaseTags
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
IICTag* findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
IICTag* findReplacement(Addr addr, PacketList &writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the data from the internal storage of the given cache block.
|
* Read the data from the internal storage of the given cache block.
|
||||||
|
|
5
src/mem/cache/tags/lru.cc
vendored
5
src/mem/cache/tags/lru.cc
vendored
|
@ -194,10 +194,9 @@ LRU::findBlock(Addr addr) const
|
||||||
}
|
}
|
||||||
|
|
||||||
LRUBlk*
|
LRUBlk*
|
||||||
LRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
LRU::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
unsigned set = extractSet(pkt->getAddr());
|
unsigned set = extractSet(addr);
|
||||||
// grab a replacement candidate
|
// grab a replacement candidate
|
||||||
LRUBlk *blk = sets[set].blks[assoc-1];
|
LRUBlk *blk = sets[set].blks[assoc-1];
|
||||||
sets[set].moveToHead(blk);
|
sets[set].moveToHead(blk);
|
||||||
|
|
15
src/mem/cache/tags/lru.hh
vendored
15
src/mem/cache/tags/lru.hh
vendored
|
@ -189,11 +189,9 @@ public:
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
LRUBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
LRUBlk* findReplacement(Addr addr, PacketList &writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the tag from the given address.
|
* Generate the tag from the given address.
|
||||||
|
@ -205,17 +203,6 @@ public:
|
||||||
return (addr >> tagShift);
|
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.
|
* Calculate the set index from the address.
|
||||||
* @param addr The address to get the set from.
|
* @param addr The address to get the set from.
|
||||||
|
|
25
src/mem/cache/tags/split.cc
vendored
25
src/mem/cache/tags/split.cc
vendored
|
@ -298,27 +298,25 @@ Split::findBlock(Addr addr) const
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitBlk*
|
SplitBlk*
|
||||||
Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
Split::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
SplitBlk *blk;
|
SplitBlk *blk;
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
#if 0
|
||||||
if (pkt->nic_pkt()) {
|
if (pkt->nic_pkt()) {
|
||||||
DPRINTF(Split, "finding a replacement for nic_req\n");
|
DPRINTF(Split, "finding a replacement for nic_req\n");
|
||||||
nic_repl++;
|
nic_repl++;
|
||||||
if (lifo && lifo_net)
|
if (lifo && lifo_net)
|
||||||
blk = lifo_net->findReplacement(pkt, writebacks,
|
blk = lifo_net->findReplacement(addr, writebacks);
|
||||||
compress_blocks);
|
|
||||||
else if (lru_net)
|
else if (lru_net)
|
||||||
blk = lru_net->findReplacement(pkt, writebacks,
|
blk = lru_net->findReplacement(addr, writebacks);
|
||||||
compress_blocks);
|
|
||||||
// in this case, this is an LRU only cache, it's non partitioned
|
// in this case, this is an LRU only cache, it's non partitioned
|
||||||
else
|
else
|
||||||
blk = lru->findReplacement(pkt, writebacks, compress_blocks);
|
blk = lru->findReplacement(addr, writebacks);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(Split, "finding replacement for cpu_req\n");
|
DPRINTF(Split, "finding replacement for cpu_req\n");
|
||||||
blk = lru->findReplacement(pkt, writebacks,
|
blk = lru->findReplacement(addr, writebacks);
|
||||||
compress_blocks);
|
|
||||||
cpu_repl++;
|
cpu_repl++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,6 +344,7 @@ Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
||||||
// blk attributes for the new blk coming IN
|
// blk attributes for the new blk coming IN
|
||||||
blk->ts = curTick;
|
blk->ts = curTick;
|
||||||
blk->isNIC = (pkt->nic_pkt()) ? true : false;
|
blk->isNIC = (pkt->nic_pkt()) ? true : false;
|
||||||
|
#endif
|
||||||
|
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
@ -400,8 +399,13 @@ Split::regenerateBlkAddr(Addr tag, int set) const
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr
|
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 (blk->part == 2) {
|
||||||
if (lifo_net)
|
if (lifo_net)
|
||||||
return lifo_net->extractTag(addr);
|
return lifo_net->extractTag(addr);
|
||||||
|
@ -411,5 +415,6 @@ Split::extractTag(Addr addr, SplitBlk *blk) const
|
||||||
panic("this shouldn't happen");
|
panic("this shouldn't happen");
|
||||||
} else
|
} else
|
||||||
return lru->extractTag(addr);
|
return lru->extractTag(addr);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
src/mem/cache/tags/split.hh
vendored
7
src/mem/cache/tags/split.hh
vendored
|
@ -212,20 +212,17 @@ class Split : public BaseTags
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the tag from the given address.
|
* Generate the tag from the given address.
|
||||||
* @param addr The address to get the tag from.
|
* @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.
|
* @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.
|
* Calculate the set index from the address.
|
||||||
|
|
7
src/mem/cache/tags/split_lifo.cc
vendored
7
src/mem/cache/tags/split_lifo.cc
vendored
|
@ -266,10 +266,9 @@ SplitLIFO::findBlock(Addr addr) const
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitBlk*
|
SplitBlk*
|
||||||
SplitLIFO::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
SplitLIFO::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
unsigned set = extractSet(pkt->getAddr());
|
unsigned set = extractSet(addr);
|
||||||
|
|
||||||
SplitBlk *firstIn = sets[set].firstIn;
|
SplitBlk *firstIn = sets[set].firstIn;
|
||||||
SplitBlk *lastIn = sets[set].lastIn;
|
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",
|
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()) {
|
if (blk->isValid()) {
|
||||||
replacements[0]++;
|
replacements[0]++;
|
||||||
totalRefs += blk->refCount;
|
totalRefs += blk->refCount;
|
||||||
|
|
15
src/mem/cache/tags/split_lifo.hh
vendored
15
src/mem/cache/tags/split_lifo.hh
vendored
|
@ -212,11 +212,9 @@ public:
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the tag from the given address.
|
* Generate the tag from the given address.
|
||||||
|
@ -228,17 +226,6 @@ public:
|
||||||
return (addr >> tagShift);
|
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.
|
* Calculate the set index from the address.
|
||||||
* @param addr The address to get the set from.
|
* @param addr The address to get the set from.
|
||||||
|
|
5
src/mem/cache/tags/split_lru.cc
vendored
5
src/mem/cache/tags/split_lru.cc
vendored
|
@ -213,10 +213,9 @@ SplitLRU::findBlock(Addr addr) const
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitBlk*
|
SplitBlk*
|
||||||
SplitLRU::findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
SplitLRU::findReplacement(Addr addr, PacketList &writebacks)
|
||||||
BlkList &compress_blocks)
|
|
||||||
{
|
{
|
||||||
unsigned set = extractSet(pkt->getAddr());
|
unsigned set = extractSet(addr);
|
||||||
// grab a replacement candidate
|
// grab a replacement candidate
|
||||||
SplitBlk *blk = sets[set].blks[assoc-1];
|
SplitBlk *blk = sets[set].blks[assoc-1];
|
||||||
sets[set].moveToHead(blk);
|
sets[set].moveToHead(blk);
|
||||||
|
|
15
src/mem/cache/tags/split_lru.hh
vendored
15
src/mem/cache/tags/split_lru.hh
vendored
|
@ -195,11 +195,9 @@ public:
|
||||||
* Find a replacement block for the address provided.
|
* Find a replacement block for the address provided.
|
||||||
* @param pkt The request to a find a replacement candidate for.
|
* @param pkt The request to a find a replacement candidate for.
|
||||||
* @param writebacks List for any writebacks to be performed.
|
* @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.
|
* @return The block to place the replacement in.
|
||||||
*/
|
*/
|
||||||
SplitBlk* findReplacement(PacketPtr &pkt, PacketList &writebacks,
|
SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
|
||||||
BlkList &compress_blocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the tag from the given address.
|
* Generate the tag from the given address.
|
||||||
|
@ -211,17 +209,6 @@ public:
|
||||||
return (addr >> tagShift);
|
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.
|
* Calculate the set index from the address.
|
||||||
* @param addr The address to get the set from.
|
* @param addr The address to get the set from.
|
||||||
|
|
|
@ -59,15 +59,15 @@ MemCmd::commandInfo[] =
|
||||||
/* ReadResp */
|
/* ReadResp */
|
||||||
{ SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
|
{ SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
|
||||||
/* WriteReq */
|
/* WriteReq */
|
||||||
{ SET4(IsWrite, IsRequest, NeedsResponse, HasData),
|
{ SET5(IsWrite, NeedsExclusive, IsRequest, NeedsResponse, HasData),
|
||||||
WriteResp, "WriteReq" },
|
WriteResp, "WriteReq" },
|
||||||
/* WriteResp */
|
/* WriteResp */
|
||||||
{ SET2(IsWrite, IsResponse), InvalidCmd, "WriteResp" },
|
{ SET3(IsWrite, NeedsExclusive, IsResponse), InvalidCmd, "WriteResp" },
|
||||||
/* Writeback */
|
/* Writeback */
|
||||||
{ SET4(IsWrite, IsRequest, HasData, NeedsResponse),
|
{ SET5(IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
|
||||||
WritebackAck, "Writeback" },
|
WritebackAck, "Writeback" },
|
||||||
/* WritebackAck */
|
/* WritebackAck */
|
||||||
{ SET2(IsWrite, IsResponse), InvalidCmd, "WritebackAck" },
|
{ SET3(IsWrite, NeedsExclusive, IsResponse), InvalidCmd, "WritebackAck" },
|
||||||
/* SoftPFReq */
|
/* SoftPFReq */
|
||||||
{ SET4(IsRead, IsRequest, IsSWPrefetch, NeedsResponse),
|
{ SET4(IsRead, IsRequest, IsSWPrefetch, NeedsResponse),
|
||||||
SoftPFResp, "SoftPFReq" },
|
SoftPFResp, "SoftPFReq" },
|
||||||
|
@ -80,27 +80,39 @@ MemCmd::commandInfo[] =
|
||||||
/* HardPFResp */
|
/* HardPFResp */
|
||||||
{ SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
|
{ SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
|
||||||
InvalidCmd, "HardPFResp" },
|
InvalidCmd, "HardPFResp" },
|
||||||
/* InvalidateReq */
|
|
||||||
{ SET2(IsInvalidate, IsRequest), InvalidCmd, "InvalidateReq" },
|
|
||||||
/* WriteInvalidateReq */
|
/* WriteInvalidateReq */
|
||||||
{ SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse),
|
{ SET6(IsWrite, NeedsExclusive, IsInvalidate,
|
||||||
|
IsRequest, HasData, NeedsResponse),
|
||||||
WriteInvalidateResp, "WriteInvalidateReq" },
|
WriteInvalidateResp, "WriteInvalidateReq" },
|
||||||
/* WriteInvalidateResp */
|
/* WriteInvalidateResp */
|
||||||
{ SET3(IsWrite, IsInvalidate, IsResponse),
|
{ SET4(IsWrite, NeedsExclusive, IsInvalidate, IsResponse),
|
||||||
InvalidCmd, "WriteInvalidateResp" },
|
InvalidCmd, "WriteInvalidateResp" },
|
||||||
/* UpgradeReq */
|
/* UpgradeReq */
|
||||||
{ SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" },
|
{ SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" },
|
||||||
/* ReadExReq */
|
/* ReadExReq */
|
||||||
{ SET4(IsRead, IsInvalidate, IsRequest, NeedsResponse),
|
{ SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
|
||||||
ReadExResp, "ReadExReq" },
|
ReadExResp, "ReadExReq" },
|
||||||
/* ReadExResp */
|
/* ReadExResp */
|
||||||
{ SET4(IsRead, IsInvalidate, IsResponse, HasData),
|
{ SET5(IsRead, NeedsExclusive, IsInvalidate, IsResponse, HasData),
|
||||||
InvalidCmd, "ReadExResp" },
|
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 */
|
/* SwapReq -- for Swap ldstub type operations */
|
||||||
{ SET4(IsReadWrite, IsRequest, HasData, NeedsResponse),
|
{ SET6(IsRead, IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
|
||||||
SwapResp, "SwapReq" },
|
SwapResp, "SwapReq" },
|
||||||
/* SwapResp -- for Swap ldstub type operations */
|
/* SwapResp -- for Swap ldstub type operations */
|
||||||
{ SET3(IsReadWrite, IsResponse, HasData),
|
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
|
||||||
InvalidCmd, "SwapResp" }
|
InvalidCmd, "SwapResp" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,27 +183,28 @@ fixDelayedResponsePacket(PacketPtr func, PacketPtr timing)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
fixPacket(PacketPtr func, PacketPtr timing)
|
Packet::checkFunctional(Addr addr, int size, uint8_t *data)
|
||||||
{
|
{
|
||||||
Addr funcStart = func->getAddr();
|
Addr func_start = getAddr();
|
||||||
Addr funcEnd = func->getAddr() + func->getSize() - 1;
|
Addr func_end = getAddr() + getSize() - 1;
|
||||||
Addr timingStart = timing->getAddr();
|
Addr val_start = addr;
|
||||||
Addr timingEnd = timing->getAddr() + timing->getSize() - 1;
|
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
|
// offset of functional request into supplied value (could be
|
||||||
if (!timing->hasData())
|
// negative if partial overlap)
|
||||||
return true;
|
int offset = func_start - val_start;
|
||||||
|
|
||||||
if (func->isRead()) {
|
if (isRead()) {
|
||||||
if (funcStart >= timingStart && funcEnd <= timingEnd) {
|
if (func_start >= val_start && func_end <= val_end) {
|
||||||
func->allocate();
|
allocate();
|
||||||
std::memcpy(func->getPtr<uint8_t>(), timing->getPtr<uint8_t>() +
|
std::memcpy(getPtr<uint8_t>(), data + offset, getSize());
|
||||||
funcStart - timingStart, func->getSize());
|
result = Packet::Success;
|
||||||
func->result = Packet::Success;
|
return true;
|
||||||
func->flags |= SATISFIED;
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
// In this case the timing packet only partially satisfies
|
// In this case the timing packet only partially satisfies
|
||||||
// the request, so we would need more information to make
|
// the request, so we would need more information to make
|
||||||
|
@ -199,25 +212,21 @@ fixPacket(PacketPtr func, PacketPtr timing)
|
||||||
// something, so the request could continue and get this
|
// something, so the request could continue and get this
|
||||||
// bit of possibly newer data along with the older data
|
// bit of possibly newer data along with the older data
|
||||||
// not written to yet.
|
// not written to yet.
|
||||||
panic("Timing packet only partially satisfies the functional"
|
panic("Memory value only partially satisfies the functional "
|
||||||
"request. Now what?");
|
"request. Now what?");
|
||||||
}
|
}
|
||||||
} else if (func->isWrite()) {
|
} else if (isWrite()) {
|
||||||
if (funcStart >= timingStart) {
|
if (offset >= 0) {
|
||||||
std::memcpy(timing->getPtr<uint8_t>() + (funcStart - timingStart),
|
std::memcpy(data + offset, getPtr<uint8_t>(),
|
||||||
func->getPtr<uint8_t>(),
|
(std::min(func_end, val_end) - func_start) + 1);
|
||||||
(std::min(funcEnd, timingEnd) - funcStart) + 1);
|
} else { // val_start > func_start
|
||||||
} else { // timingStart > funcStart
|
std::memcpy(data, getPtr<uint8_t>() - offset,
|
||||||
std::memcpy(timing->getPtr<uint8_t>(),
|
(std::min(func_end, val_end) - val_start) + 1);
|
||||||
func->getPtr<uint8_t>() + (timingStart - funcStart),
|
|
||||||
(std::min(funcEnd, timingEnd) - timingStart) + 1);
|
|
||||||
}
|
}
|
||||||
// we always want to keep going with a write
|
// we always want to keep going with a write
|
||||||
return true;
|
return false;
|
||||||
} else
|
} else
|
||||||
panic("Don't know how to handle command type %#x\n",
|
panic("Don't know how to handle command %s\n", cmdString());
|
||||||
func->cmdToIndex());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -247,8 +256,6 @@ operator<<(std::ostream &o, const Packet &p)
|
||||||
o << "Read ";
|
o << "Read ";
|
||||||
if (p.isWrite())
|
if (p.isWrite())
|
||||||
o << "Write ";
|
o << "Write ";
|
||||||
if (p.isReadWrite())
|
|
||||||
o << "Read/Write ";
|
|
||||||
if (p.isInvalidate())
|
if (p.isInvalidate())
|
||||||
o << "Invalidate ";
|
o << "Invalidate ";
|
||||||
if (p.isRequest())
|
if (p.isRequest())
|
||||||
|
|
|
@ -54,16 +54,6 @@ typedef Packet *PacketPtr;
|
||||||
typedef uint8_t* PacketDataPtr;
|
typedef uint8_t* PacketDataPtr;
|
||||||
typedef std::list<PacketPtr> PacketList;
|
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 EXPRESS_SNOOP (1 << 7)
|
|
||||||
|
|
||||||
class MemCmd
|
class MemCmd
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -82,12 +72,15 @@ class MemCmd
|
||||||
HardPFReq,
|
HardPFReq,
|
||||||
SoftPFResp,
|
SoftPFResp,
|
||||||
HardPFResp,
|
HardPFResp,
|
||||||
InvalidateReq,
|
|
||||||
WriteInvalidateReq,
|
WriteInvalidateReq,
|
||||||
WriteInvalidateResp,
|
WriteInvalidateResp,
|
||||||
UpgradeReq,
|
UpgradeReq,
|
||||||
ReadExReq,
|
ReadExReq,
|
||||||
ReadExResp,
|
ReadExResp,
|
||||||
|
LoadLockedReq,
|
||||||
|
LoadLockedResp,
|
||||||
|
StoreCondReq,
|
||||||
|
StoreCondResp,
|
||||||
SwapReq,
|
SwapReq,
|
||||||
SwapResp,
|
SwapResp,
|
||||||
NUM_MEM_CMDS
|
NUM_MEM_CMDS
|
||||||
|
@ -97,18 +90,19 @@ class MemCmd
|
||||||
/** List of command attributes. */
|
/** List of command attributes. */
|
||||||
enum Attribute
|
enum Attribute
|
||||||
{
|
{
|
||||||
IsRead,
|
IsRead, //!< Data flows from responder to requester
|
||||||
IsWrite,
|
IsWrite, //!< Data flows from requester to responder
|
||||||
IsPrefetch,
|
IsPrefetch, //!< Not a demand access
|
||||||
IsInvalidate,
|
IsInvalidate,
|
||||||
IsRequest,
|
NeedsExclusive, //!< Requires exclusive copy to complete in-cache
|
||||||
IsResponse,
|
IsRequest, //!< Issued by requester
|
||||||
NeedsResponse,
|
IsResponse, //!< Issue by responder
|
||||||
|
NeedsResponse, //!< Requester needs response from target
|
||||||
IsSWPrefetch,
|
IsSWPrefetch,
|
||||||
IsHWPrefetch,
|
IsHWPrefetch,
|
||||||
IsUpgrade,
|
IsUpgrade,
|
||||||
HasData,
|
IsLocked, //!< Alpha/MIPS LL or SC access
|
||||||
IsReadWrite,
|
HasData, //!< There is an associated payload
|
||||||
NUM_COMMAND_ATTRIBUTES
|
NUM_COMMAND_ATTRIBUTES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,10 +135,12 @@ class MemCmd
|
||||||
bool isWrite() const { return testCmdAttrib(IsWrite); }
|
bool isWrite() const { return testCmdAttrib(IsWrite); }
|
||||||
bool isRequest() const { return testCmdAttrib(IsRequest); }
|
bool isRequest() const { return testCmdAttrib(IsRequest); }
|
||||||
bool isResponse() const { return testCmdAttrib(IsResponse); }
|
bool isResponse() const { return testCmdAttrib(IsResponse); }
|
||||||
|
bool needsExclusive() const { return testCmdAttrib(NeedsExclusive); }
|
||||||
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
|
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
|
||||||
bool isInvalidate() const { return testCmdAttrib(IsInvalidate); }
|
bool isInvalidate() const { return testCmdAttrib(IsInvalidate); }
|
||||||
bool hasData() const { return testCmdAttrib(HasData); }
|
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 {
|
const Command responseCommand() const {
|
||||||
return commandInfo[cmd].response;
|
return commandInfo[cmd].response;
|
||||||
|
@ -188,9 +184,6 @@ class Packet
|
||||||
|
|
||||||
typedef MemCmd::Command Command;
|
typedef MemCmd::Command Command;
|
||||||
|
|
||||||
/** Temporary FLAGS field until cache gets working, this should be in coherence/sender state. */
|
|
||||||
uint64_t flags;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** A pointer to the data being transfered. It can be differnt
|
/** A pointer to the data being transfered. It can be differnt
|
||||||
* sizes at each level of the heirarchy so it belongs in the
|
* sizes at each level of the heirarchy so it belongs in the
|
||||||
|
@ -235,6 +228,14 @@ class Packet
|
||||||
/** Is the 'src' field valid? */
|
/** Is the 'src' field valid? */
|
||||||
bool srcValid;
|
bool srcValid;
|
||||||
|
|
||||||
|
enum SnoopFlag {
|
||||||
|
MemInhibit,
|
||||||
|
Shared,
|
||||||
|
NUM_SNOOP_FLAGS
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Coherence snoopFlags for snooping */
|
||||||
|
std::bitset<NUM_SNOOP_FLAGS> snoopFlags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -301,14 +302,17 @@ class Packet
|
||||||
bool isWrite() const { return cmd.isWrite(); }
|
bool isWrite() const { return cmd.isWrite(); }
|
||||||
bool isRequest() const { return cmd.isRequest(); }
|
bool isRequest() const { return cmd.isRequest(); }
|
||||||
bool isResponse() const { return cmd.isResponse(); }
|
bool isResponse() const { return cmd.isResponse(); }
|
||||||
|
bool needsExclusive() const { return cmd.needsExclusive(); }
|
||||||
bool needsResponse() const { return cmd.needsResponse(); }
|
bool needsResponse() const { return cmd.needsResponse(); }
|
||||||
bool isInvalidate() const { return cmd.isInvalidate(); }
|
bool isInvalidate() const { return cmd.isInvalidate(); }
|
||||||
bool hasData() const { return cmd.hasData(); }
|
bool hasData() const { return cmd.hasData(); }
|
||||||
bool isReadWrite() const { return cmd.isReadWrite(); }
|
bool isReadWrite() const { return cmd.isReadWrite(); }
|
||||||
|
bool isLocked() const { return cmd.isLocked(); }
|
||||||
|
|
||||||
bool isCacheFill() const { return (flags & CACHE_LINE_FILL) != 0; }
|
void assertMemInhibit() { snoopFlags[MemInhibit] = true; }
|
||||||
bool isNoAllocate() const { return (flags & NO_ALLOCATE) != 0; }
|
void assertShared() { snoopFlags[Shared] = true; }
|
||||||
bool isCompressed() const { return (flags & COMPRESSED) != 0; }
|
bool memInhibitAsserted() { return snoopFlags[MemInhibit]; }
|
||||||
|
bool sharedAsserted() { return snoopFlags[Shared]; }
|
||||||
|
|
||||||
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
|
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
|
||||||
|
|
||||||
|
@ -327,6 +331,8 @@ class Packet
|
||||||
/** Accessor function that returns the source index of the packet. */
|
/** Accessor function that returns the source index of the packet. */
|
||||||
short getSrc() const { assert(srcValid); return src; }
|
short getSrc() const { assert(srcValid); return src; }
|
||||||
void setSrc(short _src) { src = _src; srcValid = true; }
|
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
|
/** Accessor function that returns the destination index of
|
||||||
the packet. */
|
the packet. */
|
||||||
|
@ -347,13 +353,12 @@ class Packet
|
||||||
Packet(Request *_req, MemCmd _cmd, short _dest)
|
Packet(Request *_req, MemCmd _cmd, short _dest)
|
||||||
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
|
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
|
||||||
addr(_req->paddr), size(_req->size), dest(_dest),
|
addr(_req->paddr), size(_req->size), dest(_dest),
|
||||||
addrSizeValid(_req->validPaddr),
|
addrSizeValid(_req->validPaddr), srcValid(false),
|
||||||
srcValid(false),
|
snoopFlags(0),
|
||||||
|
time(curTick),
|
||||||
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
|
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
|
||||||
result(Unknown)
|
result(Unknown)
|
||||||
{
|
{
|
||||||
flags = 0;
|
|
||||||
time = curTick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Alternate constructor if you are trying to create a packet with
|
/** Alternate constructor if you are trying to create a packet with
|
||||||
|
@ -361,14 +366,32 @@ class Packet
|
||||||
* this allows for overriding the size/addr of the req.*/
|
* this allows for overriding the size/addr of the req.*/
|
||||||
Packet(Request *_req, MemCmd _cmd, short _dest, int _blkSize)
|
Packet(Request *_req, MemCmd _cmd, short _dest, int _blkSize)
|
||||||
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
|
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
|
||||||
addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize),
|
addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize), dest(_dest),
|
||||||
dest(_dest),
|
|
||||||
addrSizeValid(_req->validPaddr), srcValid(false),
|
addrSizeValid(_req->validPaddr), srcValid(false),
|
||||||
|
snoopFlags(0),
|
||||||
|
time(curTick),
|
||||||
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
|
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
|
||||||
result(Unknown)
|
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. */
|
/** Destructor. */
|
||||||
|
@ -382,7 +405,7 @@ class Packet
|
||||||
* multiple transactions. */
|
* multiple transactions. */
|
||||||
void reinitFromRequest() {
|
void reinitFromRequest() {
|
||||||
assert(req->validPaddr);
|
assert(req->validPaddr);
|
||||||
flags = 0;
|
snoopFlags = 0;
|
||||||
addr = req->paddr;
|
addr = req->paddr;
|
||||||
size = req->size;
|
size = req->size;
|
||||||
time = req->time;
|
time = req->time;
|
||||||
|
@ -395,29 +418,40 @@ class Packet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Take a request packet and modify it in place to be suitable
|
/**
|
||||||
* for returning as a response to that request. Used for timing
|
* Take a request packet and modify it in place to be suitable for
|
||||||
* accesses only. For atomic and functional accesses, the
|
* returning as a response to that request. The source and
|
||||||
* request packet is always implicitly passed back *without*
|
* destination fields are *not* modified, as is appropriate for
|
||||||
* modifying the destination fields, so this function
|
* atomic accesses.
|
||||||
* should not be called. */
|
*/
|
||||||
void makeTimingResponse() {
|
void makeAtomicResponse()
|
||||||
|
{
|
||||||
assert(needsResponse());
|
assert(needsResponse());
|
||||||
assert(isRequest());
|
assert(isRequest());
|
||||||
|
assert(result == Unknown);
|
||||||
cmd = cmd.responseCommand();
|
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;
|
dest = src;
|
||||||
srcValid = false;
|
srcValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a request packet and modify it in place to be suitable for
|
* 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());
|
makeAtomicResponse();
|
||||||
assert(isRequest());
|
convertAtomicToTimingResponse();
|
||||||
cmd = cmd.responseCommand();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -493,6 +527,40 @@ class Packet
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void set(T v);
|
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
|
* delete the data pointed to in the data pointer. Ok to call to
|
||||||
* matter how data was allocted.
|
* matter how data was allocted.
|
||||||
|
@ -504,15 +572,35 @@ class Packet
|
||||||
|
|
||||||
/** Do the packet modify the same addresses. */
|
/** Do the packet modify the same addresses. */
|
||||||
bool intersect(PacketPtr p);
|
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
|
/** Temporary for backwards compatibility.
|
||||||
* functional packet should continue to traverse the memory hierarchy
|
|
||||||
* or not.
|
|
||||||
*/
|
*/
|
||||||
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
|
/** This function is a wrapper for the fixPacket field that toggles
|
||||||
* the hasData bit it is used when a response is waiting in the
|
* the hasData bit it is used when a response is waiting in the
|
||||||
|
|
|
@ -58,8 +58,9 @@ PhysicalMemory::PhysicalMemory(Params *p)
|
||||||
panic("Memory Size not divisible by page size\n");
|
panic("Memory Size not divisible by page size\n");
|
||||||
|
|
||||||
int map_flags = MAP_ANON | MAP_PRIVATE;
|
int map_flags = MAP_ANON | MAP_PRIVATE;
|
||||||
pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
|
pmemAddr =
|
||||||
map_flags, -1, 0);
|
(uint8_t *)mmap(NULL, params()->addrRange.size(),
|
||||||
|
PROT_READ | PROT_WRITE, map_flags, -1, 0);
|
||||||
|
|
||||||
if (pmemAddr == (void *)MAP_FAILED) {
|
if (pmemAddr == (void *)MAP_FAILED) {
|
||||||
perror("mmap");
|
perror("mmap");
|
||||||
|
@ -121,8 +122,9 @@ PhysicalMemory::calculateLatency(PacketPtr pkt)
|
||||||
// Add load-locked to tracking list. Should only be called if the
|
// Add load-locked to tracking list. Should only be called if the
|
||||||
// operation is a load and the LOCKED flag is set.
|
// operation is a load and the LOCKED flag is set.
|
||||||
void
|
void
|
||||||
PhysicalMemory::trackLoadLocked(Request *req)
|
PhysicalMemory::trackLoadLocked(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
Request *req = pkt->req;
|
||||||
Addr paddr = LockedAddr::mask(req->getPaddr());
|
Addr paddr = LockedAddr::mask(req->getPaddr());
|
||||||
|
|
||||||
// first we check if we already have a locked addr for this
|
// 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
|
// conflict with locked addresses, and for success/failure of store
|
||||||
// conditionals.
|
// conditionals.
|
||||||
bool
|
bool
|
||||||
PhysicalMemory::checkLockedAddrList(Request *req)
|
PhysicalMemory::checkLockedAddrList(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
Request *req = pkt->req;
|
||||||
Addr paddr = LockedAddr::mask(req->getPaddr());
|
Addr paddr = LockedAddr::mask(req->getPaddr());
|
||||||
bool isLocked = req->isLocked();
|
bool isLocked = pkt->isLocked();
|
||||||
|
|
||||||
// Initialize return value. Non-conditional stores always
|
// Initialize return value. Non-conditional stores always
|
||||||
// succeed. Assume conditional stores will fail until proven
|
// succeed. Assume conditional stores will fail until proven
|
||||||
|
@ -198,74 +201,50 @@ PhysicalMemory::checkLockedAddrList(Request *req)
|
||||||
return success;
|
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() &&
|
assert(pkt->getAddr() >= start() &&
|
||||||
pkt->getAddr() + pkt->getSize() <= start() + size());
|
pkt->getAddr() + pkt->getSize() <= start() + size());
|
||||||
|
|
||||||
if (pkt->isRead()) {
|
if (pkt->memInhibitAsserted()) {
|
||||||
if (pkt->req->isLocked()) {
|
DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
|
||||||
trackLoadLocked(pkt->req);
|
pkt->getAddr());
|
||||||
}
|
return 0;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
else if (pkt->isWrite()) {
|
|
||||||
if (writeOK(pkt->req)) {
|
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
|
||||||
memcpy(pmemAddr + pkt->getAddr() - start(), pkt->getPtr<uint8_t>(),
|
|
||||||
pkt->getSize());
|
if (pkt->cmd == MemCmd::SwapReq) {
|
||||||
#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()) {
|
|
||||||
IntReg overwrite_val;
|
IntReg overwrite_val;
|
||||||
bool overwrite_mem;
|
bool overwrite_mem;
|
||||||
uint64_t condition_val64;
|
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
|
// keep a copy of our possible write value, and copy what is at the
|
||||||
// memory address into the packet
|
// memory address into the packet
|
||||||
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
|
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
|
||||||
std::memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
|
std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
||||||
pkt->getSize());
|
|
||||||
|
|
||||||
if (pkt->req->isCondSwap()) {
|
if (pkt->req->isCondSwap()) {
|
||||||
if (pkt->getSize() == sizeof(uint64_t)) {
|
if (pkt->getSize() == sizeof(uint64_t)) {
|
||||||
condition_val64 = pkt->req->getExtraData();
|
condition_val64 = pkt->req->getExtraData();
|
||||||
overwrite_mem = !std::memcmp(&condition_val64, pmemAddr +
|
overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
|
||||||
pkt->getAddr() - start(), sizeof(uint64_t));
|
sizeof(uint64_t));
|
||||||
} else if (pkt->getSize() == sizeof(uint32_t)) {
|
} else if (pkt->getSize() == sizeof(uint32_t)) {
|
||||||
condition_val32 = (uint32_t)pkt->req->getExtraData();
|
condition_val32 = (uint32_t)pkt->req->getExtraData();
|
||||||
overwrite_mem = !std::memcmp(&condition_val32, pmemAddr +
|
overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
|
||||||
pkt->getAddr() - start(), sizeof(uint32_t));
|
sizeof(uint32_t));
|
||||||
} else
|
} else
|
||||||
panic("Invalid size for conditional read/write\n");
|
panic("Invalid size for conditional read/write\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overwrite_mem)
|
if (overwrite_mem)
|
||||||
std::memcpy(pmemAddr + pkt->getAddr() - start(),
|
std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
|
||||||
&overwrite_val, pkt->getSize());
|
|
||||||
|
|
||||||
#if TRACING_ON
|
TRACE_PACKET("Read/Write");
|
||||||
switch (pkt->getSize()) {
|
} else if (pkt->isRead()) {
|
||||||
case sizeof(uint64_t):
|
assert(!pkt->isWrite());
|
||||||
DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
|
if (pkt->isLocked()) {
|
||||||
pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
|
trackLoadLocked(pkt);
|
||||||
DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
|
}
|
||||||
overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
|
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
||||||
condition_val64, overwrite_mem ? "happened" : "didn't happen");
|
TRACE_PACKET("Read");
|
||||||
break;
|
} else if (pkt->isWrite()) {
|
||||||
case sizeof(uint32_t):
|
if (writeOK(pkt)) {
|
||||||
DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
|
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
|
||||||
pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
|
TRACE_PACKET("Write");
|
||||||
DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
|
}
|
||||||
overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
|
} else if (pkt->isInvalidate()) {
|
||||||
condition_val32, overwrite_mem ? "happened" : "didn't happen");
|
//upgrade or invalidate
|
||||||
break;
|
if (pkt->needsResponse()) {
|
||||||
case sizeof(uint16_t):
|
pkt->makeAtomicResponse();
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
panic("unimplemented");
|
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;
|
pkt->result = Packet::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Port *
|
Port *
|
||||||
PhysicalMemory::getPort(const std::string &if_name, int idx)
|
PhysicalMemory::getPort(const std::string &if_name, int idx)
|
||||||
{
|
{
|
||||||
|
@ -407,8 +396,7 @@ PhysicalMemory::MemoryPort::deviceBlockSize()
|
||||||
Tick
|
Tick
|
||||||
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
|
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
memory->doFunctionalAccess(pkt);
|
return memory->doAtomicAccess(pkt);
|
||||||
return memory->calculateLatency(pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -112,12 +112,12 @@ class PhysicalMemory : public MemObject
|
||||||
// inline a quick check for an empty locked addr list (hopefully
|
// inline a quick check for an empty locked addr list (hopefully
|
||||||
// the common case), and do the full list search (if necessary) in
|
// the common case), and do the full list search (if necessary) in
|
||||||
// this out-of-line function
|
// 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
|
// Record the address of a load-locked operation so that we can
|
||||||
// clear the execution context's lock flag if a matching store is
|
// clear the execution context's lock flag if a matching store is
|
||||||
// performed
|
// performed
|
||||||
void trackLoadLocked(Request *req);
|
void trackLoadLocked(PacketPtr pkt);
|
||||||
|
|
||||||
// Compare a store address with any locked addresses so we can
|
// Compare a store address with any locked addresses so we can
|
||||||
// clear the lock flag appropriately. Return value set to 'false'
|
// 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
|
// requesting execution context), 'true' otherwise. Note that
|
||||||
// this method must be called on *all* stores since even
|
// this method must be called on *all* stores since even
|
||||||
// non-conditional stores must clear any matching lock addresses.
|
// non-conditional stores must clear any matching lock addresses.
|
||||||
bool writeOK(Request *req) {
|
bool writeOK(PacketPtr pkt) {
|
||||||
|
Request *req = pkt->req;
|
||||||
if (lockedAddrList.empty()) {
|
if (lockedAddrList.empty()) {
|
||||||
// no locked addrs: nothing to check, store_conditional fails
|
// no locked addrs: nothing to check, store_conditional fails
|
||||||
bool isLocked = req->isLocked();
|
bool isLocked = pkt->isLocked();
|
||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
req->setExtraData(0);
|
req->setExtraData(0);
|
||||||
}
|
}
|
||||||
return !isLocked; // only do write if not an sc
|
return !isLocked; // only do write if not an sc
|
||||||
} else {
|
} else {
|
||||||
// iterate over list...
|
// iterate over list...
|
||||||
return checkLockedAddrList(req);
|
return checkLockedAddrList(pkt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +176,7 @@ class PhysicalMemory : public MemObject
|
||||||
unsigned int drain(Event *de);
|
unsigned int drain(Event *de);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Tick doAtomicAccess(PacketPtr pkt);
|
||||||
void doFunctionalAccess(PacketPtr pkt);
|
void doFunctionalAccess(PacketPtr pkt);
|
||||||
virtual Tick calculateLatency(PacketPtr pkt);
|
virtual Tick calculateLatency(PacketPtr pkt);
|
||||||
void recvStatusChange(Port::Status status);
|
void recvStatusChange(Port::Status status);
|
||||||
|
|
|
@ -67,14 +67,17 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
|
||||||
// code to hanldle nacks here, but I'm pretty sure it didn't work
|
// 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
|
// correctly with the drain code, so that would need to be fixed
|
||||||
// if we ever added it back.
|
// 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);
|
Tick latency = recvAtomic(pkt);
|
||||||
// turn packet around to go back to requester if response expected
|
// turn packet around to go back to requester if response expected
|
||||||
if (pkt->needsResponse()) {
|
if (needsResponse) {
|
||||||
pkt->makeTimingResponse();
|
// recvAtomic() should already have turned packet into atomic response
|
||||||
|
assert(pkt->isResponse());
|
||||||
|
pkt->convertAtomicToTimingResponse();
|
||||||
schedSendTiming(pkt, curTick + latency);
|
schedSendTiming(pkt, curTick + latency);
|
||||||
}
|
} else {
|
||||||
else if (pkt->cmd != MemCmd::UpgradeReq) {
|
|
||||||
delete pkt->req;
|
delete pkt->req;
|
||||||
delete pkt;
|
delete pkt;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue