ruby: improved support for functional accesses
authorNilay Vaish <nilay@cs.wisc.edu>
Mon, 15 Oct 2012 22:51:57 +0000 (17:51 -0500)
committerNilay Vaish <nilay@cs.wisc.edu>
Mon, 15 Oct 2012 22:51:57 +0000 (17:51 -0500)
This patch adds support to different entities in the ruby memory system
for more reliable functional read/write accesses. Only the simple network
has been augmented as of now. Later on Garnet will also support functional
accesses.
The patch adds functional access code to all the different types of messages
that protocols can send around. These messages are functionally accessed
by going through the buffers maintained by the network entities.
The patch also rectifies some of the bugs found in coherence protocols while
testing the patch.

With this patch applied, functional writes always succeed. But functional
reads can still fail.

45 files changed:
configs/example/ruby_mem_test.py
src/mem/protocol/MESI_CMP_directory-L1cache.sm
src/mem/protocol/MESI_CMP_directory-L2cache.sm
src/mem/protocol/MESI_CMP_directory-dir.sm
src/mem/protocol/MESI_CMP_directory-msg.sm
src/mem/protocol/MI_example-cache.sm
src/mem/protocol/MI_example-dir.sm
src/mem/protocol/MI_example-msg.sm
src/mem/protocol/MOESI_CMP_directory-L1cache.sm
src/mem/protocol/MOESI_CMP_directory-L2cache.sm
src/mem/protocol/MOESI_CMP_directory-dir.sm
src/mem/protocol/MOESI_CMP_directory-msg.sm
src/mem/protocol/MOESI_CMP_token-L1cache.sm
src/mem/protocol/MOESI_CMP_token-dir.sm
src/mem/protocol/MOESI_CMP_token-msg.sm
src/mem/protocol/MOESI_hammer-cache.sm
src/mem/protocol/MOESI_hammer-dir.sm
src/mem/protocol/MOESI_hammer-msg.sm
src/mem/protocol/Network_test-msg.sm
src/mem/protocol/RubySlicc_Exports.sm
src/mem/protocol/RubySlicc_MemControl.sm
src/mem/ruby/buffers/MessageBuffer.cc
src/mem/ruby/buffers/MessageBuffer.hh
src/mem/ruby/buffers/MessageBufferNode.hh
src/mem/ruby/network/Network.hh
src/mem/ruby/network/simple/PerfectSwitch.cc
src/mem/ruby/network/simple/SimpleNetwork.cc
src/mem/ruby/network/simple/SimpleNetwork.hh
src/mem/ruby/network/simple/Switch.cc
src/mem/ruby/network/simple/Switch.hh
src/mem/ruby/slicc_interface/AbstractController.hh
src/mem/ruby/slicc_interface/Message.hh
src/mem/ruby/slicc_interface/NetworkMessage.hh
src/mem/ruby/slicc_interface/RubyRequest.cc
src/mem/ruby/slicc_interface/RubyRequest.hh
src/mem/ruby/slicc_interface/RubySlicc_Util.hh
src/mem/ruby/system/MemoryControl.cc
src/mem/ruby/system/MemoryControl.hh
src/mem/ruby/system/RubyMemoryControl.cc
src/mem/ruby/system/RubyMemoryControl.hh
src/mem/ruby/system/System.cc
src/mem/slicc/ast/TypeDeclAST.py
src/mem/slicc/symbols/StateMachine.py
src/mem/slicc/symbols/SymbolTable.py
src/mem/slicc/symbols/Type.py

index 858d13ee84a3f6274fe8ca2fd061e32f90e62999..1d3e20412867f069b8d760e365336c14c0394801 100644 (file)
@@ -43,7 +43,6 @@ import Ruby
 # Get paths we might need.  It's expected this file is in m5/configs/example.
 config_path = os.path.dirname(os.path.abspath(__file__))
 config_root = os.path.dirname(config_path)
-m5_root = os.path.dirname(config_root)
 
 parser = optparse.OptionParser()
 Options.addCommonOptions(parser)
index d54f7e71c0a02a671796c0fa40c2a9ed22806fbb..eb8e62d30bb577fd9caa3c3cf6851642224d523b 100644 (file)
@@ -201,6 +201,11 @@ machine(L1Cache, "MESI Directory L1 Cache CMP")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := L1_TBEs[addr];
+    if(is_valid(tbe)) {
+        return tbe.DataBlk;
+    }
+
     return getCacheEntry(addr).DataBlk;
   }
 
index 88053aeb876f0830fccf33119aa0302cee8ca4ec..fbdc10ac2e866a6026630ff5cb59cfe14ac0d1a8 100644 (file)
@@ -232,6 +232,11 @@ machine(L2Cache, "MESI Directory L2 Cache CMP")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := L2_TBEs[addr];
+    if(is_valid(tbe)) {
+        return tbe.DataBlk;
+    }
+
     return getCacheEntry(addr).DataBlk;
   }
 
index 7e1280337a4aeb784ebdd1afe2c0024c1223e014..d98326b34a0531b5f622265553f10b71a6d12960 100644 (file)
@@ -110,7 +110,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
   void set_tbe(TBE tbe);
   void unset_tbe();
   void wakeUpBuffers(Address a);
-      
+
   Entry getDirectoryEntry(Address addr), return_by_pointer="yes" {
     Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
 
@@ -170,6 +170,11 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+        return tbe.DataBlk;
+    }
+
     return getDirectoryEntry(addr).DataBlk;
   }
 
index 67619f075fe34f079570a03deff228b851262cfb..473012c61e36a153deeb87e8c28d229544dde8a8 100644 (file)
@@ -35,11 +35,9 @@ enumeration(CoherenceRequestType, desc="...") {
   GETS,      desc="Get Shared";
   GET_INSTR, desc="Get Instruction";
   INV,       desc="INValidate";
-  PUTX,      desc="replacement message";
+  PUTX,      desc="Replacement message";
 
   WB_ACK,    desc="Writeback ack";
-  WB_NACK,   desc="Writeback neg. ack";
-  FWD,      desc="Generic FWD";
 
   DMA_READ, desc="DMA Read";
   DMA_WRITE, desc="DMA Write";
@@ -47,14 +45,14 @@ enumeration(CoherenceRequestType, desc="...") {
 
 // CoherenceResponseType
 enumeration(CoherenceResponseType, desc="...") {
-  MEMORY_ACK,  desc="Ack from memory controller";
-  DATA,      desc="Data";
-  DATA_EXCLUSIVE,      desc="Data";
-  MEMORY_DATA,    desc="Data";
-  ACK,            desc="Generic invalidate ack";
-  WB_ACK,            desc="writeback ack";
-  UNBLOCK,         desc="unblock";
-  EXCLUSIVE_UNBLOCK,         desc="exclusive unblock";
+  MEMORY_ACK, desc="Ack from memory controller";
+  DATA, desc="Data block for L1 cache in S state";
+  DATA_EXCLUSIVE, desc="Data block for L1 cache in M/E state";
+  MEMORY_DATA, desc="Data block from / to main memory";
+  ACK, desc="Generic invalidate ack";
+  WB_ACK, desc="writeback ack";
+  UNBLOCK, desc="unblock";
+  EXCLUSIVE_UNBLOCK, desc="exclusive unblock";
   INV, desc="Invalidate from directory";
 }
 
@@ -70,6 +68,21 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   int Len;
   bool Dirty, default="false",  desc="Dirty bit";
   PrefetchBit Prefetch,         desc="Is this a prefetch request";
+
+  bool functionalRead(Packet *pkt) {
+    // Only PUTX messages contains the data block
+    if (Type == CoherenceRequestType:PUTX) {
+        return testAndRead(Address, DataBlk, pkt);
+    }
+
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check on message type required since the protocol should
+    // read data from those messages that contain the block
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 // ResponseMsg
@@ -82,4 +95,22 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
   bool Dirty, default="false",  desc="Dirty bit";
   int AckCount, default="0",  desc="number of acks in this message";
   MessageSizeType MessageSize,  desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    // Valid data block is only present in message with following types
+    if (Type == CoherenceResponseType:DATA ||
+        Type == CoherenceResponseType:DATA_EXCLUSIVE ||
+        Type == CoherenceResponseType:MEMORY_DATA) {
+
+        return testAndRead(Address, DataBlk, pkt);
+    }
+
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check on message type required since the protocol should
+    // read data from those messages that contain the block
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
index cf5cf9505385a189597b82001b39cb1e21cad4b6..5040eb85dacf561566ba191d17b8cf78af705d9c 100644 (file)
@@ -168,6 +168,11 @@ machine(L1Cache, "MI Example L1 Cache")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+      return tbe.DataBlk;
+    }
+
     return getCacheEntry(addr).DataBlk;
   }
 
index 241ad3b30e253dfc2e4f380326d9ee3412305ed7..f15ccb14e92fcd9b32b2dd55544b10a9f5e49d76 100644 (file)
@@ -172,6 +172,11 @@ machine(Directory, "Directory protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+      return tbe.DataBlk;
+    }
+
     return getDirectoryEntry(addr).DataBlk;
   }
 
@@ -506,7 +511,6 @@ machine(Directory, "Directory protocol")
         out_msg.OriginalRequestorMachId := in_msg.Requestor;
         out_msg.DataBlk := in_msg.DataBlk;
         out_msg.MessageSize := in_msg.MessageSize;
-        //out_msg.Prefetch := in_msg.Prefetch;
 
         DPRINTF(RubySlicc,"%s\n", out_msg);
       }
@@ -518,12 +522,8 @@ machine(Directory, "Directory protocol")
   }
 
   action(w_writeDataToMemoryFromTBE, "\w", desc="Write date to directory memory from TBE") {
-    //getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk;
     assert(is_valid(tbe));
-    getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, 
-                                addressOffset(tbe.PhysicalAddress), 
-                                tbe.Len);
-
+    getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk;
   }
 
   // TRANSITIONS
@@ -633,7 +633,6 @@ machine(Directory, "Directory protocol")
   }
 
   transition(M, PUTX, MI) {
-    l_writeDataToMemory;
     c_clearOwner;
     v_allocateTBEFromRequestNet;
     l_queueMemoryWBRequest;
index 2fb1c48ba6f8b693f4c1f6c917e88c96744520d2..0645371f6b53501108eccc22f8af4d33791c7080 100644 (file)
@@ -31,11 +31,9 @@ enumeration(CoherenceRequestType, desc="...") {
   GETX,      desc="Get eXclusive";
   GETS,      desc="Get Shared";
   PUTX,      desc="Put eXclusive";
-  PUTO,      desc="Put Owned";
   WB_ACK,    desc="Writeback ack";
   WB_NACK,   desc="Writeback neg. ack";
   INV,       desc="Invalidation";
-  FWD,      desc="Generic FWD";
 }
 
 // CoherenceResponseType
@@ -59,6 +57,20 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   NetDest Destination,             desc="Multicast destination mask";
   DataBlock DataBlk,           desc="data for the cache line";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    // Valid data block is only present in PUTX messages
+    if (Type == CoherenceRequestType:PUTX) {
+        return testAndRead(Address, DataBlk, pkt);
+    }
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check on message type required since the protocol should read
+    // data block from only those messages that contain valid data
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 // ResponseMsg (and also unblock requests)
@@ -70,6 +82,18 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
   DataBlock DataBlk,           desc="data for the cache line";
   bool Dirty,                  desc="Is the data dirty (different than memory)?";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    // A check on message type should appear here so that only those
+    // messages that contain data
+    return testAndRead(Address, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check on message type required since the protocol should read
+    // data block from only those messages that contain valid data
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@@ -93,6 +117,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   int Len,                   desc="The length of the request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(LineAddress, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
 
 structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@@ -102,4 +134,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
   NetDest Destination,       desc="Destination";
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(LineAddress, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
index 43c2def2ee8513dd64e5b7d288bb115664a100b9..6295f90fda3e79e3973da306444037519b9371f2 100644 (file)
@@ -219,7 +219,17 @@ machine(L1Cache, "Directory protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
-    return getCacheEntry(addr).DataBlk;
+    Entry cache_entry := getCacheEntry(addr);
+    if(is_valid(cache_entry)) {
+        return cache_entry.DataBlk;
+    }
+
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+      return tbe.DataBlk;
+    }
+
+    error("Data block missing!");
   }
 
   Event mandatory_request_type_to_event(RubyRequestType type) {
index 6238953ad6e87a4b0c44ee4552c47882e0da8930..2e4e66a7bb4a2037fcd7abe3e54470d704c58288 100644 (file)
@@ -193,7 +193,7 @@ machine(L2Cache, "Token protocol")
 
   // TBE fields
   structure(TBE, desc="...") {
-    Address Address,                      desc="Physical address for this TBE";
+    Address address,                      desc="Physical address for this TBE";
     State TBEState,                       desc="Transient state";
     Address PC,                           desc="Program counter of request";
     DataBlock DataBlk,                    desc="Buffer for the data block";
@@ -512,11 +512,6 @@ machine(L2Cache, "Token protocol")
       return L2Cache_State_to_permission(cache_entry.CacheState);
     }
 
-    else if (localDirectory.isTagPresent(addr)) {
-      DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(localDirectory[addr].DirState));
-      return L2Cache_State_to_permission(localDirectory[addr].DirState);
-    }
-
     DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
     return AccessPermission:NotPresent;
   }
@@ -528,6 +523,11 @@ machine(L2Cache, "Token protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+        return tbe.DataBlk;
+    }
+
     return getCacheEntry(addr).DataBlk;
   }
 
@@ -1451,6 +1451,8 @@ machine(L2Cache, "Token protocol")
     peek(responseNetwork_in, ResponseMsg) {
       assert(is_valid(cache_entry));
       cache_entry.DataBlk := in_msg.DataBlk;
+      DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
+            address, cache_entry.DataBlk);
       if ((cache_entry.Dirty == false) && in_msg.Dirty) {
         cache_entry.Dirty := in_msg.Dirty;
       }
index 1635267f602e2eaa1c1a1b0e12c97731a3346dbe..0dd4239a933e9d51e22ef81078c6911d5eb131f9 100644 (file)
@@ -473,6 +473,9 @@ 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
+      DPRINTF(RubySlicc, "Address: %s, MsgDataBlock: %s MemoryDataBlock: %s\n",
+              in_msg.Address, in_msg.DataBlk,
+              getDirectoryEntry(in_msg.Address).DataBlk);
       assert(getDirectoryEntry(in_msg.Address).DataBlk == in_msg.DataBlk);
     }
   }
index 7b203537f9f36b5edc49f36e010dac3766ca344e..e428be7f79427f906d2b4e80c74a7dfd1a98713a 100644 (file)
@@ -71,6 +71,16 @@ enumeration(TriggerType, desc="...") {
 structure(TriggerMsg, desc="...", interface="Message") {
   Address Address,             desc="Physical address for this request";
   TriggerType Type,            desc="Type of trigger";
+
+  bool functionalRead(Packet *pkt) {
+    // Trigger message does not hold data
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // Trigger message does not hold data
+    return false;
+  }
 }
 
 // RequestMsg (and also forwarded requests)
@@ -86,6 +96,20 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   MessageSizeType MessageSize, desc="size category of the message";
   RubyAccessMode AccessMode,    desc="user/supervisor access type";
   PrefetchBit Prefetch,         desc="Is this a prefetch request";
+
+  bool functionalRead(Packet *pkt) {
+    // Read only those messages that contain the data
+    if (Type == CoherenceRequestType:DMA_READ ||
+        Type == CoherenceRequestType:DMA_WRITE) {
+        return testAndRead(Address, DataBlk, pkt);
+    }
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check required since all messages are written
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 // ResponseMsg (and also unblock requests)
@@ -99,4 +123,20 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
   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";
+
+  bool functionalRead(Packet *pkt) {
+    // Read only those messages that contain the data
+    if (Type == CoherenceResponseType:DATA ||
+        Type == CoherenceResponseType:DATA_EXCLUSIVE ||
+        Type == CoherenceResponseType:WRITEBACK_CLEAN_DATA ||
+        Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
+        return testAndRead(Address, DataBlk, pkt);
+    }
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check required since all messages are written
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
index b6de5a714fd9c5578e4c9d0401e4cfe1a66c5ee5..8cf40974e5fde300b249452bfa65c6478f05c73e 100644 (file)
@@ -139,7 +139,7 @@ machine(L1Cache, "Token protocol")
 
   // TBE fields
   structure(TBE, desc="...") {
-    Address Address,                      desc="Physical address for this TBE";
+    Address address,                      desc="Physical address for this TBE";
     State TBEState,                       desc="Transient state";
     int IssueCount,      default="0",     desc="The number of times we've issued a request for this line.";
     Address PC,                           desc="Program counter of request";
index 8d78be40cf6be3d7bf3686ec0065dec4d23a6d23..fd51e292441b4f7d0ea0cae95b3f57c13001d076 100644 (file)
@@ -677,6 +677,7 @@ machine(Directory, "Token protocol")
     enqueue(memQueue_out, MemoryMsg, latency="1") {
       out_msg.Address := address;
       out_msg.Type := MemoryRequestType:MEMORY_WB;
+      out_msg.DataBlk := getDirectoryEntry(address).DataBlk;
       DPRINTF(RubySlicc, "%s\n", out_msg);
     }
   }
index b1c3f458068224f2750f585929958de9cda2a8b1..6a8d6c6bcb373ad7c64fbeff65bd4e48fc2d9d5b 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
  * All rights reserved.
@@ -66,6 +65,16 @@ structure(PersistentMsg, desc="...", interface="NetworkMessage") {
   MessageSizeType MessageSize, desc="size category of the message";
   RubyAccessMode AccessMode,    desc="user/supervisor access type";
   PrefetchBit Prefetch,         desc="Is this a prefetch request";
+
+  bool functionalRead(Packet *pkt) {
+    // No data in persistent messages
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No data in persistent messages
+    return false;
+  }
 }
 
 // RequestMsg
@@ -79,6 +88,16 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   MessageSizeType MessageSize, desc="size category of the message";
   RubyAccessMode AccessMode,    desc="user/supervisor access type";
   PrefetchBit Prefetch,         desc="Is this a prefetch request";
+
+  bool functionalRead(Packet *pkt) {
+    // No data in request messages
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No data in request messages
+    return false;
+  }
 }
 
 // ResponseMsg
@@ -91,6 +110,16 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
   DataBlock DataBlk,           desc="data for the cache line";
   bool Dirty,                  desc="Is the data dirty (different than memory)?";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    // No check being carried out on the message type. Would be added later.
+    return testAndRead(Address, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // No check required since all messages are written.
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@@ -114,6 +143,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   int Len,                   desc="The length of the request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
 
 structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@@ -123,4 +160,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
   NetDest Destination,       desc="Destination";
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
index 6eb0974b06d0f2f2ff591cbad2ce7c838a203741..a3fa1219f7a8f5a0fe8aae52045196769916c828 100644 (file)
@@ -198,7 +198,17 @@ machine(L1Cache, "AMD Hammer-like protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
-    return getCacheEntry(addr).DataBlk;
+    Entry cache_entry := getCacheEntry(addr);
+    if(is_valid(cache_entry)) {
+        return cache_entry.DataBlk;
+    }
+
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+      return tbe.DataBlk;
+    }
+
+    error("Missing data block");
   }
 
   Entry getL2CacheEntry(Address address), return_by_pointer="yes" {
@@ -879,6 +889,7 @@ machine(L1Cache, "AMD Hammer-like protocol")
                               tbe.ForwardRequestTime,
                               tbe.FirstResponseTime);
     }
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
     cache_entry.Dirty := true;
   }
 
index ed1fb7669d5c97b77574496c6653524de2332245..22ca568a8a83ded3a13538b56e9c431937b8777a 100644 (file)
@@ -87,7 +87,7 @@ machine(Directory, "AMD Hammer-like protocol")
     O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
     WB, AccessPermission:Busy, desc="Blocked on a writeback";
     WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
-    WB_E_W, AccessPermission:Read_Write, desc="Blocked on memory write, will go to E";
+    WB_E_W, AccessPermission:Busy, desc="Blocked on memory write, will go to E";
 
     NO_F,  AccessPermission:Busy, desc="Blocked on a flush";
     NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
@@ -199,7 +199,17 @@ machine(Directory, "AMD Hammer-like protocol")
   }
 
   DataBlock getDataBlock(Address addr), return_by_ref="yes" {
-    return getDirectoryEntry(addr).DataBlk;
+    Entry dir_entry := getDirectoryEntry(addr);
+    if(is_valid(dir_entry)) {
+        return dir_entry.DataBlk;
+    }
+
+    TBE tbe := TBEs[addr];
+    if(is_valid(tbe)) {
+      return tbe.DataBlk;
+    }
+
+    error("Data block missing!");
   }
 
   PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" {
@@ -222,7 +232,7 @@ machine(Directory, "AMD Hammer-like protocol")
       return getDirectoryEntry(addr).DirectoryState;
     }
   }
-  
+
   void setState(TBE tbe, PfEntry pf_entry, Address addr, State state) {
     if (is_valid(tbe)) {
       tbe.TBEState := state;
@@ -1168,9 +1178,7 @@ machine(Directory, "AMD Hammer-like protocol")
   }
 
   action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
-    peek(unblockNetwork_in, ResponseMsg) {
-      assert(in_msg.Dirty);
-      assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
+    peek(memQueue_in, MemoryMsg) {
       getDirectoryEntry(address).DataBlk := in_msg.DataBlk;
       DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
               in_msg.Address, in_msg.DataBlk);
@@ -1236,8 +1244,11 @@ machine(Directory, "AMD Hammer-like protocol")
   action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") {
     peek(unblockNetwork_in, ResponseMsg) {
       enqueue(memQueue_out, MemoryMsg, latency="1") {
+        assert(in_msg.Dirty);
+        assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
         out_msg.Address := address;
         out_msg.Type := MemoryRequestType:MEMORY_WB;
+        out_msg.DataBlk := in_msg.DataBlk;
         DPRINTF(RubySlicc, "%s\n", out_msg);
       }
     }
@@ -1854,26 +1865,26 @@ machine(Directory, "AMD Hammer-like protocol")
 
   // WB State Transistions
   transition(WB, Writeback_Dirty, WB_O_W) {
-    l_writeDataToMemory;
     rs_removeSharer;
     l_queueMemoryWBRequest;
     j_popIncomingUnblockQueue;
   }
 
   transition(WB, Writeback_Exclusive_Dirty, WB_E_W) {
-    l_writeDataToMemory;
     rs_removeSharer;
     l_queueMemoryWBRequest;
     j_popIncomingUnblockQueue;
   }
 
   transition(WB_E_W, Memory_Ack, E) {
+    l_writeDataToMemory;
     pfd_probeFilterDeallocate;
     k_wakeUpDependents;
     l_popMemQueue;
   }
 
   transition(WB_O_W, Memory_Ack, O) {
+    l_writeDataToMemory;
     k_wakeUpDependents;
     l_popMemQueue;
   }
index 6ead7200af053954c4c574eeac117259d56dff6a..41d176a9cae4e386d2bd3111e3ebaa9661e4deb8 100644 (file)
@@ -73,6 +73,16 @@ enumeration(TriggerType, desc="...") {
 structure(TriggerMsg, desc="...", interface="Message") {
   Address Address,             desc="Physical address for this request";
   TriggerType Type,            desc="Type of trigger";
+
+  bool functionalRead(Packet *pkt) {
+    // Trigger messages do not hold any data!
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // Trigger messages do not hold any data!
+    return false;
+  }
 }
 
 // RequestMsg (and also forwarded requests)
@@ -87,6 +97,16 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   Time InitialRequestTime, default="0", desc="time the initial requests was sent from the L1Cache";
   Time ForwardRequestTime, default="0", desc="time the dir forwarded the request";
   int SilentAcks, default="0", desc="silent acks from the full-bit directory";
+
+  bool functionalRead(Packet *pkt) {
+    // Request messages do not hold any data
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // Request messages do not hold any data
+    return false;
+  }
 }
 
 // ResponseMsg (and also unblock requests)
@@ -103,6 +123,27 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
   Time InitialRequestTime, default="0", desc="time the initial requests was sent from the L1Cache";
   Time ForwardRequestTime, default="0", desc="time the dir forwarded the request";
   int SilentAcks, default="0", desc="silent acks from the full-bit directory";
+
+  bool functionalRead(Packet *pkt) {
+    // The check below ensures that data is read only from messages that
+    // actually hold data.
+    if (Type == CoherenceResponseType:DATA ||
+        Type == CoherenceResponseType:DATA_SHARED ||
+        Type == CoherenceResponseType:DATA_EXCLUSIVE ||
+        Type == CoherenceResponseType:WB_DIRTY ||
+        Type == CoherenceResponseType:WB_EXCLUSIVE_DIRTY) {
+        return testAndRead(Address, DataBlk, pkt);
+    }
+
+    return false;
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    // Message type does not matter since all messages are written.
+    // If a protocol reads data from a packet that is not supposed
+    // to hold the data, then the fault lies with the protocol.
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
 
 enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@@ -126,6 +167,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   int Len,                   desc="The length of the request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(LineAddress, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
 
 structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@@ -135,4 +184,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
   NetDest Destination,       desc="Destination";
   DataBlock DataBlk,         desc="DataBlk attached to this request";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(LineAddress, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(LineAddress, DataBlk, pkt);
+  }
 }
index 6492024d81206dcaa44aecb65aa900b20958a388..9e21d39bb49d3f3e263a752840b59719f798344d 100644 (file)
@@ -40,4 +40,8 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
   NetDest Destination,             desc="Multicast destination mask";
   DataBlock DataBlk,           desc="data for the cache line";
   MessageSizeType MessageSize, desc="size category of the message";
+
+  void functionalWrite(Packet *pkt) {
+    error("Network test does not support functional accesses!");
+  }
 }
index b42f9c3a94bb6b1e08f9f6a627099737746b4d45..2a4281757a1fdcff6eb1c4349fb7bd4e9ba5367c 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/*
- * $Id$
- *
- */
-
-// defines
+// Declarations of external types that are common to all protocols
 external_type(int, primitive="yes", default="0");
 external_type(bool, primitive="yes", default="false");
 external_type(std::string, primitive="yes");
 external_type(uint64, primitive="yes");
 external_type(Time, primitive="yes", default="0");
+external_type(PacketPtr, primitive="yes");
+external_type(Packet, primitive="yes");
 external_type(Address);
+
 structure(DataBlock, external = "yes", desc="..."){
   void clear();
   void copyPartial(DataBlock, int, int);
 }
 
-// Declarations of external types that are common to all protocols
+bool testAndRead(Address addr, DataBlock datablk, Packet *pkt);
+bool testAndWrite(Address addr, DataBlock datablk, Packet *pkt);
 
 // AccessPermission
 // The following five states define the access permission of all memory blocks.
@@ -265,6 +264,14 @@ structure(SequencerMsg, desc="...", interface="Message") {
   DataBlock DataBlk,         desc="Data";
   int Len,                   desc="size in bytes of access";
   PrefetchBit Prefetch,      desc="Is this a prefetch request";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(PhysicalAddress, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(PhysicalAddress, DataBlk, pkt);
+  }
 }
 
 // MaskPredictorType
index 66bb37bca38b8636a500f47dfdcb30d754db6a93..08bff6e36a06ab029b46f19e93f20cd704677c75 100644 (file)
@@ -61,4 +61,12 @@ structure(MemoryMsg, desc="...", interface="Message") {
   PrefetchBit Prefetch,         desc="Is this a prefetch request";
   bool ReadX,                   desc="Exclusive";
   int Acks,                     desc="How many acks to expect";
+
+  bool functionalRead(Packet *pkt) {
+    return testAndRead(Address, DataBlk, pkt);
+  }
+
+  bool functionalWrite(Packet *pkt) {
+    return testAndWrite(Address, DataBlk, pkt);
+  }
 }
index f0d372a5214f2bc0036c21793fbb6481594a7c14..f960cc0339de4c646d34b3d88d0f014338fd4fee 100644 (file)
@@ -435,3 +435,69 @@ MessageBuffer::printStats(ostream& out)
     out << "MessageBuffer: " << m_name << " stats - msgs:" << m_msg_counter
         << " full:" << m_not_avail_count << endl;
 }
+
+bool
+MessageBuffer::isReady() const
+{
+    return ((m_prio_heap.size() > 0) &&
+            (m_prio_heap.front().m_time <= g_system_ptr->getTime()));
+}
+
+bool
+MessageBuffer::functionalRead(Packet *pkt)
+{
+    // Check the priority heap and read any messages that may
+    // correspond to the address in the packet.
+    for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
+        Message *msg = m_prio_heap[i].m_msgptr.get();
+        if (msg->functionalRead(pkt)) return true;
+    }
+
+    // Read the messages in the stall queue that correspond
+    // to the address in the packet.
+    for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
+         map_iter != m_stall_msg_map.end();
+         ++map_iter) {
+
+        for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
+            it != (map_iter->second).end(); ++it) {
+
+            Message *msg = (*it).get();
+            if (msg->functionalRead(pkt)) return true;
+        }
+    }
+    return false;
+}
+
+uint32_t
+MessageBuffer::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+
+    // Check the priority heap and write any messages that may
+    // correspond to the address in the packet.
+    for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
+        Message *msg = m_prio_heap[i].m_msgptr.get();
+        if (msg->functionalWrite(pkt)) {
+            num_functional_writes++;
+        }
+    }
+
+    // Check the stall queue and write any messages that may
+    // correspond to the address in the packet.
+    for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
+         map_iter != m_stall_msg_map.end();
+         ++map_iter) {
+
+        for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
+            it != (map_iter->second).end(); ++it) {
+
+            Message *msg = (*it).get();
+            if (msg->functionalWrite(pkt)) {
+                num_functional_writes++;
+            }
+        }
+    }
+
+    return num_functional_writes;
+}
index cf7e77c2d404ef26ae342c05e052f18b32f3ddfa..c4fd7165ded3f9680b753de6bc387dd14256c252 100644 (file)
 #include <string>
 #include <vector>
 
+#include "mem/packet.hh"
 #include "mem/ruby/buffers/MessageBufferNode.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Consumer.hh"
-#include "mem/ruby/common/Global.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
 
 class MessageBuffer
@@ -65,12 +65,7 @@ class MessageBuffer
     void stallMessage(const Address& addr);
 
     // TRUE if head of queue timestamp <= SystemTime
-    bool
-    isReady() const
-    {
-        return ((m_prio_heap.size() > 0) &&
-                (m_prio_heap.front().m_time <= g_system_ptr->getTime()));
-    }
+    bool isReady() const;
 
     void
     delayHead()
@@ -145,6 +140,17 @@ class MessageBuffer
     void setIncomingLink(int link_id) { m_input_link_id = link_id; }
     void setVnet(int net) { m_vnet_id = net; }
 
+    // Function for figuring out if any of the messages in the buffer can
+    // satisfy the read request for the address in the packet.
+    // Return value, if true, indicates that the request was fulfilled.
+    bool functionalRead(Packet *pkt);
+
+    // Function for figuring out if any of the messages in the buffer need
+    // to be updated with the data from the packet.
+    // Return value indicates the number of messages that were updated.
+    // This required for debugging the code.
+    uint32_t functionalWrite(Packet *pkt);
+
   private:
     //added by SS
     int m_recycle_latency;
index 70afa9831382ee3eae4177bafb2168dee2b26695..5e7a52e1228cd244848398dd560b0dfb06d9fab3 100644 (file)
@@ -31,7 +31,6 @@
 
 #include <iostream>
 
-#include "mem/ruby/common/Global.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
 
 class MessageBufferNode
index e9c5a98b72098dcf487334610f42929ba343b2a5..9236a2207aba865717fd54b8faa285928f0755ac 100644 (file)
@@ -44,6 +44,7 @@
 #include <string>
 #include <vector>
 
+#include "mem/packet.hh"
 #include "mem/protocol/LinkDirection.hh"
 #include "mem/protocol/MessageSizeType.hh"
 #include "mem/ruby/common/TypeDefines.hh"
@@ -81,7 +82,7 @@ class Network : public SimObject
                              bool isReconfiguration) = 0;
     virtual void makeInLink(NodeID src, SwitchID dest, BasicLink* link,
                             LinkDirection direction,
-                            const NetDest& routing_table_entry, 
+                            const NetDest& routing_table_entry,
                             bool isReconfiguration) = 0;
     virtual void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
                                   LinkDirection direction,
@@ -94,6 +95,16 @@ class Network : public SimObject
     virtual void clearStats() = 0;
     virtual void print(std::ostream& out) const = 0;
 
+    /*
+     * Virtual functions for functionally reading and writing packets in
+     * the network. Each network needs to implement these for functional
+     * accesses to work correctly.
+     */
+    virtual bool functionalRead(Packet *pkt)
+    { fatal("Functional read not implemented.\n"); }
+    virtual uint32_t functionalWrite(Packet *pkt)
+    { fatal("Functional write not implemented.\n"); }
+
   protected:
     // Private copy constructor and assignment operator
     Network(const Network& obj);
index 2c845683d035dae56cfbf684970f318fb4c76d96..b38b6d53906c6c109c04871349828a045659cd57 100644 (file)
@@ -343,4 +343,3 @@ PerfectSwitch::print(std::ostream& out) const
 {
     out << "[PerfectSwitch " << m_switch_id << "]";
 }
-
index 7aa8e62f97665edfbe8422c8c7910881c6b8dc5d..9df9ed3a56428bad574270aed990454d22b8d362 100644 (file)
@@ -327,3 +327,41 @@ SimpleNetworkParams::create()
 {
     return new SimpleNetwork(this);
 }
+
+/*
+ * The simple network has an array of switches. These switches have buffers
+ * that need to be accessed for functional reads and writes. Also the links
+ * between different switches have buffers that need to be accessed.
+ */
+bool
+SimpleNetwork::functionalRead(Packet *pkt)
+{
+    for (unsigned int i = 0; i < m_switch_ptr_vector.size(); i++) {
+        if (m_switch_ptr_vector[i]->functionalRead(pkt)) {
+            return true;
+        }
+    }
+
+    for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
+        if (m_buffers_to_free[i]->functionalRead(pkt)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+uint32_t
+SimpleNetwork::functionalWrite(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+
+    for (unsigned int i = 0; i < m_switch_ptr_vector.size(); i++) {
+        num_functional_writes += m_switch_ptr_vector[i]->functionalWrite(pkt);
+    }
+
+    for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
+        num_functional_writes += m_buffers_to_free[i]->functionalWrite(pkt);
+    }
+    return num_functional_writes;
+}
index 6dfaa2724a78cd68de2752d5c4e806e639df784f..8794468229d902d011f0fefb2cc2c9ae93c61dc0 100644 (file)
@@ -86,6 +86,9 @@ class SimpleNetwork : public Network
 
     void print(std::ostream& out) const;
 
+    bool functionalRead(Packet *pkt);
+    uint32_t functionalWrite(Packet *pkt);
+
   private:
     void checkNetworkAllocation(NodeID id, bool ordered, int network_num);
     void addLink(SwitchID src, SwitchID dest, int link_latency);
index 5c2f5a7170fbd66a68fe7e08630ae0f23418efd2..a0a27f7581a8fa85a7bbc7988a560abc5e42a5ba 100644 (file)
@@ -217,6 +217,28 @@ Switch::print(std::ostream& out) const
     // FIXME printing
     out << "[Switch]";
 }
+bool
+Switch::functionalRead(Packet *pkt)
+{
+    // Access the buffers in the switch for performing a functional read
+    for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
+        if (m_buffers_to_free[i]->functionalRead(pkt)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+uint32_t
+Switch::functionalWrite(Packet *pkt)
+{
+    // Access the buffers in the switch for performing a functional write
+    uint32_t num_functional_writes = 0;
+    for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
+        num_functional_writes += m_buffers_to_free[i]->functionalWrite(pkt);
+    }
+    return num_functional_writes;
+}
 
 Switch *
 SwitchParams::create()
index 9946e5cc122ba752bf61a26a70c16b098a9f3512..05e90f2782a32c143e89dab50459ddbce50821a6 100644 (file)
@@ -74,6 +74,9 @@ class Switch : public BasicRouter
     void print(std::ostream& out) const;
     void init_net_ptr(SimpleNetwork* net_ptr) { m_network_ptr = net_ptr; }
 
+    bool functionalRead(Packet *);
+    uint32_t functionalWrite(Packet *);
+
   private:
     // Private copy constructor and assignment operator
     Switch(const Switch& obj);
index 70b9968c7b92f75b9c53cb2aa49ced48f30a5896..c5cb46f1e303e37562d82735475ee9e5eaaa3bcb 100644 (file)
@@ -32,6 +32,7 @@
 #include <iostream>
 #include <string>
 
+#include "mem/packet.hh"
 #include "mem/protocol/AccessPermission.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Consumer.hh"
@@ -68,6 +69,15 @@ class AbstractController : public SimObject, public Consumer
     virtual void clearStats() = 0;
     virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
     virtual Sequencer* getSequencer() const = 0;
+
+    //! These functions are used by ruby system to read/write the message
+    //! queues that exist with in the controller.
+    //! The boolean return value indicates if the read was performed
+    //! successfully.
+    virtual bool functionalReadBuffers(PacketPtr&) = 0;
+    //! The return value indicates the number of messages written with the
+    //! data from the packet.
+    virtual uint32_t functionalWriteBuffers(PacketPtr&) = 0;
 };
 
 #endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
index 48156a99a2033a8f5995509eee9d6b6635ee41b1..7b94a01e2da3a226eeb5835ddebdf3138d7d522b 100644 (file)
@@ -61,6 +61,18 @@ class Message : public RefCounted
     virtual void setIncomingLink(int) {}
     virtual void setVnet(int) {}
 
+    /**
+     * The two functions below are used for reading / writing the message
+     * functionally. The methods return true if the address in the packet
+     * matches the address / address range in the message. Each message
+     * class that can be potentially searched for the address needs to
+     * implement these methods.
+     */
+    virtual bool functionalRead(Packet *pkt) = 0;
+    //{ fatal("Read functional access not implemented!"); }
+    virtual bool functionalWrite(Packet *pkt) = 0;
+    //{ fatal("Write functional access not implemented!"); }
+
     void setDelayedCycles(const int& cycles) { m_DelayedCycles = cycles; }
     const int& getDelayedCycles() const {return m_DelayedCycles;}
     int& getDelayedCycles() {return m_DelayedCycles;}
index a8f9c625b3b993507fa3d6388275355941fa409b..d2bcb1241b137395a0560e5692be50cee89a2c3e 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "base/refcnt.hh"
 #include "mem/protocol/MessageSizeType.hh"
-#include "mem/ruby/common/Global.hh"
 #include "mem/ruby/common/NetDest.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
 
index 2aae61d7bef971257f5d58c27e32b584f84beafb..7ff2b75d839b2b3b8568ec28fead4c19235ab57b 100644 (file)
@@ -18,3 +18,40 @@ RubyRequest::print(ostream& out) const
 //  out << "Time = " << getTime() << " ";
   out << "]";
 }
+
+bool
+RubyRequest::functionalRead(Packet *pkt)
+{
+    // This needs a little explanation. Initially I thought that this
+    // message should be read. But the way the memtester works for now,
+    // we should not be reading this message as memtester updates the
+    // functional memory only after a write has actually taken place.
+    return false;
+}
+
+bool
+RubyRequest::functionalWrite(Packet *pkt)
+{
+    // This needs a little explanation. I am not sure if this message
+    // should be written. Essentially the question is how are writes
+    // ordered. I am assuming that if a functional write is issued after
+    // a timing write to the same address, then the functional write
+    // has to overwrite the data for the timing request, even if the
+    // timing request has still not been ordered globally.
+
+    Address pktLineAddr(pkt->getAddr());
+    pktLineAddr.makeLineAddress();
+
+    if (pktLineAddr == m_LineAddress) {
+        uint8_t *pktData = pkt->getPtr<uint8_t>(true);
+        unsigned int size_in_bytes = pkt->getSize();
+        unsigned startByte = pkt->getAddr() - m_LineAddress.getAddress();
+
+        for (unsigned i = 0; i < size_in_bytes; ++i) {
+            data[i + startByte] = pktData[i];
+        }
+
+        return true;
+    }
+    return false;
+}
index 870ad1d0e4505852f86ac65c51f821fab0edb7cf..a4dadc7a72b0104343e7f62e24fbf03113054919 100644 (file)
@@ -126,6 +126,9 @@ class RubyRequest : public Message
     }
 
     void print(std::ostream& out) const;
+
+    bool functionalRead(Packet *pkt);
+    bool functionalWrite(Packet *pkt);
 };
 
 inline std::ostream&
index 06372c9fc92daac10e2426f2001dc4fbd1c1c5e7..06c540db59094b206894c9fb399f6d19e7764141 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <cassert>
 
+#include "debug/RubySlicc.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Global.hh"
 #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
@@ -129,4 +130,60 @@ mod(int val, int mod)
     return val % mod;
 }
 
+/**
+ * This function accepts an address, a data block and a packet. If the address
+ * range for the data block contains the address which the packet needs to
+ * read, then the data from the data block is written to the packet. True is
+ * returned if the data block was read, otherwise false is returned.
+ */
+inline bool
+testAndRead(Address addr, DataBlock& blk, Packet *pkt)
+{
+    Address pktLineAddr(pkt->getAddr());
+    pktLineAddr.makeLineAddress();
+
+    Address lineAddr = addr;
+    lineAddr.makeLineAddress();
+
+    if (pktLineAddr == lineAddr) {
+        uint8_t *data = pkt->getPtr<uint8_t>(true);
+        unsigned int size_in_bytes = pkt->getSize();
+        unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
+
+        for (unsigned i = 0; i < size_in_bytes; ++i) {
+            data[i] = blk.getByte(i + startByte);
+        }
+        return true;
+    }
+    return false;
+}
+
+/**
+ * This function accepts an address, a data block and a packet. If the address
+ * range for the data block contains the address which the packet needs to
+ * write, then the data from the packet is written to the data block. True is
+ * returned if the data block was written, otherwise false is returned.
+ */
+inline bool
+testAndWrite(Address addr, DataBlock& blk, Packet *pkt)
+{
+    Address pktLineAddr(pkt->getAddr());
+    pktLineAddr.makeLineAddress();
+
+    Address lineAddr = addr;
+    lineAddr.makeLineAddress();
+
+    if (pktLineAddr == lineAddr) {
+        uint8_t *data = pkt->getPtr<uint8_t>(true);
+        unsigned int size_in_bytes = pkt->getSize();
+        unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
+
+        for (unsigned i = 0; i < size_in_bytes; ++i) {
+            blk.setByte(i + startByte, data[i]);
+        }
+        return true;
+    }
+    return false;
+}
+
 #endif // __MEM_RUBY_SLICC_INTERFACE_RUBYSLICCUTIL_HH__
index c5ddb0c44d7ebc4d61e7f096250659811cae2627..e58b36f639784b671f0732bdb7d288149bf96b81 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "base/cast.hh"
-#include "base/cprintf.hh"
 #include "debug/RubyStats.hh"
-#include "mem/ruby/common/Address.hh"
-#include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/common/Global.hh"
-#include "mem/ruby/network/Network.hh"
-#include "mem/ruby/profiler/Profiler.hh"
-#include "mem/ruby/slicc_interface/NetworkMessage.hh"
 #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
 #include "mem/ruby/system/MemoryControl.hh"
-#include "mem/ruby/system/RubyMemoryControl.hh"
 #include "mem/ruby/system/System.hh"
 
 using namespace std;
@@ -55,9 +47,3 @@ MemoryControl::recordRequestType(MemoryControlRequestType request) {
     DPRINTF(RubyStats, "Recorded request: %s\n",
             MemoryControlRequestType_to_string(request));
 }
-
-RubyMemoryControl *
-RubyMemoryControlParams::create()
-{
-    return new RubyMemoryControl(this);
-}
index 7bdc14cfcf0bb7ff5592c24c518d37aba002838b..8d15b8decc1803b1a2b04c9bb575c3174ba2485c 100644 (file)
 #include <string>
 
 #include "mem/protocol/MemoryControlRequestType.hh"
-#include "mem/protocol/MemoryMsg.hh"
 #include "mem/ruby/common/Consumer.hh"
-#include "mem/ruby/profiler/MemCntrlProfiler.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
 #include "mem/ruby/system/MemoryNode.hh"
-#include "mem/ruby/system/System.hh"
 #include "params/MemoryControl.hh"
 #include "sim/clocked_object.hh"
 
 //////////////////////////////////////////////////////////////////////////////
 
-class Consumer;
-
 class MemoryControl : public ClockedObject, public Consumer
 {
   public:
@@ -97,6 +92,11 @@ class MemoryControl : public ClockedObject, public Consumer
 
     virtual void recordRequestType(MemoryControlRequestType requestType);
 
+    virtual bool functionalReadBuffers(Packet *pkt)
+    { fatal("Functional read access not implemented!");}
+    virtual uint32_t functionalWriteBuffers(Packet *pkt)
+    { fatal("Functional read access not implemented!");}
+
 protected:
     class MemCntrlEvent : public Event
     {
index cfdaaaef7184f8725860e7f779daa3e8f5cba168..c0e91c28b211e0161269ab3ba352dd8001483bce 100644 (file)
@@ -708,3 +708,91 @@ RubyMemoryControl::wakeup()
     }
 }
 
+/**
+ * This function reads the different buffers that exist in the Ruby Memory
+ * Controller, and figures out if any of the buffers hold a message that
+ * contains the data for the address provided in the packet. True is returned
+ * if any of the messages was read, otherwise false is returned.
+ *
+ * I think we should move these buffers to being message buffers, instead of
+ * being lists.
+ */
+bool
+RubyMemoryControl::functionalReadBuffers(Packet *pkt)
+{
+    for (std::list<MemoryNode>::iterator it = m_input_queue.begin();
+         it != m_input_queue.end(); ++it) {
+        Message* msg_ptr = (*it).m_msgptr.get();
+        if (msg_ptr->functionalRead(pkt)) {
+            return true;
+        }
+    }
+
+    for (std::list<MemoryNode>::iterator it = m_response_queue.begin();
+         it != m_response_queue.end(); ++it) {
+        Message* msg_ptr = (*it).m_msgptr.get();
+        if (msg_ptr->functionalRead(pkt)) {
+            return true;
+        }
+    }
+
+    for (uint32_t bank = 0; bank < m_total_banks; ++bank) {
+        for (std::list<MemoryNode>::iterator it = m_bankQueues[bank].begin();
+             it != m_bankQueues[bank].end(); ++it) {
+            Message* msg_ptr = (*it).m_msgptr.get();
+            if (msg_ptr->functionalRead(pkt)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+/**
+ * This function reads the different buffers that exist in the Ruby Memory
+ * Controller, and figures out if any of the buffers hold a message that
+ * needs to functionally written with the data in the packet.
+ *
+ * The number of messages written is returned at the end. This is required
+ * for debugging purposes.
+ */
+uint32_t
+RubyMemoryControl::functionalWriteBuffers(Packet *pkt)
+{
+    uint32_t num_functional_writes = 0;
+
+    for (std::list<MemoryNode>::iterator it = m_input_queue.begin();
+         it != m_input_queue.end(); ++it) {
+        Message* msg_ptr = (*it).m_msgptr.get();
+        if (msg_ptr->functionalWrite(pkt)) {
+            num_functional_writes++;
+        }
+    }
+
+    for (std::list<MemoryNode>::iterator it = m_response_queue.begin();
+         it != m_response_queue.end(); ++it) {
+        Message* msg_ptr = (*it).m_msgptr.get();
+        if (msg_ptr->functionalWrite(pkt)) {
+            num_functional_writes++;
+        }
+    }
+
+    for (uint32_t bank = 0; bank < m_total_banks; ++bank) {
+        for (std::list<MemoryNode>::iterator it = m_bankQueues[bank].begin();
+             it != m_bankQueues[bank].end(); ++it) {
+            Message* msg_ptr = (*it).m_msgptr.get();
+            if (msg_ptr->functionalWrite(pkt)) {
+                num_functional_writes++;
+            }
+        }
+    }
+
+    return num_functional_writes;
+}
+
+RubyMemoryControl *
+RubyMemoryControlParams::create()
+{
+    return new RubyMemoryControl(this);
+}
index 98636e4086444d769bde8c410f73a9120aa1e5e4..1f3a8acf56b94930179c6fd5648f4b9c69049571 100644 (file)
@@ -96,6 +96,8 @@ class RubyMemoryControl : public MemoryControl
     int getRanksPerDimm() { return m_ranks_per_dimm; };
     int getDimmsPerChannel() { return m_dimms_per_channel; }
 
+    bool functionalReadBuffers(Packet *pkt);
+    uint32_t functionalWriteBuffers(Packet *pkt);
 
   private:
     void enqueueToDirectory(MemoryNode req, int latency);
index b41f2d727a94d4547496cc7f550f038501be21dd..5ee22e9f5229be01f21260ce110a4cf431b0de77 100644 (file)
@@ -417,7 +417,7 @@ RubySystem::functionalRead(PacketPtr pkt)
 
     // In this loop we count the number of controllers that have the given
     // address in read only, read write and busy states.
-    for (int i = 0; i < num_controllers; ++i) {
+    for (unsigned int i = 0; i < num_controllers; ++i) {
         access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address);
         if (access_perm == AccessPermission_Read_Only)
             num_ro++;
@@ -452,7 +452,7 @@ RubySystem::functionalRead(PacketPtr pkt)
     if (num_invalid == (num_controllers - 1) &&
             num_backing_store == 1) {
         DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n");
-        for (int i = 0; i < num_controllers; ++i) {
+        for (unsigned int i = 0; i < num_controllers; ++i) {
             access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address);
             if (access_perm == AccessPermission_Backing_Store) {
                 DataBlock& block = m_abs_cntrl_vec[i]->
@@ -466,7 +466,7 @@ RubySystem::functionalRead(PacketPtr pkt)
                 return true;
             }
         }
-    } else {
+    } else if (num_ro > 0 || num_rw == 1) {
         // In Broadcast/Snoop protocols, this covers if you know the block
         // exists somewhere in the caching hierarchy, then you want to read any
         // valid RO or RW block.  In directory protocols, same thing, you want
@@ -476,7 +476,7 @@ RubySystem::functionalRead(PacketPtr pkt)
         // In this loop, we try to figure which controller has a read only or
         // a read write copy of the given address. Any valid copy would suffice
         // for a functional read.
-        for (int i = 0;i < num_controllers;++i) {
+        for (unsigned int i = 0;i < num_controllers;++i) {
             access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address);
             if (access_perm == AccessPermission_Read_Only ||
                 access_perm == AccessPermission_Read_Write) {
@@ -492,9 +492,34 @@ RubySystem::functionalRead(PacketPtr pkt)
             }
         }
     }
+
+    // Since we are here, this means that none of the controllers hold this
+    // address in a stable/base state. The function searches through all the
+    // buffers that exist in different cache, directory and memory
+    // controllers, and in the network components and reads the data portion
+    // of the first message that holds address specified in the packet.
+    for (unsigned int i = 0; i < num_controllers;++i) {
+        if (m_abs_cntrl_vec[i]->functionalReadBuffers(pkt)) {
+            return true;
+        }
+    }
+
+    for (unsigned int i = 0; i < m_memory_controller_vec.size(); ++i) {
+        if (m_memory_controller_vec[i]->functionalReadBuffers(pkt)) {
+            return true;
+        }
+    }
+
+    if (m_network_ptr->functionalRead(pkt)) {
+        return true;
+    }
     return false;
 }
 
+// The function searches through all the buffers that exist in different
+// cache, directory and memory controllers, and in the network components
+// and writes the data portion of those that hold the address specified
+// in the packet.
 bool
 RubySystem::functionalWrite(PacketPtr pkt)
 {
@@ -505,69 +530,36 @@ RubySystem::functionalWrite(PacketPtr pkt)
 
     DPRINTF(RubySystem, "Functional Write request for %s\n",addr);
 
-    unsigned int num_ro = 0;
-    unsigned int num_rw = 0;
-    unsigned int num_busy = 0;
-    unsigned int num_backing_store = 0;
-    unsigned int num_invalid = 0;
-
-    // In this loop we count the number of controllers that have the given
-    // address in read only, read write and busy states.
-    for (int i = 0;i < num_controllers;++i) {
-        access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr);
-        if (access_perm == AccessPermission_Read_Only)
-            num_ro++;
-        else if (access_perm == AccessPermission_Read_Write)
-            num_rw++;
-        else if (access_perm == AccessPermission_Busy)
-            num_busy++;
-        else if (access_perm == AccessPermission_Backing_Store)
-            // See RubySlicc_Exports.sm for details, but Backing_Store is meant
-            // to represent blocks in memory *for Broadcast/Snooping protocols*,
-            // where memory has no idea whether it has an exclusive copy of data
-            // or not.
-            num_backing_store++;
-        else if (access_perm == AccessPermission_Invalid ||
-                 access_perm == AccessPermission_NotPresent)
-            num_invalid++;
-    }
-
-    // If the number of read write copies is more than 1, then there is bug in
-    // coherence protocol. Otherwise, if all copies are in stable states, i.e.
-    // num_busy == 0, we update all the copies. If there is at least one copy
-    // in busy state, then we check if there is read write copy. If yes, then
-    // also we let the access go through. Or, if there is no copy in the cache
-    // hierarchy at all, we still want to do the write to the memory
-    // (Backing_Store) instead of failing.
-
-    DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n",
-            num_busy, num_ro, num_rw);
-    assert(num_rw <= 1);
-
     uint8_t *data = pkt->getPtr<uint8_t>(true);
     unsigned int size_in_bytes = pkt->getSize();
     unsigned startByte = addr.getAddress() - line_addr.getAddress();
 
-    if ((num_busy == 0 && num_ro > 0) || num_rw == 1 ||
-        (num_invalid == (num_controllers - 1) && num_backing_store == 1)) {
-        for (int i = 0; i < num_controllers;++i) {
-            access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr);
-            if (access_perm == AccessPermission_Read_Only ||
-                access_perm == AccessPermission_Read_Write||
-                access_perm == AccessPermission_Maybe_Stale ||
-                access_perm == AccessPermission_Backing_Store) {
+    for (unsigned int i = 0; i < num_controllers;++i) {
+        m_abs_cntrl_vec[i]->functionalWriteBuffers(pkt);
 
-                DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr);
-                DPRINTF(RubySystem, "%s\n",block);
-                for (unsigned i = 0; i < size_in_bytes; ++i) {
-                  block.setByte(i + startByte, data[i]);
-                }
-                DPRINTF(RubySystem, "%s\n",block);
+        access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr);
+        if (access_perm != AccessPermission_Invalid &&
+            access_perm != AccessPermission_NotPresent) {
+
+            DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr);
+            DPRINTF(RubySystem, "%s\n",block);
+            for (unsigned i = 0; i < size_in_bytes; ++i) {
+              block.setByte(i + startByte, data[i]);
             }
+            DPRINTF(RubySystem, "%s\n",block);
         }
-        return true;
     }
-    return false;
+
+    uint32_t M5_VAR_USED num_functional_writes = 0;
+    for (unsigned int i = 0; i < m_memory_controller_vec.size() ;++i) {
+        num_functional_writes +=
+            m_memory_controller_vec[i]->functionalWriteBuffers(pkt);
+    }
+
+    num_functional_writes += m_network_ptr->functionalWrite(pkt);
+    DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes);
+
+    return true;
 }
 
 #ifdef CHECK_COHERENCE
index 983e86882562722b897168ccdcd5638c15067fa1..8a58853ac66bc8f5b8cfad78774a49e43b593fba 100644 (file)
@@ -60,7 +60,10 @@ class TypeDeclAST(DeclAST):
             machine.addType(new_type)
 
         self.symtab.newSymbol(new_type)
+        self.symtab.pushFrame()
 
         # Add all of the fields of the type to it
         for field in self.field_asts:
             field.generate(new_type)
+
+        self.symtab.popFrame()
index bb69b70bf1b3bfd2d0ae2b47d96d764c29e3fc92..427dbf7000db94a2b41c322b78105bc14b6d2fb2 100644 (file)
@@ -269,6 +269,9 @@ class $c_ident : public AbstractController
     void recordCacheTrace(int cntrl, CacheRecorder* tr);
     Sequencer* getSequencer() const;
 
+    bool functionalReadBuffers(PacketPtr&);
+    uint32_t functionalWriteBuffers(PacketPtr&);
+
 private:
 ''')
 
@@ -987,6 +990,39 @@ $c_ident::${{action.ident}}(const Address& addr)
         for func in self.functions:
             code(func.generateCode())
 
+        # Function for functional reads from messages buffered in the controller
+        code('''
+bool
+$c_ident::functionalReadBuffers(PacketPtr& pkt)
+{
+''')
+        for var in self.objects:
+            vtype = var.type
+            if vtype.isBuffer:
+                vid = "m_%s_ptr" % var.c_ident
+                code('if ($vid->functionalRead(pkt)) { return true; }')
+        code('''
+                return false;
+}
+''')
+
+        # Function for functional writes to messages buffered in the controller
+        code('''
+uint32_t
+$c_ident::functionalWriteBuffers(PacketPtr& pkt)
+{
+    uint32_t num_functional_writes = 0;
+''')
+        for var in self.objects:
+            vtype = var.type
+            if vtype.isBuffer:
+                vid = "m_%s_ptr" % var.c_ident
+                code('num_functional_writes += $vid->functionalWrite(pkt);')
+        code('''
+    return num_functional_writes;
+}
+''')
+
         code.write(path, "%s.cc" % c_ident)
 
     def printCWakeup(self, path, includes):
index d2c9337f1b7328921e73d9d09f540497d69b1d46..43cfe87408ed62898e7102e3e029e8b64ab885c4 100644 (file)
@@ -81,8 +81,7 @@ class SymbolTable(object):
             if types is not None:
                 if not isinstance(symbol, types):
                     symbol.error("Symbol '%s' is not of types '%s'.",
-                                 symbol,
-                                 types)
+                                 symbol, types)
 
             return symbol
 
index 3832919110503e22851a0de7ec2493c4936e9040..19c144048f34b62b3acf13696f6aa51cecaaa9ac 100644 (file)
@@ -29,6 +29,7 @@ from m5.util import orderdict
 
 from slicc.util import PairContainer
 from slicc.symbols.Symbol import Symbol
+from slicc.symbols.Var import Var
 
 class DataMember(PairContainer):
     def __init__(self, ident, type, pairs, init_code):
@@ -151,6 +152,9 @@ class Type(Symbol):
         member = DataMember(ident, type, pairs, init_code)
         self.data_members[ident] = member
 
+        var = Var(self.symtab, ident, self.location, type,
+                "m_%s" % ident, {}, None)
+        self.symtab.registerSym(ident, var)
         return True
 
     def dataMemberType(self, ident):
@@ -415,6 +419,7 @@ operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
 #include <iostream>
 
 #include "mem/protocol/${{self.c_ident}}.hh"
+#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
 
 using namespace std;
 ''')