839 lines
26 KiB
Text
839 lines
26 KiB
Text
|
|
||
|
/*
|
||
|
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* $Id: MOSI_directory_1level-cache.sm 1.18 04/09/07 13:52:52-05:00 mikem@maya.cs.wisc.edu $
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
machine(L1Cache, "MOSI Directory Optimized") {
|
||
|
|
||
|
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="false";
|
||
|
MessageBuffer responseFromCache, network="To", virtual_network="2", ordered="false";
|
||
|
|
||
|
MessageBuffer forwardedRequestToCache, network="From", virtual_network="1", ordered="true";
|
||
|
MessageBuffer responseToCache, network="From", virtual_network="2", ordered="false";
|
||
|
|
||
|
// STATES
|
||
|
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||
|
// Base states
|
||
|
I, desc="Idle";
|
||
|
S, desc="Shared";
|
||
|
O, desc="Owned";
|
||
|
M, desc="Modified", format="!b";
|
||
|
|
||
|
// Transient States
|
||
|
MI, desc="modified, issued PUTX, have not seen response yet";
|
||
|
OI, desc="owned, issued PUTX, have not seen response yet";
|
||
|
|
||
|
IS, desc="idle, issued GETS, have not seen response yet";
|
||
|
ISI, desc="idle, issued GETS, saw INV, have not seen data for GETS yet", format="!b";
|
||
|
|
||
|
IM, desc="idle, issued GETX, have not seen response yet";
|
||
|
IMI, desc="idle, issued GETX, saw forwarded GETX";
|
||
|
IMO, desc="idle, issued GETX, saw forwarded GETS";
|
||
|
IMOI, desc="idle, issued GETX, saw forwarded GETS, saw forwarded GETX";
|
||
|
|
||
|
// Note: OM is a strange state, because it is waiting for the line
|
||
|
// to be stolen away, or look like it has been stolen away. The
|
||
|
// common case is that we see a forward from the directory that is
|
||
|
// really from us, we forwarded the data to our dataqueue, and
|
||
|
// everythings works fine.
|
||
|
|
||
|
OM, desc="owned, issued GETX, have not seen response yet";
|
||
|
}
|
||
|
|
||
|
// EVENTS
|
||
|
enumeration(Event, desc="Cache events") {
|
||
|
Load, desc="Load request from the processor";
|
||
|
Load_prefetch, desc="Load prefetch request from the processor";
|
||
|
Ifetch, desc="I-fetch request from the processor";
|
||
|
Store_prefetch, desc="Store prefetch request from the processor";
|
||
|
Store, desc="Store request from the processor";
|
||
|
Replacement, desc="Replacement", format="!r";
|
||
|
|
||
|
Forwarded_GETS, "Forwarded GETS", desc="Directory forwards GETS to us";
|
||
|
Forwarded_GETX, "Forwarded GETX", desc="Directory forwards GETX to us";
|
||
|
INV, "INV", desc="Invalidation", format="!r";
|
||
|
|
||
|
Proc_ack, "Proc ack", desc="Ack from proc";
|
||
|
Proc_last_ack, "Proc last ack", desc="Last ack", format="!r";
|
||
|
|
||
|
Data_ack_0, "Data ack 0", desc="Data with ack count = 0";
|
||
|
Data_ack_not_0, "Data ack not 0", desc="Data with ack count != 0 (but haven't seen all acks first";
|
||
|
Data_ack_not_0_last, "Data ack not 0 last", desc="Data with ack count != 0 after having received all acks";
|
||
|
|
||
|
Dir_WB_ack, "WB ack", desc="Writeback ack from dir";
|
||
|
}
|
||
|
|
||
|
// TYPES
|
||
|
|
||
|
// CacheEntry
|
||
|
structure(Entry, desc="...", interface="AbstractCacheEntry") {
|
||
|
State CacheState, desc="cache state";
|
||
|
DataBlock DataBlk, desc="data for the block";
|
||
|
}
|
||
|
|
||
|
// TBE fields
|
||
|
structure(TBE, desc="...") {
|
||
|
Address Address, desc="Physical address for this TBE";
|
||
|
State TBEState, desc="Transient state";
|
||
|
DataBlock DataBlk, desc="Buffer for the data block";
|
||
|
int NumPendingAcks, desc="Number of acks that this processor is waiting for";
|
||
|
NetDest ForwardGetS_IDs, desc="Set of the processors to forward the block";
|
||
|
MachineID ForwardGetX_ID, desc="ID of the processor to forward the block";
|
||
|
int ForwardGetX_AckCount, desc="Number of acks the GetX we are forwarded needs";
|
||
|
bool isPrefetch, desc="Set if this was caused by a prefetch";
|
||
|
}
|
||
|
|
||
|
external_type(CacheMemory) {
|
||
|
bool cacheAvail(Address);
|
||
|
Address cacheProbe(Address);
|
||
|
void allocate(Address);
|
||
|
void deallocate(Address);
|
||
|
Entry lookup(Address);
|
||
|
void changePermission(Address, AccessPermission);
|
||
|
bool isTagPresent(Address);
|
||
|
}
|
||
|
|
||
|
external_type(TBETable) {
|
||
|
TBE lookup(Address);
|
||
|
void allocate(Address);
|
||
|
void deallocate(Address);
|
||
|
bool isPresent(Address);
|
||
|
}
|
||
|
|
||
|
MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
|
||
|
MessageBuffer optionalQueue, ordered="false", abstract_chip_ptr="true";
|
||
|
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||
|
StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i";
|
||
|
|
||
|
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||
|
CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_unified L1"', abstract_chip_ptr="true";
|
||
|
|
||
|
State getState(Address addr) {
|
||
|
if(TBEs.isPresent(addr)) {
|
||
|
return TBEs[addr].TBEState;
|
||
|
} else if (cacheMemory.isTagPresent(addr)) {
|
||
|
return cacheMemory[addr].CacheState;
|
||
|
}
|
||
|
return State:I;
|
||
|
}
|
||
|
|
||
|
void setState(Address addr, State state) {
|
||
|
if (TBEs.isPresent(addr)) {
|
||
|
TBEs[addr].TBEState := state;
|
||
|
}
|
||
|
if (cacheMemory.isTagPresent(addr)) {
|
||
|
cacheMemory[addr].CacheState := state;
|
||
|
|
||
|
// Set permission
|
||
|
if ((state == State:I) || (state == State:MI) || (state == State:OI)) {
|
||
|
cacheMemory.changePermission(addr, AccessPermission:Invalid);
|
||
|
} else if (state == State:S || state == State:O) {
|
||
|
cacheMemory.changePermission(addr, AccessPermission:Read_Only);
|
||
|
} else if (state == State:M) {
|
||
|
cacheMemory.changePermission(addr, AccessPermission:Read_Write);
|
||
|
} else {
|
||
|
cacheMemory.changePermission(addr, AccessPermission:Busy);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ** OUT_PORTS **
|
||
|
|
||
|
out_port(requestNetwork_out, RequestMsg, requestFromCache);
|
||
|
out_port(responseNetwork_out, ResponseMsg, responseFromCache);
|
||
|
|
||
|
// ** IN_PORTS **
|
||
|
|
||
|
// Response Network
|
||
|
in_port(responseNetwork_in, ResponseMsg, responseToCache) {
|
||
|
if (responseNetwork_in.isReady()) {
|
||
|
peek(responseNetwork_in, ResponseMsg) {
|
||
|
if(in_msg.Type == CoherenceResponseType:DATA) {
|
||
|
if(in_msg.NumPendingAcks == 0) {
|
||
|
trigger(Event:Data_ack_0, in_msg.Address);
|
||
|
} else {
|
||
|
if(in_msg.NumPendingAcks + TBEs[in_msg.Address].NumPendingAcks != 0) {
|
||
|
trigger(Event:Data_ack_not_0, in_msg.Address);
|
||
|
} else {
|
||
|
trigger(Event:Data_ack_not_0_last, in_msg.Address);
|
||
|
}
|
||
|
}
|
||
|
} else if(in_msg.Type == CoherenceResponseType:ACK) {
|
||
|
if(TBEs[in_msg.Address].NumPendingAcks != 1){
|
||
|
trigger(Event:Proc_ack, in_msg.Address);
|
||
|
} else {
|
||
|
trigger(Event:Proc_last_ack, in_msg.Address);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Forwarded Request network
|
||
|
in_port(forwardedRequestNetwork_in, RequestMsg, forwardedRequestToCache) {
|
||
|
if(forwardedRequestNetwork_in.isReady()) {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
if(in_msg.Type == CoherenceRequestType:GETS) {
|
||
|
trigger(Event:Forwarded_GETS, in_msg.Address);
|
||
|
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||
|
trigger(Event:Forwarded_GETX, in_msg.Address);
|
||
|
} else if (in_msg.Type == CoherenceRequestType:INV) {
|
||
|
trigger(Event:INV, in_msg.Address);
|
||
|
} else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
|
||
|
trigger(Event:Dir_WB_ack, in_msg.Address);
|
||
|
} else {
|
||
|
error("Invalid forwarded request type");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Mandatory Queue
|
||
|
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||
|
if (mandatoryQueue_in.isReady()) {
|
||
|
peek(mandatoryQueue_in, CacheMsg) {
|
||
|
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||
|
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||
|
} else {
|
||
|
if (in_msg.Type == CacheRequestType:LD) {
|
||
|
trigger(Event:Load, in_msg.Address);
|
||
|
} else if (in_msg.Type == CacheRequestType:IFETCH) {
|
||
|
trigger(Event:Ifetch, in_msg.Address);
|
||
|
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||
|
trigger(Event:Store, in_msg.Address);
|
||
|
} else {
|
||
|
error("Invalid CacheRequestType");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Optional Queue
|
||
|
in_port(optionalQueue_in, CacheMsg, optionalQueue, desc="...") {
|
||
|
if (optionalQueue_in.isReady()) {
|
||
|
peek(optionalQueue_in, CacheMsg) {
|
||
|
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||
|
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||
|
} else {
|
||
|
if (in_msg.Type == CacheRequestType:LD) {
|
||
|
trigger(Event:Load_prefetch, in_msg.Address);
|
||
|
} else if (in_msg.Type == CacheRequestType:IFETCH) {
|
||
|
trigger(Event:Load_prefetch, in_msg.Address);
|
||
|
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||
|
trigger(Event:Store_prefetch, in_msg.Address);
|
||
|
} else {
|
||
|
error("Invalid CacheRequestType");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ACTIONS
|
||
|
|
||
|
action(a_issueGETS, "a", desc="Issue GETS") {
|
||
|
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceRequestType:GETS;
|
||
|
out_msg.Requestor := machineID;
|
||
|
out_msg.Destination.add(map_Address_to_Directory(address));
|
||
|
out_msg.MessageSize := MessageSizeType:Control;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(b_issueGETX, "b", desc="Issue GETX") {
|
||
|
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceRequestType:GETX;
|
||
|
out_msg.Requestor := machineID;
|
||
|
out_msg.Destination.add(map_Address_to_Directory(address));
|
||
|
out_msg.MessageSize := MessageSizeType:Control;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(d_issuePUTX, "d", desc="Issue PUTX") {
|
||
|
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceRequestType:PUTX;
|
||
|
out_msg.Requestor := machineID;
|
||
|
out_msg.Destination.add(map_Address_to_Directory(address));
|
||
|
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||
|
out_msg.MessageSize := MessageSizeType:Data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(e_dataFromCacheToRequestor, "e", desc="Send data from cache to requestor") {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceResponseType:DATA;
|
||
|
out_msg.Sender := machineID;
|
||
|
out_msg.SenderMachine := MachineType:L1Cache;
|
||
|
out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state O and we see a GetX
|
||
|
out_msg.Destination.add(in_msg.Requestor);
|
||
|
out_msg.DestMachine := MachineType:L1Cache;
|
||
|
DEBUG_EXPR(out_msg.Destination);
|
||
|
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||
|
out_msg.MessageSize := MessageSizeType:Data;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(g_allocateCacheBlock, "g", desc="Allocate cache block") {
|
||
|
if (cacheMemory.isTagPresent(address) == false) {
|
||
|
cacheMemory.allocate(address);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||
|
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||
|
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||
|
// Non-prefetch
|
||
|
sequencer.readCallback(address, cacheMemory[address].DataBlk);
|
||
|
} else {
|
||
|
// Prefetch - don't call back
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||
|
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||
|
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||
|
// Non-prefetch
|
||
|
sequencer.writeCallback(address, cacheMemory[address].DataBlk);
|
||
|
} else {
|
||
|
// Prefetch - don't call back
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
|
||
|
check_allocate(TBEs);
|
||
|
TBEs.allocate(address);
|
||
|
TBEs[address].NumPendingAcks := 0; // default value
|
||
|
TBEs[address].isPrefetch := false;
|
||
|
TBEs[address].ForwardGetS_IDs.clear();
|
||
|
}
|
||
|
|
||
|
action(j_setPrefetchBit, "j", desc="Set prefetch bit") {
|
||
|
TBEs[address].isPrefetch := true;
|
||
|
}
|
||
|
|
||
|
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||
|
mandatoryQueue_in.dequeue();
|
||
|
}
|
||
|
|
||
|
action(l_popForwardedRequestQueue, "l", desc="Pop incoming forwarded request queue") {
|
||
|
forwardedRequestNetwork_in.dequeue();
|
||
|
}
|
||
|
|
||
|
action(m_popOptionalQueue, "m", desc="Pop optional queue") {
|
||
|
optionalQueue_in.dequeue();
|
||
|
}
|
||
|
|
||
|
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
|
||
|
responseNetwork_in.dequeue();
|
||
|
}
|
||
|
|
||
|
action(p_addNumberOfPendingAcks, "p", desc="Add number of pending acks to TBE") {
|
||
|
peek(responseNetwork_in, ResponseMsg) {
|
||
|
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||
|
TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks + in_msg.NumPendingAcks;
|
||
|
DEBUG_EXPR(in_msg.NumPendingAcks);
|
||
|
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(q_decrementNumberOfPendingAcks, "q", desc="Decrement number of pending invalidations by one") {
|
||
|
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||
|
TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks - 1;
|
||
|
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||
|
}
|
||
|
|
||
|
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||
|
TBEs.deallocate(address);
|
||
|
}
|
||
|
|
||
|
action(t_sendAckToInvalidator, "t", desc="Send ack to invalidator") {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceResponseType:ACK;
|
||
|
out_msg.Sender := machineID;
|
||
|
out_msg.SenderMachine := MachineType:L1Cache;
|
||
|
out_msg.Destination.add(in_msg.Requestor);
|
||
|
out_msg.DestMachine := MachineType:L1Cache;
|
||
|
DEBUG_EXPR(out_msg.Destination);
|
||
|
out_msg.NumPendingAcks := 0;
|
||
|
out_msg.MessageSize := MessageSizeType:Control;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(u_writeDataToCache, "u", desc="Write data to cache") {
|
||
|
peek(responseNetwork_in, ResponseMsg) {
|
||
|
cacheMemory[address].DataBlk := in_msg.DataBlk;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") {
|
||
|
TBEs[address].DataBlk := cacheMemory[address].DataBlk;
|
||
|
}
|
||
|
|
||
|
action(y_dataFromTBEToRequestor, "y", desc="Send data from TBE to requestor") {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceResponseType:DATA;
|
||
|
out_msg.Sender := machineID;
|
||
|
out_msg.SenderMachine := MachineType:L1Cache;
|
||
|
out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state MS and we see a GetX
|
||
|
out_msg.Destination.add(in_msg.Requestor);
|
||
|
out_msg.DestMachine := MachineType:L1Cache;
|
||
|
DEBUG_EXPR(out_msg.Destination);
|
||
|
out_msg.DataBlk := TBEs[address].DataBlk;
|
||
|
out_msg.MessageSize := MessageSizeType:Data;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(z_stall, "z", desc="Stall") {
|
||
|
}
|
||
|
|
||
|
action(dd_recordGetSForwardID, "\d", desc="Record forwarded GetS for future forwarding") {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
TBEs[address].ForwardGetS_IDs.add(in_msg.Requestor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(ee_dataFromCacheToGetSForwardIDs, "\e", desc="Send data from cache to GetS ForwardIDs") {
|
||
|
// FIXME - In some cases this should be from the TBE, not the cache.
|
||
|
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceResponseType:DATA;
|
||
|
out_msg.Sender := machineID;
|
||
|
out_msg.SenderMachine := MachineType:L1Cache;
|
||
|
out_msg.Destination := TBEs[address].ForwardGetS_IDs;
|
||
|
out_msg.DestMachine := MachineType:L1Cache;
|
||
|
DEBUG_EXPR(out_msg.Destination);
|
||
|
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||
|
out_msg.NumPendingAcks := 0;
|
||
|
out_msg.MessageSize := MessageSizeType:Data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(ff_deallocateCacheBlock, "\f", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
|
||
|
cacheMemory.deallocate(address);
|
||
|
}
|
||
|
|
||
|
action(gg_dataFromCacheToGetXForwardID, "\g", desc="Send data from cache to GetX ForwardID") {
|
||
|
// FIXME - In some cases this should be from the TBE, not the cache.
|
||
|
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||
|
out_msg.Address := address;
|
||
|
out_msg.Type := CoherenceResponseType:DATA;
|
||
|
out_msg.Sender := machineID;
|
||
|
out_msg.SenderMachine := MachineType:L1Cache;
|
||
|
out_msg.Destination.add(TBEs[address].ForwardGetX_ID);
|
||
|
out_msg.DestMachine := MachineType:L1Cache;
|
||
|
DEBUG_EXPR(out_msg.Destination);
|
||
|
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||
|
out_msg.NumPendingAcks := TBEs[address].ForwardGetX_AckCount;
|
||
|
out_msg.MessageSize := MessageSizeType:Data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
action(ii_recordGetXForwardID, "\i", desc="Record forwarded GetX and ack count for future forwarding") {
|
||
|
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||
|
TBEs[address].ForwardGetX_ID := in_msg.Requestor;
|
||
|
TBEs[address].ForwardGetX_AckCount := in_msg.NumPendingAcks;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************
|
||
|
// TRANSITIONS
|
||
|
//*****************************************************
|
||
|
|
||
|
// Transitions for Load/Store/Prefetch/Replacement from transient states
|
||
|
transition({OM, OI, IS, ISI, IM, IMO, IMOI, IMI, MI}, {Load, Load_prefetch, Ifetch, Store, Store_prefetch, Replacement}) {
|
||
|
z_stall;
|
||
|
}
|
||
|
|
||
|
// Transitions from Idle
|
||
|
transition(I, {Load,Ifetch}, IS) {
|
||
|
g_allocateCacheBlock;
|
||
|
i_allocateTBE;
|
||
|
a_issueGETS;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(I, {Load_prefetch}, IS) {
|
||
|
g_allocateCacheBlock;
|
||
|
i_allocateTBE;
|
||
|
j_setPrefetchBit;
|
||
|
a_issueGETS;
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(I, Store, IM) {
|
||
|
g_allocateCacheBlock;
|
||
|
i_allocateTBE;
|
||
|
b_issueGETX;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(I, Store_prefetch, IM) {
|
||
|
g_allocateCacheBlock;
|
||
|
i_allocateTBE;
|
||
|
j_setPrefetchBit;
|
||
|
b_issueGETX;
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(I, Replacement) {
|
||
|
ff_deallocateCacheBlock;
|
||
|
}
|
||
|
|
||
|
transition(I, INV) {
|
||
|
t_sendAckToInvalidator;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from Shared
|
||
|
transition({S, O}, {Load,Ifetch}) {
|
||
|
h_load_hit;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition({S, O, M}, Load_prefetch) {
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(S, Store, IM) {
|
||
|
i_allocateTBE;
|
||
|
b_issueGETX;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(S, Store_prefetch, IM) {
|
||
|
i_allocateTBE;
|
||
|
j_setPrefetchBit;
|
||
|
b_issueGETX;
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(S, Replacement, I) {
|
||
|
ff_deallocateCacheBlock;
|
||
|
}
|
||
|
|
||
|
transition(S, INV, I) {
|
||
|
t_sendAckToInvalidator;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from Modified
|
||
|
transition(M, {Load, Ifetch}) {
|
||
|
h_load_hit;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(M, Store) {
|
||
|
hh_store_hit;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(M, Store_prefetch) {
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(M, Replacement, MI) {
|
||
|
i_allocateTBE;
|
||
|
d_issuePUTX;
|
||
|
x_copyDataFromCacheToTBE;
|
||
|
ff_deallocateCacheBlock;
|
||
|
}
|
||
|
|
||
|
transition(M, Forwarded_GETS, O) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(M, Forwarded_GETX, I) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from O
|
||
|
transition(O, Store, OM) {
|
||
|
i_allocateTBE;
|
||
|
b_issueGETX;
|
||
|
k_popMandatoryQueue;
|
||
|
}
|
||
|
|
||
|
transition(O, Store_prefetch, OM) {
|
||
|
i_allocateTBE;
|
||
|
j_setPrefetchBit;
|
||
|
b_issueGETX;
|
||
|
m_popOptionalQueue;
|
||
|
}
|
||
|
|
||
|
transition(O, Replacement, OI){
|
||
|
i_allocateTBE;
|
||
|
d_issuePUTX;
|
||
|
x_copyDataFromCacheToTBE;
|
||
|
ff_deallocateCacheBlock;
|
||
|
}
|
||
|
|
||
|
transition(O, Forwarded_GETS) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(O, Forwarded_GETX, I) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// transitions from OI
|
||
|
|
||
|
transition(OI, Forwarded_GETS) {
|
||
|
y_dataFromTBEToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(OI, Forwarded_GETX) {
|
||
|
y_dataFromTBEToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(OI, Dir_WB_ack, I) {
|
||
|
s_deallocateTBE;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from IS
|
||
|
|
||
|
transition(IS, INV, ISI) {
|
||
|
t_sendAckToInvalidator;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(IS, Data_ack_0, S) {
|
||
|
u_writeDataToCache;
|
||
|
h_load_hit;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
// transitions from ISI
|
||
|
|
||
|
// in ISI, could get data from the Proc whose GETX caused INV to go from IS to ISI
|
||
|
// or, could get data from Dir if Dir's data lost race to Dir's INV
|
||
|
// or, could get data from Dir, if my GETS took forever to get to Dir, and the GETX
|
||
|
// processor already wrote it back
|
||
|
|
||
|
transition(ISI, Data_ack_0, I) {
|
||
|
u_writeDataToCache;
|
||
|
h_load_hit;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(ISI, INV) {
|
||
|
t_sendAckToInvalidator;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from IM
|
||
|
|
||
|
transition(IM, INV) { // do not need to go to IMI, since INV is for earlier epoch
|
||
|
t_sendAckToInvalidator;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition({IM, IMO}, Forwarded_GETS, IMO) {
|
||
|
dd_recordGetSForwardID;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(IM, Forwarded_GETX, IMI) {
|
||
|
ii_recordGetXForwardID;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(IM, {Data_ack_0, Data_ack_not_0_last}, M) {
|
||
|
u_writeDataToCache;
|
||
|
hh_store_hit;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IM, Data_ack_not_0) {
|
||
|
u_writeDataToCache;
|
||
|
p_addNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IM, Proc_ack) {
|
||
|
q_decrementNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IM, Proc_last_ack, M) {
|
||
|
hh_store_hit;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
// transitions from IMO
|
||
|
|
||
|
transition(IMO, Forwarded_GETX, IMOI) {
|
||
|
ii_recordGetXForwardID;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMO, {Data_ack_0, Data_ack_not_0_last}, O) {
|
||
|
u_writeDataToCache;
|
||
|
hh_store_hit;
|
||
|
ee_dataFromCacheToGetSForwardIDs;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMO, Data_ack_not_0) {
|
||
|
u_writeDataToCache;
|
||
|
p_addNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMO, Proc_ack) {
|
||
|
q_decrementNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMO, Proc_last_ack, O) {
|
||
|
hh_store_hit;
|
||
|
ee_dataFromCacheToGetSForwardIDs;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
// transitions from IMI
|
||
|
|
||
|
transition(IMI, {Data_ack_0, Data_ack_not_0_last}, I) {
|
||
|
u_writeDataToCache;
|
||
|
hh_store_hit;
|
||
|
gg_dataFromCacheToGetXForwardID;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMI, Data_ack_not_0) {
|
||
|
u_writeDataToCache;
|
||
|
p_addNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMI, Proc_ack) {
|
||
|
q_decrementNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMI, Proc_last_ack, I) {
|
||
|
hh_store_hit;
|
||
|
gg_dataFromCacheToGetXForwardID;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
// transitions from IMOI
|
||
|
|
||
|
transition(IMOI, {Data_ack_0, Data_ack_not_0_last}, I) {
|
||
|
u_writeDataToCache;
|
||
|
hh_store_hit;
|
||
|
ee_dataFromCacheToGetSForwardIDs;
|
||
|
gg_dataFromCacheToGetXForwardID;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMOI, Data_ack_not_0) {
|
||
|
u_writeDataToCache;
|
||
|
p_addNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMOI, Proc_ack) {
|
||
|
q_decrementNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(IMOI, Proc_last_ack, I) {
|
||
|
hh_store_hit;
|
||
|
ee_dataFromCacheToGetSForwardIDs;
|
||
|
gg_dataFromCacheToGetXForwardID;
|
||
|
s_deallocateTBE;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from OM
|
||
|
transition(OM, Proc_ack) {
|
||
|
q_decrementNumberOfPendingAcks;
|
||
|
o_popIncomingResponseQueue;
|
||
|
}
|
||
|
|
||
|
transition(OM, Forwarded_GETS) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(OM, Forwarded_GETX, IM) {
|
||
|
e_dataFromCacheToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
// Transitions from MI
|
||
|
|
||
|
transition(MI, Forwarded_GETS) {
|
||
|
y_dataFromTBEToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(MI, Forwarded_GETX) {
|
||
|
y_dataFromTBEToRequestor;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
|
||
|
transition(MI, Dir_WB_ack, I) {
|
||
|
s_deallocateTBE;
|
||
|
l_popForwardedRequestQueue;
|
||
|
}
|
||
|
}
|