summaryrefslogtreecommitdiff
path: root/src/mem/protocol
diff options
context:
space:
mode:
authorNathan Binkert <nate@binkert.org>2009-07-06 15:49:47 -0700
committerNathan Binkert <nate@binkert.org>2009-07-06 15:49:47 -0700
commit92de70b69aaf3f399a855057b556ed198139e5d8 (patch)
treef8e7d0d494df8810cc960be4c52d8b555471f157 /src/mem/protocol
parent05f6a4a6b92370162da17ef5cccb5a7e3ba508e5 (diff)
downloadgem5-92de70b69aaf3f399a855057b556ed198139e5d8.tar.xz
ruby: Import the latest ruby changes from gems.
This was done with an automated process, so there could be things that were done in this tree in the past that didn't make it. One known regression is that atomic memory operations do not seem to work properly anymore.
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;
+}
+