Ruby: Add support for functional accesses
[gem5.git] / src / mem / protocol / MOESI_CMP_directory-dir.sm
index edd67707e14fb5158c92132b6f921808e15be049..b71518b3f65a7c104d16a8551aceefd53b2bb344 100644 (file)
  */
 
 machine(Directory, "Directory protocol") 
-: int directory_latency 
+:  DirectoryMemory * directory,
+   MemoryControl * memBuffer,
+   int directory_latency = 6
 {
 
   // ** IN QUEUES **
-  MessageBuffer foo1, network="From", virtual_network="0", ordered="false";  // a mod-L2 bank -> this Dir
-  MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false";  // a mod-L2 bank -> this Dir
-  MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false";  // a mod-L2 bank -> this Dir
+  MessageBuffer foo1, network="From", virtual_network="0", ordered="false", vnet_type="foo";  // a mod-L2 bank -> this Dir
+  MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false", vnet_type="request";  // a mod-L2 bank -> this Dir
+  MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false", vnet_type="response";  // a mod-L2 bank -> this Dir
   
-  MessageBuffer goo1, network="To", virtual_network="0", ordered="false";
-  MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false";
-  MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false";  // Dir -> mod-L2 bank
+  MessageBuffer goo1, network="To", virtual_network="0", ordered="false", vnet_type="goo";
+  MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false", vnet_type="forward";
+  MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false", vnet_type="response";  // Dir -> mod-L2 bank
 
 
   // STATES
-  enumeration(State, desc="Directory states", default="Directory_State_I") {
+  state_declaration(State, desc="Directory states", default="Directory_State_I") {
     // Base states
-    I, desc="Invalid";
-    S, desc="Shared";
-    O, desc="Owner";
-    M, desc="Modified";
+    I, AccessPermission:Read_Write, desc="Invalid";
+    S, AccessPermission:Read_Only, desc="Shared";
+    O, AccessPermission:Maybe_Stale, desc="Owner";
+    M, AccessPermission:Maybe_Stale, desc="Modified";
 
-    IS, desc="Blocked, was in idle";
-    SS, desc="Blocked, was in shared";
-    OO, desc="Blocked, was in owned";
-    MO, desc="Blocked, going to owner or maybe modified";
-    MM, desc="Blocked, going to modified";
-    MM_DMA, desc="Blocked, going to I";
+    IS, AccessPermission:Busy, desc="Blocked, was in idle";
+    SS, AccessPermission:Read_Only, desc="Blocked, was in shared";
+    OO, AccessPermission:Busy, desc="Blocked, was in owned";
+    MO, AccessPermission:Busy, desc="Blocked, going to owner or maybe modified";
+    MM, AccessPermission:Busy, desc="Blocked, going to modified";
+    MM_DMA, AccessPermission:Busy, desc="Blocked, going to I";
 
-    MI, desc="Blocked on a writeback";
-    MIS, desc="Blocked on a writeback, but don't remove from sharers when received";
-    OS, desc="Blocked on a writeback";
-    OSS, desc="Blocked on a writeback, but don't remove from sharers when received";
+    MI, AccessPermission:Busy, desc="Blocked on a writeback";
+    MIS, AccessPermission:Busy, desc="Blocked on a writeback, but don't remove from sharers when received";
+    OS, AccessPermission:Busy, desc="Blocked on a writeback";
+    OSS, AccessPermission:Busy, desc="Blocked on a writeback, but don't remove from sharers when received";
 
-    XI_M, desc="In a stable state, going to I, waiting for the memory controller";
-    XI_U, desc="In a stable state, going to I, waiting for an unblock";
-    OI_D, desc="In O, going to I, waiting for data";
+    XI_M, AccessPermission:Busy, desc="In a stable state, going to I, waiting for the memory controller";
+    XI_U, AccessPermission:Busy, desc="In a stable state, going to I, waiting for an unblock";
+    OI_D, AccessPermission:Busy, desc="In O, going to I, waiting for data";
+
+    OD, AccessPermission:Busy, desc="In O, waiting for dma ack from L2";
+    MD, AccessPermission:Busy, desc="In M, waiting for dma ack from L2";
   }
 
   // Events
@@ -86,13 +91,14 @@ machine(Directory, "Directory protocol")
     Memory_Ack,    desc="Writeback Ack from memory arrives";
     DMA_READ,      desc="DMA Read";
     DMA_WRITE,     desc="DMA Write";
+    DMA_ACK,       desc="DMA Ack";
     Data,          desc="Data to directory";
   }
 
   // TYPES
 
   // DirectoryEntry
-  structure(Entry, desc="...") {
+  structure(Entry, desc="...", interface='AbstractEntry') {
     State DirectoryState,          desc="Directory state";
     DataBlock DataBlk,             desc="data for the block";
     NetDest Sharers,                   desc="Sharers for this block";
@@ -101,81 +107,94 @@ machine(Directory, "Directory protocol")
   }
 
   structure(TBE, desc="...") {
-    Address address,   desc="Address for this entry";
+    Address PhysicalAddress,   desc="Physical address for this entry";
     int Len,           desc="Length of request";
     DataBlock DataBlk, desc="DataBlk";
     MachineID Requestor, desc="original requestor";
   }
 
-  external_type(DirectoryMemory) {
-    Entry lookup(Address);
-    bool isPresent(Address);
-  }
-
-  external_type(TBETable) {
+  structure(TBETable, external = "yes") {
     TBE lookup(Address);
     void allocate(Address);
     void deallocate(Address);
     bool isPresent(Address);
   }
 
-  // to simulate detailed DRAM
-  external_type(MemoryControl, inport="yes", outport="yes") {
-
-  }
-
-
   // ** OBJECTS **
-
-  DirectoryMemory directory, factory='RubySystem::getDirectory(m_cfg["directory_name"])';
-  MemoryControl memBuffer, factory='RubySystem::getMemoryControl(m_cfg["memory_controller_name"])';
   TBETable TBEs, template_hack="<Directory_TBE>";
 
-  State getState(Address addr) {
-    return directory[addr].DirectoryState;
+  void set_tbe(TBE b);
+  void unset_tbe();
+
+  Entry getDirectoryEntry(Address addr), return_by_ref="yes" {
+    return static_cast(Entry, directory[addr]);
+  }
+
+  State getState(TBE tbe, Address addr) {
+    return getDirectoryEntry(addr).DirectoryState;
   }
 
-  void setState(Address addr, State state) {
+  void setState(TBE tbe, Address addr, State state) {
     if (directory.isPresent(addr)) {
 
       if (state == State:I) {
-        assert(directory[addr].Owner.count() == 0);
-        assert(directory[addr].Sharers.count() == 0);
+        assert(getDirectoryEntry(addr).Owner.count() == 0);
+        assert(getDirectoryEntry(addr).Sharers.count() == 0);
       }
 
       if (state == State:S) {
-        assert(directory[addr].Owner.count() == 0);
+        assert(getDirectoryEntry(addr).Owner.count() == 0);
       }
 
       if (state == State:O) {
-        assert(directory[addr].Owner.count() == 1);
-        assert(directory[addr].Sharers.isSuperset(directory[addr].Owner) == false);
+        assert(getDirectoryEntry(addr).Owner.count() == 1);
+        assert(getDirectoryEntry(addr).Sharers.isSuperset(getDirectoryEntry(addr).Owner) == false);
       }
 
       if (state == State:M) {
-        assert(directory[addr].Owner.count() == 1);
-        assert(directory[addr].Sharers.count() == 0);
+        assert(getDirectoryEntry(addr).Owner.count() == 1);
+        assert(getDirectoryEntry(addr).Sharers.count() == 0);
       }
 
       if ((state != State:SS) && (state != State:OO)) {
-        assert(directory[addr].WaitingUnblocks == 0);
+        assert(getDirectoryEntry(addr).WaitingUnblocks == 0);
       }
 
-      if ( (directory[addr].DirectoryState != State:I) && (state == State:I) ) {
-        directory[addr].DirectoryState := state;
+      if ( (getDirectoryEntry(addr).DirectoryState != State:I) && (state == State:I) ) {
+        getDirectoryEntry(addr).DirectoryState := state;
          // disable coherence checker
         // sequencer.checkCoherence(addr);
       }
       else {
-        directory[addr].DirectoryState := state;
+        getDirectoryEntry(addr).DirectoryState := state;
       }
     }
   }
 
+  AccessPermission getAccessPermission(Address addr) {
+    if (directory.isPresent(addr)) {
+      DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
+      return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+    }
+
+    DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
+    return AccessPermission:NotPresent;
+  }
+
+  void setAccessPermission(Address addr, State state) {
+    if (directory.isPresent(addr)) {
+      getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
+    }
+  }
+
+  DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    return getDirectoryEntry(addr).DataBlk;
+  }
+
   // if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking
   bool isBlockShared(Address addr) {
     if (directory.isPresent(addr)) {
-      if (directory[addr].DirectoryState == State:I) {
+      if (getDirectoryEntry(addr).DirectoryState == State:I) {
         return true;
       }
     }
@@ -184,7 +203,7 @@ machine(Directory, "Directory protocol")
 
   bool isBlockExclusive(Address addr) {
     if (directory.isPresent(addr)) {
-      if (directory[addr].DirectoryState == State:I) {
+      if (getDirectoryEntry(addr).DirectoryState == State:I) {
         return true;
       }
     }
@@ -211,19 +230,28 @@ machine(Directory, "Directory protocol")
     if (unblockNetwork_in.isReady()) {
       peek(unblockNetwork_in, ResponseMsg) {
         if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
-          if (directory[in_msg.Address].WaitingUnblocks == 1) {
-            trigger(Event:Last_Unblock, in_msg.Address);
+          if (getDirectoryEntry(in_msg.Address).WaitingUnblocks == 1) {
+            trigger(Event:Last_Unblock, in_msg.Address,
+                    TBEs[in_msg.Address]);
           } else {
-            trigger(Event:Unblock, in_msg.Address);
+            trigger(Event:Unblock, in_msg.Address,
+                    TBEs[in_msg.Address]);
           }
         } else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
-          trigger(Event:Exclusive_Unblock, in_msg.Address);
+          trigger(Event:Exclusive_Unblock, in_msg.Address,
+                  TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
-          trigger(Event:Dirty_Writeback, in_msg.Address);
+          trigger(Event:Dirty_Writeback, in_msg.Address,
+                  TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_ACK) {
-          trigger(Event:Clean_Writeback, in_msg.Address);
+          trigger(Event:Clean_Writeback, in_msg.Address,
+                  TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
-          trigger(Event:Data, in_msg.Address);        
+          trigger(Event:Data, in_msg.Address,
+                  TBEs[in_msg.Address]);
+        } else if (in_msg.Type == CoherenceResponseType:DMA_ACK) {
+          trigger(Event:DMA_ACK, in_msg.Address,
+                  TBEs[in_msg.Address]);
         } else {
           error("Invalid message");
         }
@@ -235,19 +263,21 @@ machine(Directory, "Directory protocol")
     if (requestQueue_in.isReady()) {
       peek(requestQueue_in, RequestMsg) {
         if (in_msg.Type == CoherenceRequestType:GETS) {
-          trigger(Event:GETS, in_msg.Address);
+          trigger(Event:GETS, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceRequestType:GETX) {
-          trigger(Event:GETX, in_msg.Address);
+          trigger(Event:GETX, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceRequestType:PUTX) {
-          trigger(Event:PUTX, in_msg.Address);
+          trigger(Event:PUTX, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceRequestType:PUTO) {
-          trigger(Event:PUTO, in_msg.Address);
+          trigger(Event:PUTO, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) {
-          trigger(Event:PUTO_SHARERS, in_msg.Address);
+          trigger(Event:PUTO_SHARERS, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == CoherenceRequestType:DMA_READ) {
-          trigger(Event:DMA_READ, in_msg.Address);
+          trigger(Event:DMA_READ, makeLineAddress(in_msg.Address),
+                  TBEs[makeLineAddress(in_msg.Address)]);
         } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) {
-          trigger(Event:DMA_WRITE, in_msg.Address);
+          trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address),
+                  TBEs[makeLineAddress(in_msg.Address)]);
         } else {
           error("Invalid message");
         }
@@ -260,11 +290,11 @@ machine(Directory, "Directory protocol")
     if (memQueue_in.isReady()) {
       peek(memQueue_in, MemoryMsg) {
         if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
-          trigger(Event:Memory_Data, in_msg.Address);
+          trigger(Event:Memory_Data, in_msg.Address, TBEs[in_msg.Address]);
         } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
-          trigger(Event:Memory_Ack, in_msg.Address);
+          trigger(Event:Memory_Ack, in_msg.Address, TBEs[in_msg.Address]);
         } else {
-          DEBUG_EXPR(in_msg.Type);
+          DPRINTF(RubySlicc, "%s\n", in_msg.Type);
           error("Invalid message");
         }
       }
@@ -279,6 +309,7 @@ machine(Directory, "Directory protocol")
         out_msg.Address := address;
         out_msg.Type := CoherenceRequestType:WB_ACK;
         out_msg.Requestor := in_msg.Requestor;
+        out_msg.RequestorMachine := MachineType:Directory;
         out_msg.Destination.add(in_msg.Requestor);
         out_msg.MessageSize := MessageSizeType:Writeback_Control;
       }
@@ -291,6 +322,7 @@ machine(Directory, "Directory protocol")
         out_msg.Address := address;
         out_msg.Type := CoherenceRequestType:WB_NACK;
         out_msg.Requestor := in_msg.Requestor;
+        out_msg.RequestorMachine := MachineType:Directory;
         out_msg.Destination.add(in_msg.Requestor);
         out_msg.MessageSize := MessageSizeType:Writeback_Control;
       }
@@ -298,16 +330,16 @@ machine(Directory, "Directory protocol")
   }
 
   action(c_clearOwner, "c", desc="Clear the owner field") {
-    directory[address].Owner.clear();
+    getDirectoryEntry(address).Owner.clear();
   }
 
   action(c_moveOwnerToSharer, "cc", desc="Move owner to sharers") {
-    directory[address].Sharers.addNetDest(directory[address].Owner);
-    directory[address].Owner.clear();
+    getDirectoryEntry(address).Sharers.addNetDest(getDirectoryEntry(address).Owner);
+    getDirectoryEntry(address).Owner.clear();
   }
 
   action(cc_clearSharers, "\c", desc="Clear the sharers field") {
-    directory[address].Sharers.clear();
+    getDirectoryEntry(address).Sharers.clear();
   }
 
   action(d_sendDataMsg, "d", desc="Send data to requestor") {
@@ -317,7 +349,7 @@ machine(Directory, "Directory protocol")
         out_msg.Sender := machineID;
         out_msg.SenderMachine := MachineType:Directory;
         out_msg.Destination.add(in_msg.OriginalRequestorMachId);
-        //out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+        //out_msg.DataBlk := getDirectoryEntry(in_msg.Address).DataBlk;
         out_msg.DataBlk := in_msg.DataBlk;
         out_msg.Dirty := false; // By definition, the block is now clean
         out_msg.Acks := in_msg.Acks;
@@ -331,10 +363,27 @@ machine(Directory, "Directory protocol")
     }
   }
 
+  action(p_fwdDataToDMA, "\d", desc="Send data to requestor") {
+    peek(requestQueue_in, RequestMsg) {
+      enqueue(responseNetwork_out, ResponseMsg, latency="1") {
+        out_msg.Address := address;
+        out_msg.Sender := machineID;
+        out_msg.SenderMachine := MachineType:Directory;
+        out_msg.Destination.add(in_msg.Requestor);
+        out_msg.DataBlk := getDirectoryEntry(in_msg.Address).DataBlk;
+        out_msg.Dirty := false; // By definition, the block is now clean
+        out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
+        out_msg.MessageSize := MessageSizeType:Response_Data;
+      }
+    }
+  }
+
+
+
   action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
     peek(unblockNetwork_in, ResponseMsg) {
-      directory[address].Owner.clear();
-      directory[address].Owner.add(in_msg.Sender);
+      getDirectoryEntry(address).Owner.clear();
+      getDirectoryEntry(address).Owner.add(in_msg.Sender);
     }
   }
 
@@ -344,9 +393,10 @@ machine(Directory, "Directory protocol")
         out_msg.Address := address;
         out_msg.Type := in_msg.Type;
         out_msg.Requestor := in_msg.Requestor;
-        out_msg.Destination.addNetDest(directory[in_msg.Address].Owner);
-        out_msg.Acks := directory[address].Sharers.count();
-        if (directory[address].Sharers.isElement(in_msg.Requestor)) {
+        out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
+        out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.Address).Owner);
+        out_msg.Acks := getDirectoryEntry(address).Sharers.count();
+        if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) {
           out_msg.Acks := out_msg.Acks - 1;
         }
         out_msg.MessageSize := MessageSizeType:Forwarded_Control;
@@ -360,9 +410,10 @@ machine(Directory, "Directory protocol")
         out_msg.Address := address;
         out_msg.Type := in_msg.Type;
         out_msg.Requestor := machineID;
-        out_msg.Destination.addNetDest(directory[in_msg.Address].Owner);
-        out_msg.Acks := directory[address].Sharers.count();
-        if (directory[address].Sharers.isElement(in_msg.Requestor)) {
+        out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
+        out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.Address).Owner);
+        out_msg.Acks := getDirectoryEntry(address).Sharers.count();
+        if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) {
           out_msg.Acks := out_msg.Acks - 1;
         }
         out_msg.MessageSize := MessageSizeType:Forwarded_Control;
@@ -372,14 +423,15 @@ machine(Directory, "Directory protocol")
 
   action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
     peek(requestQueue_in, RequestMsg) {
-      if ((directory[in_msg.Address].Sharers.count() > 1) ||
-          ((directory[in_msg.Address].Sharers.count() > 0) && (directory[in_msg.Address].Sharers.isElement(in_msg.Requestor) == false))) {
+      if ((getDirectoryEntry(in_msg.Address).Sharers.count() > 1) ||
+          ((getDirectoryEntry(in_msg.Address).Sharers.count() > 0) && (getDirectoryEntry(in_msg.Address).Sharers.isElement(in_msg.Requestor) == false))) {
         enqueue(forwardNetwork_out, RequestMsg, latency=directory_latency) {
           out_msg.Address := address;
           out_msg.Type := CoherenceRequestType:INV;
           out_msg.Requestor := in_msg.Requestor;
-          // out_msg.Destination := directory[in_msg.Address].Sharers;
-          out_msg.Destination.addNetDest(directory[in_msg.Address].Sharers);
+          out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
+          // out_msg.Destination := getDirectoryEntry(in_msg.Address).Sharers;
+          out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.Address).Sharers);
           out_msg.Destination.remove(in_msg.Requestor);
           out_msg.MessageSize := MessageSizeType:Invalidate_Control;
         }
@@ -399,12 +451,20 @@ machine(Directory, "Directory protocol")
     peek(unblockNetwork_in, ResponseMsg) {
       assert(in_msg.Dirty);
       assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
-      directory[in_msg.Address].DataBlk := in_msg.DataBlk;
-      DEBUG_EXPR(in_msg.Address);
-      DEBUG_EXPR(in_msg.DataBlk);
+      getDirectoryEntry(in_msg.Address).DataBlk := in_msg.DataBlk;
+      DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
+              in_msg.Address, in_msg.DataBlk);
     }
   }
 
+  action(p_writeFwdDataToMemory, "p", desc="Write Response data to memory") {
+     peek(unblockNetwork_in, ResponseMsg) {
+      getDirectoryEntry(in_msg.Address).DataBlk := in_msg.DataBlk;
+      DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
+              in_msg.Address, in_msg.DataBlk);
+    }
+ }
+
   action(ll_checkDataInMemory, "\ld", desc="Check PUTX/PUTO data is same as in the memory") {
     peek(unblockNetwork_in, ResponseMsg) {
       assert(in_msg.Dirty == false);
@@ -414,23 +474,23 @@ machine(Directory, "Directory protocol")
       // implementation.  We include the data in the "dataless"
       // message so we can assert the clean data matches the datablock
       // in memory
-      assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
+      assert(getDirectoryEntry(in_msg.Address).DataBlk == in_msg.DataBlk);
     }
   }
 
   action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
     peek(unblockNetwork_in, ResponseMsg) {
-      directory[address].Sharers.add(in_msg.Sender);
+      getDirectoryEntry(address).Sharers.add(in_msg.Sender);
     }
   }
 
   action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
-    directory[address].WaitingUnblocks := directory[address].WaitingUnblocks + 1;
+    getDirectoryEntry(address).WaitingUnblocks := getDirectoryEntry(address).WaitingUnblocks + 1;
   }
 
   action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
-    directory[address].WaitingUnblocks := directory[address].WaitingUnblocks - 1;
-    assert(directory[address].WaitingUnblocks >= 0);
+    getDirectoryEntry(address).WaitingUnblocks := getDirectoryEntry(address).WaitingUnblocks - 1;
+    assert(getDirectoryEntry(address).WaitingUnblocks >= 0);
   }
 
   action(q_popMemQueue, "q", desc="Pop off-chip request queue") {
@@ -444,16 +504,16 @@ machine(Directory, "Directory protocol")
         out_msg.Type := MemoryRequestType:MEMORY_READ;
         out_msg.Sender := machineID;
         out_msg.OriginalRequestorMachId := in_msg.Requestor;
-        out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+        out_msg.DataBlk := getDirectoryEntry(in_msg.Address).DataBlk;
         out_msg.MessageSize := in_msg.MessageSize;
         //out_msg.Prefetch := false;
         // These are not used by memory but are passed back here with the read data:
-        out_msg.ReadX := (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0);
-        out_msg.Acks := directory[address].Sharers.count();
-        if (directory[address].Sharers.isElement(in_msg.Requestor)) {
+        out_msg.ReadX := (in_msg.Type == CoherenceRequestType:GETS && getDirectoryEntry(address).Sharers.count() == 0);
+        out_msg.Acks := getDirectoryEntry(address).Sharers.count();
+        if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) {
           out_msg.Acks := out_msg.Acks - 1;
         }
-        DEBUG_EXPR(out_msg);
+        DPRINTF(RubySlicc, "%s\n", out_msg);
       }
     }
   }
@@ -464,16 +524,16 @@ machine(Directory, "Directory protocol")
         out_msg.Address := address;
         out_msg.Type := MemoryRequestType:MEMORY_WB;
         out_msg.Sender := machineID;
-       if (TBEs.isPresent(address)) {
-          out_msg.OriginalRequestorMachId := TBEs[address].Requestor;
-       }
+        if (is_valid(tbe)) {
+          out_msg.OriginalRequestorMachId := tbe.Requestor;
+        }
         out_msg.DataBlk := in_msg.DataBlk;
         out_msg.MessageSize := in_msg.MessageSize;
         //out_msg.Prefetch := false;
         // Not used:
         out_msg.ReadX := false;
-        out_msg.Acks := directory[address].Sharers.count();  // for dma requests
-        DEBUG_EXPR(out_msg);
+        out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
+        DPRINTF(RubySlicc, "%s\n", out_msg);
       }
     }
   }
@@ -490,8 +550,8 @@ machine(Directory, "Directory protocol")
         //out_msg.Prefetch := false;
         // Not used:
         out_msg.ReadX := false;
-        out_msg.Acks := directory[address].Sharers.count();  // for dma requests
-        DEBUG_EXPR(out_msg);
+        out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
+        DPRINTF(RubySlicc, "%s\n", out_msg);
       }
     }
   }
@@ -506,14 +566,31 @@ machine(Directory, "Directory protocol")
   }
 
   action(a_sendDMAAck, "\a", desc="Send DMA Ack that write completed, along with Inv Ack count") {
-    peek(memQueue_in, MemoryMsg) {
+    peek(requestQueue_in, RequestMsg) {
       enqueue(responseNetwork_out, ResponseMsg, latency="1") {
       out_msg.Address := address;
       out_msg.Sender := machineID;
       out_msg.SenderMachine := MachineType:Directory;
-        out_msg.Destination.add(in_msg.OriginalRequestorMachId);
+      out_msg.Destination.add(in_msg.Requestor);
       out_msg.DataBlk := in_msg.DataBlk;
-      out_msg.Acks := in_msg.Acks;
+      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
+      out_msg.Type := CoherenceResponseType:DMA_ACK;
+      out_msg.MessageSize := MessageSizeType:Writeback_Control;
+      }
+    }
+  }
+
+  action(a_sendDMAAck2, "\aa", desc="Send DMA Ack that write completed, along with Inv Ack count") {
+    peek(unblockNetwork_in, ResponseMsg) {
+      enqueue(responseNetwork_out, ResponseMsg, latency="1") {
+      out_msg.Address := address;
+      out_msg.Sender := machineID;
+      out_msg.SenderMachine := MachineType:Directory;
+      if (is_valid(tbe)) {
+        out_msg.Destination.add(tbe.Requestor);
+      }
+      out_msg.DataBlk := in_msg.DataBlk;
+      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
       out_msg.Type := CoherenceResponseType:DMA_ACK;
       out_msg.MessageSize := MessageSizeType:Writeback_Control;
       }
@@ -522,25 +599,30 @@ machine(Directory, "Directory protocol")
 
   action(l_writeDMADataToMemory, "\l", desc="Write data from a DMA_WRITE to memory") {
     peek(requestQueue_in, RequestMsg) {
-      directory[address].DataBlk.copyPartial(in_msg.DataBlk, addressOffset(in_msg.Address), in_msg.Len);
+      getDirectoryEntry(address).DataBlk.copyPartial(in_msg.DataBlk, addressOffset(in_msg.Address), in_msg.Len);
     }
   }
 
   action(l_writeDMADataToMemoryFromTBE, "\ll", desc="Write data from a DMA_WRITE to memory") {
-    directory[address].DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(address), TBEs[address].Len);
+    assert(is_valid(tbe));
+    getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, 
+                      addressOffset(tbe.PhysicalAddress), tbe.Len);
   }
 
   action(v_allocateTBE, "v", desc="Allocate TBE entry") {
     peek (requestQueue_in, RequestMsg) {
       TBEs.allocate(address);
-      TBEs[address].Len := in_msg.Len;
-      TBEs[address].DataBlk := in_msg.DataBlk;
-      TBEs[address].Requestor := in_msg.Requestor;
+      set_tbe(TBEs[address]);
+      tbe.PhysicalAddress := in_msg.Address;
+      tbe.Len := in_msg.Len;
+      tbe.DataBlk := in_msg.DataBlk;
+      tbe.Requestor := in_msg.Requestor;
     }
   }
 
   action(w_deallocateTBE, "w", desc="Deallocate TBE entry") {
     TBEs.deallocate(address);
+    unset_tbe();
   }
 
 
@@ -557,22 +639,18 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(I, DMA_WRITE, XI_M) {
+  transition(I, DMA_WRITE, XI_U) {
     qw_queueMemoryWBRequest2;
+    a_sendDMAAck;  // ack count may be zero
     l_writeDMADataToMemory;
     i_popIncomingRequestQueue;
   }
 
-  transition(XI_M, Memory_Data, XI_U) {
+  transition(XI_M, Memory_Data, I) {
     d_sendDataMsg;  // ack count may be zero
     q_popMemQueue;
   }
 
-  transition(XI_M, Memory_Ack, XI_U) {
-    a_sendDMAAck;  // ack count may be zero
-    q_popMemQueue;
-  }
-
   transition(XI_U, Exclusive_Unblock, I) {
     cc_clearSharers;
     c_clearOwner;
@@ -585,14 +663,16 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(S, DMA_READ, XI_M) {
-    qf_queueMemoryFetchRequest;
-    g_sendInvalidations;  // the DMA will collect the invalidations then send an Unblock Exclusive
+  transition(S, DMA_READ) {
+    //qf_queueMemoryFetchRequest;
+    p_fwdDataToDMA;
+    //g_sendInvalidations;  // the DMA will collect the invalidations then send an Unblock Exclusive
     i_popIncomingRequestQueue;
   }
 
-  transition(S, DMA_WRITE, XI_M) {
+  transition(S, DMA_WRITE, XI_U) {
     qw_queueMemoryWBRequest2;
+    a_sendDMAAck;  // ack count may be zero
     l_writeDMADataToMemory;
     g_sendInvalidations;  // the DMA will collect invalidations
     i_popIncomingRequestQueue;
@@ -625,12 +705,16 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(O, DMA_READ, XI_U) {
+  transition(O, DMA_READ, OD) {
     f_forwardRequest;     // this will cause the data to go to DMA directly
-    g_sendInvalidations;  // this will cause acks to be sent to the DMA
+    //g_sendInvalidations;  // this will cause acks to be sent to the DMA
     i_popIncomingRequestQueue;
   }
 
+  transition(OD, DMA_ACK, O) {
+    j_popIncomingUnblockQueue;
+  }
+
   transition({O,M}, DMA_WRITE, OI_D) {
     f_forwardRequestDirIsRequestor;    // need the modified data before we can proceed
     g_sendInvalidations;               // these go to the DMA Controller
@@ -638,9 +722,10 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(OI_D, Data, XI_M) {
+  transition(OI_D, Data, XI_U) {
     qw_queueMemoryWBRequest;
-    l_writeDataToMemory;
+    a_sendDMAAck2;  // ack count may be zero
+    p_writeFwdDataToMemory;
     l_writeDMADataToMemoryFromTBE;
     w_deallocateTBE;
     j_popIncomingUnblockQueue;
@@ -658,11 +743,15 @@ machine(Directory, "Directory protocol")
   }
 
   // no exclusive unblock will show up to the directory
-  transition(M, DMA_READ, XI_U) {
+  transition(M, DMA_READ, MD) {
     f_forwardRequest;     // this will cause the data to go to DMA directly
     i_popIncomingRequestQueue;
   }
 
+  transition(MD, DMA_ACK, M) {
+    j_popIncomingUnblockQueue;
+  }
+
   transition(M, GETS, MO) {
     f_forwardRequest;
     i_popIncomingRequestQueue;
@@ -695,7 +784,7 @@ machine(Directory, "Directory protocol")
   }
 
 
-  transition({MM, MO, MI, MIS, OS, OSS}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ}) {
+  transition({MM, MO, MI, MIS, OS, OSS, XI_M, XI_U, OI_D, OD, MD}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) {
     zz_recycleRequest;
   }
 
@@ -710,7 +799,7 @@ machine(Directory, "Directory protocol")
     j_popIncomingUnblockQueue;
   }
 
-  transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ}) {
+  transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) {
     zz_recycleRequest;
   }
 
@@ -818,7 +907,7 @@ machine(Directory, "Directory protocol")
     q_popMemQueue;
   }
 
-  transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS}, Memory_Ack) {
+  transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS, XI_U, XI_M}, Memory_Ack) {
     //a_sendAck;
     q_popMemQueue;
   }