RubyTester.cc revision 10920:58fbfddff18d
1/* 2 * Copyright (c) 2012-2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 15 * Copyright (c) 2009 Advanced Micro Devices, Inc. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42#include "base/misc.hh" 43#include "cpu/testers/rubytest/Check.hh" 44#include "cpu/testers/rubytest/RubyTester.hh" 45#include "debug/RubyTest.hh" 46#include "mem/ruby/common/SubBlock.hh" 47#include "mem/ruby/system/System.hh" 48#include "sim/sim_exit.hh" 49#include "sim/system.hh" 50 51RubyTester::RubyTester(const Params *p) 52 : MemObject(p), checkStartEvent(this), 53 _masterId(p->system->getMasterId(name())), 54 m_checkTable_ptr(nullptr), 55 m_num_cpus(p->num_cpus), 56 m_checks_to_complete(p->checks_to_complete), 57 m_deadlock_threshold(p->deadlock_threshold), 58 m_num_writers(0), 59 m_num_readers(0), 60 m_wakeup_frequency(p->wakeup_frequency), 61 m_check_flush(p->check_flush), 62 m_num_inst_ports(p->port_cpuInstPort_connection_count) 63{ 64 m_checks_completed = 0; 65 66 // 67 // Create the requested inst and data ports and place them on the 68 // appropriate read and write port lists. The reason for the subtle 69 // difference between inst and data ports vs. read and write ports is 70 // from the tester's perspective, it only needs to know whether a port 71 // supports reads (checks) or writes (actions). Meanwhile, the protocol 72 // controllers have data ports (support read and writes) or inst ports 73 // (support only reads). 74 // Note: the inst ports are the lowest elements of the readPort vector, 75 // then the data ports are added to the readPort vector 76 // 77 for (int i = 0; i < p->port_cpuInstPort_connection_count; ++i) { 78 readPorts.push_back(new CpuPort(csprintf("%s-instPort%d", name(), i), 79 this, i)); 80 } 81 for (int i = 0; i < p->port_cpuDataPort_connection_count; ++i) { 82 CpuPort *port = new CpuPort(csprintf("%s-dataPort%d", name(), i), 83 this, i); 84 readPorts.push_back(port); 85 writePorts.push_back(port); 86 } 87 88 // add the check start event to the event queue 89 schedule(checkStartEvent, 1); 90} 91 92RubyTester::~RubyTester() 93{ 94 delete m_checkTable_ptr; 95 // Only delete the readPorts since the writePorts are just a subset 96 for (int i = 0; i < readPorts.size(); i++) 97 delete readPorts[i]; 98} 99 100void 101RubyTester::init() 102{ 103 assert(writePorts.size() > 0 && readPorts.size() > 0); 104 105 m_last_progress_vector.resize(m_num_cpus); 106 for (int i = 0; i < m_last_progress_vector.size(); i++) { 107 m_last_progress_vector[i] = Cycles(0); 108 } 109 110 m_num_writers = writePorts.size(); 111 m_num_readers = readPorts.size(); 112 113 m_checkTable_ptr = new CheckTable(m_num_writers, m_num_readers, this); 114} 115 116BaseMasterPort & 117RubyTester::getMasterPort(const std::string &if_name, PortID idx) 118{ 119 if (if_name != "cpuInstPort" && if_name != "cpuDataPort") { 120 // pass it along to our super class 121 return MemObject::getMasterPort(if_name, idx); 122 } else { 123 if (if_name == "cpuInstPort") { 124 if (idx > m_num_inst_ports) { 125 panic("RubyTester::getMasterPort: unknown inst port idx %d\n", 126 idx); 127 } 128 // 129 // inst ports directly map to the lowest readPort elements 130 // 131 return *readPorts[idx]; 132 } else { 133 assert(if_name == "cpuDataPort"); 134 // 135 // add the inst port offset to translate to the correct read port 136 // index 137 // 138 int read_idx = idx + m_num_inst_ports; 139 if (read_idx >= static_cast<PortID>(readPorts.size())) { 140 panic("RubyTester::getMasterPort: unknown data port idx %d\n", 141 idx); 142 } 143 return *readPorts[read_idx]; 144 } 145 } 146} 147 148bool 149RubyTester::CpuPort::recvTimingResp(PacketPtr pkt) 150{ 151 // retrieve the subblock and call hitCallback 152 RubyTester::SenderState* senderState = 153 safe_cast<RubyTester::SenderState*>(pkt->senderState); 154 SubBlock& subblock = senderState->subBlock; 155 156 tester->hitCallback(id, &subblock); 157 158 // Now that the tester has completed, delete the senderState 159 // (includes sublock) and the packet, then return 160 delete pkt->senderState; 161 delete pkt->req; 162 delete pkt; 163 return true; 164} 165 166bool 167RubyTester::isInstReadableCpuPort(int idx) 168{ 169 return idx < m_num_inst_ports; 170} 171 172MasterPort* 173RubyTester::getReadableCpuPort(int idx) 174{ 175 assert(idx >= 0 && idx < readPorts.size()); 176 177 return readPorts[idx]; 178} 179 180MasterPort* 181RubyTester::getWritableCpuPort(int idx) 182{ 183 assert(idx >= 0 && idx < writePorts.size()); 184 185 return writePorts[idx]; 186} 187 188void 189RubyTester::hitCallback(NodeID proc, SubBlock* data) 190{ 191 // Mark that we made progress 192 m_last_progress_vector[proc] = curCycle(); 193 194 DPRINTF(RubyTest, "completed request for proc: %d\n", proc); 195 DPRINTF(RubyTest, "addr: 0x%x, size: %d, data: ", 196 data->getAddress(), data->getSize()); 197 for (int byte = 0; byte < data->getSize(); byte++) { 198 DPRINTF(RubyTest, "%d", data->getByte(byte)); 199 } 200 DPRINTF(RubyTest, "\n"); 201 202 // This tells us our store has 'completed' or for a load gives us 203 // back the data to make the check 204 Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress()); 205 assert(check_ptr != NULL); 206 check_ptr->performCallback(proc, data, curCycle()); 207} 208 209void 210RubyTester::wakeup() 211{ 212 if (m_checks_completed < m_checks_to_complete) { 213 // Try to perform an action or check 214 Check* check_ptr = m_checkTable_ptr->getRandomCheck(); 215 assert(check_ptr != NULL); 216 check_ptr->initiate(); 217 218 checkForDeadlock(); 219 220 schedule(checkStartEvent, curTick() + m_wakeup_frequency); 221 } else { 222 exitSimLoop("Ruby Tester completed"); 223 } 224} 225 226void 227RubyTester::checkForDeadlock() 228{ 229 int size = m_last_progress_vector.size(); 230 Cycles current_time = curCycle(); 231 for (int processor = 0; processor < size; processor++) { 232 if ((current_time - m_last_progress_vector[processor]) > 233 m_deadlock_threshold) { 234 panic("Deadlock detected: current_time: %d last_progress_time: %d " 235 "difference: %d processor: %d\n", 236 current_time, m_last_progress_vector[processor], 237 current_time - m_last_progress_vector[processor], processor); 238 } 239 } 240} 241 242void 243RubyTester::print(std::ostream& out) const 244{ 245 out << "[RubyTester]" << std::endl; 246} 247 248RubyTester * 249RubyTesterParams::create() 250{ 251 return new RubyTester(this); 252} 253