summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Beckmann <Brad.Beckmann@amd.com>2010-01-29 20:29:23 -0800
committerBrad Beckmann <Brad.Beckmann@amd.com>2010-01-29 20:29:23 -0800
commit45230a4f6b82af61c05fcf93b6e1a9319fcb0a2e (patch)
treebe5514d8ae75df903599758fa2fa86834e9142b1
parent4eb3bfc31b66a6835a398ba2f0a11ea9b78d525d (diff)
downloadgem5-45230a4f6b82af61c05fcf93b6e1a9319fcb0a2e.tar.xz
ruby: added the GEMS ruby tester
-rw-r--r--configs/example/rubytest.py126
-rw-r--r--src/cpu/rubytest/Check.cc397
-rw-r--r--src/cpu/rubytest/Check.hh105
-rw-r--r--src/cpu/rubytest/CheckTable.cc130
-rw-r--r--src/cpu/rubytest/CheckTable.hh91
-rw-r--r--src/cpu/rubytest/RubyTester.cc202
-rw-r--r--src/cpu/rubytest/RubyTester.hh162
-rw-r--r--src/cpu/rubytest/RubyTester.py38
-rw-r--r--src/cpu/rubytest/SConscript47
-rw-r--r--src/mem/request.hh7
-rw-r--r--src/mem/ruby/common/SubBlock.hh2
-rw-r--r--src/mem/ruby/system/RubyPort.cc10
-rw-r--r--src/mem/ruby/system/RubyPort.hh15
-rw-r--r--src/mem/ruby/system/Sequencer.cc28
-rw-r--r--src/mem/ruby/system/Sequencer.hh2
-rw-r--r--src/mem/ruby/system/Sequencer.py1
16 files changed, 1355 insertions, 8 deletions
diff --git a/configs/example/rubytest.py b/configs/example/rubytest.py
new file mode 100644
index 000000000..13b862756
--- /dev/null
+++ b/configs/example/rubytest.py
@@ -0,0 +1,126 @@
+# Copyright (c) 2006-2007 The Regents of The University of Michigan
+# Copyright (c) 2009 Advanced Micro Devices, Inc.
+# 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.
+#
+# Authors: Ron Dreslinski
+# Brad Beckmann
+
+import m5
+from m5.objects import *
+from m5.defines import buildEnv
+from m5.util import addToPath
+import os, optparse, sys
+addToPath('../common')
+addToPath('../ruby')
+
+import Ruby
+
+if buildEnv['FULL_SYSTEM']:
+ panic("This script requires system-emulation mode (*_SE).")
+
+# 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()
+
+parser.add_option("-l", "--checks", metavar="N", default=100,
+ help="Stop after N checks (loads)")
+parser.add_option("-f", "--wakeup_freq", metavar="N", default=10,
+ help="Wakeup every N cycles")
+
+#
+# Set the default cache size and associativity to be very small to encourage
+# races between requests and writebacks.
+#
+parser.add_option("--l1d_size", type="string", default="256B")
+parser.add_option("--l1i_size", type="string", default="256B")
+parser.add_option("--l2_size", type="string", default="512B")
+parser.add_option("--l1d_assoc", type="int", default=2)
+parser.add_option("--l1i_assoc", type="int", default=2)
+parser.add_option("--l2_assoc", type="int", default=2)
+
+execfile(os.path.join(config_root, "common", "Options.py"))
+
+(options, args) = parser.parse_args()
+
+if args:
+ print "Error: script doesn't take any positional arguments"
+ sys.exit(1)
+
+#
+# Create the ruby random tester
+#
+tester = RubyTester(checks_to_complete = options.checks,
+ wakeup_frequency = options.wakeup_freq)
+
+#
+# Create the M5 system. Note that the PhysicalMemory Object isn't
+# actually used by the rubytester, but is included to support the
+# M5 memory size == Ruby memory size checks
+#
+system = System(physmem = PhysicalMemory())
+
+system.ruby = Ruby.create_system(options, system.physmem)
+
+assert(options.num_cpus == len(system.ruby.cpu_ruby_ports))
+
+#
+# The tester is most effective when randomization is turned on and
+# artifical delay is randomly inserted on messages
+#
+system.ruby.randomization = True
+
+for ruby_port in system.ruby.cpu_ruby_ports:
+ #
+ # Tie the ruby tester ports to the ruby cpu ports
+ #
+ tester.cpuPort = ruby_port.port
+
+ #
+ # Tell each sequencer this is the ruby tester so that it
+ # copies the subblock back to the checker
+ #
+ ruby_port.using_ruby_tester = True
+
+# -----------------------
+# run simulation
+# -----------------------
+
+root = Root( system = system )
+root.system.mem_mode = 'timing'
+
+# Not much point in this being higher than the L1 latency
+m5.ticks.setGlobalFrequency('1ns')
+
+# instantiate configuration
+m5.instantiate(root)
+
+# simulate until program terminates
+exit_event = m5.simulate(options.maxtick)
+
+print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
diff --git a/src/cpu/rubytest/Check.cc b/src/cpu/rubytest/Check.cc
new file mode 100644
index 000000000..3b358e633
--- /dev/null
+++ b/src/cpu/rubytest/Check.cc
@@ -0,0 +1,397 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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);
+
+ //
+ // Prefetches are assumed to be 0 sized
+ //
+ Request *req = new Request(m_address.getAddress(),
+ 0,
+ flags,
+ curTick,
+ m_pc.getAddress());
+
+ 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);
+ }
+ } else {
+ cmd = MemCmd::WriteReq;
+ flags.set(Request::PF_EXCLUSIVE);
+ }
+
+ PacketPtr pkt = new Packet(req, cmd, port->idx);
+
+ //
+ // 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(),
+ pkt->senderState);
+
+ if (port->sendTiming(pkt)) {
+ DPRINTF(RubyTest, "successfully initiated prefetch.\n");
+ } else {
+ //
+ // If the packet did not issue, must delete
+ //
+ RubyTester::SenderState* senderState =
+ safe_cast<RubyTester::SenderState*>(pkt->senderState);
+ pkt->senderState = senderState->saved;
+ delete senderState;
+ delete pkt->req;
+ delete pkt;
+
+ 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;
+
+ //
+ // 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,
+ curTick,
+ m_pc.getAddress());
+
+ 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);
+ uint8_t* writeData = new uint8_t;
+ *writeData = m_value + m_store_count;
+ pkt->dataDynamic(writeData);
+
+ DPRINTF(RubyTest,
+ "data 0x%x check 0x%x\n",
+ *(pkt->getPtr<uint8_t>()),
+ *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(),
+ pkt->senderState);
+
+ 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 {
+ //
+ // If the packet did not issue, must delete
+ // Note: No need to delete the data, the packet destructor will delete it
+ //
+ RubyTester::SenderState* senderState =
+ safe_cast<RubyTester::SenderState*>(pkt->senderState);
+ pkt->senderState = senderState->saved;
+ delete senderState;
+ delete pkt->req;
+ delete pkt;
+
+ 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;
+
+ //
+ // Checks are sized depending on the number of bytes written
+ //
+ Request *req = new Request(m_address.getAddress(),
+ CHECK_SIZE,
+ flags,
+ curTick,
+ m_pc.getAddress());
+
+ //
+ // 50% chance that the request will be an instruction fetch
+ //
+ if ((random() & 0x1) == 0) {
+ flags.set(Request::INST_FETCH);
+ }
+
+ PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx);
+ uint8_t* dataArray = new uint8_t[CHECK_SIZE];
+ pkt->dataDynamicArray(dataArray);
+
+ //
+ // 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(),
+ pkt->senderState);
+
+ 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 {
+ //
+ // If the packet did not issue, must delete
+ // Note: No need to delete the data, the packet destructor will delete it
+ //
+ RubyTester::SenderState* senderState =
+ safe_cast<RubyTester::SenderState*>(pkt->senderState);
+ pkt->senderState = senderState->saved;
+ delete senderState;
+ delete pkt->req;
+ delete pkt;
+
+ 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 --git a/src/cpu/rubytest/Check.hh b/src/cpu/rubytest/Check.hh
new file mode 100644
index 000000000..ce42ed376
--- /dev/null
+++ b/src/cpu/rubytest/Check.hh
@@ -0,0 +1,105 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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 --git a/src/cpu/rubytest/CheckTable.cc b/src/cpu/rubytest/CheckTable.cc
new file mode 100644
index 000000000..a589fbdd3
--- /dev/null
+++ b/src/cpu/rubytest/CheckTable.cc
@@ -0,0 +1,130 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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 --git a/src/cpu/rubytest/CheckTable.hh b/src/cpu/rubytest/CheckTable.hh
new file mode 100644
index 000000000..23726d26b
--- /dev/null
+++ b/src/cpu/rubytest/CheckTable.hh
@@ -0,0 +1,91 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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 --git a/src/cpu/rubytest/RubyTester.cc b/src/cpu/rubytest/RubyTester.cc
new file mode 100644
index 000000000..547b0eb17
--- /dev/null
+++ b/src/cpu/rubytest/RubyTester.cc
@@ -0,0 +1,202 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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_wakeup_frequency(p->wakeup_frequency)
+{
+ 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 =
+ safe_cast<RubyTester::SenderState*>(pkt->senderState);
+ SubBlock* subblock = senderState->subBlock;
+ assert(subblock != NULL);
+
+ // pop the sender state from the packet
+ pkt->senderState = senderState->saved;
+
+ tester->hitCallback(idx, subblock);
+
+ //
+ // Now that the tester has completed, delete the senderState
+ // (includes sublock) and the packet, then return
+ //
+ delete senderState;
+ delete pkt->req;
+ delete pkt;
+ 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 + m_wakeup_frequency);
+ } 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 --git a/src/cpu/rubytest/RubyTester.hh b/src/cpu/rubytest/RubyTester.hh
new file mode 100644
index 000000000..f1ed7e34e
--- /dev/null
+++ b/src/cpu/rubytest/RubyTester.hh
@@ -0,0 +1,162 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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);}
+
+ ~SenderState() {delete subBlock;}
+ };
+
+ 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;
+ int m_wakeup_frequency;
+};
+
+// 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 --git a/src/cpu/rubytest/RubyTester.py b/src/cpu/rubytest/RubyTester.py
new file mode 100644
index 000000000..af37d2ff1
--- /dev/null
+++ b/src/cpu/rubytest/RubyTester.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# Copyright (c) 2009 Advanced Micro Devices, Inc.
+# 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")
+ wakeup_frequency = Param.Int(10, "number of cycles between wakeups")
diff --git a/src/cpu/rubytest/SConscript b/src/cpu/rubytest/SConscript
new file mode 100644
index 000000000..9352dd793
--- /dev/null
+++ b/src/cpu/rubytest/SConscript
@@ -0,0 +1,47 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# Copyright (c) 2009 Advanced Micro Devices, Inc.
+# 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('*')
+
+#
+# Currently the ruby testser relies on Ruby specific objects (SubBlock, etc.)
+# When this dependency is removed, the ruby tester should be compiled
+# independently from Ruby
+#
+if not env['RUBY']:
+ Return()
+
+SimObject('RubyTester.py')
+
+Source('RubyTester.cc')
+Source('Check.cc')
+Source('CheckTable.cc')
+
+TraceFlag('RubyTest')
diff --git a/src/mem/request.hh b/src/mem/request.hh
index f2cc4647c..8d1697ad2 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -194,6 +194,13 @@ class Request : public FastAlloc
setPhys(paddr, size, flags, time);
}
+ Request(Addr paddr, int size, Flags flags, Tick time, Addr pc)
+ {
+ setPhys(paddr, size, flags, time);
+ privateFlags.set(VALID_PC);
+ _pc = pc;
+ }
+
Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
int cid, ThreadID tid)
{
diff --git a/src/mem/ruby/common/SubBlock.hh b/src/mem/ruby/common/SubBlock.hh
index 753666a17..8acdd9f4d 100644
--- a/src/mem/ruby/common/SubBlock.hh
+++ b/src/mem/ruby/common/SubBlock.hh
@@ -75,7 +75,7 @@ private:
// Data Members (m_ prefix)
Address m_address;
- Vector<uint> m_data;
+ Vector<uint8_t> m_data;
};
// Output operator declaration
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 692c9ea81..e4742dbab 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -30,6 +30,7 @@
#include "mem/physical.hh"
#include "mem/ruby/system/RubyPort.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
+#include "cpu/rubytest/RubyTester.hh"
uint16_t RubyPort::m_num_ports = 0;
@@ -205,11 +206,18 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
// sending them to our assigned ruby port.
//
RubyRequestType type = RubyRequestType_NULL;
+
+ //
+ // If valid, copy the pc to the ruby request
+ //
Addr pc = 0;
+ if (pkt->req->hasPC()) {
+ pc = pkt->req->getPC();
+ }
+
if (pkt->isRead()) {
if (pkt->req->isInstFetch()) {
type = RubyRequestType_IFETCH;
- pc = pkt->req->getPC();
} else {
type = RubyRequestType_LD;
}
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index e57f663c9..267b557ec 100644
--- a/src/mem/ruby/system/RubyPort.hh
+++ b/src/mem/ruby/system/RubyPort.hh
@@ -152,11 +152,10 @@ protected:
MessageBuffer* m_mandatory_q_ptr;
PioPort* pio_port;
-private:
- static uint16_t m_num_ports;
- uint16_t m_port_id;
- uint64_t m_request_cnt;
-
+ //
+ // The pending request map is protected so that the Sequencer can access it.
+ // This is a temporary fix until the libruby inteface is cleaned
+ //
struct RequestCookie {
Packet *pkt;
M5Port *m5Port;
@@ -167,6 +166,12 @@ private:
typedef std::map<int64_t, RequestCookie*> RequestMap;
static RequestMap pending_cpu_requests;
+
+private:
+ static uint16_t m_num_ports;
+ uint16_t m_port_id;
+ uint64_t m_request_cnt;
+
static void ruby_hit_callback(int64_t req_id);
M5Port* physMemPort;
diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc
index 00ae5364c..578dcbf58 100644
--- a/src/mem/ruby/system/Sequencer.cc
+++ b/src/mem/ruby/system/Sequencer.cc
@@ -41,6 +41,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"
@@ -74,7 +75,8 @@ Sequencer::Sequencer(const Params *p)
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);
assert(m_instCache_ptr != NULL);
@@ -344,6 +346,30 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) {
}
}
+ //
+ // 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.
+ //
+ if (m_usingRubyTester) {
+ //
+ // Since the hit callback func only takes a request id, we must iterate
+ // through the requests and update the packet's subBlock here.
+ // All this would be fixed if we could attach a M5 pkt pointer to the
+ // ruby request, however that change will break the libruby interface so
+ // we'll hold off on that for now.
+ //
+ RequestMap::iterator i = pending_cpu_requests.find(srequest->id);
+ if (i == pending_cpu_requests.end())
+ panic("could not find pending request %d\n", srequest->id);
+ RequestCookie *cookie = i->second;
+ Packet *pkt = cookie->pkt;
+
+ RubyTester::SenderState* testerSenderState;
+ testerSenderState = safe_cast<RubyTester::SenderState*>(pkt->senderState);
+ testerSenderState->subBlock->mergeFrom(data);
+ }
+
m_hit_callback(srequest->id);
delete srequest;
}
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index f24edbf74..a571092f7 100644
--- a/src/mem/ruby/system/Sequencer.hh
+++ b/src/mem/ruby/system/Sequencer.hh
@@ -129,6 +129,8 @@ private:
int m_load_waiting_on_store_cycles;
int m_load_waiting_on_load_cycles;
+ bool m_usingRubyTester;
+
class SequencerWakeupEvent : public Event
{
Sequencer *m_sequencer_ptr;
diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py
index 30cb9add0..be8ac94b8 100644
--- a/src/mem/ruby/system/Sequencer.py
+++ b/src/mem/ruby/system/Sequencer.py
@@ -20,6 +20,7 @@ class RubySequencer(RubyPort):
"max requests (incl. prefetches) outstanding")
deadlock_threshold = Param.Int(500000,
"max outstanding cycles for a request before deadlock/livelock declared")
+ using_ruby_tester = Param.Bool(False, "")
class DMASequencer(RubyPort):
type = 'DMASequencer'