diff options
author | Brad Beckmann <Brad.Beckmann@amd.com> | 2010-08-24 12:07:22 -0700 |
---|---|---|
committer | Brad Beckmann <Brad.Beckmann@amd.com> | 2010-08-24 12:07:22 -0700 |
commit | e983ef9e8c6749c1cd0bf083a2092cb4683d0346 (patch) | |
tree | 02d262e1b84e5c4675df54cb27678526f756169b /src/cpu/testers/rubytest/Check.cc | |
parent | 20b2f0ce9f09bc4166bc3ee001eab4d6b2b84a04 (diff) | |
download | gem5-e983ef9e8c6749c1cd0bf083a2092cb4683d0346.tar.xz |
testers: move testers to a new directory
This patch moves the testers to a new subdirectory under src/cpu and includes
the necessary fixes to work with latest m5 initialization patches.
--HG--
rename : configs/example/determ_test.py => configs/example/ruby_direct_test.py
rename : src/cpu/directedtest/DirectedGenerator.cc => src/cpu/testers/directedtest/DirectedGenerator.cc
rename : src/cpu/directedtest/DirectedGenerator.hh => src/cpu/testers/directedtest/DirectedGenerator.hh
rename : src/cpu/directedtest/InvalidateGenerator.cc => src/cpu/testers/directedtest/InvalidateGenerator.cc
rename : src/cpu/directedtest/InvalidateGenerator.hh => src/cpu/testers/directedtest/InvalidateGenerator.hh
rename : src/cpu/directedtest/RubyDirectedTester.cc => src/cpu/testers/directedtest/RubyDirectedTester.cc
rename : src/cpu/directedtest/RubyDirectedTester.hh => src/cpu/testers/directedtest/RubyDirectedTester.hh
rename : src/cpu/directedtest/RubyDirectedTester.py => src/cpu/testers/directedtest/RubyDirectedTester.py
rename : src/cpu/directedtest/SConscript => src/cpu/testers/directedtest/SConscript
rename : src/cpu/directedtest/SeriesRequestGenerator.cc => src/cpu/testers/directedtest/SeriesRequestGenerator.cc
rename : src/cpu/directedtest/SeriesRequestGenerator.hh => src/cpu/testers/directedtest/SeriesRequestGenerator.hh
rename : src/cpu/memtest/MemTest.py => src/cpu/testers/memtest/MemTest.py
rename : src/cpu/memtest/SConscript => src/cpu/testers/memtest/SConscript
rename : src/cpu/memtest/memtest.cc => src/cpu/testers/memtest/memtest.cc
rename : src/cpu/memtest/memtest.hh => src/cpu/testers/memtest/memtest.hh
rename : src/cpu/rubytest/Check.cc => src/cpu/testers/rubytest/Check.cc
rename : src/cpu/rubytest/Check.hh => src/cpu/testers/rubytest/Check.hh
rename : src/cpu/rubytest/CheckTable.cc => src/cpu/testers/rubytest/CheckTable.cc
rename : src/cpu/rubytest/CheckTable.hh => src/cpu/testers/rubytest/CheckTable.hh
rename : src/cpu/rubytest/RubyTester.cc => src/cpu/testers/rubytest/RubyTester.cc
rename : src/cpu/rubytest/RubyTester.hh => src/cpu/testers/rubytest/RubyTester.hh
rename : src/cpu/rubytest/RubyTester.py => src/cpu/testers/rubytest/RubyTester.py
rename : src/cpu/rubytest/SConscript => src/cpu/testers/rubytest/SConscript
Diffstat (limited to 'src/cpu/testers/rubytest/Check.cc')
-rw-r--r-- | src/cpu/testers/rubytest/Check.cc | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/cpu/testers/rubytest/Check.cc b/src/cpu/testers/rubytest/Check.cc new file mode 100644 index 000000000..9ace655a8 --- /dev/null +++ b/src/cpu/testers/rubytest/Check.cc @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/testers/rubytest/Check.hh" +#include "mem/ruby/common/SubBlock.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/system/System.hh" + +typedef RubyTester::SenderState SenderState; + +Check::Check(const Address& address, const Address& pc, + int _num_cpu_sequencers, RubyTester* _tester) + : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester) +{ + m_status = TesterStatus_Idle; + + pickValue(); + pickInitiatingNode(); + changeAddress(address); + m_pc = pc; + m_access_mode = AccessModeType(random() % AccessModeType_NUM); + m_store_count = 0; +} + +void +Check::initiate() +{ + DPRINTF(RubyTest, "initiating\n"); + debugPrint(); + + // currently no protocols support prefetches + if (false && (random() & 0xf) == 0) { + initiatePrefetch(); // Prefetch from random processor + } + + if (m_status == TesterStatus_Idle) { + initiateAction(); + } else if (m_status == TesterStatus_Ready) { + initiateCheck(); + } else { + // Pending - do nothing + DPRINTF(RubyTest, + "initiating action/check - failed: action/check is pending\n"); + } +} + +void +Check::initiatePrefetch() +{ + DPRINTF(RubyTest, "initiating prefetch\n"); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + flags.set(Request::PREFETCH); + + Packet::Command cmd; + + // 1 in 8 chance this will be an exclusive prefetch + if ((random() & 0x7) != 0) { + cmd = MemCmd::ReadReq; + + // 50% chance that the request will be an instruction fetch + if ((random() & 0x1) == 0) { + flags.set(Request::INST_FETCH); + } + } else { + cmd = MemCmd::WriteReq; + flags.set(Request::PF_EXCLUSIVE); + } + + // Prefetches are assumed to be 0 sized + Request *req = new Request(m_address.getAddress(), 0, flags, curTick, + m_pc.getAddress()); + + PacketPtr pkt = new Packet(req, cmd, port->idx); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(m_address, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "successfully initiated prefetch.\n"); + } else { + // If the packet did not issue, must delete + SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, + "prefetch initiation failed because Port was busy.\n"); + } +} + +void +Check::initiateAction() +{ + DPRINTF(RubyTest, "initiating Action\n"); + assert(m_status == TesterStatus_Idle); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + + // Create the particular address for the next byte to be written + Address writeAddr(m_address.getAddress() + m_store_count); + + // Stores are assumed to be 1 byte-sized + Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick, + m_pc.getAddress()); + + Packet::Command cmd; + + // 1 out of 8 chance, issue an atomic rather than a write + // if ((random() & 0x7) == 0) { + // cmd = MemCmd::SwapReq; + // } else { + cmd = MemCmd::WriteReq; + // } + + PacketPtr pkt = new Packet(req, cmd, port->idx); + uint8_t* writeData = new uint8_t; + *writeData = m_value + m_store_count; + pkt->dataDynamic(writeData); + + DPRINTF(RubyTest, "data 0x%x check 0x%x\n", + *(pkt->getPtr<uint8_t>()), *writeData); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(writeAddr, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "initiating action - successful\n"); + DPRINTF(RubyTest, "status before action update: %s\n", + (TesterStatus_to_string(m_status)).c_str()); + m_status = TesterStatus_Action_Pending; + } else { + // If the packet did not issue, must delete + // Note: No need to delete the data, the packet destructor + // will delete it + SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); + } + + DPRINTF(RubyTest, "status after action update: %s\n", + (TesterStatus_to_string(m_status)).c_str()); +} + +void +Check::initiateCheck() +{ + DPRINTF(RubyTest, "Initiating Check\n"); + assert(m_status == TesterStatus_Ready); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + + // 50% chance that the request will be an instruction fetch + if ((random() & 0x1) == 0) { + flags.set(Request::INST_FETCH); + } + + // Checks are sized depending on the number of bytes written + Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, + curTick, m_pc.getAddress()); + + PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx); + uint8_t* dataArray = new uint8_t[CHECK_SIZE]; + pkt->dataDynamicArray(dataArray); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(m_address, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "initiating check - successful\n"); + DPRINTF(RubyTest, "status before check update: %s\n", + TesterStatus_to_string(m_status).c_str()); + m_status = TesterStatus_Check_Pending; + } else { + // If the packet did not issue, must delete + // Note: No need to delete the data, the packet destructor + // will delete it + SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); + } + + DPRINTF(RubyTest, "status after check update: %s\n", + TesterStatus_to_string(m_status).c_str()); +} + +void +Check::performCallback(NodeID proc, SubBlock* data) +{ + Address address = data->getAddress(); + + // This isn't exactly right since we now have multi-byte checks + // assert(getAddress() == address); + + assert(getAddress().getLineAddress() == address.getLineAddress()); + assert(data != NULL); + + DPRINTF(RubyTest, "RubyTester Callback\n"); + debugPrint(); + + if (m_status == TesterStatus_Action_Pending) { + DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n", + (m_value + m_store_count), data->getByte(0)); + // Perform store one byte at a time + data->setByte(0, (m_value + m_store_count)); + m_store_count++; + if (m_store_count == CHECK_SIZE) { + m_status = TesterStatus_Ready; + } else { + m_status = TesterStatus_Idle; + } + DPRINTF(RubyTest, "Action callback return data now %d\n", + data->getByte(0)); + } else if (m_status == TesterStatus_Check_Pending) { + DPRINTF(RubyTest, "Check callback\n"); + // Perform load/check + for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { + if (uint8(m_value + byte_number) != data->getByte(byte_number)) { + WARN_EXPR(proc); + WARN_EXPR(address); + WARN_EXPR(data); + WARN_EXPR(byte_number); + WARN_EXPR((int)m_value + byte_number); + WARN_EXPR((int)data->getByte(byte_number)); + WARN_EXPR(*this); + WARN_EXPR(g_eventQueue_ptr->getTime()); + ERROR_MSG("Action/check failure"); + } + } + DPRINTF(RubyTest, "Action/check success\n"); + debugPrint(); + + // successful check complete, increment complete + m_tester_ptr->incrementCheckCompletions(); + + m_status = TesterStatus_Idle; + pickValue(); + + } else { + WARN_EXPR(*this); + WARN_EXPR(proc); + WARN_EXPR(data); + WARN_EXPR(m_status); + WARN_EXPR(g_eventQueue_ptr->getTime()); + ERROR_MSG("Unexpected TesterStatus"); + } + + DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, + getAddress().getLineAddress()); + DPRINTF(RubyTest, "Callback done\n"); + debugPrint(); +} + +void +Check::changeAddress(const Address& address) +{ + assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); + m_status = TesterStatus_Idle; + m_address = address; + m_store_count = 0; +} + +void +Check::pickValue() +{ + assert(m_status == TesterStatus_Idle); + m_status = TesterStatus_Idle; + m_value = random() & 0xff; // One byte + m_store_count = 0; +} + +void +Check::pickInitiatingNode() +{ + assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); + m_status = TesterStatus_Idle; + m_initiatingNode = (random() % m_num_cpu_sequencers); + DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); + m_store_count = 0; +} + +void +Check::print(std::ostream& out) const +{ + out << "[" + << m_address << ", value: " + << (int)m_value << ", status: " + << m_status << ", initiating node: " + << m_initiatingNode << ", store_count: " + << m_store_count + << "]" << std::flush; +} + +void +Check::debugPrint() +{ + DPRINTF(RubyTest, + "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", + m_address.getAddress(), (int)m_value, + TesterStatus_to_string(m_status).c_str(), + m_initiatingNode, m_store_count); +} |