gem5/src/mem/cache/coherence/coherence_protocol.cc
Nathan Binkert abc76f20cb Major changes to how SimObjects are created and initialized. Almost all
creation and initialization now happens in python.  Parameter objects
are generated and initialized by python.  The .ini file is now solely for
debugging purposes and is not used in construction of the objects in any
way.

--HG--
extra : convert_revision : 7e722873e417cb3d696f2e34c35ff488b7bff4ed
2007-07-23 21:51:38 -07:00

468 lines
15 KiB
C++

/*
* 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
* Steve Reinhardt
* Ron Dreslinski
*/
/**
* @file
* Definitions of CoherenceProtocol.
*/
#include <string>
#include "base/misc.hh"
#include "mem/cache/miss/mshr.hh"
#include "mem/cache/cache.hh"
#include "mem/cache/coherence/coherence_protocol.hh"
#include "params/CoherenceProtocol.hh"
using namespace std;
CoherenceProtocol::StateTransition::StateTransition()
: busCmd(MemCmd::InvalidCmd), newState(-1), snoopFunc(invalidTransition)
{
}
void
CoherenceProtocol::regStats()
{
// Even though we count all the possible transitions in the
// requestCount and snoopCount arrays, most of these are invalid,
// so we just select the interesting ones to print here.
requestCount[Invalid][MemCmd::ReadReq]
.name(name() + ".read_invalid")
.desc("read misses to invalid blocks")
;
requestCount[Invalid][MemCmd::WriteReq]
.name(name() +".write_invalid")
.desc("write misses to invalid blocks")
;
requestCount[Invalid][MemCmd::SoftPFReq]
.name(name() +".swpf_invalid")
.desc("soft prefetch misses to invalid blocks")
;
requestCount[Invalid][MemCmd::HardPFReq]
.name(name() +".hwpf_invalid")
.desc("hard prefetch misses to invalid blocks")
;
requestCount[Shared][MemCmd::WriteReq]
.name(name() + ".write_shared")
.desc("write misses to shared blocks")
;
requestCount[Owned][MemCmd::WriteReq]
.name(name() + ".write_owned")
.desc("write misses to owned blocks")
;
snoopCount[Shared][MemCmd::ReadReq]
.name(name() + ".snoop_read_shared")
.desc("read snoops on shared blocks")
;
snoopCount[Shared][MemCmd::ReadExReq]
.name(name() + ".snoop_readex_shared")
.desc("readEx snoops on shared blocks")
;
snoopCount[Shared][MemCmd::UpgradeReq]
.name(name() + ".snoop_upgrade_shared")
.desc("upgradee snoops on shared blocks")
;
snoopCount[Modified][MemCmd::ReadReq]
.name(name() + ".snoop_read_modified")
.desc("read snoops on modified blocks")
;
snoopCount[Modified][MemCmd::ReadExReq]
.name(name() + ".snoop_readex_modified")
.desc("readEx snoops on modified blocks")
;
snoopCount[Owned][MemCmd::ReadReq]
.name(name() + ".snoop_read_owned")
.desc("read snoops on owned blocks")
;
snoopCount[Owned][MemCmd::ReadExReq]
.name(name() + ".snoop_readex_owned")
.desc("readEx snoops on owned blocks")
;
snoopCount[Owned][MemCmd::UpgradeReq]
.name(name() + ".snoop_upgrade_owned")
.desc("upgrade snoops on owned blocks")
;
snoopCount[Exclusive][MemCmd::ReadReq]
.name(name() + ".snoop_read_exclusive")
.desc("read snoops on exclusive blocks")
;
snoopCount[Exclusive][MemCmd::ReadExReq]
.name(name() + ".snoop_readex_exclusive")
.desc("readEx snoops on exclusive blocks")
;
snoopCount[Shared][MemCmd::InvalidateReq]
.name(name() + ".snoop_inv_shared")
.desc("Invalidate snoops on shared blocks")
;
snoopCount[Owned][MemCmd::InvalidateReq]
.name(name() + ".snoop_inv_owned")
.desc("Invalidate snoops on owned blocks")
;
snoopCount[Exclusive][MemCmd::InvalidateReq]
.name(name() + ".snoop_inv_exclusive")
.desc("Invalidate snoops on exclusive blocks")
;
snoopCount[Modified][MemCmd::InvalidateReq]
.name(name() + ".snoop_inv_modified")
.desc("Invalidate snoops on modified blocks")
;
snoopCount[Invalid][MemCmd::InvalidateReq]
.name(name() + ".snoop_inv_invalid")
.desc("Invalidate snoops on invalid blocks")
;
snoopCount[Shared][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_shared")
.desc("WriteInvalidate snoops on shared blocks")
;
snoopCount[Owned][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_owned")
.desc("WriteInvalidate snoops on owned blocks")
;
snoopCount[Exclusive][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_exclusive")
.desc("WriteInvalidate snoops on exclusive blocks")
;
snoopCount[Modified][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_modified")
.desc("WriteInvalidate snoops on modified blocks")
;
snoopCount[Invalid][MemCmd::WriteInvalidateReq]
.name(name() + ".snoop_writeinv_invalid")
.desc("WriteInvalidate snoops on invalid blocks")
;
}
bool
CoherenceProtocol::invalidateTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk, MSHR *mshr,
CacheBlk::State & new_state)
{
// invalidate the block
new_state = (blk->status & ~stateMask) | Invalid;
return false;
}
bool
CoherenceProtocol::supplyTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
return true;
}
bool
CoherenceProtocol::supplyAndGotoSharedTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Shared;
pkt->flags |= SHARED_LINE;
return supplyTrans(cache, pkt, blk, mshr, new_state);
}
bool
CoherenceProtocol::supplyAndGotoOwnedTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Owned;
pkt->flags |= SHARED_LINE;
return supplyTrans(cache, pkt, blk, mshr, new_state);
}
bool
CoherenceProtocol::supplyAndInvalidateTrans(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Invalid;
return supplyTrans(cache, pkt, blk, mshr, new_state);
}
bool
CoherenceProtocol::assertShared(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
new_state = (blk->status & ~stateMask) | Shared;
pkt->flags |= SHARED_LINE;
return false;
}
CoherenceProtocol::CoherenceProtocol(const string &name,
Enums::Coherence protocol,
const bool doUpgrades)
: SimObject(name)
{
bool hasOwned = (protocol == Enums::mosi || protocol == Enums::moesi);
bool hasExclusive = (protocol == Enums::mesi || protocol == Enums::moesi);
if (hasOwned && !doUpgrades) {
fatal("CoherenceProtocol: ownership protocols require upgrade "
"transactions\n(write miss on owned block generates ReadExcl, "
"which will clobber dirty block)\n");
}
// set up a few shortcuts to save typing & visual clutter
typedef MemCmd MC;
StateTransition (&tt)[stateMax+1][MC::NUM_MEM_CMDS] = transitionTable;
MC::Command writeToSharedCmd =
doUpgrades ? MC::UpgradeReq : MC::ReadExReq;
MC::Command writeToSharedResp =
doUpgrades ? MC::UpgradeReq : MC::ReadExResp;
// Note that all transitions by default cause a panic.
// Override the valid transitions with the appropriate actions here.
//
// ----- incoming requests: specify outgoing bus request -----
//
tt[Invalid][MC::ReadReq].onRequest(MC::ReadReq);
// we only support write allocate right now
tt[Invalid][MC::WriteReq].onRequest(MC::ReadExReq);
tt[Invalid][MC::SwapReq].onRequest(MC::ReadExReq);
tt[Shared][MC::WriteReq].onRequest(writeToSharedCmd);
tt[Shared][MC::SwapReq].onRequest(writeToSharedCmd);
if (hasOwned) {
tt[Owned][MC::WriteReq].onRequest(writeToSharedCmd);
tt[Owned][MC::SwapReq].onRequest(writeToSharedCmd);
}
// Prefetching causes a read
tt[Invalid][MC::SoftPFReq].onRequest(MC::ReadReq);
tt[Invalid][MC::HardPFReq].onRequest(MC::ReadReq);
//
// ----- on response to given request: specify new state -----
//
tt[Invalid][MC::ReadExResp].onResponse(Modified);
tt[Shared][writeToSharedResp].onResponse(Modified);
// Go to Exclusive state on read response if we have one (will
// move into shared if the shared line is asserted in the
// getNewState function)
//
// originally had this as:
// tt[Invalid][MC::ReadResp].onResponse(hasExclusive ? Exclusive: Shared);
// ...but for some reason that caused a link error...
if (hasExclusive) {
tt[Invalid][MC::ReadResp].onResponse(Exclusive);
} else {
tt[Invalid][MC::ReadResp].onResponse(Shared);
}
if (hasOwned) {
tt[Owned][writeToSharedResp].onResponse(Modified);
}
//
// ----- bus snoop transition functions -----
//
tt[Invalid][MC::ReadReq].onSnoop(nullTransition);
tt[Invalid][MC::ReadExReq].onSnoop(nullTransition);
tt[Invalid][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Invalid][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
tt[Shared][MC::ReadReq].onSnoop(hasExclusive
? assertShared : nullTransition);
tt[Shared][MC::ReadExReq].onSnoop(invalidateTrans);
tt[Shared][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Shared][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
if (doUpgrades) {
tt[Invalid][MC::UpgradeReq].onSnoop(nullTransition);
tt[Shared][MC::UpgradeReq].onSnoop(invalidateTrans);
}
tt[Modified][MC::ReadExReq].onSnoop(supplyAndInvalidateTrans);
tt[Modified][MC::ReadReq].onSnoop(hasOwned
? supplyAndGotoOwnedTrans
: supplyAndGotoSharedTrans);
tt[Modified][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Modified][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
if (hasExclusive) {
tt[Exclusive][MC::ReadReq].onSnoop(assertShared);
tt[Exclusive][MC::ReadExReq].onSnoop(invalidateTrans);
tt[Exclusive][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Exclusive][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
}
if (hasOwned) {
tt[Owned][MC::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
tt[Owned][MC::ReadExReq].onSnoop(supplyAndInvalidateTrans);
tt[Owned][MC::UpgradeReq].onSnoop(invalidateTrans);
tt[Owned][MC::InvalidateReq].onSnoop(invalidateTrans);
tt[Owned][MC::WriteInvalidateReq].onSnoop(invalidateTrans);
}
// @todo add in hardware prefetch to this list
}
MemCmd
CoherenceProtocol::getBusCmd(MemCmd cmdIn, CacheBlk::State state,
MSHR *mshr)
{
state &= stateMask;
int cmd_idx = cmdIn.toInt();
assert(0 <= state && state <= stateMax);
assert(0 <= cmd_idx && cmd_idx < MemCmd::NUM_MEM_CMDS);
MemCmd::Command cmdOut = transitionTable[state][cmd_idx].busCmd;
assert(cmdOut != MemCmd::InvalidCmd);
++requestCount[state][cmd_idx];
return cmdOut;
}
CacheBlk::State
CoherenceProtocol::getNewState(PacketPtr &pkt, CacheBlk::State oldState)
{
CacheBlk::State state = oldState & stateMask;
int cmd_idx = pkt->cmdToIndex();
assert(0 <= state && state <= stateMax);
assert(0 <= cmd_idx && cmd_idx < MemCmd::NUM_MEM_CMDS);
CacheBlk::State newState = transitionTable[state][cmd_idx].newState;
//Check if it's exclusive and the shared line was asserted,
//then goto shared instead
if (newState == Exclusive && (pkt->flags & SHARED_LINE)) {
newState = Shared;
}
assert(newState != -1);
//Make sure not to loose any other state information
newState = (oldState & ~stateMask) | newState;
return newState;
}
bool
CoherenceProtocol::handleBusRequest(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk,
MSHR *mshr,
CacheBlk::State & new_state)
{
if (blk == NULL) {
// nothing to do if we don't have a block
return false;
}
CacheBlk::State state = blk->status & stateMask;
int cmd_idx = pkt->cmdToIndex();
assert(0 <= state && state <= stateMax);
assert(0 <= cmd_idx && cmd_idx < MemCmd::NUM_MEM_CMDS);
// assert(mshr == NULL); // can't currently handle outstanding requests
//Check first if MSHR, and also insure, if there is one, that it is not in service
assert(!mshr || mshr->inService == 0);
++snoopCount[state][cmd_idx];
bool ret = transitionTable[state][cmd_idx].snoopFunc(cache, pkt, blk, mshr,
new_state);
return ret;
}
bool
CoherenceProtocol::nullTransition(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk, MSHR *mshr,
CacheBlk::State & new_state)
{
// do nothing
if (blk)
new_state = blk->status;
return false;
}
bool
CoherenceProtocol::invalidTransition(BaseCache *cache, PacketPtr &pkt,
CacheBlk *blk, MSHR *mshr,
CacheBlk::State & new_state)
{
panic("Invalid transition");
return false;
}
CoherenceProtocol *
CoherenceProtocolParams::create()
{
return new CoherenceProtocol(name, protocol, do_upgrades);
}