gem5/src/mem/protocol/MI_example-cache.sm

399 lines
10 KiB
Text
Raw Normal View History

machine(L1Cache, "MI Example L1 Cache")
: Sequencer * sequencer,
CacheMemory * cacheMemory,
int cache_response_latency = 12,
int issue_latency = 2
{
// NETWORK BUFFERS
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="true";
MessageBuffer responseFromCache, network="To", virtual_network="1", ordered="true";
MessageBuffer forwardToCache, network="From", virtual_network="2", ordered="true";
MessageBuffer responseToCache, network="From", virtual_network="1", ordered="true";
// STATES
enumeration(State, desc="Cache states") {
I, desc="Not Present/Invalid";
II, desc="Not Present/Invalid, issued PUT";
M, desc="Modified";
MI, desc="Modified, issued PUT";
MII, desc="Modified, issued PUTX, received nack";
IS, desc="Issued request for LOAD/IFETCH";
IM, desc="Issued request for STORE/ATOMIC";
}
// EVENTS
enumeration(Event, desc="Cache events") {
// From processor
Load, desc="Load request from processor";
Ifetch, desc="Ifetch request from processor";
Store, desc="Store request from processor";
Data, desc="Data from network";
Fwd_GETX, desc="Forward from network";
Inv, desc="Invalidate request from dir";
Replacement, desc="Replace a block";
Writeback_Ack, desc="Ack from the directory for a writeback";
Writeback_Nack, desc="Nack from the directory for a writeback";
}
// STRUCTURE DEFINITIONS
MessageBuffer mandatoryQueue, ordered="false";
// CacheEntry
structure(Entry, desc="...", interface="AbstractCacheEntry") {
State CacheState, desc="cache state";
bool Dirty, desc="Is the data dirty (different than memory)?";
DataBlock DataBlk, desc="Data in the block";
}
// TBE fields
structure(TBE, desc="...") {
State TBEState, desc="Transient state";
DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
}
external_type(TBETable) {
TBE lookup(Address);
void allocate(Address);
void deallocate(Address);
bool isPresent(Address);
}
// STRUCTURES
TBETable TBEs, template_hack="<L1Cache_TBE>";
// FUNCTIONS
Event mandatory_request_type_to_event(CacheRequestType type) {
if (type == CacheRequestType:LD) {
return Event:Load;
} else if (type == CacheRequestType:IFETCH) {
return Event:Ifetch;
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
return Event:Store;
} else {
error("Invalid CacheRequestType");
}
}
Entry getCacheEntry(Address addr), return_by_ref="yes" {
return static_cast(Entry, cacheMemory[addr]);
}
State getState(Address addr) {
if (TBEs.isPresent(addr)) {
return TBEs[addr].TBEState;
}
else if (cacheMemory.isTagPresent(addr)) {
return getCacheEntry(addr).CacheState;
}
else {
return State:I;
}
}
void setState(Address addr, State state) {
if (TBEs.isPresent(addr)) {
TBEs[addr].TBEState := state;
}
if (cacheMemory.isTagPresent(addr)) {
getCacheEntry(addr).CacheState := state;
if (state == State:M) {
cacheMemory.changePermission(addr, AccessPermission:Read_Write);
} else {
cacheMemory.changePermission(addr, AccessPermission:Invalid);
}
}
}
// NETWORK PORTS
out_port(requestNetwork_out, RequestMsg, requestFromCache);
out_port(responseNetwork_out, ResponseMsg, responseFromCache);
in_port(forwardRequestNetwork_in, RequestMsg, forwardToCache) {
if (forwardRequestNetwork_in.isReady()) {
peek(forwardRequestNetwork_in, RequestMsg, block_on="Address") {
if (in_msg.Type == CoherenceRequestType:GETX) {
trigger(Event:Fwd_GETX, in_msg.Address);
}
else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
trigger(Event:Writeback_Ack, in_msg.Address);
}
else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
trigger(Event:Writeback_Nack, in_msg.Address);
}
else if (in_msg.Type == CoherenceRequestType:INV) {
trigger(Event:Inv, in_msg.Address);
}
else {
error("Unexpected message");
}
}
}
}
in_port(responseNetwork_in, ResponseMsg, responseToCache) {
if (responseNetwork_in.isReady()) {
peek(responseNetwork_in, ResponseMsg, block_on="Address") {
if (in_msg.Type == CoherenceResponseType:DATA) {
trigger(Event:Data, in_msg.Address);
}
else {
error("Unexpected message");
}
}
}
}
// Mandatory Queue
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
if (mandatoryQueue_in.isReady()) {
peek(mandatoryQueue_in, CacheMsg, block_on="LineAddress") {
if (cacheMemory.isTagPresent(in_msg.LineAddress) == false &&
cacheMemory.cacheAvail(in_msg.LineAddress) == false ) {
// make room for the block
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress));
}
else {
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
}
}
}
}
// ACTIONS
action(a_issueRequest, "a", desc="Issue a request") {
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(b_issuePUT, "b", desc="Issue a PUT request") {
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 := getCacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
}
action(e_sendData, "e", desc="Send data from cache to requestor") {
peek(forwardRequestNetwork_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.Destination.add(in_msg.Requestor);
out_msg.DataBlk := getCacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
}
action(ee_sendDataFromTBE, "\e", desc="Send data from TBE to requestor") {
peek(forwardRequestNetwork_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.Destination.add(in_msg.Requestor);
out_msg.DataBlk := TBEs[address].DataBlk;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
}
action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") {
if (cacheMemory.isTagPresent(address) == false) {
cacheMemory.allocate(address, new Entry);
}
}
action(h_deallocateL1CacheBlock, "h", desc="deallocate a cache block") {
if (cacheMemory.isTagPresent(address) == true) {
cacheMemory.deallocate(address);
}
}
action(m_popMandatoryQueue, "m", desc="Pop the mandatory request queue") {
mandatoryQueue_in.dequeue();
}
action(n_popResponseQueue, "n", desc="Pop the response queue") {
profileMsgDelay(1, responseNetwork_in.dequeue_getDelayCycles());
}
action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
profileMsgDelay(2, forwardRequestNetwork_in.dequeue_getDelayCycles());
}
action(p_profileMiss, "p", desc="Profile cache miss") {
peek(mandatoryQueue_in, CacheMsg) {
cacheMemory.profileMiss(in_msg);
}
}
action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
DEBUG_EXPR(getCacheEntry(address).DataBlk);
sequencer.readCallback(address, getCacheEntry(address).DataBlk);
}
action(s_store_hit, "s", desc="Notify sequencer that store completed.") {
DEBUG_EXPR(getCacheEntry(address).DataBlk);
sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
}
action(u_writeDataToCache, "u", desc="Write data to the cache") {
peek(responseNetwork_in, ResponseMsg) {
getCacheEntry(address).DataBlk := in_msg.DataBlk;
}
}
action(v_allocateTBE, "v", desc="Allocate TBE") {
TBEs.allocate(address);
}
action(w_deallocateTBE, "w", desc="Deallocate TBE") {
TBEs.deallocate(address);
}
action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") {
TBEs[address].DataBlk := getCacheEntry(address).DataBlk;
}
action(z_stall, "z", desc="stall") {
// do nothing
}
// TRANSITIONS
transition({IS, IM, MI, II}, {Load, Ifetch, Store, Replacement}) {
z_stall;
}
transition({IS, IM}, {Fwd_GETX, Inv}) {
z_stall;
}
transition(MI, Inv) {
o_popForwardedRequestQueue;
}
transition(M, Store) {
s_store_hit;
m_popMandatoryQueue;
}
transition(M, {Load, Ifetch}) {
r_load_hit;
m_popMandatoryQueue;
}
transition(I, Inv) {
o_popForwardedRequestQueue;
}
transition(I, Store, IM) {
v_allocateTBE;
i_allocateL1CacheBlock;
a_issueRequest;
p_profileMiss;
m_popMandatoryQueue;
}
transition(I, {Load, Ifetch}, IS) {
v_allocateTBE;
i_allocateL1CacheBlock;
a_issueRequest;
p_profileMiss;
m_popMandatoryQueue;
}
transition(IS, Data, M) {
u_writeDataToCache;
r_load_hit;
w_deallocateTBE;
n_popResponseQueue;
}
transition(IM, Data, M) {
u_writeDataToCache;
s_store_hit;
w_deallocateTBE;
n_popResponseQueue;
}
transition(M, Fwd_GETX, I) {
e_sendData;
o_popForwardedRequestQueue;
}
transition(I, Replacement) {
h_deallocateL1CacheBlock;
}
transition(M, {Replacement,Inv}, MI) {
v_allocateTBE;
b_issuePUT;
x_copyDataFromCacheToTBE;
h_deallocateL1CacheBlock;
}
transition(MI, Writeback_Ack, I) {
w_deallocateTBE;
o_popForwardedRequestQueue;
}
transition(MI, Fwd_GETX, II) {
ee_sendDataFromTBE;
o_popForwardedRequestQueue;
}
transition(MI, Writeback_Nack, MII) {
o_popForwardedRequestQueue;
}
transition(MII, Fwd_GETX, I) {
ee_sendDataFromTBE;
w_deallocateTBE;
o_popForwardedRequestQueue;
}
transition(II, Writeback_Nack, I) {
w_deallocateTBE;
o_popForwardedRequestQueue;
}
}