summaryrefslogtreecommitdiff
path: root/src/cpu/testers
diff options
context:
space:
mode:
authorBrad Beckmann <Brad.Beckmann@amd.com>2010-08-24 12:07:22 -0700
committerBrad Beckmann <Brad.Beckmann@amd.com>2010-08-24 12:07:22 -0700
commite983ef9e8c6749c1cd0bf083a2092cb4683d0346 (patch)
tree02d262e1b84e5c4675df54cb27678526f756169b /src/cpu/testers
parent20b2f0ce9f09bc4166bc3ee001eab4d6b2b84a04 (diff)
downloadgem5-e983ef9e8c6749c1cd0bf083a2092cb4683d0346.tar.xz
testers: move testers to a new directory
This patch moves the testers to a new subdirectory under src/cpu and includes the necessary fixes to work with latest m5 initialization patches. --HG-- rename : configs/example/determ_test.py => configs/example/ruby_direct_test.py rename : src/cpu/directedtest/DirectedGenerator.cc => src/cpu/testers/directedtest/DirectedGenerator.cc rename : src/cpu/directedtest/DirectedGenerator.hh => src/cpu/testers/directedtest/DirectedGenerator.hh rename : src/cpu/directedtest/InvalidateGenerator.cc => src/cpu/testers/directedtest/InvalidateGenerator.cc rename : src/cpu/directedtest/InvalidateGenerator.hh => src/cpu/testers/directedtest/InvalidateGenerator.hh rename : src/cpu/directedtest/RubyDirectedTester.cc => src/cpu/testers/directedtest/RubyDirectedTester.cc rename : src/cpu/directedtest/RubyDirectedTester.hh => src/cpu/testers/directedtest/RubyDirectedTester.hh rename : src/cpu/directedtest/RubyDirectedTester.py => src/cpu/testers/directedtest/RubyDirectedTester.py rename : src/cpu/directedtest/SConscript => src/cpu/testers/directedtest/SConscript rename : src/cpu/directedtest/SeriesRequestGenerator.cc => src/cpu/testers/directedtest/SeriesRequestGenerator.cc rename : src/cpu/directedtest/SeriesRequestGenerator.hh => src/cpu/testers/directedtest/SeriesRequestGenerator.hh rename : src/cpu/memtest/MemTest.py => src/cpu/testers/memtest/MemTest.py rename : src/cpu/memtest/SConscript => src/cpu/testers/memtest/SConscript rename : src/cpu/memtest/memtest.cc => src/cpu/testers/memtest/memtest.cc rename : src/cpu/memtest/memtest.hh => src/cpu/testers/memtest/memtest.hh rename : src/cpu/rubytest/Check.cc => src/cpu/testers/rubytest/Check.cc rename : src/cpu/rubytest/Check.hh => src/cpu/testers/rubytest/Check.hh rename : src/cpu/rubytest/CheckTable.cc => src/cpu/testers/rubytest/CheckTable.cc rename : src/cpu/rubytest/CheckTable.hh => src/cpu/testers/rubytest/CheckTable.hh rename : src/cpu/rubytest/RubyTester.cc => src/cpu/testers/rubytest/RubyTester.cc rename : src/cpu/rubytest/RubyTester.hh => src/cpu/testers/rubytest/RubyTester.hh rename : src/cpu/rubytest/RubyTester.py => src/cpu/testers/rubytest/RubyTester.py rename : src/cpu/rubytest/SConscript => src/cpu/testers/rubytest/SConscript
Diffstat (limited to 'src/cpu/testers')
-rw-r--r--src/cpu/testers/directedtest/DirectedGenerator.cc44
-rw-r--r--src/cpu/testers/directedtest/DirectedGenerator.hh56
-rw-r--r--src/cpu/testers/directedtest/InvalidateGenerator.cc142
-rw-r--r--src/cpu/testers/directedtest/InvalidateGenerator.hh63
-rw-r--r--src/cpu/testers/directedtest/RubyDirectedTester.cc136
-rw-r--r--src/cpu/testers/directedtest/RubyDirectedTester.hh118
-rw-r--r--src/cpu/testers/directedtest/RubyDirectedTester.py52
-rw-r--r--src/cpu/testers/directedtest/SConscript48
-rw-r--r--src/cpu/testers/directedtest/SeriesRequestGenerator.cc114
-rw-r--r--src/cpu/testers/directedtest/SeriesRequestGenerator.hh63
-rw-r--r--src/cpu/testers/memtest/MemTest.py52
-rw-r--r--src/cpu/testers/memtest/SConscript38
-rw-r--r--src/cpu/testers/memtest/memtest.cc434
-rw-r--r--src/cpu/testers/memtest/memtest.hh198
-rw-r--r--src/cpu/testers/rubytest/Check.cc356
-rw-r--r--src/cpu/testers/rubytest/Check.hh89
-rw-r--r--src/cpu/testers/rubytest/CheckTable.cc130
-rw-r--r--src/cpu/testers/rubytest/CheckTable.hh81
-rw-r--r--src/cpu/testers/rubytest/RubyTester.cc195
-rw-r--r--src/cpu/testers/rubytest/RubyTester.hh148
-rw-r--r--src/cpu/testers/rubytest/RubyTester.py38
-rw-r--r--src/cpu/testers/rubytest/SConscript47
22 files changed, 2642 insertions, 0 deletions
diff --git a/src/cpu/testers/directedtest/DirectedGenerator.cc b/src/cpu/testers/directedtest/DirectedGenerator.cc
new file mode 100644
index 000000000..68ea55449
--- /dev/null
+++ b/src/cpu/testers/directedtest/DirectedGenerator.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009-2010 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/testers/directedtest/DirectedGenerator.hh"
+
+DirectedGenerator::DirectedGenerator(const Params *p)
+ : SimObject(p)
+{
+ m_num_cpus = p->num_cpus;
+ m_directed_tester = NULL;
+}
+
+void
+DirectedGenerator::setDirectedTester(RubyDirectedTester* directed_tester)
+{
+ assert(m_directed_tester == NULL);
+ m_directed_tester = directed_tester;
+}
diff --git a/src/cpu/testers/directedtest/DirectedGenerator.hh b/src/cpu/testers/directedtest/DirectedGenerator.hh
new file mode 100644
index 000000000..904dcf399
--- /dev/null
+++ b/src/cpu/testers/directedtest/DirectedGenerator.hh
@@ -0,0 +1,56 @@
+/*
+ * 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 __CPU_DIRECTEDTEST_DIRECTEDGENERATOR_HH__
+#define __CPU_DIRECTEDTEST_DIRECTEDGENERATOR_HH__
+
+#include "cpu/testers/directedtest/DirectedGenerator.hh"
+#include "cpu/testers/directedtest/RubyDirectedTester.hh"
+#include "params/DirectedGenerator.hh"
+#include "sim/sim_object.hh"
+
+class DirectedGenerator : public SimObject
+{
+ public:
+ typedef DirectedGeneratorParams Params;
+ DirectedGenerator(const Params *p);
+
+ virtual ~DirectedGenerator() {}
+
+ virtual bool initiate() = 0;
+ virtual void performCallback(uint proc, Addr address) = 0;
+
+ void setDirectedTester(RubyDirectedTester* directed_tester);
+
+ protected:
+ int m_num_cpus;
+ RubyDirectedTester* m_directed_tester;
+};
+
+#endif //__CPU_DIRECTEDTEST_DIRECTEDGENERATOR_HH__
+
diff --git a/src/cpu/testers/directedtest/InvalidateGenerator.cc b/src/cpu/testers/directedtest/InvalidateGenerator.cc
new file mode 100644
index 000000000..724702d61
--- /dev/null
+++ b/src/cpu/testers/directedtest/InvalidateGenerator.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009-2010 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/testers/directedtest/RubyDirectedTester.hh"
+#include "cpu/testers/directedtest/DirectedGenerator.hh"
+#include "cpu/testers/directedtest/InvalidateGenerator.hh"
+
+InvalidateGenerator::InvalidateGenerator(const Params *p)
+ : DirectedGenerator(p)
+{
+ //
+ // First, issue loads to bring the block into S state
+ //
+ m_status = InvalidateGeneratorStatus_Load_Waiting;
+ m_active_read_node = 0;
+ m_active_inv_node = 0;
+ m_address = 0x0;
+ m_addr_increment_size = p->addr_increment_size;
+}
+
+InvalidateGenerator::~InvalidateGenerator()
+{
+}
+
+bool
+InvalidateGenerator::initiate()
+{
+ RubyDirectedTester::CpuPort* port;
+ Request::Flags flags;
+ PacketPtr pkt;
+ Packet::Command cmd;
+
+ // For simplicity, requests are assumed to be 1 byte-sized
+ Request *req = new Request(m_address, 1, flags);
+
+ //
+ // Based on the current state, issue a load or a store
+ //
+ if (m_status == InvalidateGeneratorStatus_Load_Waiting) {
+ DPRINTF(DirectedTest, "initiating read\n");
+ cmd = MemCmd::ReadReq;
+ port = safe_cast<RubyDirectedTester::CpuPort*>(m_directed_tester->
+ getCpuPort(m_active_read_node));
+ pkt = new Packet(req, cmd, m_active_read_node);
+ } else if (m_status == InvalidateGeneratorStatus_Inv_Waiting) {
+ DPRINTF(DirectedTest, "initiating invalidating write\n");
+ cmd = MemCmd::WriteReq;
+ port = safe_cast<RubyDirectedTester::CpuPort*>(m_directed_tester->
+ getCpuPort(m_active_inv_node));
+ pkt = new Packet(req, cmd, m_active_inv_node);
+ } else {
+ panic("initiate was unexpectedly called\n");
+ }
+ uint8_t* dummyData = new uint8_t;
+ *dummyData = 0;
+ pkt->dataDynamic(dummyData);
+
+ if (port->sendTiming(pkt)) {
+ DPRINTF(DirectedTest, "initiating request - successful\n");
+ if (m_status == InvalidateGeneratorStatus_Load_Waiting) {
+ m_status = InvalidateGeneratorStatus_Load_Pending;
+ } else {
+ m_status = InvalidateGeneratorStatus_Inv_Pending;
+ }
+ return true;
+ } else {
+ // If the packet did not issue, must delete
+ // Note: No need to delete the data, the packet destructor
+ // will delete it
+ delete pkt->req;
+ delete pkt;
+
+ DPRINTF(DirectedTest, "failed to issue request - sequencer not ready\n");
+ return false;
+ }
+}
+
+void
+InvalidateGenerator::performCallback(uint proc, Addr address)
+{
+ assert(m_address == address);
+
+ if (m_status == InvalidateGeneratorStatus_Load_Pending) {
+ assert(m_active_read_node == proc);
+ m_active_read_node++;
+ //
+ // Once all cpus have the block in S state, issue the invalidate
+ //
+ if (m_active_read_node == m_num_cpus) {
+ m_status = InvalidateGeneratorStatus_Inv_Waiting;
+ m_active_read_node = 0;
+ } else {
+ m_status = InvalidateGeneratorStatus_Load_Waiting;
+ }
+ } else if (m_status == InvalidateGeneratorStatus_Inv_Pending) {
+ assert(m_active_inv_node == proc);
+ m_active_inv_node++;
+ if (m_active_inv_node == m_num_cpus) {
+ m_address += m_addr_increment_size;
+ m_active_inv_node = 0;
+ }
+ //
+ // Invalidate completed, send that info to the tester and restart
+ // the cycle
+ //
+ m_directed_tester->incrementCycleCompletions();
+ m_status = InvalidateGeneratorStatus_Load_Waiting;
+ }
+
+}
+
+InvalidateGenerator *
+InvalidateGeneratorParams::create()
+{
+ return new InvalidateGenerator(this);
+}
diff --git a/src/cpu/testers/directedtest/InvalidateGenerator.hh b/src/cpu/testers/directedtest/InvalidateGenerator.hh
new file mode 100644
index 000000000..ab68c859f
--- /dev/null
+++ b/src/cpu/testers/directedtest/InvalidateGenerator.hh
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+//
+// This Directed Generator generates GETX requests for all nodes in the
+// system. The GETX requests are generated one at a time in round-robin fashion
+// 0...1...2...etc.
+//
+
+#ifndef __CPU_DIRECTEDTEST_INVALIDATEGENERATOR_HH__
+#define __CPU_DIRECTEDTEST_INVALIDATEGENERATOR_HH__
+
+#include "cpu/testers/directedtest/RubyDirectedTester.hh"
+#include "cpu/testers/directedtest/DirectedGenerator.hh"
+#include "mem/protocol/InvalidateGeneratorStatus.hh"
+#include "params/InvalidateGenerator.hh"
+
+class InvalidateGenerator : public DirectedGenerator
+{
+ public:
+ typedef InvalidateGeneratorParams Params;
+ InvalidateGenerator(const Params *p);
+
+ ~InvalidateGenerator();
+
+ bool initiate();
+ void performCallback(uint proc, Addr address);
+
+ private:
+ InvalidateGeneratorStatus m_status;
+ Addr m_address;
+ uint m_active_read_node;
+ uint m_active_inv_node;
+ uint m_addr_increment_size;
+};
+
+#endif //__CPU_DIRECTEDTEST_INVALIDATEGENERATOR_HH__
+
diff --git a/src/cpu/testers/directedtest/RubyDirectedTester.cc b/src/cpu/testers/directedtest/RubyDirectedTester.cc
new file mode 100644
index 000000000..56352d14a
--- /dev/null
+++ b/src/cpu/testers/directedtest/RubyDirectedTester.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009-2010 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/testers/directedtest/DirectedGenerator.hh"
+#include "cpu/testers/directedtest/RubyDirectedTester.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "sim/sim_exit.hh"
+
+RubyDirectedTester::RubyDirectedTester(const Params *p)
+ : MemObject(p), directedStartEvent(this),
+ m_requests_to_complete(p->requests_to_complete),
+ generator(p->generator)
+{
+ m_requests_completed = 0;
+
+ // add the check start event to the event queue
+ schedule(directedStartEvent, 1);
+}
+
+RubyDirectedTester::~RubyDirectedTester()
+{
+ for (int i = 0; i < ports.size(); i++)
+ delete ports[i];
+}
+
+void
+RubyDirectedTester::init()
+{
+ assert(ports.size() > 0);
+ generator->setDirectedTester(this);
+}
+
+Port *
+RubyDirectedTester::getPort(const std::string &if_name, int idx)
+{
+ if (if_name != "cpuPort") {
+ panic("RubyDirectedTester::getPort: unknown port %s requested", if_name);
+ }
+
+ if (idx >= (int)ports.size()) {
+ ports.resize(idx + 1);
+ }
+
+ if (ports[idx] != NULL) {
+ panic("RubyDirectedTester::getPort: port %d already assigned", idx);
+ }
+
+ CpuPort *port = new CpuPort(csprintf("%s-port%d", name(), idx), this, idx);
+
+ ports[idx] = port;
+ return port;
+}
+
+Tick
+RubyDirectedTester::CpuPort::recvAtomic(PacketPtr pkt)
+{
+ panic("RubyDirectedTester::CpuPort::recvAtomic() not implemented!\n");
+ return 0;
+}
+
+bool
+RubyDirectedTester::CpuPort::recvTiming(PacketPtr pkt)
+{
+ tester->hitCallback(idx, pkt->getAddr());
+
+ //
+ // Now that the tester has completed, delete the packet, then return
+ //
+ delete pkt->req;
+ delete pkt;
+ return true;
+}
+
+Port*
+RubyDirectedTester::getCpuPort(int idx)
+{
+ assert(idx >= 0 && idx < ports.size());
+
+ return ports[idx];
+}
+
+void
+RubyDirectedTester::hitCallback(NodeID proc, Addr addr)
+{
+ DPRINTF(DirectedTest,
+ "completed request for proc: %d addr: 0x%x\n",
+ proc,
+ addr);
+
+ generator->performCallback(proc, addr);
+ schedule(directedStartEvent, curTick);
+}
+
+void
+RubyDirectedTester::wakeup()
+{
+ if (m_requests_completed < m_requests_to_complete) {
+ if (!generator->initiate()) {
+ schedule(directedStartEvent, curTick + 1);
+ }
+ } else {
+ exitSimLoop("Ruby DirectedTester completed");
+ }
+}
+
+RubyDirectedTester *
+RubyDirectedTesterParams::create()
+{
+ return new RubyDirectedTester(this);
+}
diff --git a/src/cpu/testers/directedtest/RubyDirectedTester.hh b/src/cpu/testers/directedtest/RubyDirectedTester.hh
new file mode 100644
index 000000000..bd3989c04
--- /dev/null
+++ b/src/cpu/testers/directedtest/RubyDirectedTester.hh
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009-2010 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 __CPU_DIRECTEDTEST_RUBYDIRECTEDTESTER_HH__
+#define __CPU_DIRECTEDTEST_RUBYDIRECTEDTESTER_HH__
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/ruby/common/DataBlock.hh"
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/system/RubyPort.hh"
+#include "params/RubyDirectedTester.hh"
+
+class DirectedGenerator;
+
+class RubyDirectedTester : public MemObject
+{
+ public:
+ class CpuPort : public SimpleTimingPort
+ {
+ private:
+ RubyDirectedTester *tester;
+
+ public:
+ CpuPort(const std::string &_name, RubyDirectedTester *_tester, uint _idx)
+ : SimpleTimingPort(_name, _tester), tester(_tester), idx(_idx)
+ {}
+
+ uint idx;
+
+ protected:
+ virtual bool recvTiming(PacketPtr pkt);
+ virtual Tick recvAtomic(PacketPtr pkt);
+ };
+
+ typedef RubyDirectedTesterParams Params;
+ RubyDirectedTester(const Params *p);
+ ~RubyDirectedTester();
+
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ Port* getCpuPort(int idx);
+
+ virtual void init();
+
+ void wakeup();
+
+ void incrementCycleCompletions() { m_requests_completed++; }
+
+ void printStats(std::ostream& out) const {}
+ void clearStats() {}
+ void printConfig(std::ostream& out) const {}
+
+ void print(std::ostream& out) const;
+
+ protected:
+ class DirectedStartEvent : public Event
+ {
+ private:
+ RubyDirectedTester *tester;
+
+ public:
+ DirectedStartEvent(RubyDirectedTester *_tester)
+ : Event(CPU_Tick_Pri), tester(_tester)
+ {}
+ void process() { tester->wakeup(); }
+ virtual const char *description() const { return "Directed tick"; }
+ };
+
+ DirectedStartEvent directedStartEvent;
+
+ private:
+ void hitCallback(NodeID proc, Addr addr);
+
+ void checkForDeadlock();
+
+ // Private copy constructor and assignment operator
+ RubyDirectedTester(const RubyDirectedTester& obj);
+ RubyDirectedTester& operator=(const RubyDirectedTester& obj);
+
+ uint64 m_requests_completed;
+ std::vector<CpuPort*> ports;
+ uint64 m_requests_to_complete;
+ DirectedGenerator* generator;
+};
+
+#endif // __CPU_DIRECTEDTEST_RUBYDIRECTEDTESTER_HH__
diff --git a/src/cpu/testers/directedtest/RubyDirectedTester.py b/src/cpu/testers/directedtest/RubyDirectedTester.py
new file mode 100644
index 000000000..af1970594
--- /dev/null
+++ b/src/cpu/testers/directedtest/RubyDirectedTester.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2010 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: Brad Beckmann
+
+from m5.SimObject import SimObject
+from MemObject import MemObject
+from m5.params import *
+from m5.proxy import *
+
+class DirectedGenerator(SimObject):
+ type = 'DirectedGenerator'
+ abstract = True
+ num_cpus = Param.Int("num of cpus")
+
+class SeriesRequestGenerator(DirectedGenerator):
+ type = 'SeriesRequestGenerator'
+ addr_increment_size = Param.Int(64, "address increment size")
+ issue_writes = Param.Bool(True, "issue writes if true, otherwise reads")
+
+class InvalidateGenerator(DirectedGenerator):
+ type = 'InvalidateGenerator'
+ addr_increment_size = Param.Int(64, "address increment size")
+
+class RubyDirectedTester(MemObject):
+ type = 'RubyDirectedTester'
+ cpuPort = VectorPort("the cpu ports")
+ requests_to_complete = Param.Int("checks to complete")
+ generator = Param.DirectedGenerator("the request generator")
diff --git a/src/cpu/testers/directedtest/SConscript b/src/cpu/testers/directedtest/SConscript
new file mode 100644
index 000000000..1afa15984
--- /dev/null
+++ b/src/cpu/testers/directedtest/SConscript
@@ -0,0 +1,48 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# Copyright (c) 2009-2010 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('RubyDirectedTester.py')
+
+Source('RubyDirectedTester.cc')
+Source('DirectedGenerator.cc')
+Source('SeriesRequestGenerator.cc')
+Source('InvalidateGenerator.cc')
+
+TraceFlag('DirectedTest')
diff --git a/src/cpu/testers/directedtest/SeriesRequestGenerator.cc b/src/cpu/testers/directedtest/SeriesRequestGenerator.cc
new file mode 100644
index 000000000..5b6395f93
--- /dev/null
+++ b/src/cpu/testers/directedtest/SeriesRequestGenerator.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009-2010 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/testers/directedtest/DirectedGenerator.hh"
+#include "cpu/testers/directedtest/RubyDirectedTester.hh"
+#include "cpu/testers/directedtest/SeriesRequestGenerator.hh"
+
+SeriesRequestGenerator::SeriesRequestGenerator(const Params *p)
+ : DirectedGenerator(p)
+{
+ m_status = SeriesRequestGeneratorStatus_Thinking;
+ m_active_node = 0;
+ m_address = 0x0;
+ m_addr_increment_size = p->addr_increment_size;
+ m_issue_writes = p->issue_writes;
+}
+
+SeriesRequestGenerator::~SeriesRequestGenerator()
+{
+}
+
+bool
+SeriesRequestGenerator::initiate()
+{
+ DPRINTF(DirectedTest, "initiating request\n");
+ assert(m_status == SeriesRequestGeneratorStatus_Thinking);
+
+ RubyDirectedTester::CpuPort* port =
+ safe_cast<RubyDirectedTester::CpuPort*>(m_directed_tester->
+ getCpuPort(m_active_node));
+
+ Request::Flags flags;
+
+ // For simplicity, requests are assumed to be 1 byte-sized
+ Request *req = new Request(m_address, 1, flags);
+
+ Packet::Command cmd;
+ if (m_issue_writes) {
+ cmd = MemCmd::WriteReq;
+ } else {
+ cmd = MemCmd::ReadReq;
+ }
+ PacketPtr pkt = new Packet(req, cmd, m_active_node);
+ uint8_t* dummyData = new uint8_t;
+ *dummyData = 0;
+ pkt->dataDynamic(dummyData);
+
+ if (port->sendTiming(pkt)) {
+ DPRINTF(DirectedTest, "initiating request - successful\n");
+ m_status = SeriesRequestGeneratorStatus_Request_Pending;
+ return true;
+ } else {
+ // If the packet did not issue, must delete
+ // Note: No need to delete the data, the packet destructor
+ // will delete it
+ delete pkt->req;
+ delete pkt;
+
+ DPRINTF(DirectedTest, "failed to initiate request - sequencer not ready\n");
+ return false;
+ }
+}
+
+void
+SeriesRequestGenerator::performCallback(uint proc, Addr address)
+{
+ assert(m_active_node == proc);
+ assert(m_address == address);
+ assert(m_status == SeriesRequestGeneratorStatus_Request_Pending);
+
+ m_status = SeriesRequestGeneratorStatus_Thinking;
+ m_active_node++;
+ if (m_active_node == m_num_cpus) {
+ //
+ // Cycle of requests completed, increment cycle completions and restart
+ // at cpu zero
+ //
+ m_directed_tester->incrementCycleCompletions();
+ m_address += m_addr_increment_size;
+ m_active_node = 0;
+ }
+}
+
+SeriesRequestGenerator *
+SeriesRequestGeneratorParams::create()
+{
+ return new SeriesRequestGenerator(this);
+}
diff --git a/src/cpu/testers/directedtest/SeriesRequestGenerator.hh b/src/cpu/testers/directedtest/SeriesRequestGenerator.hh
new file mode 100644
index 000000000..97b632a12
--- /dev/null
+++ b/src/cpu/testers/directedtest/SeriesRequestGenerator.hh
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+//
+// This Deterministic Generator generates GETX requests for all nodes in the
+// system. The GETX requests are generated one at a time in round-robin fashion
+// 0...1...2...etc.
+//
+
+#ifndef __CPU_DIRECTEDTEST_SERIESREQUESTGENERATOR_HH__
+#define __CPU_DIRECTEDTEST_SERIESREQUESTGENERATOR_HH__
+
+#include "cpu/testers/directedtest/DirectedGenerator.hh"
+#include "cpu/testers/directedtest/RubyDirectedTester.hh"
+#include "mem/protocol/SeriesRequestGeneratorStatus.hh"
+#include "params/SeriesRequestGenerator.hh"
+
+class SeriesRequestGenerator : public DirectedGenerator
+{
+ public:
+ typedef SeriesRequestGeneratorParams Params;
+ SeriesRequestGenerator(const Params *p);
+
+ ~SeriesRequestGenerator();
+
+ bool initiate();
+ void performCallback(uint proc, Addr address);
+
+ private:
+ SeriesRequestGeneratorStatus m_status;
+ Addr m_address;
+ uint m_active_node;
+ uint m_addr_increment_size;
+ bool m_issue_writes;
+};
+
+#endif //__CPU_DIRECTEDTEST_SERIESREQUESTGENERATOR_HH__
+
diff --git a/src/cpu/testers/memtest/MemTest.py b/src/cpu/testers/memtest/MemTest.py
new file mode 100644
index 000000000..957de8088
--- /dev/null
+++ b/src/cpu/testers/memtest/MemTest.py
@@ -0,0 +1,52 @@
+# 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.
+#
+# Authors: Nathan Binkert
+
+from MemObject import MemObject
+from m5.params import *
+from m5.proxy import *
+
+class MemTest(MemObject):
+ type = 'MemTest'
+ max_loads = Param.Counter(0, "number of loads to execute")
+ atomic = Param.Bool(False, "Execute tester in atomic mode? (or timing)\n")
+ memory_size = Param.Int(65536, "memory size")
+ percent_dest_unaligned = Param.Percent(50,
+ "percent of copy dest address that are unaligned")
+ percent_reads = Param.Percent(65, "target read percentage")
+ issue_dmas = Param.Bool(False, "this memtester should issue dma requests")
+ percent_source_unaligned = Param.Percent(50,
+ "percent of copy source address that are unaligned")
+ percent_functional = Param.Percent(50, "percent of access that are functional")
+ percent_uncacheable = Param.Percent(10,
+ "target uncacheable percentage")
+ progress_interval = Param.Counter(1000000,
+ "progress report interval (in accesses)")
+ trace_addr = Param.Addr(0, "address to trace")
+
+ test = Port("Port to the memory system to test")
+ functional = Port("Port to the functional memory used for verification")
diff --git a/src/cpu/testers/memtest/SConscript b/src/cpu/testers/memtest/SConscript
new file mode 100644
index 000000000..61aa0969e
--- /dev/null
+++ b/src/cpu/testers/memtest/SConscript
@@ -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.
+#
+# Authors: Nathan Binkert
+
+Import('*')
+
+#if 'O3CPU' in env['CPU_MODELS']:
+SimObject('MemTest.py')
+
+Source('memtest.cc')
+
+TraceFlag('MemTest')
diff --git a/src/cpu/testers/memtest/memtest.cc b/src/cpu/testers/memtest/memtest.cc
new file mode 100644
index 000000000..7a8e4cc52
--- /dev/null
+++ b/src/cpu/testers/memtest/memtest.cc
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2002-2005 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.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ */
+
+// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
+
+#include <iomanip>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "cpu/testers/memtest/memtest.hh"
+#include "mem/mem_object.hh"
+#include "mem/port.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+#include "sim/sim_events.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+
+int TESTER_ALLOCATOR=0;
+
+bool
+MemTest::CpuPort::recvTiming(PacketPtr pkt)
+{
+ if (pkt->isResponse()) {
+ memtest->completeRequest(pkt);
+ } else {
+ // must be snoop upcall
+ assert(pkt->isRequest());
+ assert(pkt->getDest() == Packet::Broadcast);
+ }
+ return true;
+}
+
+Tick
+MemTest::CpuPort::recvAtomic(PacketPtr pkt)
+{
+ // must be snoop upcall
+ assert(pkt->isRequest());
+ assert(pkt->getDest() == Packet::Broadcast);
+ return curTick;
+}
+
+void
+MemTest::CpuPort::recvFunctional(PacketPtr pkt)
+{
+ //Do nothing if we see one come through
+// if (curTick != 0)//Supress warning durring initialization
+// warn("Functional Writes not implemented in MemTester\n");
+ //Need to find any response values that intersect and update
+ return;
+}
+
+void
+MemTest::CpuPort::recvStatusChange(Status status)
+{
+ if (status == RangeChange) {
+ if (!snoopRangeSent) {
+ snoopRangeSent = true;
+ sendStatusChange(Port::RangeChange);
+ }
+ return;
+ }
+
+ panic("MemTest doesn't expect recvStatusChange callback!");
+}
+
+void
+MemTest::CpuPort::recvRetry()
+{
+ memtest->doRetry();
+}
+
+void
+MemTest::sendPkt(PacketPtr pkt) {
+ if (atomic) {
+ cachePort.sendAtomic(pkt);
+ completeRequest(pkt);
+ }
+ else if (!cachePort.sendTiming(pkt)) {
+ DPRINTF(MemTest, "accessRetry setting to true\n");
+
+ //
+ // dma requests should never be retried
+ //
+ if (issueDmas) {
+ panic("Nacked DMA requests are not supported\n");
+ }
+ accessRetry = true;
+ retryPkt = pkt;
+ } else {
+ if (issueDmas) {
+ dmaOutstanding = true;
+ }
+ }
+
+}
+
+MemTest::MemTest(const Params *p)
+ : MemObject(p),
+ tickEvent(this),
+ cachePort("test", this),
+ funcPort("functional", this),
+ retryPkt(NULL),
+// mainMem(main_mem),
+// checkMem(check_mem),
+ size(p->memory_size),
+ percentReads(p->percent_reads),
+ percentFunctional(p->percent_functional),
+ percentUncacheable(p->percent_uncacheable),
+ issueDmas(p->issue_dmas),
+ progressInterval(p->progress_interval),
+ nextProgressMessage(p->progress_interval),
+ percentSourceUnaligned(p->percent_source_unaligned),
+ percentDestUnaligned(p->percent_dest_unaligned),
+ maxLoads(p->max_loads),
+ atomic(p->atomic)
+{
+
+ vector<string> cmd;
+ cmd.push_back("/bin/ls");
+ vector<string> null_vec;
+ // thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);
+ curTick = 0;
+
+ cachePort.snoopRangeSent = false;
+ funcPort.snoopRangeSent = true;
+
+ id = TESTER_ALLOCATOR++;
+
+ // Needs to be masked off once we know the block size.
+ traceBlockAddr = p->trace_addr;
+ baseAddr1 = 0x100000;
+ baseAddr2 = 0x400000;
+ uncacheAddr = 0x800000;
+
+ // set up counters
+ noResponseCycles = 0;
+ numReads = 0;
+ schedule(tickEvent, 0);
+
+ accessRetry = false;
+ dmaOutstanding = false;
+}
+
+Port *
+MemTest::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "functional")
+ return &funcPort;
+ else if (if_name == "test")
+ return &cachePort;
+ else
+ panic("No Such Port\n");
+}
+
+void
+MemTest::init()
+{
+ // By the time init() is called, the ports should be hooked up.
+ blockSize = cachePort.peerBlockSize();
+ blockAddrMask = blockSize - 1;
+ traceBlockAddr = blockAddr(traceBlockAddr);
+
+ // initial memory contents for both physical memory and functional
+ // memory should be 0; no need to initialize them.
+}
+
+
+void
+MemTest::completeRequest(PacketPtr pkt)
+{
+ Request *req = pkt->req;
+
+ if (issueDmas) {
+ dmaOutstanding = false;
+ }
+
+ DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",
+ pkt->isWrite() ? "write" : "read",
+ req->getPaddr(), blockAddr(req->getPaddr()));
+
+ MemTestSenderState *state =
+ dynamic_cast<MemTestSenderState *>(pkt->senderState);
+
+ uint8_t *data = state->data;
+ uint8_t *pkt_data = pkt->getPtr<uint8_t>();
+
+ //Remove the address from the list of outstanding
+ std::set<unsigned>::iterator removeAddr =
+ outstandingAddrs.find(req->getPaddr());
+ assert(removeAddr != outstandingAddrs.end());
+ outstandingAddrs.erase(removeAddr);
+
+ assert(pkt->isResponse());
+
+ if (pkt->isRead()) {
+ if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
+ panic("%s: read of %x (blk %x) @ cycle %d "
+ "returns %x, expected %x\n", name(),
+ req->getPaddr(), blockAddr(req->getPaddr()), curTick,
+ *pkt_data, *data);
+ }
+
+ numReads++;
+ numReadsStat++;
+
+ if (numReads == (uint64_t)nextProgressMessage) {
+ ccprintf(cerr, "%s: completed %d read accesses @%d\n",
+ name(), numReads, curTick);
+ nextProgressMessage += progressInterval;
+ }
+
+ if (maxLoads != 0 && numReads >= maxLoads)
+ exitSimLoop("maximum number of loads reached");
+ } else {
+ assert(pkt->isWrite());
+ numWritesStat++;
+ }
+
+ noResponseCycles = 0;
+ delete state;
+ delete [] data;
+ delete pkt->req;
+ delete pkt;
+}
+
+void
+MemTest::regStats()
+{
+ using namespace Stats;
+
+ numReadsStat
+ .name(name() + ".num_reads")
+ .desc("number of read accesses completed")
+ ;
+
+ numWritesStat
+ .name(name() + ".num_writes")
+ .desc("number of write accesses completed")
+ ;
+
+ numCopiesStat
+ .name(name() + ".num_copies")
+ .desc("number of copy accesses completed")
+ ;
+}
+
+void
+MemTest::tick()
+{
+ if (!tickEvent.scheduled())
+ schedule(tickEvent, curTick + ticks(1));
+
+ if (++noResponseCycles >= 500000) {
+ if (issueDmas) {
+ cerr << "DMA tester ";
+ }
+ cerr << name() << ": deadlocked at cycle " << curTick << endl;
+ fatal("");
+ }
+
+ if (accessRetry || (issueDmas && dmaOutstanding)) {
+ DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n");
+ return;
+ }
+
+ //make new request
+ unsigned cmd = random() % 100;
+ unsigned offset = random() % size;
+ unsigned base = random() % 2;
+ uint64_t data = random();
+ unsigned access_size = random() % 4;
+ bool uncacheable = (random() % 100) < percentUncacheable;
+
+ unsigned dma_access_size = random() % 4;
+
+ //If we aren't doing copies, use id as offset, and do a false sharing
+ //mem tester
+ //We can eliminate the lower bits of the offset, and then use the id
+ //to offset within the blks
+ offset = blockAddr(offset);
+ offset += id;
+ access_size = 0;
+ dma_access_size = 0;
+
+ Request *req = new Request();
+ Request::Flags flags;
+ Addr paddr;
+
+ if (uncacheable) {
+ flags.set(Request::UNCACHEABLE);
+ paddr = uncacheAddr + offset;
+ } else {
+ paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
+ }
+ bool probe = (random() % 100 < percentFunctional) && !uncacheable;
+
+ if (issueDmas) {
+ paddr &= ~((1 << dma_access_size) - 1);
+ req->setPhys(paddr, 1 << dma_access_size, flags);
+ req->setThreadContext(id,0);
+ } else {
+ paddr &= ~((1 << access_size) - 1);
+ req->setPhys(paddr, 1 << access_size, flags);
+ req->setThreadContext(id,0);
+ }
+ assert(req->getSize() == 1);
+
+ uint8_t *result = new uint8_t[8];
+
+ if (cmd < percentReads) {
+ // read
+
+ // For now we only allow one outstanding request per address
+ // per tester This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
+ if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
+ delete [] result;
+ delete req;
+ return;
+ }
+
+ outstandingAddrs.insert(paddr);
+
+ // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
+ funcPort.readBlob(req->getPaddr(), result, req->getSize());
+
+ DPRINTF(MemTest,
+ "id %d initiating read at address %x (blk %x) expecting %x\n",
+ id, req->getPaddr(), blockAddr(req->getPaddr()), *result);
+
+ PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+ pkt->setSrc(0);
+ pkt->dataDynamicArray(new uint8_t[req->getSize()]);
+ MemTestSenderState *state = new MemTestSenderState(result);
+ pkt->senderState = state;
+
+ if (probe) {
+ cachePort.sendFunctional(pkt);
+ completeRequest(pkt);
+ } else {
+ sendPkt(pkt);
+ }
+ } else {
+ // write
+
+ // For now we only allow one outstanding request per addreess
+ // per tester. This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
+ if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
+ delete [] result;
+ delete req;
+ return;
+ }
+
+ outstandingAddrs.insert(paddr);
+
+ DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n",
+ req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff);
+
+ PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
+ pkt->setSrc(0);
+ uint8_t *pkt_data = new uint8_t[req->getSize()];
+ pkt->dataDynamicArray(pkt_data);
+ memcpy(pkt_data, &data, req->getSize());
+ MemTestSenderState *state = new MemTestSenderState(result);
+ pkt->senderState = state;
+
+ funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
+
+ if (probe) {
+ cachePort.sendFunctional(pkt);
+ completeRequest(pkt);
+ } else {
+ sendPkt(pkt);
+ }
+ }
+}
+
+void
+MemTest::doRetry()
+{
+ if (cachePort.sendTiming(retryPkt)) {
+ DPRINTF(MemTest, "accessRetry setting to false\n");
+ accessRetry = false;
+ retryPkt = NULL;
+ }
+}
+
+
+void
+MemTest::printAddr(Addr a)
+{
+ cachePort.printAddr(a);
+}
+
+
+MemTest *
+MemTestParams::create()
+{
+ return new MemTest(this);
+}
diff --git a/src/cpu/testers/memtest/memtest.hh b/src/cpu/testers/memtest/memtest.hh
new file mode 100644
index 000000000..bb71da355
--- /dev/null
+++ b/src/cpu/testers/memtest/memtest.hh
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2002-2005 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.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ */
+
+#ifndef __CPU_MEMTEST_MEMTEST_HH__
+#define __CPU_MEMTEST_MEMTEST_HH__
+
+#include <set>
+
+#include "base/statistics.hh"
+#include "base/fast_alloc.hh"
+#include "params/MemTest.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+#include "mem/mem_object.hh"
+#include "mem/port.hh"
+
+class Packet;
+class MemTest : public MemObject
+{
+ public:
+ typedef MemTestParams Params;
+ MemTest(const Params *p);
+
+ virtual void init();
+
+ // register statistics
+ virtual void regStats();
+
+ inline Tick ticks(int numCycles) const { return numCycles; }
+
+ // main simulation loop (one cycle)
+ void tick();
+
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ /**
+ * Print state of address in memory system via PrintReq (for
+ * debugging).
+ */
+ void printAddr(Addr a);
+
+ protected:
+ class TickEvent : public Event
+ {
+ private:
+ MemTest *cpu;
+
+ public:
+ TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {}
+ void process() { cpu->tick(); }
+ virtual const char *description() const { return "MemTest tick"; }
+ };
+
+ TickEvent tickEvent;
+
+ class CpuPort : public Port
+ {
+ MemTest *memtest;
+
+ public:
+
+ CpuPort(const std::string &_name, MemTest *_memtest)
+ : Port(_name, _memtest), memtest(_memtest)
+ { }
+
+ bool snoopRangeSent;
+
+ protected:
+
+ virtual bool recvTiming(PacketPtr pkt);
+
+ virtual Tick recvAtomic(PacketPtr pkt);
+
+ virtual void recvFunctional(PacketPtr pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void recvRetry();
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ bool &snoop)
+ { resp.clear(); snoop = false; }
+ };
+
+ CpuPort cachePort;
+ CpuPort funcPort;
+
+ bool snoopRangeSent;
+
+ class MemTestSenderState : public Packet::SenderState, public FastAlloc
+ {
+ public:
+ /** Constructor. */
+ MemTestSenderState(uint8_t *_data)
+ : data(_data)
+ { }
+
+ // Hold onto data pointer
+ uint8_t *data;
+ };
+
+ PacketPtr retryPkt;
+
+ bool accessRetry;
+
+ //
+ // The dmaOustanding flag enforces only one dma at a time
+ //
+ bool dmaOutstanding;
+
+ unsigned size; // size of testing memory region
+
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentFunctional; // target percentage of functional accesses
+ unsigned percentUncacheable;
+
+ bool issueDmas;
+
+ int id;
+
+ std::set<unsigned> outstandingAddrs;
+
+ unsigned blockSize;
+
+ Addr blockAddrMask;
+
+ Addr blockAddr(Addr addr)
+ {
+ return (addr & ~blockAddrMask);
+ }
+
+ Addr traceBlockAddr;
+
+ Addr baseAddr1; // fix this to option
+ Addr baseAddr2; // fix this to option
+ Addr uncacheAddr;
+
+ unsigned progressInterval; // frequency of progress reports
+ Tick nextProgressMessage; // access # for next progress report
+
+ unsigned percentSourceUnaligned;
+ unsigned percentDestUnaligned;
+
+ Tick noResponseCycles;
+
+ uint64_t numReads;
+ uint64_t maxLoads;
+
+ bool atomic;
+
+ Stats::Scalar numReadsStat;
+ Stats::Scalar numWritesStat;
+ Stats::Scalar numCopiesStat;
+
+ // called by MemCompleteEvent::process()
+ void completeRequest(PacketPtr pkt);
+
+ void sendPkt(PacketPtr pkt);
+
+ void doRetry();
+
+ friend class MemCompleteEvent;
+};
+
+#endif // __CPU_MEMTEST_MEMTEST_HH__
+
+
+
diff --git a/src/cpu/testers/rubytest/Check.cc b/src/cpu/testers/rubytest/Check.cc
new file mode 100644
index 000000000..9ace655a8
--- /dev/null
+++ b/src/cpu/testers/rubytest/Check.cc
@@ -0,0 +1,356 @@
+/*
+ * 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/testers/rubytest/Check.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/system/Sequencer.hh"
+#include "mem/ruby/system/System.hh"
+
+typedef RubyTester::SenderState SenderState;
+
+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");
+
+ int index = random() % m_num_cpu_sequencers;
+ RubyTester::CpuPort* port =
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+
+ Request::Flags flags;
+ flags.set(Request::PREFETCH);
+
+ 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);
+ }
+
+ // Prefetches are assumed to be 0 sized
+ Request *req = new Request(m_address.getAddress(), 0, flags, curTick,
+ m_pc.getAddress());
+
+ 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 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
+ SenderState* senderState = safe_cast<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);
+
+ int index = random() % m_num_cpu_sequencers;
+ RubyTester::CpuPort* port =
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+
+ 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 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
+ SenderState* senderState = safe_cast<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);
+
+ int index = random() % m_num_cpu_sequencers;
+ RubyTester::CpuPort* port =
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+
+ Request::Flags flags;
+
+ // 50% chance that the request will be an instruction fetch
+ if ((random() & 0x1) == 0) {
+ flags.set(Request::INST_FETCH);
+ }
+
+ // Checks are sized depending on the number of bytes written
+ Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags,
+ curTick, m_pc.getAddress());
+
+ 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 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
+ SenderState* senderState = safe_cast<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();
+
+ // This isn't exactly right since we now have multi-byte checks
+ // assert(getAddress() == address);
+
+ 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(std::ostream& out) const
+{
+ out << "["
+ << m_address << ", value: "
+ << (int)m_value << ", status: "
+ << m_status << ", initiating node: "
+ << m_initiatingNode << ", store_count: "
+ << m_store_count
+ << "]" << std::flush;
+}
+
+void
+Check::debugPrint()
+{
+ DPRINTF(RubyTest,
+ "[%#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/testers/rubytest/Check.hh b/src/cpu/testers/rubytest/Check.hh
new file mode 100644
index 000000000..1ce795a21
--- /dev/null
+++ b/src/cpu/testers/rubytest/Check.hh
@@ -0,0 +1,89 @@
+/*
+ * 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 __CPU_RUBYTEST_CHECK_HH__
+#define __CPU_RUBYTEST_CHECK_HH__
+
+#include <iostream>
+
+#include "cpu/testers/rubytest/RubyTester.hh"
+#include "mem/protocol/AccessModeType.hh"
+#include "mem/protocol/TesterStatus.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/system/NodeID.hh"
+
+class SubBlock;
+
+const int CHECK_SIZE_BITS = 2;
+const int CHECK_SIZE = (1 << CHECK_SIZE_BITS);
+
+class Check
+{
+ public:
+ Check(const Address& address, const Address& pc, int _num_cpu_sequencer,
+ RubyTester* _tester);
+
+ 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(std::ostream& out) const;
+
+ private:
+ void initiatePrefetch();
+ void initiateAction();
+ void initiateCheck();
+
+ void pickValue();
+ void pickInitiatingNode();
+
+ void debugPrint();
+
+ 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;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const Check& obj)
+{
+ obj.print(out);
+ out << std::flush;
+ return out;
+}
+
+#endif // __CPU_RUBYTEST_CHECK_HH__
diff --git a/src/cpu/testers/rubytest/CheckTable.cc b/src/cpu/testers/rubytest/CheckTable.cc
new file mode 100644
index 000000000..728ad0303
--- /dev/null
+++ b/src/cpu/testers/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 "base/intmath.hh"
+#include "cpu/testers/rubytest/Check.hh"
+#include "cpu/testers/rubytest/CheckTable.hh"
+#include "cpu/testers/rubytest/CheckTable.hh"
+
+CheckTable::CheckTable(int _num_cpu_sequencers, RubyTester* _tester)
+ : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
+{
+ 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];
+}
+
+void
+CheckTable::addCheck(const Address& address)
+{
+ if (floorLog2(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.count(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[Address(address.getAddress() + i)] = check_ptr;
+ }
+ m_check_vector.push_back(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);
+
+ m5::hash_map<Address, Check*>::iterator i = m_lookup_map.find(address);
+
+ if (i == m_lookup_map.end())
+ return NULL;
+
+ Check* check = i->second;
+ assert(check != NULL);
+ return check;
+}
+
+void
+CheckTable::print(std::ostream& out) const
+{
+}
diff --git a/src/cpu/testers/rubytest/CheckTable.hh b/src/cpu/testers/rubytest/CheckTable.hh
new file mode 100644
index 000000000..5a4ead337
--- /dev/null
+++ b/src/cpu/testers/rubytest/CheckTable.hh
@@ -0,0 +1,81 @@
+/*
+ * 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 __CPU_RUBYTEST_CHECKTABLE_HH__
+#define __CPU_RUBYTEST_CHECKTABLE_HH__
+
+#include <iostream>
+#include <vector>
+
+#include "base/hashmap.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/common/Global.hh"
+
+class Check;
+class RubyTester;
+
+class CheckTable
+{
+ public:
+ CheckTable(int _num_cpu_sequencers, RubyTester* _tester);
+ ~CheckTable();
+
+ 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(std::ostream& out) const;
+
+ private:
+ void addCheck(const Address& address);
+
+ // Private copy constructor and assignment operator
+ CheckTable(const CheckTable& obj);
+ CheckTable& operator=(const CheckTable& obj);
+
+ std::vector<Check*> m_check_vector;
+ m5::hash_map<Address, Check*> m_lookup_map;
+
+ int m_num_cpu_sequencers;
+ RubyTester* m_tester_ptr;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const CheckTable& obj)
+{
+ obj.print(out);
+ out << std::flush;
+ return out;
+}
+
+#endif // __CPU_RUBYTEST_CHECKTABLE_HH__
diff --git a/src/cpu/testers/rubytest/RubyTester.cc b/src/cpu/testers/rubytest/RubyTester.cc
new file mode 100644
index 000000000..516d6ae40
--- /dev/null
+++ b/src/cpu/testers/rubytest/RubyTester.cc
@@ -0,0 +1,195 @@
+/*
+ * 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/testers/rubytest/Check.hh"
+#include "cpu/testers/rubytest/RubyTester.hh"
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/system/System.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.resize(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(std::ostream& out) const
+{
+ out << "[RubyTester]" << std::endl;
+}
+
+RubyTester *
+RubyTesterParams::create()
+{
+ return new RubyTester(this);
+}
diff --git a/src/cpu/testers/rubytest/RubyTester.hh b/src/cpu/testers/rubytest/RubyTester.hh
new file mode 100644
index 000000000..53341bce9
--- /dev/null
+++ b/src/cpu/testers/rubytest/RubyTester.hh
@@ -0,0 +1,148 @@
+/*
+ * 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 __CPU_RUBYTEST_RUBYTESTER_HH__
+#define __CPU_RUBYTEST_RUBYTESTER_HH__
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "cpu/testers/rubytest/CheckTable.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/ruby/common/DataBlock.hh"
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/system/RubyPort.hh"
+#include "params/RubyTester.hh"
+
+class RubyTester : public MemObject
+{
+ public:
+ class CpuPort : public SimpleTimingPort
+ {
+ private:
+ 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;
+ RubyTester(const Params *p);
+ ~RubyTester();
+
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ Port* getCpuPort(int idx);
+
+ virtual void init();
+
+ void wakeup();
+
+ void incrementCheckCompletions() { m_checks_completed++; }
+
+ void printStats(std::ostream& out) const {}
+ void clearStats() {}
+ void printConfig(std::ostream& out) const {}
+
+ void print(std::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:
+ void hitCallback(NodeID proc, SubBlock* data);
+
+ void checkForDeadlock();
+
+ // Private copy constructor and assignment operator
+ RubyTester(const RubyTester& obj);
+ RubyTester& operator=(const RubyTester& obj);
+
+ CheckTable* m_checkTable_ptr;
+ std::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;
+};
+
+inline std::ostream&
+operator<<(std::ostream& out, const RubyTester& obj)
+{
+ obj.print(out);
+ out << std::flush;
+ return out;
+}
+
+#endif // __CPU_RUBYTEST_RUBYTESTER_HH__
diff --git a/src/cpu/testers/rubytest/RubyTester.py b/src/cpu/testers/rubytest/RubyTester.py
new file mode 100644
index 000000000..af37d2ff1
--- /dev/null
+++ b/src/cpu/testers/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/testers/rubytest/SConscript b/src/cpu/testers/rubytest/SConscript
new file mode 100644
index 000000000..9352dd793
--- /dev/null
+++ b/src/cpu/testers/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')