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