abc76f20cb
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
468 lines
15 KiB
C++
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);
|
|
}
|