# HG changeset patch
# User Brad Beckmann <[email protected]>
# Date 1261413068 28800
# Node ID 2bff56035b82240c99bf0db244d134100c40b8bf
# Parent  985b666fdbfc0b51ec4217d7e9b24c65a636413a
ruby: added the GEMS ruby tester

diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/Check.cc
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/Check.cc Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,350 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "cpu/rubytest/Check.hh"
+#include "mem/ruby/system/Sequencer.hh"
+#include "mem/ruby/system/System.hh"
+#include "mem/ruby/common/SubBlock.hh"
+
+Check::Check(const Address& address, 
+             const Address& pc,
+             int _num_cpu_sequencers,
+             RubyTester* _tester)
+  : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
+{
+  m_status = TesterStatus_Idle;
+
+  pickValue();
+  pickInitiatingNode();
+  changeAddress(address);
+  m_pc = pc;
+  m_access_mode = AccessModeType(random() % AccessModeType_NUM);
+  m_store_count = 0;
+}
+
+void Check::initiate()
+{
+  DPRINTF(RubyTest, "initiating\n");
+  debugPrint();
+
+  //
+  // currently no protocols support prefetches
+  //
+  if (false && (random() & 0xf) == 0) {
+    initiatePrefetch(); // Prefetch from random processor
+  }
+
+  if(m_status == TesterStatus_Idle) {
+    initiateAction();
+  } else if(m_status == TesterStatus_Ready) {
+    initiateCheck();
+  } else {
+    // Pending - do nothing
+    DPRINTF(RubyTest, "initiating action/check - failed: action/check is 
pending\n");
+  }
+}
+
+void Check::initiatePrefetch()
+{
+  DPRINTF(RubyTest, "initiating prefetch\n");
+
+  RubyTester::CpuPort* port 
+    = safe_cast<RubyTester::CpuPort*> \
+    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
+
+  Request::Flags flags;
+  flags.set(Request::PREFETCH);
+  uint8_t dummyStackdata = 0;
+
+  //
+  // Prefetches are assumed to be 0 sized
+  //
+  Request *req = new Request(m_address.getAddress(),
+                             0,
+                             flags);
+
+  Packet::Command cmd;
+
+  //
+  // 1 in 8 chance this will be an exclusive prefetch
+  //
+  if ((random() & 0x7) != 0) {
+    cmd = MemCmd::ReadReq;
+    //
+    // 50% chance that the request will be an instruction fetch
+    //
+    if ((random() & 0x1) == 0) { 
+      flags.set(Request::INST_FETCH);
+      req->setPC(m_address.getAddress());
+    }
+  } else {
+    cmd = MemCmd::WriteReq;
+    flags.set(Request::PF_EXCLUSIVE);
+  }
+
+  PacketPtr pkt = new Packet(req, cmd, port->idx);
+  pkt->dataStatic(&dummyStackdata);
+
+  //
+  // push the subblock onto the sender state.  The sequencer will update the
+  // subblock on the return
+  //
+  pkt->senderState = new RubyTester::SenderState(m_address, req->getSize());
+
+  if (port->sendTiming(pkt)) {
+    DPRINTF(RubyTest, "successfully initiated prefetch.\n");
+  } else {
+    DPRINTF(RubyTest, "prefetch initiation failed because Port was busy.\n");
+  }
+}
+
+void Check::initiateAction()
+{
+  DPRINTF(RubyTest, "initiating Action\n");
+  assert(m_status == TesterStatus_Idle);
+  
+  RubyTester::CpuPort* port
+    = safe_cast<RubyTester::CpuPort*> \
+    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
+
+  Request::Flags flags;
+  uint8_t writeData = m_value + m_store_count;
+
+  //
+  // Create the particular address for the next byte to be written
+  //
+  Address writeAddr(m_address.getAddress() + m_store_count);
+
+  //
+  // Stores are assumed to be 1 byte-sized
+  //
+  Request *req = new Request(writeAddr.getAddress(),
+                             1,
+                             flags);
+
+  Packet::Command cmd;
+
+  //
+  // 1 out of 8 chance, issue an atomic rather than a write
+  //
+//   if ((random() & 0x7) == 0) {
+//     cmd = MemCmd::SwapReq;
+//   } else {
+    cmd = MemCmd::WriteReq;
+//   }
+
+  PacketPtr pkt = new Packet(req, cmd, port->idx);
+  pkt->dataStatic(&writeData);
+
+  //
+  // push the subblock onto the sender state.  The sequencer will update the
+  // subblock on the return
+  //
+  pkt->senderState = new RubyTester::SenderState(writeAddr, req->getSize());
+
+  if (port->sendTiming(pkt)) {
+    DPRINTF(RubyTest, "initiating action - successful\n");
+    DPRINTF(RubyTest, 
+            "status before action update: %s\n",
+            (TesterStatus_to_string(m_status)).c_str());
+    m_status = TesterStatus_Action_Pending;
+  } else {
+    DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n");
+  }
+    
+  DPRINTF(RubyTest, 
+          "status after action update: %s\n",
+          (TesterStatus_to_string(m_status)).c_str());
+}
+
+void Check::initiateCheck()
+{
+  DPRINTF(RubyTest, "Initiating Check\n");
+  assert(m_status == TesterStatus_Ready);
+  
+  RubyTester::CpuPort* port
+    = safe_cast<RubyTester::CpuPort*> \
+    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
+
+  Request::Flags flags;
+  uint8_t dummyStackdata = 0;
+
+  //
+  // Checks are sized depending on the number of bytes written
+  //
+  Request *req = new Request(m_address.getAddress(),
+                             CHECK_SIZE,
+                             flags);
+
+  //
+  // 50% chance that the request will be an instruction fetch
+  //
+  if ((random() & 0x1) == 0) {
+    flags.set(Request::INST_FETCH);
+    req->setPC(m_address.getAddress());
+  }
+
+  PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx);
+  pkt->dataStatic(&dummyStackdata);
+
+  //
+  // push the subblock onto the sender state.  The sequencer will update the
+  // subblock on the return
+  //
+  pkt->senderState = new RubyTester::SenderState(m_address, req->getSize());
+
+  if (port->sendTiming(pkt)) {
+    DPRINTF(RubyTest, "initiating check - successful\n");
+    DPRINTF(RubyTest, 
+            "status before check update: %s\n",
+            (TesterStatus_to_string(m_status)).c_str());
+    m_status = TesterStatus_Check_Pending;
+  } else {
+    DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n");
+  }
+
+  DPRINTF(RubyTest, 
+          "status after check update: %s\n",
+          (TesterStatus_to_string(m_status)).c_str());
+}
+
+void Check::performCallback(NodeID proc, SubBlock* data)
+{
+  Address address = data->getAddress();
+  //  assert(getAddress() == address);  // This isn't exactly right since we 
now have multi-byte checks
+  assert(getAddress().getLineAddress() == address.getLineAddress());
+  assert(data != NULL);
+
+  DPRINTF(RubyTest, "RubyTester Callback\n");
+  debugPrint();
+
+  if (m_status == TesterStatus_Action_Pending) {
+    DPRINTF(RubyTest, 
+            "Action callback write value: %d, currently %d\n",
+            (m_value + m_store_count),
+            data->getByte(0));
+    //
+    // Perform store one byte at a time
+    //
+    data->setByte(0, (m_value + m_store_count));
+    m_store_count++;
+    if (m_store_count == CHECK_SIZE) {
+      m_status = TesterStatus_Ready;
+    } else {
+      m_status = TesterStatus_Idle;
+    }
+    DPRINTF(RubyTest, 
+            "Action callback return data now %d\n",
+            data->getByte(0));
+  } else if (m_status == TesterStatus_Check_Pending) {
+    DPRINTF(RubyTest, "Check callback\n");
+    // Perform load/check
+    for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) {
+      if (uint8(m_value+byte_number) != data->getByte(byte_number)) {
+        WARN_EXPR(proc);
+        WARN_EXPR(address);
+        WARN_EXPR(data);
+        WARN_EXPR(byte_number);
+        WARN_EXPR((int)m_value+byte_number);
+        WARN_EXPR((int)data->getByte(byte_number));
+        WARN_EXPR(*this);
+        WARN_EXPR(g_eventQueue_ptr->getTime());
+        ERROR_MSG("Action/check failure");
+      }
+    } 
+    DPRINTF(RubyTest, "Action/check success\n");
+    debugPrint();
+
+    // successful check complete, increment complete
+    m_tester_ptr->incrementCheckCompletions();
+
+    m_status = TesterStatus_Idle;
+    pickValue();
+
+  } else {
+    WARN_EXPR(*this);
+    WARN_EXPR(proc);
+    WARN_EXPR(data);
+    WARN_EXPR(m_status);
+    WARN_EXPR(g_eventQueue_ptr->getTime());
+    ERROR_MSG("Unexpected TesterStatus");
+  }
+  
+  DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, 
getAddress().getLineAddress());
+  DPRINTF(RubyTest, "Callback done\n");
+  debugPrint();
+}
+
+void Check::changeAddress(const Address& address)
+{
+  assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
+  m_status = TesterStatus_Idle;
+  m_address = address;
+  m_store_count = 0;
+}
+
+void Check::pickValue()
+{
+  assert(m_status == TesterStatus_Idle);
+  m_status = TesterStatus_Idle;
+  m_value = random() & 0xff; // One byte
+  m_store_count = 0;
+}
+
+void Check::pickInitiatingNode()
+{
+  assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
+  m_status = TesterStatus_Idle; 
+  m_initiatingNode = (random() % m_num_cpu_sequencers);
+  DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
+  m_store_count = 0;
+}
+
+void Check::print(ostream& out) const
+{
+  out << "[" 
+      << m_address << ", value: " 
+      << (int) m_value << ", status: " 
+      << m_status << ", initiating node: " 
+      << m_initiatingNode << ", store_count: "
+      << m_store_count
+      << "]" << flush;
+}
+
+void Check::debugPrint()
+{
+  DPRINTF(RubyTest, 
+        "[0x%x, value: %d, status: %s, initiating node: %d, store_count: 
%d]\n",
+          m_address.getAddress(), 
+          (int)m_value,
+          (TesterStatus_to_string(m_status)).c_str(),
+          m_initiatingNode,
+          m_store_count);
+}
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/Check.hh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/Check.hh Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,104 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CHECK_H
+#define CHECK_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/system/NodeID.hh"
+#include "mem/protocol/TesterStatus.hh"
+#include "mem/protocol/AccessModeType.hh"
+#include "cpu/rubytest/RubyTester.hh"
+class SubBlock;
+
+const int CHECK_SIZE_BITS = 2;
+const int CHECK_SIZE = (1<<CHECK_SIZE_BITS);
+
+class Check {
+public:
+  // Constructors
+  Check(const Address& address, 
+        const Address& pc,
+        int _num_cpu_sequencer,
+        RubyTester* _tester);
+
+  // Default Destructor
+  //~Check(); 
+  
+  // Public Methods
+
+  void initiate(); // Does Action or Check or nether
+  void performCallback(NodeID proc, SubBlock* data);
+  const Address& getAddress() { return m_address; }
+  void changeAddress(const Address& address);
+
+  void print(ostream& out) const;
+private:
+  // Private Methods
+  void initiatePrefetch();
+  void initiateAction();
+  void initiateCheck();
+
+  void pickValue();
+  void pickInitiatingNode();
+
+  void debugPrint();
+
+  // Using default copy constructor and assignment operator
+  //  Check(const Check& obj);
+  //  Check& operator=(const Check& obj);
+  
+  // Data Members (m_ prefix)
+  TesterStatus m_status;
+  uint8 m_value;
+  int m_store_count;
+  NodeID m_initiatingNode;
+  Address m_address;
+  Address m_pc;
+  AccessModeType m_access_mode;
+  int m_num_cpu_sequencers;
+  RubyTester* m_tester_ptr;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const Check& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline 
+ostream& operator<<(ostream& out, const Check& obj)
+{
+  obj.print(out);
+  out << flush;
+  return out;
+}
+
+#endif //CHECK_H
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/CheckTable.cc
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/CheckTable.cc    Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "cpu/rubytest/CheckTable.hh"
+#include "cpu/rubytest/CheckTable.hh"
+#include "cpu/rubytest/Check.hh"
+#include "mem/gems_common/Map.hh"
+
+CheckTable::CheckTable(int _num_cpu_sequencers, RubyTester* _tester)
+  : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
+{
+  m_lookup_map_ptr = new Map<Address, Check*>;
+  physical_address_t physical = 0;
+  Address address;
+
+  const int size1 = 32;
+  const int size2 = 100;
+
+  // The first set is to get some false sharing
+  physical = 1000;
+  for (int i=0; i<size1; i++) {
+    // Setup linear addresses
+    address.setAddress(physical);
+    addCheck(address);
+    physical += CHECK_SIZE;
+  }
+
+  // The next two sets are to get some limited false sharing and cache 
conflicts
+  physical = 1000;
+  for (int i=0; i<size2; i++) {
+    // Setup linear addresses
+    address.setAddress(physical);
+    addCheck(address);
+    physical += 256;
+  }
+
+  physical = 1000 + CHECK_SIZE;
+  for (int i=0; i<size2; i++) {
+    // Setup linear addresses
+    address.setAddress(physical);
+    addCheck(address);
+    physical += 256;
+  }
+}
+
+CheckTable::~CheckTable()
+{
+  int size = m_check_vector.size();
+  for (int i=0; i<size; i++) {
+    delete m_check_vector[i];
+  }
+  delete m_lookup_map_ptr;
+}
+
+void CheckTable::addCheck(const Address& address)
+{
+  if (log_int(CHECK_SIZE) != 0) {
+    if (address.bitSelect(0,CHECK_SIZE_BITS-1) != 0) {
+      ERROR_MSG("Check not aligned");
+    }
+  }
+
+  for (int i=0; i<CHECK_SIZE; i++) {
+    if (m_lookup_map_ptr->exist(Address(address.getAddress()+i))) {
+      // A mapping for this byte already existed, discard the entire check
+      return;
+    }
+  }
+
+  Check* check_ptr = new Check(address, 
+                               Address(100+m_check_vector.size()),
+                               m_num_cpu_sequencers,
+                               m_tester_ptr);
+  for (int i=0; i<CHECK_SIZE; i++) {
+    // Insert it once per byte
+    m_lookup_map_ptr->add(Address(address.getAddress()+i), check_ptr);
+  }
+  m_check_vector.insertAtBottom(check_ptr);
+}
+
+Check* CheckTable::getRandomCheck()
+{
+  return m_check_vector[random() % m_check_vector.size()];
+}
+
+Check* CheckTable::getCheck(const Address& address)
+{
+  DEBUG_MSG(TESTER_COMP, MedPrio, "Looking for check by address");
+  DEBUG_EXPR(TESTER_COMP, MedPrio, address);
+
+  if (m_lookup_map_ptr->exist(address)) {
+    Check* check = m_lookup_map_ptr->lookup(address);
+    assert(check != NULL);
+    return check;
+  } else {
+    return NULL;
+  }
+}
+
+void CheckTable::print(ostream& out) const
+{
+}
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/CheckTable.hh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/CheckTable.hh    Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CHECKTABLE_H
+#define CHECKTABLE_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/gems_common/Vector.hh"
+
+class Address;
+class Check;
+class RubyTester;
+template <class KEY_TYPE, class VALUE_TYPE> class Map;
+
+class CheckTable {
+public:
+  // Constructors
+  CheckTable(int _num_cpu_sequencers, RubyTester* _tester);
+
+  // Destructor
+  ~CheckTable();
+  
+  // Public Methods
+
+  Check* getRandomCheck();
+  Check* getCheck(const Address& address);
+
+  //  bool isPresent(const Address& address) const;
+  //  void removeCheckFromTable(const Address& address);
+  //  bool isTableFull() const;
+  // Need a method to select a check or retrieve a check
+
+  void print(ostream& out) const;
+private:
+  // Private Methods
+  void addCheck(const Address& address);
+
+  // Private copy constructor and assignment operator
+  CheckTable(const CheckTable& obj);
+  CheckTable& operator=(const CheckTable& obj);
+  
+  // Data Members (m_ prefix)
+  Vector<Check*> m_check_vector;
+  Map<Address, Check*>* m_lookup_map_ptr;
+
+  int m_num_cpu_sequencers;
+  RubyTester* m_tester_ptr;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const CheckTable& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline 
+ostream& operator<<(ostream& out, const CheckTable& obj)
+{
+  obj.print(out);
+  out << flush;
+  return out;
+}
+
+#endif //CHECKTABLE_H
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/RubyTester.cc
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/RubyTester.cc    Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,198 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/system/System.hh"
+#include "cpu/rubytest/RubyTester.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "cpu/rubytest/Check.hh"
+#include "sim/sim_exit.hh"
+
+RubyTester::RubyTester(const Params *p)
+  : MemObject(p),
+    checkStartEvent(this),
+    m_checks_to_complete(p->checks_to_complete),
+    m_deadlock_threshold(p->deadlock_threshold)
+{
+  m_checks_completed = 0;
+
+  // add the check start event to the event queue
+  schedule(checkStartEvent, 1);
+
+}
+
+RubyTester::~RubyTester()
+{
+  delete m_checkTable_ptr;
+  for (int i = 0; i < ports.size(); i++) {
+    delete ports[i];
+  }
+}
+
+void RubyTester::init()
+{
+  assert(ports.size() > 0);
+
+  m_last_progress_vector.setSize(ports.size());
+  for (int i = 0; i < m_last_progress_vector.size(); i++) {
+    m_last_progress_vector[i] = 0;
+  }
+
+  m_num_cpu_sequencers = ports.size();
+
+  m_checkTable_ptr = new CheckTable(m_num_cpu_sequencers, this);
+}
+
+Port *
+RubyTester::getPort(const std::string &if_name, int idx)
+{
+
+    if (if_name != "cpuPort") {
+        panic("RubyTester::getPort: unknown port %s requested", if_name);
+    }
+
+    if (idx >= (int)ports.size()) {
+        ports.resize(idx + 1);
+    }
+
+    if (ports[idx] != NULL) {
+        panic("RubyTester::getPort: port %d already assigned", idx);
+    }
+
+    CpuPort *port = new CpuPort(csprintf("%s-port%d", name(), idx), this, idx);
+
+    ports[idx] = port;
+    return port;
+}
+
+Tick
+RubyTester::CpuPort::recvAtomic(PacketPtr pkt)
+{
+  panic("RubyTester::CpuPort::recvAtomic() not implemented!\n");
+  return 0;
+}
+
+bool
+RubyTester::CpuPort::recvTiming(PacketPtr pkt)
+{
+  //
+  // retrieve the subblock and call hitCallback
+  //
+  RubyTester::SenderState* senderState = 
+    static_cast<RubyTester::SenderState*>(pkt->senderState);
+  SubBlock* data = senderState->subBlock;
+  assert(data != NULL);
+  
+  // pop the sender state from the packet
+  pkt->senderState = senderState->saved;
+  delete senderState;
+
+  tester->hitCallback(idx, data);
+
+  //
+  // Now that the tester has completed, delete the sublock and return
+  //
+  delete data;
+  return true;
+}
+
+Port* 
+RubyTester::getCpuPort(int idx)
+{
+  assert(idx >= 0 && idx < ports.size());
+
+  return ports[idx];
+}
+
+void RubyTester::hitCallback(NodeID proc, SubBlock* data)
+{
+  // Mark that we made progress
+  m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+
+  DPRINTF(RubyTest, "completed request for proc: %d\n", proc);
+  DPRINTF(RubyTest, 
+          "addr: 0x%x, size: %d, data: ", 
+          data->getAddress(),
+          data->getSize());
+  for (int byte = 0; byte < data->getSize(); byte++) {
+    DPRINTF(RubyTest, "%d", data->getByte(byte));
+  }
+  DPRINTF(RubyTest, "\n");
+
+  //
+  // This tells us our store has 'completed' or for a load gives us
+  // back the data to make the check 
+  //
+  Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress());
+  assert(check_ptr != NULL);
+  check_ptr->performCallback(proc, data);
+}
+
+void RubyTester::wakeup()
+{ 
+  if (m_checks_completed < m_checks_to_complete) {
+    // Try to perform an action or check
+    Check* check_ptr = m_checkTable_ptr->getRandomCheck();
+    assert(check_ptr != NULL);
+    check_ptr->initiate();
+    
+    checkForDeadlock();
+    
+    schedule(checkStartEvent, curTick + 2);
+  } else {
+    exitSimLoop("Ruby Tester completed");
+  }
+}
+
+void RubyTester::checkForDeadlock()
+{
+  int size = m_last_progress_vector.size();
+  Time current_time = g_eventQueue_ptr->getTime();
+  for (int processor = 0; processor < size; processor++) {
+    if ((current_time - m_last_progress_vector[processor]) > 
m_deadlock_threshold) {
+      WARN_EXPR(current_time);
+      WARN_EXPR(m_last_progress_vector[processor]);
+      WARN_EXPR(current_time - m_last_progress_vector[processor]);
+      WARN_EXPR(processor);
+      ERROR_MSG("Deadlock detected.");
+    }
+  }
+}
+
+void RubyTester::print(ostream& out) const
+{
+  out << "[RubyTester]" << endl;
+}
+
+RubyTester *
+RubyTesterParams::create()
+{
+    return new RubyTester(this);
+}
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/RubyTester.hh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/RubyTester.hh    Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,158 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RUBY_TESTER_H
+#define RUBY_TESTER_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/mem_object.hh"
+#include "cpu/rubytest/CheckTable.hh"
+#include "mem/ruby/system/RubyPort.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/common/DataBlock.hh"
+#include "mem/packet.hh"
+#include "params/RubyTester.hh"
+
+class RubyTester : public MemObject 
+{
+
+ public:
+
+  class CpuPort : public SimpleTimingPort
+  {
+    RubyTester *tester;
+
+   public:
+    
+    CpuPort(const std::string &_name, 
+            RubyTester *_tester,
+            int _idx)
+      : SimpleTimingPort(_name, _tester), tester(_tester), idx(_idx)
+    {}
+
+    int idx;
+    
+   protected:
+    
+    virtual bool recvTiming(PacketPtr pkt);
+
+    virtual Tick recvAtomic(PacketPtr pkt);
+    
+  };
+
+  struct SenderState : public Packet::SenderState
+  {
+    SubBlock* subBlock;
+    Packet::SenderState *saved;
+    
+    SenderState(Address addr,
+                int size,
+                Packet::SenderState *sender_state = NULL)
+      : saved(sender_state)
+    {subBlock = new SubBlock(addr, size);}
+  };
+
+  typedef RubyTesterParams Params;
+  // Constructors
+  RubyTester(const Params *p);
+
+  // Destructor
+  ~RubyTester();
+  
+  // Public Methods
+  
+  virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+  Port* getCpuPort(int idx);
+
+  void virtual init();
+
+  void wakeup();
+
+  void incrementCheckCompletions() { m_checks_completed++; }
+
+  void printStats(ostream& out) const {}
+  void clearStats() {}
+  void printConfig(ostream& out) const {}
+
+  void print(ostream& out) const;
+
+ protected:
+  class CheckStartEvent : public Event
+  {
+  private:
+    RubyTester *tester;
+    
+  public:
+    CheckStartEvent(RubyTester *_tester) : Event(CPU_Tick_Pri), 
tester(_tester) {}
+    void process() { tester->wakeup(); }
+    virtual const char *description() const { return "RubyTester tick"; }
+  };
+  
+  CheckStartEvent checkStartEvent;
+
+
+ private:
+  // Private Methods
+
+  void hitCallback(NodeID proc, SubBlock* data);
+
+  void checkForDeadlock();
+
+  // Private copy constructor and assignment operator
+  RubyTester(const RubyTester& obj);
+  RubyTester& operator=(const RubyTester& obj);
+  
+  // Data Members (m_ prefix)
+  
+  CheckTable* m_checkTable_ptr;
+  Vector<Time> m_last_progress_vector;
+
+  uint64 m_checks_completed;
+  std::vector<CpuPort*> ports;
+  uint64 m_checks_to_complete;
+  int m_deadlock_threshold;
+  int m_num_cpu_sequencers;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const RubyTester& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline 
+ostream& operator<<(ostream& out, const RubyTester& obj)
+{
+  obj.print(out);
+  out << flush;
+  return out;
+}
+
+#endif //RUBY_TESTER_H
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/RubyTester.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/RubyTester.py    Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,36 @@
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+from MemObject import MemObject
+from m5.params import *
+from m5.proxy import *
+
+class RubyTester(MemObject):
+    type = 'RubyTester'
+    cpuPort = VectorPort("the cpu ports")
+    checks_to_complete = Param.Int(100, "checks to complete")
+    deadlock_threshold = Param.Int(50000, "how often to check for deadlock")
diff -r 985b666fdbfc -r 2bff56035b82 src/cpu/rubytest/SConscript
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/rubytest/SConscript       Mon Dec 21 08:31:08 2009 -0800
@@ -0,0 +1,38 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Import('*')
+
+SimObject('RubyTester.py')
+
+Source('RubyTester.cc')
+Source('Check.cc')
+Source('CheckTable.cc')
+
+TraceFlag('RubyTest')
diff -r 985b666fdbfc -r 2bff56035b82 src/mem/ruby/common/SubBlock.hh
--- a/src/mem/ruby/common/SubBlock.hh   Mon Dec 21 08:31:07 2009 -0800
+++ b/src/mem/ruby/common/SubBlock.hh   Mon Dec 21 08:31:08 2009 -0800
@@ -75,7 +75,7 @@
 
   // Data Members (m_ prefix)
   Address m_address;
-  Vector<uint> m_data;
+  Vector<uint8_t> m_data;
 };
 
 // Output operator declaration
diff -r 985b666fdbfc -r 2bff56035b82 src/mem/ruby/system/RubyPort.cc
--- a/src/mem/ruby/system/RubyPort.cc   Mon Dec 21 08:31:07 2009 -0800
+++ b/src/mem/ruby/system/RubyPort.cc   Mon Dec 21 08:31:08 2009 -0800
@@ -1,6 +1,7 @@
 #include "mem/physical.hh"
 #include "mem/ruby/system/RubyPort.hh"
 #include "mem/ruby/slicc_interface/AbstractController.hh"
+#include "cpu/rubytest/RubyTester.hh"
 
 RubyPort::RubyPort(const Params *p)
     : MemObject(p)
diff -r 985b666fdbfc -r 2bff56035b82 src/mem/ruby/system/Sequencer.cc
--- a/src/mem/ruby/system/Sequencer.cc  Mon Dec 21 08:31:07 2009 -0800
+++ b/src/mem/ruby/system/Sequencer.cc  Mon Dec 21 08:31:08 2009 -0800
@@ -40,6 +40,7 @@
 #include "mem/gems_common/Map.hh"
 #include "mem/ruby/buffers/MessageBuffer.hh"
 #include "mem/ruby/slicc_interface/AbstractController.hh"
+#include "cpu/rubytest/RubyTester.hh"
 
 #include "params/RubySequencer.hh"
 
@@ -72,6 +73,7 @@
     m_dataCache_ptr = p->dcache;
     m_max_outstanding_requests = p->max_outstanding_requests;
     m_deadlock_threshold = p->deadlock_threshold;
+    m_usingRubyTester = p->using_ruby_tester;
 
     assert(m_max_outstanding_requests > 0);
     assert(m_deadlock_threshold > 0);
@@ -332,7 +334,20 @@
     }
   }
 
+  //
+  // If using the RubyTester, update the RubyTester sender state's subBlock 
+  // with the recieved data.  The tester will later access this state.
+  // Note: RubyPort will access it's sender state before the RubyTester.
+  // Also note this code should be removed once ruby 
+  //
+  RubyTester::SenderState* testerSenderState;
+  if (m_usingRubyTester) {
+      testerSenderState = safe_cast<RubyTester::SenderState*>( \
+           
safe_cast<RubyPort::SenderState*>(ruby_request.pkt->senderState)->saved);
+      testerSenderState->subBlock->mergeFrom(data);
+  }
   (*this.*m_hit_callback)(ruby_request.pkt);
+
   delete srequest;
 }
 
diff -r 985b666fdbfc -r 2bff56035b82 src/mem/ruby/system/Sequencer.hh
--- a/src/mem/ruby/system/Sequencer.hh  Mon Dec 21 08:31:07 2009 -0800
+++ b/src/mem/ruby/system/Sequencer.hh  Mon Dec 21 08:31:08 2009 -0800
@@ -126,6 +126,8 @@
   int m_servicing_atomic;
   int m_atomics_counter;
 
+  bool m_usingRubyTester;
+
   class SequencerWakeupEvent : public Event
   {
       Sequencer *m_sequencer_ptr;
diff -r 985b666fdbfc -r 2bff56035b82 src/mem/ruby/system/Sequencer.py
--- a/src/mem/ruby/system/Sequencer.py  Mon Dec 21 08:31:07 2009 -0800
+++ b/src/mem/ruby/system/Sequencer.py  Mon Dec 21 08:31:08 2009 -0800
@@ -18,6 +18,7 @@
     dcache = Param.RubyCache("")
     max_outstanding_requests = Param.Int(16, "")
     deadlock_threshold = Param.Int(500000, "")
+    using_ruby_tester = Param.Bool(False, "")
 
 class DMASequencer(RubyPort):
     type = 'DMASequencer'

_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to