RubyTester.cc revision 11793:ef606668d247
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 "cpu/testers/rubytest/RubyTester.hh" 43 44#include "base/misc.hh" 45#include "cpu/testers/rubytest/Check.hh" 46#include "debug/RubyTest.hh" 47#include "mem/ruby/common/SubBlock.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_only_ports(p->port_cpuInstPort_connection_count), 63 m_num_inst_data_ports(p->port_cpuInstDataPort_connection_count) 64{ 65 m_checks_completed = 0; 66 67 // 68 // Create the requested inst and data ports and place them on the 69 // appropriate read and write port lists. The reason for the subtle 70 // difference between inst and data ports vs. read and write ports is 71 // from the tester's perspective, it only needs to know whether a port 72 // supports reads (checks) or writes (actions). Meanwhile, the protocol 73 // controllers have data ports (support read and writes) or inst ports 74 // (support only reads). 75 // Note: the inst ports are the lowest elements of the readPort vector, 76 // then the data ports are added to the readPort vector 77 // 78 int idx = 0; 79 for (int i = 0; i < p->port_cpuInstPort_connection_count; ++i) { 80 readPorts.push_back(new CpuPort(csprintf("%s-instPort%d", name(), i), 81 this, i, idx)); 82 idx++; 83 } 84 for (int i = 0; i < p->port_cpuInstDataPort_connection_count; ++i) { 85 CpuPort *port = new CpuPort(csprintf("%s-instDataPort%d", name(), i), 86 this, i, idx); 87 readPorts.push_back(port); 88 writePorts.push_back(port); 89 idx++; 90 } 91 for (int i = 0; i < p->port_cpuDataPort_connection_count; ++i) { 92 CpuPort *port = new CpuPort(csprintf("%s-dataPort%d", name(), i), 93 this, i, idx); 94 readPorts.push_back(port); 95 writePorts.push_back(port); 96 idx++; 97 } 98 99 // add the check start event to the event queue 100 schedule(checkStartEvent, 1); 101} 102 103RubyTester::~RubyTester() 104{ 105 delete m_checkTable_ptr; 106 // Only delete the readPorts since the writePorts are just a subset 107 for (int i = 0; i < readPorts.size(); i++) 108 delete readPorts[i]; 109} 110 111void 112RubyTester::init() 113{ 114 assert(writePorts.size() > 0 && readPorts.size() > 0); 115 116 m_last_progress_vector.resize(m_num_cpus); 117 for (int i = 0; i < m_last_progress_vector.size(); i++) { 118 m_last_progress_vector[i] = Cycles(0); 119 } 120 121 m_num_writers = writePorts.size(); 122 m_num_readers = readPorts.size(); 123 assert(m_num_readers == m_num_cpus); 124 125 m_checkTable_ptr = new CheckTable(m_num_writers, m_num_readers, this); 126} 127 128BaseMasterPort & 129RubyTester::getMasterPort(const std::string &if_name, PortID idx) 130{ 131 if (if_name != "cpuInstPort" && if_name != "cpuInstDataPort" && 132 if_name != "cpuDataPort") { 133 // pass it along to our super class 134 return MemObject::getMasterPort(if_name, idx); 135 } else { 136 if (if_name == "cpuInstPort") { 137 if (idx > m_num_inst_only_ports) { 138 panic("RubyTester::getMasterPort: unknown inst port %d\n", 139 idx); 140 } 141 // 142 // inst ports map to the lowest readPort elements 143 // 144 return *readPorts[idx]; 145 } else if (if_name == "cpuInstDataPort") { 146 if (idx > m_num_inst_data_ports) { 147 panic("RubyTester::getMasterPort: unknown inst+data port %d\n", 148 idx); 149 } 150 int read_idx = idx + m_num_inst_only_ports; 151 // 152 // inst+data ports map to the next readPort elements 153 // 154 return *readPorts[read_idx]; 155 } else { 156 assert(if_name == "cpuDataPort"); 157 // 158 // data only ports map to the final readPort elements 159 // 160 if (idx > (static_cast<int>(readPorts.size()) - 161 (m_num_inst_only_ports + m_num_inst_data_ports))) { 162 panic("RubyTester::getMasterPort: unknown data port %d\n", 163 idx); 164 } 165 int read_idx = idx + m_num_inst_only_ports + m_num_inst_data_ports; 166 return *readPorts[read_idx]; 167 } 168 // Note: currently the Ruby Tester does not support write only ports 169 // but that could easily be added here 170 } 171} 172 173bool 174RubyTester::CpuPort::recvTimingResp(PacketPtr pkt) 175{ 176 // retrieve the subblock and call hitCallback 177 RubyTester::SenderState* senderState = 178 safe_cast<RubyTester::SenderState*>(pkt->senderState); 179 SubBlock& subblock = senderState->subBlock; 180 181 tester->hitCallback(globalIdx, &subblock); 182 183 // Now that the tester has completed, delete the senderState 184 // (includes sublock) and the packet, then return 185 delete pkt->senderState; 186 delete pkt->req; 187 delete pkt; 188 return true; 189} 190 191bool 192RubyTester::isInstOnlyCpuPort(int idx) 193{ 194 return idx < m_num_inst_only_ports; 195} 196 197bool 198RubyTester::isInstDataCpuPort(int idx) 199{ 200 return ((idx >= m_num_inst_only_ports) && 201 (idx < (m_num_inst_only_ports + m_num_inst_data_ports))); 202} 203 204MasterPort* 205RubyTester::getReadableCpuPort(int idx) 206{ 207 assert(idx >= 0 && idx < readPorts.size()); 208 209 return readPorts[idx]; 210} 211 212MasterPort* 213RubyTester::getWritableCpuPort(int idx) 214{ 215 assert(idx >= 0 && idx < writePorts.size()); 216 217 return writePorts[idx]; 218} 219 220void 221RubyTester::hitCallback(NodeID proc, SubBlock* data) 222{ 223 // Mark that we made progress 224 m_last_progress_vector[proc] = curCycle(); 225 226 DPRINTF(RubyTest, "completed request for proc: %d", proc); 227 DPRINTFR(RubyTest, " addr: 0x%x, size: %d, data: ", 228 data->getAddress(), data->getSize()); 229 for (int byte = 0; byte < data->getSize(); byte++) { 230 DPRINTFR(RubyTest, "%d ", data->getByte(byte)); 231 } 232 DPRINTFR(RubyTest, "\n"); 233 234 // This tells us our store has 'completed' or for a load gives us 235 // back the data to make the check 236 Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress()); 237 assert(check_ptr != NULL); 238 check_ptr->performCallback(proc, data, curCycle()); 239} 240 241void 242RubyTester::wakeup() 243{ 244 if (m_checks_completed < m_checks_to_complete) { 245 // Try to perform an action or check 246 Check* check_ptr = m_checkTable_ptr->getRandomCheck(); 247 assert(check_ptr != NULL); 248 check_ptr->initiate(); 249 250 checkForDeadlock(); 251 252 schedule(checkStartEvent, curTick() + m_wakeup_frequency); 253 } else { 254 exitSimLoop("Ruby Tester completed"); 255 } 256} 257 258void 259RubyTester::checkForDeadlock() 260{ 261 int size = m_last_progress_vector.size(); 262 Cycles current_time = curCycle(); 263 for (int processor = 0; processor < size; processor++) { 264 if ((current_time - m_last_progress_vector[processor]) > 265 m_deadlock_threshold) { 266 panic("Deadlock detected: current_time: %d last_progress_time: %d " 267 "difference: %d processor: %d\n", 268 current_time, m_last_progress_vector[processor], 269 current_time - m_last_progress_vector[processor], processor); 270 } 271 } 272} 273 274void 275RubyTester::print(std::ostream& out) const 276{ 277 out << "[RubyTester]" << std::endl; 278} 279 280RubyTester * 281RubyTesterParams::create() 282{ 283 return new RubyTester(this); 284} 285