Ruby: Add support for functional accesses
[gem5.git] / src / mem / protocol / MOESI_CMP_directory-dir.sm
index 8e48fc9ab989a0dcf947ead442733b55d0b77ae0..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";
@@ -107,75 +113,88 @@ machine(Directory, "Directory protocol")
     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, makeLineAddress(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, makeLineAddress(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;
@@ -338,7 +370,7 @@ machine(Directory, "Directory protocol")
         out_msg.Sender := machineID;
         out_msg.SenderMachine := MachineType:Directory;
         out_msg.Destination.add(in_msg.Requestor);
-        out_msg.DataBlk := directory[in_msg.Address].DataBlk;
+        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;
@@ -350,8 +382,8 @@ machine(Directory, "Directory protocol")
 
   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);
     }
   }
 
@@ -361,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;
@@ -377,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;
@@ -389,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;
         }
@@ -416,17 +451,17 @@ 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) {
-      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);
     }
  }
 
@@ -439,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") {
@@ -469,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);
       }
     }
   }
@@ -489,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);
       }
     }
   }
@@ -515,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);
       }
     }
   }
@@ -538,7 +573,7 @@ machine(Directory, "Directory protocol")
       out_msg.SenderMachine := MachineType:Directory;
       out_msg.Destination.add(in_msg.Requestor);
       out_msg.DataBlk := in_msg.DataBlk;
-      out_msg.Acks := directory[address].Sharers.count();  // for dma requests
+      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
       out_msg.Type := CoherenceResponseType:DMA_ACK;
       out_msg.MessageSize := MessageSizeType:Writeback_Control;
       }
@@ -551,11 +586,11 @@ machine(Directory, "Directory protocol")
       out_msg.Address := address;
       out_msg.Sender := machineID;
       out_msg.SenderMachine := MachineType:Directory;
-      if (TBEs.isPresent(address)) {
-        out_msg.Destination.add(TBEs[address].Requestor);
+      if (is_valid(tbe)) {
+        out_msg.Destination.add(tbe.Requestor);
       }
       out_msg.DataBlk := in_msg.DataBlk;
-      out_msg.Acks := directory[address].Sharers.count();  // for dma requests
+      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
       out_msg.Type := CoherenceResponseType:DMA_ACK;
       out_msg.MessageSize := MessageSizeType:Writeback_Control;
       }
@@ -564,28 +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(TBEs[address].PhysicalAddress)
-                                          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].PhysicalAddress := in_msg.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();
   }
 
 
@@ -626,7 +663,7 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(S, DMA_READ, S) {
+  transition(S, DMA_READ) {
     //qf_queueMemoryFetchRequest;
     p_fwdDataToDMA;
     //g_sendInvalidations;  // the DMA will collect the invalidations then send an Unblock Exclusive
@@ -668,12 +705,16 @@ machine(Directory, "Directory protocol")
     i_popIncomingRequestQueue;
   }
 
-  transition(O, DMA_READ, O) {
+  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
     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
@@ -702,11 +743,15 @@ machine(Directory, "Directory protocol")
   }
 
   // no exclusive unblock will show up to the directory
-  transition(M, DMA_READ, M) {
+  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;
@@ -739,7 +784,7 @@ machine(Directory, "Directory protocol")
   }
 
 
-  transition({MM, MO, MI, MIS, OS, OSS, XI_M, XI_U, OI_D}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) {
+  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;
   }