RubyTester.cc revision 9475:736909f5c13b
112870Sgabeblack@google.com/* 212870Sgabeblack@google.com * Copyright (c) 2012 ARM Limited 312870Sgabeblack@google.com * All rights reserved 412870Sgabeblack@google.com * 512870Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612870Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712870Sgabeblack@google.com * property including but not limited to intellectual property relating 812870Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912870Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012870Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112870Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212870Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312870Sgabeblack@google.com * 1412870Sgabeblack@google.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 1512870Sgabeblack@google.com * Copyright (c) 2009 Advanced Micro Devices, Inc. 1612870Sgabeblack@google.com * All rights reserved. 1712870Sgabeblack@google.com * 1812870Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1912870Sgabeblack@google.com * modification, are permitted provided that the following conditions are 2012870Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2112870Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2212870Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2312870Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2412870Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2512870Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2612870Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2712870Sgabeblack@google.com * this software without specific prior written permission. 2812870Sgabeblack@google.com * 2912870Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3012870Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3112870Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3212870Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3313003Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3413003Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3512870Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3612870Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3712870Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3812870Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3913000Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4012870Sgabeblack@google.com */ 4113003Sgabeblack@google.com 4212870Sgabeblack@google.com#include "base/misc.hh" 4312870Sgabeblack@google.com#include "cpu/testers/rubytest/Check.hh" 4412870Sgabeblack@google.com#include "cpu/testers/rubytest/RubyTester.hh" 4512870Sgabeblack@google.com#include "debug/RubyTest.hh" 4612870Sgabeblack@google.com#include "mem/ruby/common/Global.hh" 4712870Sgabeblack@google.com#include "mem/ruby/common/SubBlock.hh" 4812870Sgabeblack@google.com#include "mem/ruby/system/System.hh" 4912870Sgabeblack@google.com#include "sim/sim_exit.hh" 5012870Sgabeblack@google.com#include "sim/system.hh" 5112870Sgabeblack@google.com 5212870Sgabeblack@google.comRubyTester::RubyTester(const Params *p) 5312870Sgabeblack@google.com : MemObject(p), checkStartEvent(this), 5412870Sgabeblack@google.com _masterId(p->system->getMasterId(name())), 5512870Sgabeblack@google.com m_num_cpus(p->num_cpus), 5612870Sgabeblack@google.com m_checks_to_complete(p->checks_to_complete), 5712870Sgabeblack@google.com m_deadlock_threshold(p->deadlock_threshold), 5812870Sgabeblack@google.com m_wakeup_frequency(p->wakeup_frequency), 5912870Sgabeblack@google.com m_check_flush(p->check_flush), 6012870Sgabeblack@google.com m_num_inst_ports(p->port_cpuInstPort_connection_count) 6112870Sgabeblack@google.com{ 6212870Sgabeblack@google.com m_checks_completed = 0; 6312870Sgabeblack@google.com 6412870Sgabeblack@google.com // 6512870Sgabeblack@google.com // Create the requested inst and data ports and place them on the 6613003Sgabeblack@google.com // appropriate read and write port lists. The reason for the subtle 6712870Sgabeblack@google.com // difference between inst and data ports vs. read and write ports is 6812870Sgabeblack@google.com // from the tester's perspective, it only needs to know whether a port 6913003Sgabeblack@google.com // supports reads (checks) or writes (actions). Meanwhile, the protocol 7013003Sgabeblack@google.com // controllers have data ports (support read and writes) or inst ports 7113003Sgabeblack@google.com // (support only reads). 7213003Sgabeblack@google.com // Note: the inst ports are the lowest elements of the readPort vector, 7313003Sgabeblack@google.com // then the data ports are added to the readPort vector 7412870Sgabeblack@google.com // 7512870Sgabeblack@google.com for (int i = 0; i < p->port_cpuInstPort_connection_count; ++i) { 7612870Sgabeblack@google.com readPorts.push_back(new CpuPort(csprintf("%s-instPort%d", name(), i), 7712870Sgabeblack@google.com this, i)); 7812870Sgabeblack@google.com } 7912897Sgabeblack@google.com for (int i = 0; i < p->port_cpuDataPort_connection_count; ++i) { 8012870Sgabeblack@google.com CpuPort *port = new CpuPort(csprintf("%s-dataPort%d", name(), i), 8112870Sgabeblack@google.com this, i); 8212870Sgabeblack@google.com readPorts.push_back(port); 8312870Sgabeblack@google.com writePorts.push_back(port); 8412870Sgabeblack@google.com } 8512870Sgabeblack@google.com 8612870Sgabeblack@google.com // add the check start event to the event queue 8712870Sgabeblack@google.com schedule(checkStartEvent, 1); 8812870Sgabeblack@google.com} 8912870Sgabeblack@google.com 9012870Sgabeblack@google.comRubyTester::~RubyTester() 9112870Sgabeblack@google.com{ 9212870Sgabeblack@google.com delete m_checkTable_ptr; 9313002Sgabeblack@google.com // Only delete the readPorts since the writePorts are just a subset 9413002Sgabeblack@google.com for (int i = 0; i < readPorts.size(); i++) 9513002Sgabeblack@google.com delete readPorts[i]; 9612870Sgabeblack@google.com} 9712870Sgabeblack@google.com 9812870Sgabeblack@google.comvoid 9912870Sgabeblack@google.comRubyTester::init() 10012870Sgabeblack@google.com{ 10112870Sgabeblack@google.com assert(writePorts.size() > 0 && readPorts.size() > 0); 10212870Sgabeblack@google.com 10312870Sgabeblack@google.com m_last_progress_vector.resize(m_num_cpus); 10412870Sgabeblack@google.com for (int i = 0; i < m_last_progress_vector.size(); i++) { 10512870Sgabeblack@google.com m_last_progress_vector[i] = 0; 10612870Sgabeblack@google.com } 10712870Sgabeblack@google.com 10812870Sgabeblack@google.com m_num_writers = writePorts.size(); 10912870Sgabeblack@google.com m_num_readers = readPorts.size(); 11012870Sgabeblack@google.com 11112870Sgabeblack@google.com m_checkTable_ptr = new CheckTable(m_num_writers, m_num_readers, this); 11212870Sgabeblack@google.com} 11312870Sgabeblack@google.com 11412870Sgabeblack@google.comBaseMasterPort & 11512870Sgabeblack@google.comRubyTester::getMasterPort(const std::string &if_name, PortID idx) 11612870Sgabeblack@google.com{ 11712870Sgabeblack@google.com if (if_name != "cpuInstPort" && if_name != "cpuDataPort") { 11812870Sgabeblack@google.com // pass it along to our super class 11912870Sgabeblack@google.com return MemObject::getMasterPort(if_name, idx); 12012870Sgabeblack@google.com } else { 12112870Sgabeblack@google.com if (if_name == "cpuInstPort") { 12212870Sgabeblack@google.com if (idx > m_num_inst_ports) { 12312870Sgabeblack@google.com panic("RubyTester::getMasterPort: unknown inst port idx %d\n", 12413034Sgabeblack@google.com idx); 12512870Sgabeblack@google.com } 12612870Sgabeblack@google.com // 12712870Sgabeblack@google.com // inst ports directly map to the lowest readPort elements 12812870Sgabeblack@google.com // 12912870Sgabeblack@google.com return *readPorts[idx]; 13012870Sgabeblack@google.com } else { 13112870Sgabeblack@google.com assert(if_name == "cpuDataPort"); 13213000Sgabeblack@google.com // 13313000Sgabeblack@google.com // add the inst port offset to translate to the correct read port 13413000Sgabeblack@google.com // index 13513000Sgabeblack@google.com // 13613000Sgabeblack@google.com int read_idx = idx + m_num_inst_ports; 13713000Sgabeblack@google.com if (read_idx >= static_cast<PortID>(readPorts.size())) { 13813000Sgabeblack@google.com panic("RubyTester::getMasterPort: unknown data port idx %d\n", 13913000Sgabeblack@google.com idx); 14013000Sgabeblack@google.com } 14113000Sgabeblack@google.com return *readPorts[read_idx]; 14213000Sgabeblack@google.com } 14313000Sgabeblack@google.com } 14413000Sgabeblack@google.com} 14513100Sgabeblack@google.com 14613000Sgabeblack@google.combool 14713000Sgabeblack@google.comRubyTester::CpuPort::recvTimingResp(PacketPtr pkt) 14813000Sgabeblack@google.com{ 14913000Sgabeblack@google.com // retrieve the subblock and call hitCallback 15013000Sgabeblack@google.com RubyTester::SenderState* senderState = 15112870Sgabeblack@google.com safe_cast<RubyTester::SenderState*>(pkt->senderState); 15213100Sgabeblack@google.com SubBlock* subblock = senderState->subBlock; 15312870Sgabeblack@google.com assert(subblock != NULL); 15413003Sgabeblack@google.com 15513100Sgabeblack@google.com // pop the sender state from the packet 15613100Sgabeblack@google.com pkt->senderState = senderState->saved; 15713100Sgabeblack@google.com 15813000Sgabeblack@google.com tester->hitCallback(id, subblock); 15913002Sgabeblack@google.com 16013002Sgabeblack@google.com // Now that the tester has completed, delete the senderState 16113002Sgabeblack@google.com // (includes sublock) and the packet, then return 16213001Sgabeblack@google.com delete senderState; 16313001Sgabeblack@google.com delete pkt->req; 16413001Sgabeblack@google.com delete pkt; 16513001Sgabeblack@google.com return true; 16613001Sgabeblack@google.com} 16713001Sgabeblack@google.com 16813100Sgabeblack@google.combool 16913002Sgabeblack@google.comRubyTester::isInstReadableCpuPort(int idx) 17013001Sgabeblack@google.com{ 17113000Sgabeblack@google.com return idx < m_num_inst_ports; 17213000Sgabeblack@google.com} 17313000Sgabeblack@google.com 17413000Sgabeblack@google.comMasterPort* 17513000Sgabeblack@google.comRubyTester::getReadableCpuPort(int idx) 17613000Sgabeblack@google.com{ 17713000Sgabeblack@google.com assert(idx >= 0 && idx < readPorts.size()); 17813000Sgabeblack@google.com 17913000Sgabeblack@google.com return readPorts[idx]; 18012870Sgabeblack@google.com} 18113003Sgabeblack@google.com 18213003Sgabeblack@google.comMasterPort* 18313003Sgabeblack@google.comRubyTester::getWritableCpuPort(int idx) 18413003Sgabeblack@google.com{ 18513003Sgabeblack@google.com assert(idx >= 0 && idx < writePorts.size()); 18613003Sgabeblack@google.com 18713003Sgabeblack@google.com return writePorts[idx]; 18813003Sgabeblack@google.com} 18913003Sgabeblack@google.com 19013003Sgabeblack@google.comvoid 19113055Sgabeblack@google.comRubyTester::hitCallback(NodeID proc, SubBlock* data) 19213055Sgabeblack@google.com{ 19313055Sgabeblack@google.com // Mark that we made progress 19413055Sgabeblack@google.com m_last_progress_vector[proc] = curCycle(); 19513055Sgabeblack@google.com 19613055Sgabeblack@google.com DPRINTF(RubyTest, "completed request for proc: %d\n", proc); 19713055Sgabeblack@google.com DPRINTF(RubyTest, "addr: 0x%x, size: %d, data: ", 19813055Sgabeblack@google.com data->getAddress(), data->getSize()); 19913055Sgabeblack@google.com for (int byte = 0; byte < data->getSize(); byte++) { 20013055Sgabeblack@google.com DPRINTF(RubyTest, "%d", data->getByte(byte)); 20113003Sgabeblack@google.com } 20213003Sgabeblack@google.com DPRINTF(RubyTest, "\n"); 20313003Sgabeblack@google.com 20413003Sgabeblack@google.com // This tells us our store has 'completed' or for a load gives us 20513003Sgabeblack@google.com // back the data to make the check 20613003Sgabeblack@google.com Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress()); 20713003Sgabeblack@google.com assert(check_ptr != NULL); 20813003Sgabeblack@google.com check_ptr->performCallback(proc, data, curCycle()); 20913004Sgabeblack@google.com} 21013055Sgabeblack@google.com 21113055Sgabeblack@google.comvoid 21213056Sgabeblack@google.comRubyTester::wakeup() 21313056Sgabeblack@google.com{ 21413037Sgabeblack@google.com if (m_checks_completed < m_checks_to_complete) { 21513037Sgabeblack@google.com // Try to perform an action or check 21613010Sgabeblack@google.com Check* check_ptr = m_checkTable_ptr->getRandomCheck(); 21713055Sgabeblack@google.com assert(check_ptr != NULL); 21813003Sgabeblack@google.com check_ptr->initiate(); 21913003Sgabeblack@google.com 22013055Sgabeblack@google.com checkForDeadlock(); 22113055Sgabeblack@google.com 22213003Sgabeblack@google.com schedule(checkStartEvent, curTick() + m_wakeup_frequency); 22313003Sgabeblack@google.com } else { 22413003Sgabeblack@google.com exitSimLoop("Ruby Tester completed"); 22513003Sgabeblack@google.com } 22613003Sgabeblack@google.com} 22713003Sgabeblack@google.com 22813003Sgabeblack@google.comvoid 22913003Sgabeblack@google.comRubyTester::checkForDeadlock() 23013003Sgabeblack@google.com{ 23113003Sgabeblack@google.com int size = m_last_progress_vector.size(); 23213003Sgabeblack@google.com Time current_time = curCycle(); 23313003Sgabeblack@google.com for (int processor = 0; processor < size; processor++) { 23413003Sgabeblack@google.com if ((current_time - m_last_progress_vector[processor]) > 23513003Sgabeblack@google.com m_deadlock_threshold) { 23613003Sgabeblack@google.com panic("Deadlock detected: current_time: %d last_progress_time: %d " 23713005Sgabeblack@google.com "difference: %d processor: %d\n", 23813005Sgabeblack@google.com current_time, m_last_progress_vector[processor], 23913003Sgabeblack@google.com current_time - m_last_progress_vector[processor], processor); 24013003Sgabeblack@google.com } 24113003Sgabeblack@google.com } 24213003Sgabeblack@google.com} 24313003Sgabeblack@google.com 24413003Sgabeblack@google.comvoid 24513003Sgabeblack@google.comRubyTester::print(std::ostream& out) const 24613003Sgabeblack@google.com{ 24713005Sgabeblack@google.com out << "[RubyTester]" << std::endl; 24813005Sgabeblack@google.com} 24913005Sgabeblack@google.com 25013003Sgabeblack@google.comRubyTester * 25113003Sgabeblack@google.comRubyTesterParams::create() 25213009Sgabeblack@google.com{ 25313009Sgabeblack@google.com return new RubyTester(this); 25413009Sgabeblack@google.com} 25513009Sgabeblack@google.com