diff options
Diffstat (limited to 'src/mem/ruby/tester/Check.cc')
-rw-r--r-- | src/mem/ruby/tester/Check.cc | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/mem/ruby/tester/Check.cc b/src/mem/ruby/tester/Check.cc new file mode 100644 index 000000000..7896b572a --- /dev/null +++ b/src/mem/ruby/tester/Check.cc @@ -0,0 +1,310 @@ + +/* + * 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. + */ + +/* + * $Id$ + * + */ + +#include "mem/ruby/tester/Check.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/common/SubBlock.hh" +#include "mem/protocol/Chip.hh" +#include "mem/packet.hh" + +Check::Check(const Address& address, const Address& pc) +{ + 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() +{ + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating"); + DEBUG_EXPR(TESTER_COMP, MedPrio, *this); + + // current CMP protocol doesn't support prefetches + if (!Protocol::m_CMP && (random() & 0xf) == 0) { // 1 in 16 chance + initiatePrefetch(); // Prefetch from random processor + } + + if(m_status == TesterStatus_Idle) { + initiateAction(); + } else if(m_status == TesterStatus_Ready) { + initiateCheck(); + } else { + // Pending - do nothing + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action/check - failed: action/check is pending\n"); + } +} + +void Check::initiatePrefetch(Sequencer* targetSequencer_ptr) +{ + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating prefetch"); + + CacheRequestType type; + if ((random() & 0x7) != 0) { // 1 in 8 chance + if ((random() & 0x1) == 0) { // 50% chance + type = CacheRequestType_LD; + } else { + type = CacheRequestType_IFETCH; + } + } else { + type = CacheRequestType_ST; + } + + Addr data_addr = m_address.getAddress(); + Addr pc_addr = m_pc.getAddress(); + Request request(0, data_addr, 0, Flags<unsigned int>(Request::PREFETCH), pc_addr, 0, 0); + MemCmd::Command command; + if (type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + request.setFlags(Request::INST_FETCH); + } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + } else if (type == CacheRequestType_ST) { + command = MemCmd::WriteReq; + } else if (type == CacheRequestType_ATOMIC) { + command = MemCmd::SwapReq; // TODO -- differentiate between atomic types + } else { + panic("Cannot convert request to packet"); + } + + Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + + assert(targetSequencer_ptr != NULL); + if (targetSequencer_ptr->isReady(&pkt)) { + targetSequencer_ptr->makeRequest(&pkt); + } +} + +void Check::initiatePrefetch() +{ + // Any sequencer can issue a prefetch for this address + Sequencer* targetSequencer_ptr = g_system_ptr->getChip(random() % RubyConfig::numberOfChips())->getSequencer(random() % RubyConfig::numberOfProcsPerChip()); + assert(targetSequencer_ptr != NULL); + initiatePrefetch(targetSequencer_ptr); +} + +void Check::initiateAction() +{ + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Action"); + assert(m_status == TesterStatus_Idle); + + CacheRequestType type = CacheRequestType_ST; + if ((random() & 0x1) == 0) { // 50% chance + type = CacheRequestType_ATOMIC; + } + + Addr data_addr = m_address.getAddress()+m_store_count; + Addr pc_addr = m_pc.getAddress(); + Request request(0, data_addr, 1, Flags<unsigned int>(), pc_addr, 0, 0); + MemCmd::Command command; + if (type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + request.setFlags(Request::INST_FETCH); + } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + } else if (type == CacheRequestType_ST) { + command = MemCmd::WriteReq; + } else if (type == CacheRequestType_ATOMIC) { + command = MemCmd::SwapReq; // TODO -- differentiate between atomic types + } else { + panic("Cannot convert request to packet"); + } + + Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + + Sequencer* sequencer_ptr = initiatingSequencer(); + if (sequencer_ptr->isReady(&pkt) == false) { + DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate action - sequencer not ready\n"); + } else { + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action - successful\n"); + DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); + m_status = TesterStatus_Action_Pending; + + sequencer_ptr->makeRequest(&pkt); + } + DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); +} + +void Check::initiateCheck() +{ + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Check"); + assert(m_status == TesterStatus_Ready); + + CacheRequestType type = CacheRequestType_LD; + if ((random() & 0x1) == 0) { // 50% chance + type = CacheRequestType_IFETCH; + } + + + Addr data_addr = m_address.getAddress()+m_store_count; + Addr pc_addr = m_pc.getAddress(); + Request request(0, data_addr, CHECK_SIZE, Flags<unsigned int>(), pc_addr, 0, 0); + MemCmd::Command command; + if (type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + request.setFlags(Request::INST_FETCH); + } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { + command = MemCmd::ReadReq; + } else if (type == CacheRequestType_ST) { + command = MemCmd::WriteReq; + } else if (type == CacheRequestType_ATOMIC) { + command = MemCmd::SwapReq; // TODO -- differentiate between atomic types + } else { + panic("Cannot convert request to packet"); + } + + Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + + Sequencer* sequencer_ptr = initiatingSequencer(); + if (sequencer_ptr->isReady(&pkt) == false) { + DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate check - sequencer not ready\n"); + } else { + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating check - successful\n"); + DEBUG_MSG(TESTER_COMP, MedPrio, m_status); + m_status = TesterStatus_Check_Pending; + + sequencer_ptr->makeRequest(&pkt); + } + DEBUG_MSG(TESTER_COMP, MedPrio, m_status); +} + +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()); + + DEBUG_MSG(TESTER_COMP, MedPrio, "Callback"); + DEBUG_EXPR(TESTER_COMP, MedPrio, *this); + + if (m_status == TesterStatus_Action_Pending) { + DEBUG_MSG(TESTER_COMP, MedPrio, "Action callback"); + // Perform store + data.setByte(0, m_value+m_store_count); // We store one byte at a time + m_store_count++; + + if (m_store_count == CHECK_SIZE) { + m_status = TesterStatus_Ready; + } else { + m_status = TesterStatus_Idle; + } + } else if (m_status == TesterStatus_Check_Pending) { + DEBUG_MSG(TESTER_COMP, MedPrio, "Check callback"); + // Perform load/check + for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { + if (uint8(m_value+byte_number) != data.getByte(byte_number) && (DATA_BLOCK == true)) { + 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"); + } + } + DEBUG_MSG(TESTER_COMP, HighPrio, "Action/check success:"); + DEBUG_EXPR(TESTER_COMP, HighPrio, *this); + DEBUG_EXPR(TESTER_COMP, MedPrio, data); + + 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"); + } + + DEBUG_EXPR(TESTER_COMP, MedPrio, proc); + DEBUG_EXPR(TESTER_COMP, MedPrio, data); + DEBUG_EXPR(TESTER_COMP, MedPrio, getAddress().getLineAddress()); + DEBUG_MSG(TESTER_COMP, MedPrio, "Callback done"); + DEBUG_EXPR(TESTER_COMP, MedPrio, *this); +} + +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; +} + +Sequencer* Check::initiatingSequencer() const +{ + return g_system_ptr->getChip(m_initiatingNode/RubyConfig::numberOfProcsPerChip())->getSequencer(m_initiatingNode%RubyConfig::numberOfProcsPerChip()); +} + +void Check::pickValue() +{ + assert(m_status == TesterStatus_Idle); + m_status = TesterStatus_Idle; + // DEBUG_MSG(TESTER_COMP, MedPrio, m_status); + DEBUG_MSG(TESTER_COMP, MedPrio, *this); + m_value = random() & 0xff; // One byte + // DEBUG_MSG(TESTER_COMP, MedPrio, m_value); + DEBUG_MSG(TESTER_COMP, MedPrio, *this); + m_store_count = 0; +} + +void Check::pickInitiatingNode() +{ + assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready)); + m_status = TesterStatus_Idle; + DEBUG_MSG(TESTER_COMP, MedPrio, m_status); + m_initiatingNode = (random() % RubyConfig::numberOfProcessors()); + DEBUG_MSG(TESTER_COMP, MedPrio, 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; +} |