From e983ef9e8c6749c1cd0bf083a2092cb4683d0346 Mon Sep 17 00:00:00 2001 From: Brad Beckmann Date: Tue, 24 Aug 2010 12:07:22 -0700 Subject: 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 --- src/cpu/testers/directedtest/DirectedGenerator.cc | 44 +++ src/cpu/testers/directedtest/DirectedGenerator.hh | 56 +++ .../testers/directedtest/InvalidateGenerator.cc | 142 +++++++ .../testers/directedtest/InvalidateGenerator.hh | 63 +++ src/cpu/testers/directedtest/RubyDirectedTester.cc | 136 +++++++ src/cpu/testers/directedtest/RubyDirectedTester.hh | 118 ++++++ src/cpu/testers/directedtest/RubyDirectedTester.py | 52 +++ src/cpu/testers/directedtest/SConscript | 48 +++ .../testers/directedtest/SeriesRequestGenerator.cc | 114 ++++++ .../testers/directedtest/SeriesRequestGenerator.hh | 63 +++ src/cpu/testers/memtest/MemTest.py | 52 +++ src/cpu/testers/memtest/SConscript | 38 ++ src/cpu/testers/memtest/memtest.cc | 434 +++++++++++++++++++++ src/cpu/testers/memtest/memtest.hh | 198 ++++++++++ src/cpu/testers/rubytest/Check.cc | 356 +++++++++++++++++ src/cpu/testers/rubytest/Check.hh | 89 +++++ src/cpu/testers/rubytest/CheckTable.cc | 130 ++++++ src/cpu/testers/rubytest/CheckTable.hh | 81 ++++ src/cpu/testers/rubytest/RubyTester.cc | 195 +++++++++ src/cpu/testers/rubytest/RubyTester.hh | 148 +++++++ src/cpu/testers/rubytest/RubyTester.py | 38 ++ src/cpu/testers/rubytest/SConscript | 47 +++ 22 files changed, 2642 insertions(+) create mode 100644 src/cpu/testers/directedtest/DirectedGenerator.cc create mode 100644 src/cpu/testers/directedtest/DirectedGenerator.hh create mode 100644 src/cpu/testers/directedtest/InvalidateGenerator.cc create mode 100644 src/cpu/testers/directedtest/InvalidateGenerator.hh create mode 100644 src/cpu/testers/directedtest/RubyDirectedTester.cc create mode 100644 src/cpu/testers/directedtest/RubyDirectedTester.hh create mode 100644 src/cpu/testers/directedtest/RubyDirectedTester.py create mode 100644 src/cpu/testers/directedtest/SConscript create mode 100644 src/cpu/testers/directedtest/SeriesRequestGenerator.cc create mode 100644 src/cpu/testers/directedtest/SeriesRequestGenerator.hh create mode 100644 src/cpu/testers/memtest/MemTest.py create mode 100644 src/cpu/testers/memtest/SConscript create mode 100644 src/cpu/testers/memtest/memtest.cc create mode 100644 src/cpu/testers/memtest/memtest.hh create mode 100644 src/cpu/testers/rubytest/Check.cc create mode 100644 src/cpu/testers/rubytest/Check.hh create mode 100644 src/cpu/testers/rubytest/CheckTable.cc create mode 100644 src/cpu/testers/rubytest/CheckTable.hh create mode 100644 src/cpu/testers/rubytest/RubyTester.cc create mode 100644 src/cpu/testers/rubytest/RubyTester.hh create mode 100644 src/cpu/testers/rubytest/RubyTester.py create mode 100644 src/cpu/testers/rubytest/SConscript (limited to 'src/cpu/testers') 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(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(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 +#include +#include + +#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 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(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 +#include +#include +#include + +#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 cmd; + cmd.push_back("/bin/ls"); + vector 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(pkt->senderState); + + uint8_t *data = state->data; + uint8_t *pkt_data = pkt->getPtr(); + + //Remove the address from the list of outstanding + std::set::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 + +#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 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(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(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(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()), *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(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(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(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_numbergetByte(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 + +#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::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 +#include + +#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 m_check_vector; + m5::hash_map 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(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 +#include +#include + +#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