2006-06-28 17:02:14 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are
|
|
|
|
* met: redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer;
|
|
|
|
* redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution;
|
|
|
|
* neither the name of the copyright holders nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived from
|
|
|
|
* this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* Authors: Erik Hallnor
|
|
|
|
* Dave Greene
|
|
|
|
* Nathan Binkert
|
2007-05-19 07:35:04 +02:00
|
|
|
* Steve Reinhardt
|
|
|
|
* Ron Dreslinski
|
2006-06-28 17:02:14 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* Cache definitions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
2007-01-27 00:48:51 +01:00
|
|
|
#include <cstring>
|
2006-06-28 17:02:14 +02:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "sim/host.hh"
|
|
|
|
#include "base/misc.hh"
|
|
|
|
#include "cpu/smt.hh"
|
|
|
|
|
|
|
|
#include "mem/cache/cache.hh"
|
|
|
|
#include "mem/cache/cache_blk.hh"
|
|
|
|
#include "mem/cache/miss/mshr.hh"
|
2006-12-19 06:53:06 +01:00
|
|
|
#include "mem/cache/prefetch/base_prefetcher.hh"
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-06 07:27:02 +02:00
|
|
|
#include "sim/sim_exit.hh" // for SimExitEvent
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-11-12 15:06:15 +01:00
|
|
|
bool SIGNAL_NACK_HACK;
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2007-05-19 07:35:04 +02:00
|
|
|
Cache<TagStore,Coherence>::Cache(const std::string &_name,
|
|
|
|
Cache<TagStore,Coherence>::Params ¶ms)
|
2006-06-28 23:28:33 +02:00
|
|
|
: BaseCache(_name, params.baseParams),
|
2006-06-28 17:02:14 +02:00
|
|
|
prefetchAccess(params.prefetchAccess),
|
|
|
|
tags(params.tags), missQueue(params.missQueue),
|
|
|
|
coherence(params.coherence), prefetcher(params.prefetcher),
|
2006-12-19 05:47:12 +01:00
|
|
|
hitLatency(params.hitLatency),
|
|
|
|
compressionAlg(params.compressionAlg),
|
|
|
|
blkSize(params.blkSize),
|
|
|
|
doFastWrites(params.doFastWrites),
|
|
|
|
prefetchMiss(params.prefetchMiss),
|
|
|
|
storeCompressed(params.storeCompressed),
|
|
|
|
compressOnWriteback(params.compressOnWriteback),
|
|
|
|
compLatency(params.compLatency),
|
|
|
|
adaptiveCompression(params.adaptiveCompression),
|
|
|
|
writebackCompressed(params.writebackCompressed)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2007-05-19 07:35:04 +02:00
|
|
|
cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this);
|
|
|
|
memSidePort = new MemSidePort(_name + "-mem_side_port", this);
|
|
|
|
cpuSidePort->setOtherPort(memSidePort);
|
|
|
|
memSidePort->setOtherPort(cpuSidePort);
|
|
|
|
|
2006-10-12 20:21:25 +02:00
|
|
|
tags->setCache(this);
|
2006-06-28 17:02:14 +02:00
|
|
|
missQueue->setCache(this);
|
|
|
|
missQueue->setPrefetcher(prefetcher);
|
|
|
|
coherence->setCache(this);
|
|
|
|
prefetcher->setCache(this);
|
2006-10-10 07:32:18 +02:00
|
|
|
invalidateReq = new Request((Addr) NULL, blkSize, 0);
|
2007-02-07 19:53:37 +01:00
|
|
|
invalidatePkt = new Packet(invalidateReq, MemCmd::InvalidateReq, 0);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
void
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::regStats()
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
BaseCache::regStats();
|
|
|
|
tags->regStats(name());
|
|
|
|
missQueue->regStats(name());
|
|
|
|
coherence->regStats(name());
|
|
|
|
prefetcher->regStats(name());
|
|
|
|
}
|
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
typename Cache<TagStore,Coherence>::BlkType*
|
|
|
|
Cache<TagStore,Coherence>::handleAccess(PacketPtr &pkt, int & lat,
|
|
|
|
PacketList & writebacks, bool update)
|
|
|
|
{
|
|
|
|
// Set the block offset here
|
|
|
|
int offset = tags->extractBlkOffset(pkt->getAddr());
|
|
|
|
|
|
|
|
BlkType *blk = NULL;
|
|
|
|
if (update) {
|
2006-12-19 08:07:52 +01:00
|
|
|
blk = tags->findBlock(pkt->getAddr(), lat);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else {
|
|
|
|
blk = tags->findBlock(pkt->getAddr());
|
|
|
|
lat = 0;
|
|
|
|
}
|
|
|
|
if (blk != NULL) {
|
|
|
|
|
|
|
|
if (!update) {
|
2007-03-28 00:05:25 +02:00
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
if (pkt->isWrite()){
|
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset+pkt->getSize() <= blkSize);
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data + offset, pkt->getPtr<uint8_t>(),
|
2006-12-19 05:47:12 +01:00
|
|
|
pkt->getSize());
|
2007-03-28 00:05:25 +02:00
|
|
|
} else if (pkt->isReadWrite()) {
|
|
|
|
cmpAndSwap(blk, pkt);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else if (!(pkt->flags & SATISFIED)) {
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset + pkt->getSize() <=blkSize);
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
|
2006-12-19 05:47:12 +01:00
|
|
|
pkt->getSize());
|
|
|
|
}
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hit
|
|
|
|
if (blk->isPrefetch()) {
|
|
|
|
//Signal that this was a hit under prefetch (no need for
|
|
|
|
//use prefetch (only can get here if true)
|
|
|
|
DPRINTF(HWPrefetch, "Hit a block that was prefetched\n");
|
|
|
|
blk->status &= ~BlkHWPrefetched;
|
|
|
|
if (prefetchMiss) {
|
|
|
|
//If we are using the miss stream, signal the
|
|
|
|
//prefetcher otherwise the access stream would have
|
|
|
|
//already signaled this hit
|
|
|
|
prefetcher->handleMiss(pkt, curTick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-28 00:05:25 +02:00
|
|
|
if ((pkt->isReadWrite() && blk->isWritable()) ||
|
|
|
|
(pkt->isWrite() && blk->isWritable()) ||
|
2006-12-19 05:47:12 +01:00
|
|
|
(pkt->isRead() && blk->isValid())) {
|
|
|
|
|
|
|
|
// We are satisfying the request
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
|
|
|
|
if (blk->isCompressed()) {
|
|
|
|
// If the data is compressed, need to increase the latency
|
|
|
|
lat += (compLatency/4);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool write_data = false;
|
|
|
|
|
|
|
|
assert(verifyData(blk));
|
|
|
|
|
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset+pkt->getSize() <= blkSize);
|
|
|
|
|
|
|
|
if (pkt->isWrite()) {
|
|
|
|
if (blk->checkWrite(pkt->req)) {
|
|
|
|
write_data = true;
|
|
|
|
blk->status |= BlkDirty;
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data + offset, pkt->getPtr<uint8_t>(),
|
2006-12-19 05:47:12 +01:00
|
|
|
pkt->getSize());
|
|
|
|
}
|
2007-03-28 00:05:25 +02:00
|
|
|
} else if (pkt->isReadWrite()) {
|
|
|
|
cmpAndSwap(blk, pkt);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else {
|
|
|
|
assert(pkt->isRead());
|
|
|
|
if (pkt->req->isLocked()) {
|
|
|
|
blk->trackLoadLocked(pkt->req);
|
|
|
|
}
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
|
2007-03-28 00:05:25 +02:00
|
|
|
pkt->getSize());
|
2006-12-19 05:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (write_data ||
|
|
|
|
(adaptiveCompression && blk->isCompressed()))
|
|
|
|
{
|
|
|
|
// If we wrote data, need to update the internal block
|
|
|
|
// data.
|
|
|
|
updateData(blk, writebacks,
|
|
|
|
!(adaptiveCompression &&
|
|
|
|
blk->isReferenced()));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// permission violation, treat it as a miss
|
|
|
|
blk = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// complete miss (no matching block)
|
|
|
|
if (pkt->req->isLocked() && pkt->isWrite()) {
|
|
|
|
// miss on store conditional... just give up now
|
2007-02-12 19:06:30 +01:00
|
|
|
pkt->req->setExtraData(0);
|
2006-12-19 05:47:12 +01:00
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
2007-03-28 00:05:25 +02:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::cmpAndSwap(BlkType *blk, PacketPtr &pkt){
|
|
|
|
uint64_t overwrite_val;
|
|
|
|
bool overwrite_mem;
|
|
|
|
uint64_t condition_val64;
|
|
|
|
uint32_t condition_val32;
|
|
|
|
|
|
|
|
int offset = tags->extractBlkOffset(pkt->getAddr());
|
|
|
|
|
|
|
|
assert(sizeof(uint64_t) >= pkt->getSize());
|
|
|
|
|
|
|
|
overwrite_mem = true;
|
|
|
|
// keep a copy of our possible write value, and copy what is at the
|
|
|
|
// memory address into the packet
|
|
|
|
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
|
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset,
|
|
|
|
pkt->getSize());
|
|
|
|
|
|
|
|
if (pkt->req->isCondSwap()) {
|
|
|
|
if (pkt->getSize() == sizeof(uint64_t)) {
|
|
|
|
condition_val64 = pkt->req->getExtraData();
|
|
|
|
overwrite_mem = !std::memcmp(&condition_val64, blk->data + offset,
|
|
|
|
sizeof(uint64_t));
|
|
|
|
} else if (pkt->getSize() == sizeof(uint32_t)) {
|
|
|
|
condition_val32 = (uint32_t)pkt->req->getExtraData();
|
|
|
|
overwrite_mem = !std::memcmp(&condition_val32, blk->data + offset,
|
|
|
|
sizeof(uint32_t));
|
|
|
|
} else
|
|
|
|
panic("Invalid size for conditional read/write\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overwrite_mem)
|
|
|
|
std::memcpy(blk->data + offset,
|
|
|
|
&overwrite_val, pkt->getSize());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
typename Cache<TagStore,Coherence>::BlkType*
|
|
|
|
Cache<TagStore,Coherence>::handleFill(BlkType *blk, PacketPtr &pkt,
|
|
|
|
CacheBlk::State new_state,
|
|
|
|
PacketList & writebacks,
|
|
|
|
PacketPtr target)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *tmp_blk = tags->findBlock(pkt->getAddr());
|
2006-12-19 05:47:12 +01:00
|
|
|
assert(tmp_blk == blk);
|
|
|
|
#endif
|
|
|
|
blk = doReplacement(blk, pkt, new_state, writebacks);
|
|
|
|
|
|
|
|
|
|
|
|
if (pkt->isRead()) {
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
|
2006-12-19 05:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
blk->whenReady = pkt->finishTime;
|
|
|
|
|
|
|
|
// Respond to target, if any
|
|
|
|
if (target) {
|
|
|
|
|
|
|
|
target->flags |= SATISFIED;
|
|
|
|
|
2007-02-07 19:53:37 +01:00
|
|
|
if (target->cmd == MemCmd::InvalidateReq) {
|
2006-12-19 08:07:52 +01:00
|
|
|
tags->invalidateBlk(blk);
|
2006-12-19 05:47:12 +01:00
|
|
|
blk = NULL;
|
|
|
|
}
|
|
|
|
|
2007-03-28 00:05:25 +02:00
|
|
|
if (blk && ((target->isWrite() || target->isReadWrite()) ?
|
|
|
|
blk->isWritable() : blk->isValid())) {
|
|
|
|
assert(target->isWrite() || target->isReadWrite() || target->isRead());
|
2006-12-19 05:47:12 +01:00
|
|
|
assert(target->getOffset(blkSize) + target->getSize() <= blkSize);
|
|
|
|
if (target->isWrite()) {
|
|
|
|
if (blk->checkWrite(pkt->req)) {
|
|
|
|
blk->status |= BlkDirty;
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data + target->getOffset(blkSize),
|
2006-12-19 05:47:12 +01:00
|
|
|
target->getPtr<uint8_t>(), target->getSize());
|
|
|
|
}
|
2007-03-28 00:05:25 +02:00
|
|
|
} else if (target->isReadWrite()) {
|
2007-03-28 21:38:11 +02:00
|
|
|
cmpAndSwap(blk, target);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else {
|
|
|
|
if (pkt->req->isLocked()) {
|
|
|
|
blk->trackLoadLocked(pkt->req);
|
|
|
|
}
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(target->getPtr<uint8_t>(),
|
2006-12-19 05:47:12 +01:00
|
|
|
blk->data + target->getOffset(blkSize),
|
|
|
|
target->getSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blk) {
|
|
|
|
// Need to write the data into the block
|
|
|
|
updateData(blk, writebacks, !adaptiveCompression || true);
|
|
|
|
}
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
typename Cache<TagStore,Coherence>::BlkType*
|
|
|
|
Cache<TagStore,Coherence>::handleFill(BlkType *blk, MSHR * mshr,
|
|
|
|
CacheBlk::State new_state,
|
|
|
|
PacketList & writebacks, PacketPtr pkt)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
#ifndef NDEBUG
|
|
|
|
BlkType *tmp_blk = findBlock(mshr->pkt->getAddr());
|
|
|
|
assert(tmp_blk == blk);
|
|
|
|
#endif
|
|
|
|
PacketPtr pkt = mshr->pkt;*/
|
|
|
|
blk = doReplacement(blk, pkt, new_state, writebacks);
|
|
|
|
|
|
|
|
if (pkt->isRead()) {
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
|
2006-12-19 05:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
blk->whenReady = pkt->finishTime;
|
|
|
|
|
|
|
|
|
|
|
|
// respond to MSHR targets, if any
|
|
|
|
|
|
|
|
// First offset for critical word first calculations
|
|
|
|
int initial_offset = 0;
|
|
|
|
|
|
|
|
if (mshr->hasTargets()) {
|
|
|
|
initial_offset = mshr->getTarget()->getOffset(blkSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (mshr->hasTargets()) {
|
|
|
|
PacketPtr target = mshr->getTarget();
|
|
|
|
|
|
|
|
target->flags |= SATISFIED;
|
|
|
|
|
|
|
|
// How many bytes pass the first request is this one
|
|
|
|
int transfer_offset = target->getOffset(blkSize) - initial_offset;
|
|
|
|
if (transfer_offset < 0) {
|
|
|
|
transfer_offset += blkSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If critical word (no offset) return first word time
|
|
|
|
Tick completion_time = tags->getHitLatency() +
|
|
|
|
transfer_offset ? pkt->finishTime : pkt->firstWordTime;
|
|
|
|
|
2007-02-07 19:53:37 +01:00
|
|
|
if (target->cmd == MemCmd::InvalidateReq) {
|
2006-12-19 05:47:12 +01:00
|
|
|
//Mark the blk as invalid now, if it hasn't been already
|
|
|
|
if (blk) {
|
2006-12-19 08:07:52 +01:00
|
|
|
tags->invalidateBlk(blk);
|
2006-12-19 05:47:12 +01:00
|
|
|
blk = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Also get rid of the invalidate
|
|
|
|
mshr->popTarget();
|
|
|
|
|
|
|
|
DPRINTF(Cache, "Popping off a Invalidate for addr %x\n",
|
|
|
|
pkt->getAddr());
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-03-28 00:05:25 +02:00
|
|
|
if (blk && ((target->isWrite() || target->isReadWrite()) ?
|
|
|
|
blk->isWritable() : blk->isValid())) {
|
|
|
|
assert(target->isWrite() || target->isRead() || target->isReadWrite() );
|
2006-12-19 05:47:12 +01:00
|
|
|
assert(target->getOffset(blkSize) + target->getSize() <= blkSize);
|
|
|
|
if (target->isWrite()) {
|
|
|
|
if (blk->checkWrite(pkt->req)) {
|
|
|
|
blk->status |= BlkDirty;
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(blk->data + target->getOffset(blkSize),
|
2006-12-19 05:47:12 +01:00
|
|
|
target->getPtr<uint8_t>(), target->getSize());
|
|
|
|
}
|
2007-03-28 00:05:25 +02:00
|
|
|
} else if (target->isReadWrite()) {
|
2007-03-28 21:38:11 +02:00
|
|
|
cmpAndSwap(blk, target);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else {
|
2007-02-06 21:54:44 +01:00
|
|
|
if (target->req->isLocked()) {
|
|
|
|
blk->trackLoadLocked(target->req);
|
2006-12-19 05:47:12 +01:00
|
|
|
}
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(target->getPtr<uint8_t>(),
|
2006-12-19 05:47:12 +01:00
|
|
|
blk->data + target->getOffset(blkSize),
|
|
|
|
target->getSize());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Invalid access, need to do another request
|
|
|
|
// can occur if block is invalidated, or not correct
|
|
|
|
// permissions
|
|
|
|
// mshr->pkt = pkt;
|
|
|
|
break;
|
|
|
|
}
|
2007-05-19 07:35:04 +02:00
|
|
|
if (!target->req->isUncacheable()) {
|
|
|
|
missLatency[target->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
|
|
|
|
completion_time - target->time;
|
|
|
|
}
|
|
|
|
respond(target, completion_time);
|
2006-12-19 05:47:12 +01:00
|
|
|
mshr->popTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blk) {
|
|
|
|
// Need to write the data into the block
|
|
|
|
updateData(blk, writebacks, !adaptiveCompression || true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::handleSnoop(BlkType *blk,
|
|
|
|
CacheBlk::State new_state,
|
|
|
|
PacketPtr &pkt)
|
|
|
|
{
|
|
|
|
//Must have the block to supply
|
|
|
|
assert(blk);
|
|
|
|
// Can only supply data, and if it hasn't already been supllied
|
|
|
|
assert(pkt->isRead());
|
|
|
|
assert(!(pkt->flags & SATISFIED));
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
Addr offset = pkt->getOffset(blkSize);
|
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset + pkt->getSize() <=blkSize);
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), blk->data + offset, pkt->getSize());
|
2006-12-19 05:47:12 +01:00
|
|
|
|
|
|
|
handleSnoop(blk, new_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::handleSnoop(BlkType *blk,
|
|
|
|
CacheBlk::State new_state)
|
|
|
|
{
|
|
|
|
if (blk && blk->status != new_state) {
|
|
|
|
if ((new_state && BlkValid) == 0) {
|
2006-12-19 08:07:52 +01:00
|
|
|
tags->invalidateBlk(blk);
|
2006-12-19 05:47:12 +01:00
|
|
|
} else {
|
|
|
|
assert(new_state >= 0 && new_state < 128);
|
|
|
|
blk->status = new_state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
PacketPtr
|
|
|
|
Cache<TagStore,Coherence>::writebackBlk(BlkType *blk)
|
|
|
|
{
|
|
|
|
assert(blk && blk->isValid() && blk->isModified());
|
|
|
|
int data_size = blkSize;
|
|
|
|
data_size = blk->size;
|
|
|
|
if (compressOnWriteback) {
|
|
|
|
// not already compressed
|
|
|
|
// need to compress to ship it
|
|
|
|
assert(data_size == blkSize);
|
|
|
|
uint8_t *tmp_data = new uint8_t[blkSize];
|
|
|
|
data_size = compressionAlg->compress(tmp_data,blk->data,
|
|
|
|
data_size);
|
|
|
|
delete [] tmp_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PacketPtr writeback =
|
|
|
|
buildWritebackReq(tags->regenerateBlkAddr(blk->tag, blk->set),
|
|
|
|
blk->asid, blkSize,
|
|
|
|
blk->data, data_size);
|
|
|
|
*/
|
|
|
|
|
|
|
|
Request *writebackReq =
|
|
|
|
new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0);
|
2007-02-07 19:53:37 +01:00
|
|
|
PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback, -1);
|
2006-12-19 05:47:12 +01:00
|
|
|
writeback->allocate();
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(writeback->getPtr<uint8_t>(),blk->data,blkSize);
|
2006-12-19 05:47:12 +01:00
|
|
|
|
|
|
|
blk->status &= ~BlkDirty;
|
|
|
|
return writeback;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
bool
|
|
|
|
Cache<TagStore,Coherence>::verifyData(BlkType *blk)
|
|
|
|
{
|
|
|
|
bool retval;
|
|
|
|
// The data stored in the blk
|
|
|
|
uint8_t *blk_data = new uint8_t[blkSize];
|
|
|
|
tags->readData(blk, blk_data);
|
|
|
|
// Pointer for uncompressed data, assumed uncompressed
|
|
|
|
uint8_t *tmp_data = blk_data;
|
|
|
|
// The size of the data being stored, assumed uncompressed
|
|
|
|
int data_size = blkSize;
|
|
|
|
|
|
|
|
// If the block is compressed need to uncompress to access
|
|
|
|
if (blk->isCompressed()){
|
|
|
|
// Allocate new storage for the data
|
|
|
|
tmp_data = new uint8_t[blkSize];
|
|
|
|
data_size = compressionAlg->uncompress(tmp_data,blk_data, blk->size);
|
|
|
|
assert(data_size == blkSize);
|
|
|
|
// Don't need to keep blk_data around
|
|
|
|
delete [] blk_data;
|
|
|
|
} else {
|
|
|
|
assert(blkSize == blk->size);
|
|
|
|
}
|
|
|
|
|
2007-01-27 00:48:51 +01:00
|
|
|
retval = std::memcmp(tmp_data, blk->data, blkSize) == 0;
|
2006-12-19 05:47:12 +01:00
|
|
|
delete [] tmp_data;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::updateData(BlkType *blk, PacketList &writebacks,
|
|
|
|
bool compress_block)
|
|
|
|
{
|
|
|
|
if (storeCompressed && compress_block) {
|
|
|
|
uint8_t *comp_data = new uint8_t[blkSize];
|
|
|
|
int new_size = compressionAlg->compress(comp_data, blk->data, blkSize);
|
|
|
|
if (new_size > (blkSize - tags->getSubBlockSize())){
|
|
|
|
// no benefit to storing it compressed
|
|
|
|
blk->status &= ~BlkCompressed;
|
|
|
|
tags->writeData(blk, blk->data, blkSize,
|
|
|
|
writebacks);
|
|
|
|
} else {
|
|
|
|
// Store the data compressed
|
|
|
|
blk->status |= BlkCompressed;
|
|
|
|
tags->writeData(blk, comp_data, new_size,
|
|
|
|
writebacks);
|
|
|
|
}
|
|
|
|
delete [] comp_data;
|
|
|
|
} else {
|
|
|
|
blk->status &= ~BlkCompressed;
|
|
|
|
tags->writeData(blk, blk->data, blkSize, writebacks);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
typename Cache<TagStore,Coherence>::BlkType*
|
|
|
|
Cache<TagStore,Coherence>::doReplacement(BlkType *blk, PacketPtr &pkt,
|
|
|
|
CacheBlk::State new_state,
|
|
|
|
PacketList &writebacks)
|
|
|
|
{
|
|
|
|
if (blk == NULL) {
|
|
|
|
// need to do a replacement
|
|
|
|
BlkList compress_list;
|
|
|
|
blk = tags->findReplacement(pkt, writebacks, compress_list);
|
|
|
|
while (adaptiveCompression && !compress_list.empty()) {
|
|
|
|
updateData(compress_list.front(), writebacks, true);
|
|
|
|
compress_list.pop_front();
|
|
|
|
}
|
|
|
|
if (blk->isValid()) {
|
|
|
|
DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
|
|
|
|
tags->regenerateBlkAddr(blk->tag,blk->set), pkt->getAddr(),
|
|
|
|
(blk->isModified()) ? "writeback" : "clean");
|
|
|
|
|
|
|
|
if (blk->isModified()) {
|
|
|
|
// Need to write the data back
|
|
|
|
writebacks.push_back(writebackBlk(blk));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
blk->tag = tags->extractTag(pkt->getAddr(), blk);
|
|
|
|
} else {
|
|
|
|
// must be a status change
|
|
|
|
// assert(blk->status != new_state);
|
|
|
|
if (blk->status == new_state) warn("Changing state to same value\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
blk->status = new_state;
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 23:28:33 +02:00
|
|
|
bool
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::access(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
//@todo Add back in MemDebug Calls
|
|
|
|
// MemDebug::cacheAccess(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
BlkType *blk = NULL;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-06-28 17:02:14 +02:00
|
|
|
int size = blkSize;
|
|
|
|
int lat = hitLatency;
|
|
|
|
if (prefetchAccess) {
|
|
|
|
//We are determining prefetches on access stream, call prefetcher
|
|
|
|
prefetcher->handleMiss(pkt, curTick);
|
|
|
|
}
|
2007-03-23 18:09:37 +01:00
|
|
|
|
|
|
|
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
|
|
|
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2007-03-23 18:09:37 +01:00
|
|
|
if (!missQueue->findMSHR(blk_addr)) {
|
|
|
|
blk = handleAccess(pkt, lat, writebacks);
|
|
|
|
}
|
2006-06-28 17:02:14 +02:00
|
|
|
} else {
|
2006-06-29 22:07:19 +02:00
|
|
|
size = pkt->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
// If this is a block size write/hint (WH64) allocate the block here
|
|
|
|
// if the coherence protocol allows it.
|
|
|
|
/** @todo make the fast write alloc (wh64) work with coherence. */
|
|
|
|
/** @todo Do we want to do fast writes for writebacks as well? */
|
2006-06-29 22:07:19 +02:00
|
|
|
if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
|
2007-02-07 19:53:37 +01:00
|
|
|
(pkt->cmd == MemCmd::WriteReq
|
|
|
|
|| pkt->cmd == MemCmd::WriteInvalidateReq) ) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// not outstanding misses, can do this
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR* outstanding_miss = missQueue->findMSHR(pkt->getAddr());
|
2007-02-07 19:53:37 +01:00
|
|
|
if (pkt->cmd == MemCmd::WriteInvalidateReq || !outstanding_miss) {
|
2006-06-28 17:02:14 +02:00
|
|
|
if (outstanding_miss) {
|
|
|
|
warn("WriteInv doing a fastallocate"
|
|
|
|
"with an outstanding miss to the same address\n");
|
|
|
|
}
|
2006-12-19 05:47:12 +01:00
|
|
|
blk = handleFill(NULL, pkt, BlkValid | BlkWritable,
|
2006-06-28 17:02:14 +02:00
|
|
|
writebacks);
|
|
|
|
++fastWrites;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (!writebacks.empty()) {
|
2007-03-12 19:15:32 +01:00
|
|
|
PacketPtr wbPkt = writebacks.front();
|
|
|
|
missQueue->doWriteback(wbPkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
writebacks.pop_front();
|
2007-03-12 19:15:32 +01:00
|
|
|
delete wbPkt;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
2006-10-23 06:07:38 +02:00
|
|
|
|
|
|
|
DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(), pkt->getAddr(),
|
|
|
|
(blk) ? "hit" : "miss");
|
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
if (blk) {
|
|
|
|
// Hit
|
2006-10-06 05:28:03 +02:00
|
|
|
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
// clear dirty bit if write through
|
2007-03-12 21:59:54 +01:00
|
|
|
respond(pkt, curTick+lat);
|
2006-06-28 23:28:33 +02:00
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Miss
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-10-06 05:28:03 +02:00
|
|
|
misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
/** @todo Move miss count code into BaseCache */
|
|
|
|
if (missCount) {
|
|
|
|
--missCount;
|
|
|
|
if (missCount == 0)
|
2006-10-06 07:27:02 +02:00
|
|
|
exitSimLoop("A cache reached the maximum miss count");
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-22 02:19:33 +02:00
|
|
|
|
2006-10-22 08:35:00 +02:00
|
|
|
if (pkt->flags & SATISFIED) {
|
|
|
|
// happens when a store conditional fails because it missed
|
|
|
|
// the cache completely
|
2007-03-12 21:59:54 +01:00
|
|
|
respond(pkt, curTick+lat);
|
2006-10-22 08:35:00 +02:00
|
|
|
} else {
|
2006-10-22 02:19:33 +02:00
|
|
|
missQueue->handleMiss(pkt, size, curTick + hitLatency);
|
|
|
|
}
|
|
|
|
|
2007-03-12 21:59:54 +01:00
|
|
|
if (!pkt->needsResponse()) {
|
2006-11-12 15:06:15 +01:00
|
|
|
//Need to clean up the packet on a writeback miss, but leave the request
|
2007-03-12 21:59:54 +01:00
|
|
|
//for the next level.
|
2006-11-12 15:06:15 +01:00
|
|
|
delete pkt;
|
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::getPacket()
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-10-10 07:32:18 +02:00
|
|
|
assert(missQueue->havePending());
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr pkt = missQueue->getPacket();
|
2006-06-28 17:02:14 +02:00
|
|
|
if (pkt) {
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2007-02-07 19:53:37 +01:00
|
|
|
if (pkt->cmd == MemCmd::HardPFReq)
|
|
|
|
misses[MemCmd::HardPFReq][0/*pkt->req->getThreadNum()*/]++;
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *blk = tags->findBlock(pkt->getAddr());
|
2007-02-07 19:53:37 +01:00
|
|
|
MemCmd cmd =
|
|
|
|
coherence->getBusCmd(pkt->cmd, (blk) ? blk->status : 0);
|
2006-06-28 17:02:14 +02:00
|
|
|
missQueue->setBusCmd(pkt, cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-19 07:35:04 +02:00
|
|
|
assert(!isMemSideBusRequested() || missQueue->havePending());
|
2006-06-28 17:02:14 +02:00
|
|
|
assert(!pkt || pkt->time <= curTick);
|
2006-11-12 15:06:15 +01:00
|
|
|
SIGNAL_NACK_HACK = false;
|
2006-06-28 17:02:14 +02:00
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
void
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::sendResult(PacketPtr &pkt, MSHR* mshr,
|
2006-10-18 17:41:05 +02:00
|
|
|
bool success)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-11-12 15:06:15 +01:00
|
|
|
if (success && !(SIGNAL_NACK_HACK)) {
|
|
|
|
//Remember if it was an upgrade because writeback MSHR's are removed
|
|
|
|
//in Mark in Service
|
2007-02-07 19:53:37 +01:00
|
|
|
bool upgrade = (mshr->pkt && mshr->pkt->cmd == MemCmd::UpgradeReq);
|
2006-11-12 15:06:15 +01:00
|
|
|
|
2006-10-17 21:05:21 +02:00
|
|
|
missQueue->markInService(mshr->pkt, mshr);
|
2006-11-12 15:06:15 +01:00
|
|
|
|
2006-10-10 23:10:56 +02:00
|
|
|
//Temp Hack for UPGRADES
|
2006-11-12 15:06:15 +01:00
|
|
|
if (upgrade) {
|
2006-10-17 21:07:40 +02:00
|
|
|
assert(pkt); //Upgrades need to be fixed
|
2006-10-10 23:10:56 +02:00
|
|
|
pkt->flags &= ~CACHE_LINE_FILL;
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *blk = tags->findBlock(pkt->getAddr());
|
2006-10-10 23:10:56 +02:00
|
|
|
CacheBlk::State old_state = (blk) ? blk->status : 0;
|
|
|
|
CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
|
2006-10-12 00:28:33 +02:00
|
|
|
if (old_state != new_state)
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Block for blk addr %x moving from state "
|
|
|
|
"%i to %i\n", pkt->getAddr(), old_state, new_state);
|
2006-10-10 23:10:56 +02:00
|
|
|
//Set the state on the upgrade
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), blk->data, blkSize);
|
2006-10-10 23:10:56 +02:00
|
|
|
PacketList writebacks;
|
2006-12-19 05:47:12 +01:00
|
|
|
handleFill(blk, mshr, new_state, writebacks, pkt);
|
2006-10-10 23:10:56 +02:00
|
|
|
assert(writebacks.empty());
|
|
|
|
missQueue->handleResponse(pkt, curTick + hitLatency);
|
|
|
|
}
|
2006-06-28 20:35:00 +02:00
|
|
|
} else if (pkt && !pkt->req->isUncacheable()) {
|
2006-10-10 02:18:00 +02:00
|
|
|
pkt->flags &= ~NACKED_LINE;
|
2006-11-12 15:06:15 +01:00
|
|
|
SIGNAL_NACK_HACK = false;
|
2006-10-10 02:18:00 +02:00
|
|
|
pkt->flags &= ~SATISFIED;
|
2006-10-17 22:47:22 +02:00
|
|
|
|
|
|
|
//Rmove copy from mshr
|
|
|
|
delete mshr->pkt;
|
|
|
|
mshr->pkt = pkt;
|
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
missQueue->restoreOrigCmd(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
void
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::handleResponse(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
BlkType *blk = NULL;
|
|
|
|
if (pkt->senderState) {
|
2006-10-17 21:05:21 +02:00
|
|
|
//Delete temp copy in MSHR, restore it.
|
|
|
|
delete ((MSHR*)pkt->senderState)->pkt;
|
2006-10-13 21:47:05 +02:00
|
|
|
((MSHR*)pkt->senderState)->pkt = pkt;
|
2006-10-10 00:52:20 +02:00
|
|
|
if (pkt->result == Packet::Nacked) {
|
2006-10-10 02:18:00 +02:00
|
|
|
//pkt->reinitFromRequest();
|
2006-10-18 17:41:05 +02:00
|
|
|
warn("NACKs from devices not connected to the same bus "
|
|
|
|
"not implemented\n");
|
2006-10-10 02:18:00 +02:00
|
|
|
return;
|
2006-10-10 00:52:20 +02:00
|
|
|
}
|
|
|
|
if (pkt->result == Packet::BadAddress) {
|
|
|
|
//Make the response a Bad address and send it
|
|
|
|
}
|
2006-06-28 23:28:33 +02:00
|
|
|
// MemDebug::cacheResponse(pkt);
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Handling reponse to %x\n", pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
|
2006-11-12 12:36:33 +01:00
|
|
|
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
|
|
|
|
pkt->getAddr());
|
2006-12-19 08:07:52 +01:00
|
|
|
blk = tags->findBlock(pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
CacheBlk::State old_state = (blk) ? blk->status : 0;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-10-09 22:47:55 +02:00
|
|
|
CacheBlk::State new_state = coherence->getNewState(pkt,old_state);
|
2006-10-12 00:28:33 +02:00
|
|
|
if (old_state != new_state)
|
2006-10-18 17:41:05 +02:00
|
|
|
DPRINTF(Cache, "Block for blk addr %x moving from "
|
|
|
|
"state %i to %i\n",
|
2006-10-23 06:07:38 +02:00
|
|
|
pkt->getAddr(),
|
2006-10-18 17:41:05 +02:00
|
|
|
old_state, new_state);
|
2006-12-19 05:47:12 +01:00
|
|
|
blk = handleFill(blk, (MSHR*)pkt->senderState,
|
2006-10-09 22:47:55 +02:00
|
|
|
new_state, writebacks, pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
while (!writebacks.empty()) {
|
2007-03-12 19:15:32 +01:00
|
|
|
PacketPtr wbPkt = writebacks.front();
|
|
|
|
missQueue->doWriteback(wbPkt);
|
|
|
|
writebacks.pop_front();
|
|
|
|
delete wbPkt;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
missQueue->handleResponse(pkt, curTick + hitLatency);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
void
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::snoop(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-10-12 19:33:21 +02:00
|
|
|
if (pkt->req->isUncacheable()) {
|
|
|
|
//Can't get a hit on an uncacheable address
|
|
|
|
//Revisit this for multi level coherence
|
|
|
|
return;
|
|
|
|
}
|
2006-10-20 02:02:57 +02:00
|
|
|
|
|
|
|
//Send a timing (true) invalidate up if the protocol calls for it
|
2006-11-23 02:20:38 +01:00
|
|
|
if (coherence->propogateInvalidate(pkt, true)) {
|
|
|
|
//Temp hack, we had a functional read hit in the L1, mark as success
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
|
|
|
return;
|
|
|
|
}
|
2006-10-20 02:02:57 +02:00
|
|
|
|
2006-06-29 22:07:19 +02:00
|
|
|
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *blk = tags->findBlock(pkt->getAddr());
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR *mshr = missQueue->findMSHR(blk_addr);
|
2006-10-20 02:02:57 +02:00
|
|
|
if (coherence->hasProtocol() || pkt->isInvalidate()) {
|
|
|
|
//@todo Move this into handle bus req
|
2006-10-18 17:41:05 +02:00
|
|
|
//If we find an mshr, and it is in service, we need to NACK or
|
|
|
|
//invalidate
|
2006-06-28 17:02:14 +02:00
|
|
|
if (mshr) {
|
|
|
|
if (mshr->inService) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if ((mshr->pkt->isInvalidate() || !mshr->pkt->isCacheFill())
|
2007-02-07 19:53:37 +01:00
|
|
|
&& (pkt->cmd != MemCmd::InvalidateReq
|
|
|
|
&& pkt->cmd != MemCmd::WriteInvalidateReq)) {
|
2006-10-18 17:41:05 +02:00
|
|
|
//If the outstanding request was an invalidate
|
|
|
|
//(upgrade,readex,..) Then we need to ACK the request
|
|
|
|
//until we get the data Also NACK if the outstanding
|
|
|
|
//request is not a cachefill (writeback)
|
2006-10-09 22:47:55 +02:00
|
|
|
assert(!(pkt->flags & SATISFIED));
|
2006-10-06 03:10:03 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= NACKED_LINE;
|
2006-11-12 15:06:15 +01:00
|
|
|
SIGNAL_NACK_HACK = true;
|
2006-10-10 07:32:18 +02:00
|
|
|
///@todo NACK's from other levels
|
2006-10-18 17:41:05 +02:00
|
|
|
//warn("NACKs from devices not connected to the same bus "
|
|
|
|
//"not implemented\n");
|
2006-10-10 02:18:00 +02:00
|
|
|
//respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
2006-10-18 17:41:05 +02:00
|
|
|
//The supplier will be someone else, because we are
|
|
|
|
//waiting for the data. This should cause this cache to
|
|
|
|
//be forced to go to the shared state, not the exclusive
|
|
|
|
//even though the shared line won't be asserted. But for
|
|
|
|
//now we will just invlidate ourselves and allow the other
|
|
|
|
//cache to go into the exclusive state. @todo Make it so
|
|
|
|
//a read to a pending read doesn't invalidate. @todo Make
|
|
|
|
//it so that a read to a pending read can't be exclusive
|
|
|
|
//now.
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//Set the address so find match works
|
2006-10-10 07:32:18 +02:00
|
|
|
//panic("Don't have invalidates yet\n");
|
2006-06-29 22:07:19 +02:00
|
|
|
invalidatePkt->addrOverride(pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//Append the invalidate on
|
|
|
|
missQueue->addTarget(mshr,invalidatePkt);
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Appending Invalidate to addr: %x\n",
|
|
|
|
pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//We also need to check the writeback buffers and handle those
|
|
|
|
std::vector<MSHR *> writebacks;
|
2006-08-15 22:21:46 +02:00
|
|
|
if (missQueue->findWrites(blk_addr, writebacks)) {
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Snoop hit in writeback to addr: %x\n",
|
|
|
|
pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//Look through writebacks for any non-uncachable writes, use that
|
|
|
|
for (int i=0; i<writebacks.size(); i++) {
|
|
|
|
mshr = writebacks[i];
|
|
|
|
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!mshr->pkt->req->isUncacheable()) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isRead()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Only Upgrades don't get here
|
|
|
|
//Supply the data
|
2006-10-09 22:47:55 +02:00
|
|
|
assert(!(pkt->flags & SATISFIED));
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//If we are in an exclusive protocol, make it ask again
|
|
|
|
//to get write permissions (upgrade), signal shared
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SHARED_LINE;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
assert(pkt->isRead());
|
2006-10-10 07:32:18 +02:00
|
|
|
Addr offset = pkt->getAddr() & (blkSize - 1);
|
2006-06-29 22:07:19 +02:00
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset + pkt->getSize() <=blkSize);
|
2007-01-27 00:48:51 +01:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-06 03:10:03 +02:00
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isInvalidate()) {
|
2006-10-18 17:41:05 +02:00
|
|
|
//This must be an upgrade or other cache will take
|
|
|
|
//ownership
|
2006-10-09 22:37:02 +02:00
|
|
|
missQueue->markInService(mshr->pkt, mshr);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CacheBlk::State new_state;
|
|
|
|
bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
|
2006-11-12 12:44:05 +01:00
|
|
|
|
|
|
|
if (blk && mshr && !mshr->inService && new_state == 0) {
|
|
|
|
//There was a outstanding write to a shared block, not need ReadEx
|
|
|
|
//not update, so change No Allocate param in MSHR
|
|
|
|
mshr->pkt->flags &= ~NO_ALLOCATE;
|
|
|
|
}
|
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
if (satisfy) {
|
2006-10-18 17:41:05 +02:00
|
|
|
DPRINTF(Cache, "Cache snooped a %s request for addr %x and "
|
|
|
|
"now supplying data, new state is %i\n",
|
2006-10-10 07:32:18 +02:00
|
|
|
pkt->cmdString(), blk_addr, new_state);
|
2006-10-09 22:47:55 +02:00
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
handleSnoop(blk, new_state, pkt);
|
2006-10-06 03:10:03 +02:00
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-11-12 12:44:05 +01:00
|
|
|
if (blk)
|
2006-10-18 17:41:05 +02:00
|
|
|
DPRINTF(Cache, "Cache snooped a %s request for addr %x, "
|
|
|
|
"new state is %i\n", pkt->cmdString(), blk_addr, new_state);
|
2006-11-12 12:44:05 +01:00
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
handleSnoop(blk, new_state);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
void
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::snoopResponse(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
//Need to handle the response, if NACKED
|
2006-06-29 22:07:19 +02:00
|
|
|
if (pkt->flags & NACKED_LINE) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Need to mark it as not in service, and retry for bus
|
|
|
|
assert(0); //Yeah, we saw a NACK come through
|
|
|
|
|
2006-10-18 17:41:05 +02:00
|
|
|
//For now this should never get called, we return false when we see a
|
|
|
|
//NACK instead, by doing this we allow the bus_blocked mechanism to
|
|
|
|
//handle the retry For now it retrys in just 2 cycles, need to figure
|
|
|
|
//out how to change that Eventually we will want to also have success
|
|
|
|
//come in as a parameter Need to make sure that we handle the
|
|
|
|
//functionality that happens on successufl return of the sendAddr
|
|
|
|
//function
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @todo Fix to not assume write allocate
|
|
|
|
*/
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
Tick
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::probe(PacketPtr &pkt, bool update,
|
2006-10-18 17:41:05 +02:00
|
|
|
CachePort* otherSidePort)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
// MemDebug::cacheProbe(pkt);
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-10-23 06:07:38 +02:00
|
|
|
if (pkt->isInvalidate() && !pkt->isRead() && !pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Upgrade or Invalidate, satisfy it, don't forward
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr());
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-28 17:02:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-12 12:36:33 +01:00
|
|
|
if (!update && (otherSidePort == cpuSidePort)) {
|
2006-10-20 01:00:27 +02:00
|
|
|
// Still need to change data in all locations.
|
2006-11-11 04:45:50 +01:00
|
|
|
otherSidePort->checkAndSendFunctional(pkt);
|
2006-10-20 01:00:27 +02:00
|
|
|
if (pkt->isRead() && pkt->result == Packet::Success)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-06-28 17:02:14 +02:00
|
|
|
int lat;
|
2006-11-23 02:20:38 +01:00
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
BlkType *blk = handleAccess(pkt, lat, writebacks, update);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(),
|
|
|
|
pkt->getAddr(), (blk) ? "hit" : "miss");
|
2006-10-12 00:28:33 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
|
|
|
|
// Need to check for outstanding misses and writes
|
|
|
|
Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
|
|
|
|
|
|
|
|
// There can only be one matching outstanding miss.
|
|
|
|
MSHR* mshr = missQueue->findMSHR(blk_addr);
|
|
|
|
|
|
|
|
// There can be many matching outstanding writes.
|
|
|
|
std::vector<MSHR*> writes;
|
|
|
|
missQueue->findWrites(blk_addr, writes);
|
|
|
|
|
|
|
|
if (!update) {
|
2006-11-11 04:45:50 +01:00
|
|
|
bool notDone = !(pkt->flags & SATISFIED); //Hit in cache (was a block)
|
2006-10-20 01:00:27 +02:00
|
|
|
// Check for data in MSHR and writebuffer.
|
|
|
|
if (mshr) {
|
|
|
|
MSHR::TargetList *targets = mshr->getTargetList();
|
|
|
|
MSHR::TargetList::iterator i = targets->begin();
|
|
|
|
MSHR::TargetList::iterator end = targets->end();
|
2006-11-11 04:45:50 +01:00
|
|
|
for (; i != end && notDone; ++i) {
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr target = *i;
|
2006-10-20 01:00:27 +02:00
|
|
|
// If the target contains data, and it overlaps the
|
|
|
|
// probed request, need to update data
|
2006-10-20 19:01:21 +02:00
|
|
|
if (target->intersect(pkt)) {
|
2006-11-11 04:45:50 +01:00
|
|
|
DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a MSHR\n",
|
2006-11-12 12:36:33 +01:00
|
|
|
pkt->cmdString(), blk_addr);
|
2006-11-11 04:45:50 +01:00
|
|
|
notDone = fixPacket(pkt, target);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-20 01:00:27 +02:00
|
|
|
}
|
2006-11-11 04:45:50 +01:00
|
|
|
for (int i = 0; i < writes.size() && notDone; ++i) {
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr write = writes[i]->pkt;
|
2006-10-20 01:00:27 +02:00
|
|
|
if (write->intersect(pkt)) {
|
2006-11-11 04:45:50 +01:00
|
|
|
DPRINTF(Cache, "Functional %s access to blk_addr %x intersects a writeback\n",
|
|
|
|
pkt->cmdString(), blk_addr);
|
|
|
|
notDone = fixPacket(pkt, write);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
2006-10-20 01:00:27 +02:00
|
|
|
}
|
2006-11-11 04:45:50 +01:00
|
|
|
if (notDone && otherSidePort == memSidePort) {
|
|
|
|
otherSidePort->checkAndSendFunctional(pkt);
|
2006-10-20 03:07:53 +02:00
|
|
|
assert(pkt->result == Packet::Success);
|
|
|
|
}
|
2006-10-20 02:02:57 +02:00
|
|
|
return 0;
|
2006-10-22 02:19:33 +02:00
|
|
|
} else if (!blk && !(pkt->flags & SATISFIED)) {
|
2006-10-20 01:00:27 +02:00
|
|
|
// update the cache state and statistics
|
|
|
|
if (mshr || !writes.empty()){
|
2006-10-23 05:38:34 +02:00
|
|
|
// Can't handle it, return request unsatisfied.
|
2006-10-20 01:00:27 +02:00
|
|
|
panic("Atomic access ran into outstanding MSHR's or WB's!");
|
|
|
|
}
|
2006-11-23 02:20:38 +01:00
|
|
|
if (!pkt->req->isUncacheable() /*Uncacheables just go through*/
|
2007-02-07 19:53:37 +01:00
|
|
|
&& (pkt->cmd != MemCmd::Writeback)/*Writebacks on miss fall through*/) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// Fetch the cache block to fill
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *blk = tags->findBlock(pkt->getAddr());
|
2007-02-07 19:53:37 +01:00
|
|
|
MemCmd temp_cmd =
|
|
|
|
coherence->getBusCmd(pkt->cmd, (blk) ? blk->status : 0);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr busPkt = new Packet(pkt->req,temp_cmd, -1, blkSize);
|
2006-06-29 22:07:19 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
busPkt->allocate();
|
2006-06-29 22:07:19 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
busPkt->time = curTick;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Sending a atomic %s for %x\n",
|
|
|
|
busPkt->cmdString(), busPkt->getAddr());
|
2006-10-12 00:28:33 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
lat = memSidePort->sendAtomic(busPkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
//Be sure to flip the response to a request for coherence
|
|
|
|
if (busPkt->needsResponse()) {
|
|
|
|
busPkt->makeAtomicResponse();
|
|
|
|
}
|
2006-10-06 05:28:03 +02:00
|
|
|
|
2006-06-30 23:21:58 +02:00
|
|
|
/* if (!(busPkt->flags & SATISFIED)) {
|
2006-10-20 01:00:27 +02:00
|
|
|
// blocked at a higher level, just return
|
|
|
|
return 0;
|
|
|
|
}
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-06 05:28:03 +02:00
|
|
|
*/ misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-20 01:00:27 +02:00
|
|
|
CacheBlk::State old_state = (blk) ? blk->status : 0;
|
|
|
|
CacheBlk::State new_state =
|
|
|
|
coherence->getNewState(busPkt, old_state);
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
|
|
|
|
busPkt->cmdString(), busPkt->getAddr(), old_state);
|
2006-10-20 01:00:27 +02:00
|
|
|
if (old_state != new_state)
|
2006-10-23 06:07:38 +02:00
|
|
|
DPRINTF(Cache, "Block for blk addr %x moving from state "
|
|
|
|
"%i to %i\n", busPkt->getAddr(), old_state, new_state);
|
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
handleFill(blk, busPkt, new_state, writebacks, pkt);
|
2006-10-20 01:00:27 +02:00
|
|
|
//Free the packet
|
|
|
|
delete busPkt;
|
|
|
|
|
|
|
|
// Handle writebacks if needed
|
|
|
|
while (!writebacks.empty()){
|
2006-10-20 09:10:12 +02:00
|
|
|
PacketPtr wbPkt = writebacks.front();
|
2006-10-20 01:00:27 +02:00
|
|
|
memSidePort->sendAtomic(wbPkt);
|
|
|
|
writebacks.pop_front();
|
|
|
|
delete wbPkt;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
2006-10-20 01:00:27 +02:00
|
|
|
return lat + hitLatency;
|
|
|
|
} else {
|
|
|
|
return memSidePort->sendAtomic(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
} else {
|
2006-10-22 02:19:33 +02:00
|
|
|
if (blk) {
|
|
|
|
// There was a cache hit.
|
|
|
|
// Handle writebacks if needed
|
|
|
|
while (!writebacks.empty()){
|
2007-03-12 19:15:32 +01:00
|
|
|
PacketPtr wbPkt = writebacks.front();
|
|
|
|
memSidePort->sendAtomic(wbPkt);
|
2006-10-22 02:19:33 +02:00
|
|
|
writebacks.pop_front();
|
2007-03-12 19:15:32 +01:00
|
|
|
delete wbPkt;
|
2006-10-22 02:19:33 +02:00
|
|
|
}
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-22 02:19:33 +02:00
|
|
|
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
|
|
|
|
}
|
2006-10-20 01:00:27 +02:00
|
|
|
|
2006-10-12 00:28:33 +02:00
|
|
|
return hitLatency;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
2006-10-22 02:19:33 +02:00
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-04 18:10:53 +01:00
|
|
|
template<class TagStore, class Coherence>
|
2006-06-28 17:02:14 +02:00
|
|
|
Tick
|
2006-12-04 18:10:53 +01:00
|
|
|
Cache<TagStore,Coherence>::snoopProbe(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-10-20 02:02:57 +02:00
|
|
|
//Send a atomic (false) invalidate up if the protocol calls for it
|
2006-11-23 02:20:38 +01:00
|
|
|
if (coherence->propogateInvalidate(pkt, false)) {
|
|
|
|
//Temp hack, we had a functional read hit in the L1, mark as success
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
return hitLatency;
|
|
|
|
}
|
2006-10-20 02:02:57 +02:00
|
|
|
|
|
|
|
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
2006-12-19 08:07:52 +01:00
|
|
|
BlkType *blk = tags->findBlock(pkt->getAddr());
|
2006-10-20 02:02:57 +02:00
|
|
|
MSHR *mshr = missQueue->findMSHR(blk_addr);
|
|
|
|
CacheBlk::State new_state = 0;
|
|
|
|
bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
|
|
|
|
if (satisfy) {
|
|
|
|
DPRINTF(Cache, "Cache snooped a %s request for addr %x and "
|
|
|
|
"now supplying data, new state is %i\n",
|
|
|
|
pkt->cmdString(), blk_addr, new_state);
|
2006-10-09 22:47:55 +02:00
|
|
|
|
2006-12-19 05:47:12 +01:00
|
|
|
handleSnoop(blk, new_state, pkt);
|
2006-10-06 05:28:03 +02:00
|
|
|
return hitLatency;
|
2006-10-20 02:02:57 +02:00
|
|
|
}
|
|
|
|
if (blk)
|
|
|
|
DPRINTF(Cache, "Cache snooped a %s request for addr %x, "
|
|
|
|
"new state is %i\n",
|
2006-10-18 17:41:05 +02:00
|
|
|
pkt->cmdString(), blk_addr, new_state);
|
2006-12-19 05:47:12 +01:00
|
|
|
handleSnoop(blk, new_state);
|
2006-10-20 02:02:57 +02:00
|
|
|
return 0;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-12-14 07:04:36 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
Port *
|
|
|
|
Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx)
|
|
|
|
{
|
2007-05-19 07:35:04 +02:00
|
|
|
if (if_name == "" || if_name == "cpu_side") {
|
2006-12-14 07:04:36 +01:00
|
|
|
return cpuSidePort;
|
2007-05-19 07:35:04 +02:00
|
|
|
} else if (if_name == "mem_side") {
|
2006-12-14 07:04:36 +01:00
|
|
|
return memSidePort;
|
2007-05-19 07:35:04 +02:00
|
|
|
} else if (if_name == "functional") {
|
|
|
|
return new CpuSidePort(name() + "-cpu_side_funcport", this);
|
|
|
|
} else {
|
|
|
|
panic("Port name %s unrecognized\n", if_name);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-09 00:57:15 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::deletePortRefs(Port *p)
|
|
|
|
{
|
|
|
|
if (cpuSidePort == p || memSidePort == p)
|
|
|
|
panic("Can only delete functional ports\n");
|
2007-04-04 19:56:38 +02:00
|
|
|
|
|
|
|
delete p;
|
2007-03-09 00:57:15 +01:00
|
|
|
}
|
|
|
|
|
2006-12-14 07:04:36 +01:00
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
bool
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt)
|
|
|
|
{
|
2007-05-10 00:20:24 +02:00
|
|
|
assert(pkt->result != Packet::Nacked);
|
|
|
|
|
2006-12-14 07:04:36 +01:00
|
|
|
if (!pkt->req->isUncacheable()
|
|
|
|
&& pkt->isInvalidate()
|
|
|
|
&& !pkt->isRead() && !pkt->isWrite()) {
|
|
|
|
//Upgrade or Invalidate
|
|
|
|
//Look into what happens if two slave caches on bus
|
|
|
|
DPRINTF(Cache, "%s %x ?\n", pkt->cmdString(), pkt->getAddr());
|
|
|
|
|
|
|
|
assert(!(pkt->flags & SATISFIED));
|
|
|
|
pkt->flags |= SATISFIED;
|
|
|
|
//Invalidates/Upgrades need no response if they get the bus
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->isRequest() && blocked)
|
|
|
|
{
|
|
|
|
DPRINTF(Cache,"Scheduling a retry while blocked\n");
|
|
|
|
mustSendRetry = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->isWrite() && (pkt->req->isLocked())) {
|
2007-02-12 19:06:30 +01:00
|
|
|
pkt->req->setExtraData(1);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
myCache()->access(pkt);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-05-19 07:35:04 +02:00
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::recvRetry()
|
|
|
|
{
|
|
|
|
recvRetryCommon();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::processRequestEvent()
|
|
|
|
{
|
|
|
|
if (waitingOnRetry)
|
|
|
|
return;
|
|
|
|
//We have some responses to drain first
|
|
|
|
if (!drainList.empty()) {
|
|
|
|
if (!drainResponse()) {
|
|
|
|
// more responses to drain... re-request bus
|
|
|
|
scheduleRequestEvent(curTick + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::processResponseEvent()
|
|
|
|
{
|
|
|
|
assert(transmitList.size());
|
|
|
|
assert(transmitList.front().first <= curTick);
|
|
|
|
PacketPtr pkt = transmitList.front().second;
|
|
|
|
transmitList.pop_front();
|
|
|
|
if (!transmitList.empty()) {
|
|
|
|
Tick time = transmitList.front().first;
|
|
|
|
responseEvent->schedule(time <= curTick ? curTick+1 : time);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->flags & NACKED_LINE)
|
|
|
|
pkt->result = Packet::Nacked;
|
|
|
|
else
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
pkt->makeTimingResponse();
|
|
|
|
DPRINTF(CachePort, "%s attempting to send a response\n", name());
|
|
|
|
if (!drainList.empty() || waitingOnRetry) {
|
|
|
|
//Already have a list, just append
|
|
|
|
drainList.push_back(pkt);
|
|
|
|
DPRINTF(CachePort, "%s appending response onto drain list\n", name());
|
|
|
|
}
|
|
|
|
else if (!sendTiming(pkt)) {
|
|
|
|
//It failed, save it to list of drain events
|
|
|
|
DPRINTF(CachePort, "%s now waiting for a retry\n", name());
|
|
|
|
drainList.push_back(pkt);
|
|
|
|
waitingOnRetry = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we're done draining once this list is empty
|
|
|
|
if (drainList.empty() && transmitList.empty())
|
|
|
|
myCache()->checkDrain();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-14 07:04:36 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
Tick
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::recvAtomic(PacketPtr pkt)
|
|
|
|
{
|
|
|
|
myCache()->probe(pkt, true, NULL);
|
|
|
|
//TEMP ALWAYS SUCCES FOR NOW
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
//Fix this timing info
|
|
|
|
return myCache()->hitLatency;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::CpuSidePort::recvFunctional(PacketPtr pkt)
|
|
|
|
{
|
|
|
|
if (checkFunctional(pkt)) {
|
|
|
|
//TEMP USE CPU?THREAD 0 0
|
|
|
|
pkt->req->setThreadContext(0,0);
|
|
|
|
|
|
|
|
myCache()->probe(pkt, false, cache->memSidePort);
|
|
|
|
//TEMP ALWAYS SUCCESFUL FOR NOW
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
bool
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt)
|
|
|
|
{
|
2007-05-10 00:20:24 +02:00
|
|
|
// this needs to be fixed so that the cache updates the mshr and sends the
|
|
|
|
// packet back out on the link, but it probably won't happen so until this
|
|
|
|
// gets fixed, just panic when it does
|
|
|
|
if (pkt->result == Packet::Nacked)
|
|
|
|
panic("Need to implement cache resending nacked packets!\n");
|
|
|
|
|
2007-05-19 07:35:04 +02:00
|
|
|
if (pkt->isRequest() && blocked) {
|
2006-12-14 07:04:36 +01:00
|
|
|
DPRINTF(Cache,"Scheduling a retry while blocked\n");
|
|
|
|
mustSendRetry = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-05-19 07:35:04 +02:00
|
|
|
if (pkt->isResponse()) {
|
2006-12-14 07:04:36 +01:00
|
|
|
myCache()->handleResponse(pkt);
|
2007-05-19 07:35:04 +02:00
|
|
|
} else {
|
|
|
|
myCache()->snoop(pkt);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-05-19 07:35:04 +02:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::recvRetry()
|
|
|
|
{
|
|
|
|
if (recvRetryCommon()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINTF(CachePort, "%s attempting to send a retry for MSHR\n", name());
|
|
|
|
if (!cache->isMemSideBusRequested()) {
|
|
|
|
//This can happen if I am the owner of a block and see an upgrade
|
|
|
|
//while the block was in my WB Buffers. I just remove the
|
|
|
|
//wb and de-assert the masterRequest
|
|
|
|
waitingOnRetry = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PacketPtr pkt = myCache()->getPacket();
|
|
|
|
MSHR* mshr = (MSHR*) pkt->senderState;
|
|
|
|
//Copy the packet, it may be modified/destroyed elsewhere
|
|
|
|
PacketPtr copyPkt = new Packet(*pkt);
|
|
|
|
copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
|
|
|
|
mshr->pkt = copyPkt;
|
|
|
|
|
|
|
|
bool success = sendTiming(pkt);
|
|
|
|
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
|
|
|
|
pkt->getAddr(), success ? "succesful" : "unsuccesful");
|
|
|
|
|
|
|
|
waitingOnRetry = !success;
|
|
|
|
if (waitingOnRetry) {
|
|
|
|
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
|
|
|
}
|
|
|
|
|
|
|
|
myCache()->sendResult(pkt, mshr, success);
|
|
|
|
|
|
|
|
if (success && cache->isMemSideBusRequested())
|
|
|
|
{
|
|
|
|
DPRINTF(CachePort, "%s has more requests\n", name());
|
|
|
|
//Still more to issue, rerequest in 1 cycle
|
|
|
|
new RequestEvent(this, curTick + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::processRequestEvent()
|
|
|
|
{
|
|
|
|
if (waitingOnRetry)
|
|
|
|
return;
|
|
|
|
//We have some responses to drain first
|
|
|
|
if (!drainList.empty()) {
|
|
|
|
if (!drainResponse()) {
|
|
|
|
// more responses to drain... re-request bus
|
|
|
|
scheduleRequestEvent(curTick + 1);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINTF(CachePort, "%s trying to send a MSHR request\n", name());
|
|
|
|
if (!isBusRequested()) {
|
|
|
|
//This can happen if I am the owner of a block and see an upgrade
|
|
|
|
//while the block was in my WB Buffers. I just remove the
|
|
|
|
//wb and de-assert the masterRequest
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PacketPtr pkt = myCache()->getPacket();
|
|
|
|
MSHR* mshr = (MSHR*) pkt->senderState;
|
|
|
|
//Copy the packet, it may be modified/destroyed elsewhere
|
|
|
|
PacketPtr copyPkt = new Packet(*pkt);
|
|
|
|
copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
|
|
|
|
mshr->pkt = copyPkt;
|
|
|
|
|
|
|
|
bool success = sendTiming(pkt);
|
|
|
|
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
|
|
|
|
pkt->getAddr(), success ? "succesful" : "unsuccesful");
|
|
|
|
|
|
|
|
waitingOnRetry = !success;
|
|
|
|
if (waitingOnRetry) {
|
|
|
|
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
|
|
|
}
|
|
|
|
|
|
|
|
myCache()->sendResult(pkt, mshr, success);
|
|
|
|
if (success && isBusRequested())
|
|
|
|
{
|
|
|
|
DPRINTF(CachePort, "%s still more MSHR requests to send\n", name());
|
|
|
|
//Still more to issue, rerequest in 1 cycle
|
|
|
|
scheduleRequestEvent(curTick+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::processResponseEvent()
|
|
|
|
{
|
|
|
|
assert(transmitList.size());
|
|
|
|
assert(transmitList.front().first <= curTick);
|
|
|
|
PacketPtr pkt = transmitList.front().second;
|
|
|
|
transmitList.pop_front();
|
|
|
|
if (!transmitList.empty()) {
|
|
|
|
Tick time = transmitList.front().first;
|
|
|
|
responseEvent->schedule(time <= curTick ? curTick+1 : time);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->flags & NACKED_LINE)
|
|
|
|
pkt->result = Packet::Nacked;
|
|
|
|
else
|
|
|
|
pkt->result = Packet::Success;
|
|
|
|
pkt->makeTimingResponse();
|
|
|
|
DPRINTF(CachePort, "%s attempting to send a response\n", name());
|
|
|
|
if (!drainList.empty() || waitingOnRetry) {
|
|
|
|
//Already have a list, just append
|
|
|
|
drainList.push_back(pkt);
|
|
|
|
DPRINTF(CachePort, "%s appending response onto drain list\n", name());
|
|
|
|
}
|
|
|
|
else if (!sendTiming(pkt)) {
|
|
|
|
//It failed, save it to list of drain events
|
|
|
|
DPRINTF(CachePort, "%s now waiting for a retry\n", name());
|
|
|
|
drainList.push_back(pkt);
|
|
|
|
waitingOnRetry = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we're done draining once this list is empty
|
|
|
|
if (drainList.empty() && transmitList.empty())
|
|
|
|
myCache()->checkDrain();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-14 07:04:36 +01:00
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
Tick
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::recvAtomic(PacketPtr pkt)
|
|
|
|
{
|
|
|
|
if (pkt->isResponse())
|
|
|
|
myCache()->handleResponse(pkt);
|
|
|
|
else
|
|
|
|
return myCache()->snoopProbe(pkt);
|
|
|
|
//Fix this timing info
|
|
|
|
return myCache()->hitLatency;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Coherence>::MemSidePort::recvFunctional(PacketPtr pkt)
|
|
|
|
{
|
2007-05-14 22:14:59 +02:00
|
|
|
myCache()->probe(pkt, false, cache->cpuSidePort);
|
|
|
|
if (pkt->result != Packet::Success)
|
|
|
|
checkFunctional(pkt);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
Cache<TagStore,Coherence>::
|
|
|
|
CpuSidePort::CpuSidePort(const std::string &_name,
|
|
|
|
Cache<TagStore,Coherence> *_cache)
|
2007-05-19 07:35:04 +02:00
|
|
|
: BaseCache::CachePort(_name, _cache)
|
2006-12-14 07:04:36 +01:00
|
|
|
{
|
2007-05-19 07:35:04 +02:00
|
|
|
responseEvent = new ResponseEvent(this);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Coherence>
|
|
|
|
Cache<TagStore,Coherence>::
|
|
|
|
MemSidePort::MemSidePort(const std::string &_name,
|
|
|
|
Cache<TagStore,Coherence> *_cache)
|
2007-05-19 07:35:04 +02:00
|
|
|
: BaseCache::CachePort(_name, _cache)
|
2006-12-14 07:04:36 +01:00
|
|
|
{
|
2007-05-19 07:35:04 +02:00
|
|
|
responseEvent = new ResponseEvent(this);
|
2006-12-14 07:04:36 +01:00
|
|
|
}
|
|
|
|
|