summaryrefslogtreecommitdiff
path: root/src/mem/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/protocol')
-rw-r--r--src/mem/protocol/MESI_CMP_directory-L1cache.sm51
-rw-r--r--src/mem/protocol/MESI_CMP_directory-L2cache.sm7
-rw-r--r--src/mem/protocol/MESI_CMP_directory-mem.sm242
-rw-r--r--src/mem/protocol/MESI_CMP_directory-msg.sm32
-rw-r--r--src/mem/protocol/MESI_CMP_directory.slicc2
-rw-r--r--src/mem/protocol/MI_example-cache.sm51
-rw-r--r--src/mem/protocol/MI_example-dir.sm458
-rw-r--r--src/mem/protocol/MI_example-dma.sm135
-rw-r--r--src/mem/protocol/MI_example-msg.sm32
-rw-r--r--src/mem/protocol/MI_example.slicc3
-rw-r--r--src/mem/protocol/RubySlicc_ComponentMapping.sm1
-rw-r--r--src/mem/protocol/RubySlicc_Exports.sm26
-rw-r--r--src/mem/protocol/RubySlicc_Types.sm58
-rw-r--r--src/mem/protocol/standard_1level_CMP-protocol.sm40
14 files changed, 965 insertions, 173 deletions
diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm
index 8f2096666..efdc58e1b 100644
--- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm
+++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm
@@ -33,7 +33,7 @@
*/
-machine(L1Cache, "MSI Directory L1 Cache CMP") {
+machine(L1Cache, "MSI Directory L1 Cache CMP") : LATENCY_L1_REQUEST_LATENCY LATENCY_L1_RESPONSE_LATENCY LATENCY_TO_L2_LATENCY {
// NODE L1 CACHE
// From this node's L1 cache TO the network
@@ -136,12 +136,21 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
- CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
- CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
+// CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
+// CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
- MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
+ CacheMemory L1IcacheMemory, factory='RubySystem::getCache(m_cfg["L1Icache"])';
+
+ CacheMemory L1DcacheMemory, factory='RubySystem::getCache(m_cfg["L1Dcache"])';
+
+
+// MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
+
+// Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
+
+ MessageBuffer mandatoryQueue, ordered="false";
+ Sequencer sequencer, factory='RubySystem::getSequencer(m_cfg["sequencer"])';
- Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
int cache_state_to_int(State state);
@@ -290,40 +299,40 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
// ** INSTRUCTION ACCESS ***
// Check to see if it is in the OTHER L1
- if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
+ if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
// The block is in the wrong L1, put the request on the queue to the shared L2
- trigger(Event:L1_Replacement, in_msg.Address);
+ trigger(Event:L1_Replacement, in_msg.LineAddress);
}
- if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
+ if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
// The tag matches for the L1, so the L1 asks the L2 for it.
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
} else {
- if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
+ if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
// L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
} else {
// No room in the L1, so we need to make room in the L1
- trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
+ trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress));
}
}
} else {
// *** DATA ACCESS ***
// Check to see if it is in the OTHER L1
- if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
+ if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
// The block is in the wrong L1, put the request on the queue to the shared L2
- trigger(Event:L1_Replacement, in_msg.Address);
+ trigger(Event:L1_Replacement, in_msg.LineAddress);
}
- if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
+ if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
// The tag matches for the L1, so the L1 ask the L2 for it
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
} else {
- if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
+ if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
// L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
} else {
// No room in the L1, so we need to make room in the L1
- trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
+ trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress));
}
}
}
@@ -517,7 +526,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
}
action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
- enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
+ enqueue(unblockNetwork_out, ResponseMsg, latency="TO_L2_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:UNBLOCK;
out_msg.Sender := machineID;
@@ -527,7 +536,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
}
action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
- enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
+ enqueue(unblockNetwork_out, ResponseMsg, latency="TO_L2_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
out_msg.Sender := machineID;
diff --git a/src/mem/protocol/MESI_CMP_directory-L2cache.sm b/src/mem/protocol/MESI_CMP_directory-L2cache.sm
index 43c37e832..2bd9b3ce7 100644
--- a/src/mem/protocol/MESI_CMP_directory-L2cache.sm
+++ b/src/mem/protocol/MESI_CMP_directory-L2cache.sm
@@ -156,9 +156,12 @@ machine(L2Cache, "MOSI Directory L2 Cache CMP") {
bool isPresent(Address);
}
- TBETable L2_TBEs, template_hack="<L2Cache_TBE>";
+ TBETable L2_TBEs, template_hack="<L2Cache_TBE>", no_vector="true";
- CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)';
+// CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)';
+
+
+ CacheMemory L2cacheMemory, factory='RubySystem::getCache(m_cfg["cache"])', no_vector="true";
// inclusive cache, returns L2 entries only
Entry getL2CacheEntry(Address addr), return_by_ref="yes" {
diff --git a/src/mem/protocol/MESI_CMP_directory-mem.sm b/src/mem/protocol/MESI_CMP_directory-mem.sm
index 1fcd234fe..84768c333 100644
--- a/src/mem/protocol/MESI_CMP_directory-mem.sm
+++ b/src/mem/protocol/MESI_CMP_directory-mem.sm
@@ -31,23 +31,39 @@
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
*/
+// This file is copied from Yasuko Watanabe's prefetch / memory protocol
+// Copied here by aep 12/14/07
-machine(Directory, "Token protocol") {
+
+machine(Directory, "MESI_CMP_filter_directory protocol") : LATENCY_MEMORY_LATENCY LATENCY_TO_MEM_CTRL_LATENCY {
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
+ MessageBuffer dmaRequestFromDir, network="To", virtual_network="4", ordered="true", no_vector="true";
+ MessageBuffer dmaRequestToDir, network="From", virtual_network="5", ordered="true", no_vector="true";
+
+
// STATES
enumeration(State, desc="Directory states", default="Directory_State_I") {
// Base states
I, desc="Owner";
+ ID, desc="Intermediate state for DMA_READ when in I";
+ ID_W, desc="Intermediate state for DMA_WRITE when in I";
}
// Events
enumeration(Event, desc="Directory events") {
- Fetch, desc="A GETX arrives";
- Data, desc="A GETS arrives";
+ Fetch, desc="A memory fetch arrives";
+ Data, desc="writeback data arrives";
+ Memory_Data, desc="Fetched data from memory arrives";
+ Memory_Ack, desc="Writeback Ack from memory arrives";
+//added by SS for dma
+ DMA_READ, desc="A DMA Read memory request";
+ DMA_WRITE, desc="A DMA Write memory request";
+
+
}
// TYPES
@@ -62,10 +78,21 @@ machine(Directory, "Token protocol") {
bool isPresent(Address);
}
+ // to simulate detailed DRAM
+ external_type(MemoryControl, inport="yes", outport="yes") {
+
+ }
+
// ** OBJECTS **
- DirectoryMemory directory, constructor_hack="i";
+// DirectoryMemory directory, constructor_hack="i";
+// MemoryControl memBuffer, constructor_hack="i";
+
+ DirectoryMemory directory, factory='RubySystem::getDirectory(m_cfg["directory_name"])';
+
+ MemoryControl memBuffer, factory='RubySystem::getMemoryControl(m_cfg["memory_controller_name"])';
+
State getState(Address addr) {
return State:I;
@@ -74,20 +101,44 @@ machine(Directory, "Token protocol") {
void setState(Address addr, State state) {
}
+ bool isGETRequest(CoherenceRequestType type) {
+ return (type == CoherenceRequestType:GETS) ||
+ (type == CoherenceRequestType:GET_INSTR) ||
+ (type == CoherenceRequestType:GETX);
+ }
+
+
// ** OUT_PORTS **
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
+ out_port(memQueue_out, MemoryMsg, memBuffer);
+ out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaRequestFromDir);
// ** IN_PORTS **
+//added by SS for dma
+ in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) {
+ if (dmaRequestQueue_in.isReady()) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ if (in_msg.Type == DMARequestType:READ) {
+ trigger(Event:DMA_READ, in_msg.PhysicalAddress);
+ } else if (in_msg.Type == DMARequestType:WRITE) {
+ trigger(Event:DMA_WRITE, in_msg.PhysicalAddress);
+ } else {
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+
in_port(requestNetwork_in, RequestMsg, requestToDir) {
if (requestNetwork_in.isReady()) {
peek(requestNetwork_in, RequestMsg) {
assert(in_msg.Destination.isElement(machineID));
- if (in_msg.Type == CoherenceRequestType:GETS) {
- trigger(Event:Fetch, in_msg.Address);
- } else if (in_msg.Type == CoherenceRequestType:GETX) {
+ if (isGETRequest(in_msg.Type)) {
trigger(Event:Fetch, in_msg.Address);
} else {
+ DEBUG_EXPR(in_msg);
error("Invalid message");
}
}
@@ -108,27 +159,45 @@ machine(Directory, "Token protocol") {
}
}
+ // off-chip memory request/response is done
+ in_port(memQueue_in, MemoryMsg, memBuffer) {
+ if (memQueue_in.isReady()) {
+ peek(memQueue_in, MemoryMsg) {
+ if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
+ trigger(Event:Memory_Data, in_msg.Address);
+ } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
+ trigger(Event:Memory_Ack, in_msg.Address);
+ } else {
+ DEBUG_EXPR(in_msg.Type);
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+
+
// Actions
action(a_sendAck, "a", desc="Send ack to L2") {
- peek(responseNetwork_in, ResponseMsg) {
- enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
out_msg.Sender := machineID;
- out_msg.Destination.add(in_msg.Sender);
+ out_msg.Destination.add(in_msg.OriginalRequestorMachId);
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
}
action(d_sendData, "d", desc="Send data to requestor") {
- peek(requestNetwork_in, RequestMsg) {
- enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
out_msg.Sender := machineID;
- out_msg.Destination.add(in_msg.Requestor);
- out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+ out_msg.Destination.add(in_msg.OriginalRequestorMachId);
+ out_msg.DataBlk := in_msg.DataBlk;
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
@@ -143,6 +212,42 @@ machine(Directory, "Token protocol") {
responseNetwork_in.dequeue();
}
+ action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
+ memQueue_in.dequeue();
+ }
+
+ action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
+ peek(requestNetwork_in, RequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_READ;
+ out_msg.Sender := machineID;
+ out_msg.OriginalRequestorMachId := in_msg.Requestor;
+ out_msg.MessageSize := in_msg.MessageSize;
+ out_msg.Prefetch := in_msg.Prefetch;
+ out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
+ peek(responseNetwork_in, ResponseMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_WB;
+ out_msg.Sender := machineID;
+ out_msg.OriginalRequestorMachId := in_msg.Sender;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.MessageSize := in_msg.MessageSize;
+ //out_msg.Prefetch := in_msg.Prefetch;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
peek(responseNetwork_in, ResponseMsg) {
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
@@ -150,17 +255,122 @@ machine(Directory, "Token protocol") {
DEBUG_EXPR(in_msg.DataBlk);
}
}
+//added by SS for dma
+ action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_READ;
+ out_msg.Sender := machineID;
+ out_msg.OriginalRequestorMachId := machineID;
+ out_msg.MessageSize := in_msg.MessageSize;
+ out_msg.DataBlk := directory[address].DataBlk;
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
+ dmaRequestQueue_in.dequeue();
+ }
+
+ action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMAResponseType:DATA;
+ out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
+ out_msg.Destination.add(map_Address_to_DMA(address));
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+
+ action(dw_writeDMAData, "dw", desc="DMA Write data to memory") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ directory[in_msg.PhysicalAddress].DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
+ }
+ }
+
+ action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_WB;
+ out_msg.OriginalRequestorMachId := machineID;
+ //out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
+ out_msg.MessageSize := in_msg.MessageSize;
+ //out_msg.Prefetch := in_msg.Prefetch;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMAResponseType:ACK;
+ out_msg.Destination.add(map_Address_to_DMA(address));
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+
+ action(z_recycleRequestQueue, "z", desc="recycle request queue") {
+ requestNetwork_in.dequeue();
+ }
// TRANSITIONS
transition(I, Fetch) {
- d_sendData;
+ //d_sendData;
+ qf_queueMemoryFetchRequest;
j_popIncomingRequestQueue;
}
transition(I, Data) {
m_writeDataToMemory;
- a_sendAck;
+ //a_sendAck;
+ qw_queueMemoryWBRequest;
k_popIncomingResponseQueue;
}
+
+ transition(I, Memory_Data) {
+ d_sendData;
+ l_popMemQueue;
+ }
+
+ transition(I, Memory_Ack) {
+ a_sendAck;
+ l_popMemQueue;
+ }
+
+//added by SS for dma support
+ transition(I, DMA_READ, ID) {
+ qf_queueMemoryFetchRequestDMA;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(ID, Memory_Data, I) {
+ dr_sendDMAData;
+ l_popMemQueue;
+ }
+
+ transition(I, DMA_WRITE, ID_W) {
+ dw_writeDMAData;
+ qw_queueMemoryWBRequest_partial;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(ID_W, Memory_Ack, I) {
+ da_sendDMAAck;
+ l_popMemQueue;
+ }
+
+ transition({ID, ID_W}, {Fetch, Data} ) {
+ z_recycleRequestQueue;
+ }
+
+
}
diff --git a/src/mem/protocol/MESI_CMP_directory-msg.sm b/src/mem/protocol/MESI_CMP_directory-msg.sm
index c2d02b59d..e726b062c 100644
--- a/src/mem/protocol/MESI_CMP_directory-msg.sm
+++ b/src/mem/protocol/MESI_CMP_directory-msg.sm
@@ -79,6 +79,38 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
MessageSizeType MessageSize, desc="size category of the message";
}
+enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
+ READ, desc="Memory Read";
+ WRITE, desc="Memory Write";
+ NULL, desc="Invalid";
+}
+
+enumeration(DMAResponseType, desc="...", default="DMAResponseType_NULL") {
+ DATA, desc="DATA read";
+ ACK, desc="ACK write";
+ NULL, desc="Invalid";
+}
+
+structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
+ DMARequestType Type, desc="Request type (read/write)";
+ Address PhysicalAddress, desc="Physical address for this request";
+ NetDest Destination, desc="Destination";
+ DataBlock DataBlk, desc="DataBlk attached to this request";
+ int Offset, desc="The offset into the datablock";
+ int Len, desc="The length of the request";
+ MessageSizeType MessageSize, desc="size category of the message";
+}
+
+structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
+ DMAResponseType Type, desc="Response type (DATA/ACK)";
+ Address PhysicalAddress, desc="Physical address for this request";
+ NetDest Destination, desc="Destination";
+ DataBlock DataBlk, desc="DataBlk attached to this request";
+ MessageSizeType MessageSize, desc="size category of the message";
+}
+
+
+
/*
GenericRequestType convertToGenericType(CoherenceRequestType type) {
if(type == CoherenceRequestType:PUTX) {
diff --git a/src/mem/protocol/MESI_CMP_directory.slicc b/src/mem/protocol/MESI_CMP_directory.slicc
index 34303f97e..b687873fe 100644
--- a/src/mem/protocol/MESI_CMP_directory.slicc
+++ b/src/mem/protocol/MESI_CMP_directory.slicc
@@ -2,4 +2,6 @@ MESI_CMP_directory-msg.sm
MESI_CMP_directory-L2cache.sm
MESI_CMP_directory-L1cache.sm
MESI_CMP_directory-mem.sm
+MESI_CMP_directory-dma.sm
standard_CMP-protocol.sm
+
diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm
index 6c1cb02b6..ae8ab519f 100644
--- a/src/mem/protocol/MI_example-cache.sm
+++ b/src/mem/protocol/MI_example-cache.sm
@@ -1,5 +1,5 @@
-machine(L1Cache, "MI Example") {
+machine(L1Cache, "MI Example L1 Cache"): LATENCY_CACHE_RESPONSE_LATENCY LATENCY_ISSUE_LATENCY {
// NETWORK BUFFERS
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="true";
@@ -15,7 +15,7 @@ machine(L1Cache, "MI Example") {
M, desc="Modified";
MI, desc="Modified, issued PUT";
- IS, desc="Issued request for IFETCH/GETX";
+ IS, desc="Issued request for LOAD/IFETCH";
IM, desc="Issued request for STORE/ATOMIC";
}
@@ -30,6 +30,8 @@ machine(L1Cache, "MI Example") {
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";
@@ -37,21 +39,21 @@ machine(L1Cache, "MI Example") {
// STRUCTURE DEFINITIONS
- MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
- Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
+ MessageBuffer mandatoryQueue, ordered="false";
+ Sequencer sequencer, factory='RubySystem::getSequencer(m_cfg["sequencer"])';
// 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 for the block";
+ DataBlock DataBlk, desc="Data in the block";
}
external_type(CacheMemory) {
bool cacheAvail(Address);
Address cacheProbe(Address);
- void allocate(Address);
+ void allocate(Address, Entry);
void deallocate(Address);
Entry lookup(Address);
void changePermission(Address, AccessPermission);
@@ -62,8 +64,6 @@ machine(L1Cache, "MI Example") {
structure(TBE, desc="...") {
State TBEState, desc="Transient state";
DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
- bool Trans, desc="Is this block part of a the current transaction?";
- bool Logged, desc="Has this block been logged in the current transaction?";
}
external_type(TBETable) {
@@ -76,7 +76,7 @@ machine(L1Cache, "MI Example") {
// STRUCTURES
- CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS, L1_CACHE_ASSOC, MachineType_L1Cache, int_to_string(i)+"_L1"', abstract_chip_ptr="true";
+ CacheMemory cacheMemory, factory='RubySystem::getCache(m_cfg["cache"])';
TBETable TBEs, template_hack="<L1Cache_TBE>";
@@ -117,6 +117,11 @@ machine(L1Cache, "MI Example") {
if (cacheMemory.isTagPresent(addr)) {
cacheMemory[addr].CacheState := state;
+ if (state == State:M) {
+ cacheMemory.changePermission(addr, AccessPermission:Read_Write);
+ } else {
+ cacheMemory.changePermission(addr, AccessPermission:Invalid);
+ }
}
}
@@ -138,6 +143,9 @@ machine(L1Cache, "MI Example") {
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");
}
@@ -164,13 +172,13 @@ machine(L1Cache, "MI Example") {
peek(mandatoryQueue_in, CacheMsg) {
- if (cacheMemory.isTagPresent(in_msg.Address) == false &&
- cacheMemory.cacheAvail(in_msg.Address) == false ) {
+ 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.Address));
+ trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress));
}
else {
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
}
}
}
@@ -229,7 +237,7 @@ machine(L1Cache, "MI Example") {
action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") {
if (cacheMemory.isTagPresent(address) == false) {
- cacheMemory.allocate(address);
+ cacheMemory.allocate(address, new Entry);
}
}
@@ -244,11 +252,11 @@ machine(L1Cache, "MI Example") {
}
action(n_popResponseQueue, "n", desc="Pop the response queue") {
- responseNetwork_in.dequeue();
+ profileMsgDelay(1, responseNetwork_in.dequeue_getDelayCycles());
}
action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
- forwardRequestNetwork_in.dequeue();
+ profileMsgDelay(2, forwardRequestNetwork_in.dequeue_getDelayCycles());
}
action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
@@ -292,10 +300,14 @@ machine(L1Cache, "MI Example") {
z_stall;
}
- transition({IS, IM}, Fwd_GETX) {
+ transition({IS, IM}, {Fwd_GETX, Inv}) {
z_stall;
}
+ transition(MI, Inv) {
+ o_popForwardedRequestQueue;
+ }
+
transition(M, Store) {
s_store_hit;
m_popMandatoryQueue;
@@ -306,6 +318,9 @@ machine(L1Cache, "MI Example") {
m_popMandatoryQueue;
}
+ transition(I, Inv) {
+ o_popForwardedRequestQueue;
+ }
transition(I, Store, IM) {
v_allocateTBE;
@@ -344,7 +359,7 @@ machine(L1Cache, "MI Example") {
h_deallocateL1CacheBlock;
}
- transition(M, Replacement, MI) {
+ transition(M, {Replacement,Inv}, MI) {
v_allocateTBE;
b_issuePUT;
x_copyDataFromCacheToTBE;
diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm
index 311f8488b..f597ab73c 100644
--- a/src/mem/protocol/MI_example-dir.sm
+++ b/src/mem/protocol/MI_example-dir.sm
@@ -1,11 +1,12 @@
-machine(Directory, "Directory protocol") {
+machine(Directory, "Directory protocol") : LATENCY_TO_MEM_CTRL_LATENCY LATENCY_DIRECTORY_LATENCY LATENCY_MEMORY_LATENCY {
- MessageBuffer forwardFromDir, network="To", virtual_network="2", ordered="true";
+ MessageBuffer forwardFromDir, network="To", virtual_network="2", ordered="false";
MessageBuffer responseFromDir, network="To", virtual_network="1", ordered="false";
+ MessageBuffer dmaRequestFromDir, network="To", virtual_network="4", ordered="true";
MessageBuffer requestToDir, network="From", virtual_network="0", ordered="true";
- MessageBuffer unblockToDir, network="From", virtual_network="3", ordered="true";
+ MessageBuffer dmaRequestToDir, network="From", virtual_network="5", ordered="true";
// STATES
enumeration(State, desc="Directory states", default="Directory_State_I") {
@@ -13,17 +14,32 @@ machine(Directory, "Directory protocol") {
I, desc="Invalid";
M, desc="Modified";
- MI, desc="Blocked on a writeback";
+ M_DRD, desc="Blocked on an invalidation for a DMA read";
+ M_DWR, desc="Blocked on an invalidation for a DMA write";
+
+ M_DWRI, desc="Intermediate state M_DWR-->I";
+
+ IM, desc="Intermediate state I-->M";
+ MI, desc="Intermediate state M-->I";
+ ID, desc="Intermediate state for DMA_READ when in I";
+ ID_W, desc="Intermediate state for DMA_WRITE when in I";
}
// Events
enumeration(Event, desc="Directory events") {
+ // processor requests
GETX, desc="A GETX arrives";
GETS, desc="A GETS arrives";
PUTX, desc="A PUTX arrives";
PUTX_NotOwner, desc="A PUTX arrives";
- PUTO, desc="A PUTO arrives";
- Unblock, desc="An unblock message arrives";
+
+ // DMA requests
+ DMA_READ, desc="A DMA Read memory request";
+ DMA_WRITE, desc="A DMA Write memory request";
+
+ // Memory Controller
+ Memory_Data, desc="Fetched data from memory arrives";
+ Memory_Ack, desc="Writeback Ack from memory arrives";
}
// TYPES
@@ -39,26 +55,58 @@ machine(Directory, "Directory protocol") {
external_type(DirectoryMemory) {
Entry lookup(Address);
bool isPresent(Address);
+ void invalidateBlock(Address);
+ }
+
+ external_type(MemoryControl, inport="yes", outport="yes") {
+
+ }
+
+
+ // TBE entries for DMA requests
+ structure(TBE, desc="TBE entries for outstanding DMA requests") {
+ State TBEState, desc="Transient State";
+ DataBlock DataBlk, desc="Data to be written (DMA write only)";
+ int Offset, desc="...";
+ int Len, desc="...";
}
+ external_type(TBETable) {
+ TBE lookup(Address);
+ void allocate(Address);
+ void deallocate(Address);
+ bool isPresent(Address);
+ }
// ** OBJECTS **
+ DirectoryMemory directory, factory='RubySystem::getDirectory(m_cfg["directory_name"])';
+
+ MemoryControl memBuffer, factory='RubySystem::getMemoryControl(m_cfg["memory_controller_name"])';
- DirectoryMemory directory, constructor_hack="i";
+ TBETable TBEs, template_hack="<Directory_TBE>";
State getState(Address addr) {
- return directory[addr].DirectoryState;
+ if (TBEs.isPresent(addr)) {
+ return TBEs[addr].TBEState;
+ } else if (directory.isPresent(addr)) {
+ return directory[addr].DirectoryState;
+ } else {
+ return State:I;
+ }
}
void setState(Address addr, State state) {
+
+ if (TBEs.isPresent(addr)) {
+ TBEs[addr].TBEState := state;
+ }
+
if (directory.isPresent(addr)) {
if (state == State:I) {
assert(directory[addr].Owner.count() == 0);
assert(directory[addr].Sharers.count() == 0);
- }
-
- if (state == State:M) {
+ } else if (state == State:M) {
assert(directory[addr].Owner.count() == 1);
assert(directory[addr].Sharers.count() == 0);
}
@@ -71,9 +119,25 @@ machine(Directory, "Directory protocol") {
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests
+ out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaRequestFromDir);
+//added by SS
+ out_port(memQueue_out, MemoryMsg, memBuffer);
// ** IN_PORTS **
+ in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) {
+ if (dmaRequestQueue_in.isReady()) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ if (in_msg.Type == DMARequestType:READ) {
+ trigger(Event:DMA_READ, in_msg.PhysicalAddress);
+ } else if (in_msg.Type == DMARequestType:WRITE) {
+ trigger(Event:DMA_WRITE, in_msg.PhysicalAddress);
+ } else {
+ error("Invalid message");
+ }
+ }
+ }
+ }
in_port(requestQueue_in, RequestMsg, requestToDir) {
if (requestQueue_in.isReady()) {
@@ -88,8 +152,6 @@ machine(Directory, "Directory protocol") {
} else {
trigger(Event:PUTX_NotOwner, in_msg.Address);
}
- } else if (in_msg.Type == CoherenceRequestType:PUTO) {
- trigger(Event:PUTO, in_msg.Address);
} else {
error("Invalid message");
}
@@ -97,20 +159,23 @@ machine(Directory, "Directory protocol") {
}
}
- in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
- if (unblockNetwork_in.isReady()) {
- peek(unblockNetwork_in, ResponseMsg) {
- if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
- trigger(Event:Unblock, in_msg.Address);
+//added by SS
+ // off-chip memory request/response is done
+ in_port(memQueue_in, MemoryMsg, memBuffer) {
+ if (memQueue_in.isReady()) {
+ peek(memQueue_in, MemoryMsg) {
+ if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
+ trigger(Event:Memory_Data, in_msg.Address);
+ } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
+ trigger(Event:Memory_Ack, in_msg.Address);
} else {
+ DEBUG_EXPR(in_msg.Type);
error("Invalid message");
}
}
}
}
-
-
// Actions
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
@@ -125,6 +190,18 @@ machine(Directory, "Directory protocol") {
}
}
+ action(l_sendWriteBackAck, "la", desc="Send writeback ack to requestor") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:WB_ACK;
+ out_msg.Requestor := in_msg.OriginalRequestorMachId;
+ out_msg.Destination.add(in_msg.OriginalRequestorMachId);
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
peek(requestQueue_in, RequestMsg) {
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
@@ -141,31 +218,90 @@ machine(Directory, "Directory protocol") {
directory[address].Owner.clear();
}
+// action(d_sendData, "d", desc="Send data to requestor") {
+// peek(requestQueue_in, RequestMsg) {
+// enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
+// out_msg.Address := address;
+//
+// if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
+// // out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE_CLEAN;
+// out_msg.Type := CoherenceResponseType:DATA;
+// } else {
+// out_msg.Type := CoherenceResponseType:DATA;
+// }
+//
+// out_msg.Sender := machineID;
+// out_msg.Destination.add(in_msg.Requestor);
+// out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+// out_msg.MessageSize := MessageSizeType:Response_Data;
+// }
+// }
+// }
+
action(d_sendData, "d", desc="Send data to requestor") {
- peek(requestQueue_in, RequestMsg) {
- enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_LATENCY") {
out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(in_msg.OriginalRequestorMachId);
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
- if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
- // out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE_CLEAN;
- out_msg.Type := CoherenceResponseType:DATA;
- } else {
- out_msg.Type := CoherenceResponseType:DATA;
- }
+// action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
+// peek(dmaRequestQueue_in, DMARequestMsg) {
+// enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+// out_msg.PhysicalAddress := address;
+// out_msg.Type := DMAResponseType:DATA;
+// out_msg.DataBlk := directory[in_msg.PhysicalAddress].DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
+// out_msg.Destination.add(map_Address_to_DMA(address));
+// out_msg.MessageSize := MessageSizeType:Response_Data;
+// }
+// }
+// }
+
+ action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMAResponseType:DATA;
+ out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
+ out_msg.Destination.add(map_Address_to_DMA(address));
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
- out_msg.Sender := machineID;
- out_msg.Destination.add(in_msg.Requestor);
- out_msg.DataBlk := directory[in_msg.Address].DataBlk;
- out_msg.Dirty := false; // By definition, the block is now clean
- out_msg.Acks := directory[address].Sharers.count();
- if (directory[address].Sharers.isElement(in_msg.Requestor)) {
- out_msg.Acks := out_msg.Acks - 1;
- }
+
+
+ action(drp_sendDMAData, "drp", desc="Send Data to DMA controller from incoming PUTX") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMAResponseType:DATA;
+ out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
+ out_msg.Destination.add(map_Address_to_DMA(address));
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
}
+ action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMAResponseType:ACK;
+ out_msg.Destination.add(map_Address_to_DMA(address));
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+
+ action(d_deallocateDirectory, "\d", desc="Deallocate Directory Entry") {
+ directory.invalidateBlock(address);
+ }
+
action(e_ownerIsRequestor, "e", desc="The owner is now the requestor") {
peek(requestQueue_in, RequestMsg) {
directory[address].Owner.clear();
@@ -184,26 +320,32 @@ machine(Directory, "Directory protocol") {
out_msg.Type := in_msg.Type;
out_msg.Requestor := in_msg.Requestor;
out_msg.Destination := directory[in_msg.Address].Owner;
- out_msg.Acks := directory[address].Sharers.count();
- if (directory[address].Sharers.isElement(in_msg.Requestor)) {
- out_msg.Acks := out_msg.Acks - 1;
- }
- out_msg.MessageSize := MessageSizeType:Forwarded_Control;
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
+ action(inv_sendCacheInvalidate, "inv", desc="Invalidate a cache block") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:INV;
+ out_msg.Requestor := machineID;
+ out_msg.Destination := directory[in_msg.PhysicalAddress].Owner;
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
requestQueue_in.dequeue();
}
- action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
- unblockNetwork_in.dequeue();
+ action(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
+ dmaRequestQueue_in.dequeue();
}
- action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
- // peek(unblockNetwork_in, ResponseMsg) {
+ action(l_writeDataToMemory, "l", desc="Write PUTX data to memory") {
peek(requestQueue_in, RequestMsg) {
// assert(in_msg.Dirty);
// assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
@@ -213,16 +355,218 @@ machine(Directory, "Directory protocol") {
}
}
+ action(dw_writeDMAData, "dw", desc="DMA Write data to memory") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ directory[in_msg.PhysicalAddress].DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
+ }
+ }
+
+ action(dwt_writeDMADataFromTBE, "dwt", desc="DMA Write data to memory from TBE") {
+ directory[address].DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len);
+ }
+
+ action(v_allocateTBE, "v", desc="Allocate TBE") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ TBEs.allocate(address);
+ TBEs[address].DataBlk := in_msg.DataBlk;
+ TBEs[address].Offset := in_msg.Offset;
+ TBEs[address].Len := in_msg.Len;
+ }
+ }
+
+ action(w_deallocateTBE, "w", desc="Deallocate TBE") {
+ TBEs.deallocate(address);
+ }
+
+ action(z_recycleRequestQueue, "z", desc="recycle request queue") {
+ requestQueue_in.recycle();
+ }
+ action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_READ;
+ out_msg.Sender := machineID;
+ out_msg.OriginalRequestorMachId := in_msg.Requestor;
+ out_msg.MessageSize := in_msg.MessageSize;
+ out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_READ;
+ out_msg.Sender := machineID;
+ //out_msg.OriginalRequestorMachId := machineID;
+ out_msg.MessageSize := in_msg.MessageSize;
+ out_msg.DataBlk := directory[address].DataBlk;
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+// action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
+// peek(dmaRequestQueue_in, DMARequestMsg) {
+// enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+// out_msg.Address := address;
+// out_msg.Type := MemoryRequestType:MEMORY_WB;
+// out_msg.OriginalRequestorMachId := machineID;
+// out_msg.DataBlk := in_msg.DataBlk;
+// out_msg.MessageSize := in_msg.MessageSize;
+
+// DEBUG_EXPR(out_msg);
+// }
+// }
+// }
+
+
+ action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_WB;
+ //out_msg.OriginalRequestorMachId := machineID;
+ //out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
+ out_msg.MessageSize := in_msg.MessageSize;
+ //out_msg.Prefetch := in_msg.Prefetch;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_WB;
+ out_msg.OriginalRequestorMachId := in_msg.Requestor;
+ //out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len);
+ out_msg.MessageSize := in_msg.MessageSize;
+ //out_msg.Prefetch := in_msg.Prefetch;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+
+
+ action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := MemoryRequestType:MEMORY_WB;
+ out_msg.OriginalRequestorMachId := in_msg.Requestor;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.MessageSize := in_msg.MessageSize;
+ //out_msg.Prefetch := in_msg.Prefetch;
+
+ DEBUG_EXPR(out_msg);
+ }
+ }
+ }
+
+ action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
+ memQueue_in.dequeue();
+ }
+
// TRANSITIONS
- transition(I, GETX, M) {
- d_sendData;
+ transition({M_DRD, M_DWR}, GETX) {
+ z_recycleRequestQueue;
+ }
+
+ transition({IM, MI, ID, ID_W}, {GETX, GETS, DMA_READ, DMA_WRITE, PUTX, PUTX_NotOwner} ) {
+ z_recycleRequestQueue;
+ }
+
+ transition(I, GETX, IM) {
+ //d_sendData;
+ qf_queueMemoryFetchRequest;
e_ownerIsRequestor;
i_popIncomingRequestQueue;
}
+ transition(IM, Memory_Data, M) {
+ d_sendData;
+ //e_ownerIsRequestor;
+ l_popMemQueue;
+ }
+
+
+ transition(I, DMA_READ, ID) {
+ //dr_sendDMAData;
+ qf_queueMemoryFetchRequestDMA;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(ID, Memory_Data, I) {
+ dr_sendDMAData;
+ //p_popIncomingDMARequestQueue;
+ l_popMemQueue;
+ }
+
+
+
+ transition(I, DMA_WRITE, ID_W) {
+ dw_writeDMAData;
+// da_sendDMAAck;
+ qw_queueMemoryWBRequest_partial;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(ID_W, Memory_Ack, I) {
+ da_sendDMAAck;
+ l_popMemQueue;
+ }
+
+ transition(M, DMA_READ, M_DRD) {
+ inv_sendCacheInvalidate;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(M_DRD, PUTX, I) {
+ drp_sendDMAData;
+ c_clearOwner;
+ a_sendWriteBackAck;
+ // d_deallocateDirectory;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(M, DMA_WRITE, M_DWR) {
+ v_allocateTBE;
+ inv_sendCacheInvalidate;
+ p_popIncomingDMARequestQueue;
+ }
+
+ transition(M_DWR, PUTX, M_DWRI) {
+ dwt_writeDMADataFromTBE;
+ qw_queueMemoryWBRequest_partialTBE;
+ //a_sendWriteBackAck;
+ c_clearOwner;
+ //da_sendDMAAck;
+ w_deallocateTBE;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(M_DWRI, Memory_Ack, I) {
+ //dwt_writeDMADataFromTBE;
+ l_sendWriteBackAck;
+ //c_clearOwner;
+ da_sendDMAAck;
+ //w_deallocateTBE;
+ l_popMemQueue;
+ }
+
+
transition(M, GETX, M) {
@@ -231,14 +575,20 @@ machine(Directory, "Directory protocol") {
i_popIncomingRequestQueue;
}
- // transition(M, PUTX, MI) {
- transition(M, PUTX, I) {
+ transition(M, PUTX, MI) {
c_clearOwner;
- l_writeDataToMemory;
- a_sendWriteBackAck;
+// l_writeDataToMemory;
+ l_queueMemoryWBRequest;
+// a_sendWriteBackAck;
+ d_deallocateDirectory;
i_popIncomingRequestQueue;
}
+ transition(MI, Memory_Ack, I) {
+ l_sendWriteBackAck;
+ l_popMemQueue;
+ }
+
transition(M, PUTX_NotOwner, M) {
b_sendWriteBackNack;
i_popIncomingRequestQueue;
@@ -246,12 +596,8 @@ machine(Directory, "Directory protocol") {
transition(I, PUTX_NotOwner, I) {
b_sendWriteBackNack;
+ d_deallocateDirectory;
i_popIncomingRequestQueue;
}
-
- transition(MI, Unblock, M) {
- j_popIncomingUnblockQueue;
- }
-
}
diff --git a/src/mem/protocol/MI_example-dma.sm b/src/mem/protocol/MI_example-dma.sm
new file mode 100644
index 000000000..1f929cf9b
--- /dev/null
+++ b/src/mem/protocol/MI_example-dma.sm
@@ -0,0 +1,135 @@
+
+machine(DMA, "DMA Controller") {
+
+ MessageBuffer responseFromDir, network="From", virtual_network="4", ordered="true", no_vector="true";
+ MessageBuffer reqToDirectory, network="To", virtual_network="5", ordered="false", no_vector="true";
+
+ enumeration(State, desc="DMA states", default="DMA_State_READY") {
+ READY, desc="Ready to accept a new request";
+ BUSY_RD, desc="Busy: currently processing a request";
+ BUSY_WR, desc="Busy: currently processing a request";
+ }
+
+ enumeration(Event, desc="DMA events") {
+ ReadRequest, desc="A new read request";
+ WriteRequest, desc="A new write request";
+ Data, desc="Data from a DMA memory read";
+ Ack, desc="DMA write to memory completed";
+ }
+
+ external_type(DMASequencer) {
+ void ackCallback();
+ void dataCallback(DataBlock);
+ }
+
+ MessageBuffer mandatoryQueue, ordered="false", no_vector="true";
+ DMASequencer dma_sequencer, factory='RubySystem::getDMASequencer(m_cfg["dma_sequencer"])', no_vector="true";
+ State cur_state, no_vector="true";
+
+ State getState(Address addr) {
+ return cur_state;
+ }
+ void setState(Address addr, State state) {
+ cur_state := state;
+ }
+
+ out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="...");
+
+ in_port(dmaRequestQueue_in, DMARequestMsg, mandatoryQueue, desc="...") {
+ if (dmaRequestQueue_in.isReady()) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ if (in_msg.Type == DMARequestType:READ ) {
+ trigger(Event:ReadRequest, in_msg.PhysicalAddress);
+ } else if (in_msg.Type == DMARequestType:WRITE) {
+ trigger(Event:WriteRequest, in_msg.PhysicalAddress);
+ } else {
+ error("Invalid request type");
+ }
+ }
+ }
+ }
+
+ in_port(dmaResponseQueue_in, DMAResponseMsg, responseFromDir, desc="...") {
+ if (dmaResponseQueue_in.isReady()) {
+ peek( dmaResponseQueue_in, DMAResponseMsg) {
+ if (in_msg.Type == DMAResponseType:ACK) {
+ trigger(Event:Ack, in_msg.PhysicalAddress);
+ } else if (in_msg.Type == DMAResponseType:DATA) {
+ trigger(Event:Data, in_msg.PhysicalAddress);
+ } else {
+ error("Invalid response type");
+ }
+ }
+ }
+ }
+
+ action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(reqToDirectory_out, DMARequestMsg) {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMARequestType:READ;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.Len := in_msg.Len;
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+
+ action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(reqToDirectory_out, DMARequestMsg) {
+ out_msg.PhysicalAddress := address;
+ out_msg.Type := DMARequestType:WRITE;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.Len := in_msg.Len;
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+
+ action(a_ackCallback, "a", desc="Notify dma controller that write request completed") {
+ peek (dmaResponseQueue_in, DMAResponseMsg) {
+ dma_sequencer.ackCallback();
+ }
+ }
+
+ action(d_dataCallback, "d", desc="Write data to dma sequencer") {
+ peek (dmaResponseQueue_in, DMAResponseMsg) {
+ dma_sequencer.dataCallback(in_msg.DataBlk);
+ }
+ }
+
+ action(p_popRequestQueue, "p", desc="Pop request queue") {
+ dmaRequestQueue_in.dequeue();
+ }
+
+ action(p_popResponseQueue, "\p", desc="Pop request queue") {
+ dmaResponseQueue_in.dequeue();
+ }
+
+ action(z_stall, "z", desc="dma is busy..stall") {
+ // do nothing
+ }
+
+ transition(READY, ReadRequest, BUSY_RD) {
+ s_sendReadRequest;
+ p_popRequestQueue;
+ }
+
+ transition(READY, WriteRequest, BUSY_WR) {
+ s_sendWriteRequest;
+ p_popRequestQueue;
+ }
+
+ transition(BUSY_RD, Data, READY) {
+ d_dataCallback;
+ p_popResponseQueue;
+ }
+
+ transition(BUSY_WR, Ack, READY) {
+ a_ackCallback;
+ p_popResponseQueue;
+ }
+}
diff --git a/src/mem/protocol/MI_example-msg.sm b/src/mem/protocol/MI_example-msg.sm
index f577d60df..56c2e2e01 100644
--- a/src/mem/protocol/MI_example-msg.sm
+++ b/src/mem/protocol/MI_example-msg.sm
@@ -74,7 +74,6 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
MachineID Requestor, desc="Node who initiated the request";
NetDest Destination, desc="Multicast destination mask";
- int Acks, desc="How many acks to expect";
DataBlock DataBlk, desc="data for the cache line";
MessageSizeType MessageSize, desc="size category of the message";
}
@@ -87,6 +86,35 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Node to whom the data is sent";
DataBlock DataBlk, desc="data for the cache line";
bool Dirty, desc="Is the data dirty (different than memory)?";
- int Acks, desc="How many acks to expect";
+ MessageSizeType MessageSize, desc="size category of the message";
+}
+
+enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
+ READ, desc="Memory Read";
+ WRITE, desc="Memory Write";
+ NULL, desc="Invalid";
+}
+
+enumeration(DMAResponseType, desc="...", default="DMAResponseType_NULL") {
+ DATA, desc="DATA read";
+ ACK, desc="ACK write";
+ NULL, desc="Invalid";
+}
+
+structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
+ DMARequestType Type, desc="Request type (read/write)";
+ Address PhysicalAddress, desc="Physical address for this request";
+ NetDest Destination, desc="Destination";
+ DataBlock DataBlk, desc="DataBlk attached to this request";
+ int Offset, desc="The offset into the datablock";
+ int Len, desc="The length of the request";
+ MessageSizeType MessageSize, desc="size category of the message";
+}
+
+structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
+ DMAResponseType Type, desc="Response type (DATA/ACK)";
+ Address PhysicalAddress, desc="Physical address for this request";
+ NetDest Destination, desc="Destination";
+ DataBlock DataBlk, desc="DataBlk attached to this request";
MessageSizeType MessageSize, desc="size category of the message";
}
diff --git a/src/mem/protocol/MI_example.slicc b/src/mem/protocol/MI_example.slicc
index cb1f80135..523668177 100644
--- a/src/mem/protocol/MI_example.slicc
+++ b/src/mem/protocol/MI_example.slicc
@@ -1,4 +1,5 @@
MI_example-msg.sm
MI_example-cache.sm
MI_example-dir.sm
-standard_1level_SMP-protocol.sm
+MI_example-dma.sm
+standard_1level_CMP-protocol.sm
diff --git a/src/mem/protocol/RubySlicc_ComponentMapping.sm b/src/mem/protocol/RubySlicc_ComponentMapping.sm
index 0c205ac22..022bb6862 100644
--- a/src/mem/protocol/RubySlicc_ComponentMapping.sm
+++ b/src/mem/protocol/RubySlicc_ComponentMapping.sm
@@ -30,6 +30,7 @@
// Mapping functions
// NodeID map_address_to_node(Address addr);
+MachineID map_Address_to_DMA(Address addr);
MachineID map_Address_to_Directory(Address addr);
NodeID map_Address_to_DirectoryNode(Address addr);
MachineID map_Address_to_CentralArbiterNode(Address addr);
diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm
index e1c436938..a8b58b96c 100644
--- a/src/mem/protocol/RubySlicc_Exports.sm
+++ b/src/mem/protocol/RubySlicc_Exports.sm
@@ -131,6 +131,12 @@ enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
IO, desc="I/O";
REPLACEMENT, desc="Replacement";
COMMIT, desc="Commit version";
+ LD_XACT, desc="Transactional Load";
+ LDX_XACT, desc="Transactional Load-Intend-To-Modify";
+ ST_XACT, desc="Transactional Store";
+ BEGIN_XACT, desc="Begin Transaction";
+ COMMIT_XACT, desc="Commit Transaction";
+ ABORT_XACT, desc="Abort Transaction";
NULL, desc="Invalid request type";
}
@@ -156,6 +162,12 @@ enumeration(GenericRequestType, desc="...", default="GenericRequestType_NULL") {
WB_ACK, desc="WriteBack ack";
EXE_ACK, desc="Execlusive ack";
COMMIT, desc="Commit version";
+ LD_XACT, desc="Transactional Load";
+ LDX_XACT, desc="Transactional Load-Intend-Modify";
+ ST_XACT, desc="Transactional Store";
+ BEGIN_XACT, desc="Begin Transaction";
+ COMMIT_XACT, desc="Commit Transaction";
+ ABORT_XACT, desc="Abort Transaction";
NULL, desc="null request type";
}
@@ -211,27 +223,15 @@ enumeration(PrefetchBit, default="PrefetchBit_No", desc="...") {
// CacheMsg
structure(CacheMsg, desc="...", interface="Message") {
- Address Address, desc="Line address for this request";
+ Address LineAddress, desc="Line address for this request";
Address PhysicalAddress, desc="Physical address for this request";
CacheRequestType Type, desc="Type of request (LD, ST, etc)";
Address ProgramCounter, desc="Program counter of the instruction that caused the miss";
AccessModeType AccessMode, desc="user/supervisor access type";
int Size, desc="size in bytes of access";
PrefetchBit Prefetch, desc="Is this a prefetch request";
- // following field only used for MVC
- int Version, desc="Version associated with this request";
- // trans mem fields
- //bool Aborted, desc="This flag is set if the request is from an aborted xact.";
- Address LogicalAddress, desc="Virtual address for this request";
- //int TransactionLevel, desc="Transaction Level of this request";
- //uint64 SequenceNumber, desc="Sequence number of this request";
- int ThreadID, desc="The SMT thread that initiated this request";
- //uint64 RequestTime, desc="The cycle in which this request was issued";
}
-
-
-
// MaskPredictorType
enumeration(MaskPredictorType, "MaskPredictorType_Undefined", desc="...") {
Undefined, desc="Undefined";
diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm
index 3f038031d..aa5648a9e 100644
--- a/src/mem/protocol/RubySlicc_Types.sm
+++ b/src/mem/protocol/RubySlicc_Types.sm
@@ -31,6 +31,7 @@
external_type(DataBlock, desc="..."){
void clear();
+ void copyPartial(DataBlock, int, int);
}
external_type(MessageBuffer, buffer="yes", inport="yes", outport="yes");
@@ -48,8 +49,7 @@ external_type(InPort, primitive="yes") {
external_type(NodeID, default="0");
external_type(MachineID);
-external_type(StoreBuffer);
-
+MessageBuffer getMandatoryQueue(int core_id);
external_type(Set, non_obj="yes") {
void setSize(int);
@@ -96,53 +96,11 @@ external_type(NetDest, non_obj="yes") {
MachineID smallestElement(MachineType);
}
-external_type(PersistentTable) {
- void persistentRequestLock(Address, MachineID, AccessType);
- void persistentRequestUnlock(Address, MachineID);
- bool okToIssueStarving(Address);
- MachineID findSmallest(Address);
- AccessType typeOfSmallest(Address);
- void markEntries(Address);
- bool isLocked(Address);
- int countStarvingForAddress(Address);
- int countReadStarvingForAddress(Address);
-}
-
-external_type(NodePersistentTable) {
- void persistentRequestLock(Address, NodeID, AccessType);
- void persistentRequestUnlock(Address, NodeID);
- bool okToIssueStarving(Address);
- NodeID findSmallest(Address);
- AccessType typeOfSmallest(Address);
- void markEntries(Address);
- bool isLocked(Address);
- int countStarvingForAddress(Address);
- int countReadStarvingForAddress(Address);
-}
-
external_type(Sequencer) {
- void readCallback(Address, DataBlock, GenericMachineType, PrefetchBit, int);
- void writeCallback(Address, DataBlock, GenericMachineType, PrefetchBit, int);
- void readCallback(Address, DataBlock, GenericMachineType, PrefetchBit);
- void writeCallback(Address, DataBlock, GenericMachineType, PrefetchBit);
void readCallback(Address, DataBlock);
void writeCallback(Address, DataBlock);
- void readCallback(Address);
- void writeCallback(Address);
- void readCallbackAbort(Address, int);
- void writeCallbackAbort(Address, int);
- void readConflictCallback(Address);
- void writeConflictCallback(Address);
- void xactCallback(Address);
- void updateCurrentVersion();
- void updateLastCommittedVersion();
- void systemRecovery();
- void systemRestart();
void checkCoherence(Address);
void profileNack(Address, int, int, uint64);
- void resetRequestTime(Address, int);
- bool isReadAborted(Address, int);
- bool isWriteAborted(Address, int);
}
external_type(TimerTable, inport="yes") {
@@ -153,4 +111,16 @@ external_type(TimerTable, inport="yes") {
bool isSet(Address);
}
+external_type(GenericBloomFilter) {
+
+ void clear(int);
+ void increment(Address, int);
+ void decrement(Address, int);
+ void set(Address, int);
+ void unset(Address, int);
+
+ bool isSet(Address, int);
+ int getCount(Address, int);
+}
+
diff --git a/src/mem/protocol/standard_1level_CMP-protocol.sm b/src/mem/protocol/standard_1level_CMP-protocol.sm
new file mode 100644
index 000000000..34da6201f
--- /dev/null
+++ b/src/mem/protocol/standard_1level_CMP-protocol.sm
@@ -0,0 +1,40 @@
+
+/*
+ * 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$
+ */
+
+// global protocol features
+global(Protocol, desc="Global properties of this protocol",
+ interface = "AbstractProtocol") {
+ bool TwoLevelCache := false;
+ bool CMP := true;
+}
+