Check.cc revision 6899
1 2/* 3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 4 * Copyright (c) 2009 Advanced Micro Devices, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer; 11 * redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution; 14 * neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32#include "cpu/rubytest/Check.hh" 33#include "mem/ruby/system/Sequencer.hh" 34#include "mem/ruby/system/System.hh" 35#include "mem/ruby/common/SubBlock.hh" 36 37Check::Check(const Address& address, 38 const Address& pc, 39 int _num_cpu_sequencers, 40 RubyTester* _tester) 41 : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester) 42{ 43 m_status = TesterStatus_Idle; 44 45 pickValue(); 46 pickInitiatingNode(); 47 changeAddress(address); 48 m_pc = pc; 49 m_access_mode = AccessModeType(random() % AccessModeType_NUM); 50 m_store_count = 0; 51} 52 53void Check::initiate() 54{ 55 DPRINTF(RubyTest, "initiating\n"); 56 debugPrint(); 57 58 // 59 // currently no protocols support prefetches 60 // 61 if (false && (random() & 0xf) == 0) { 62 initiatePrefetch(); // Prefetch from random processor 63 } 64 65 if(m_status == TesterStatus_Idle) { 66 initiateAction(); 67 } else if(m_status == TesterStatus_Ready) { 68 initiateCheck(); 69 } else { 70 // Pending - do nothing 71 DPRINTF(RubyTest, "initiating action/check - failed: action/check is pending\n"); 72 } 73} 74 75void Check::initiatePrefetch() 76{ 77 DPRINTF(RubyTest, "initiating prefetch\n"); 78 79 RubyTester::CpuPort* port 80 = safe_cast<RubyTester::CpuPort*> \ 81 (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers)); 82 83 Request::Flags flags; 84 flags.set(Request::PREFETCH); 85 86 // 87 // Prefetches are assumed to be 0 sized 88 // 89 Request *req = new Request(m_address.getAddress(), 90 0, 91 flags, 92 curTick, 93 m_pc.getAddress()); 94 95 Packet::Command cmd; 96 97 // 98 // 1 in 8 chance this will be an exclusive prefetch 99 // 100 if ((random() & 0x7) != 0) { 101 cmd = MemCmd::ReadReq; 102 // 103 // 50% chance that the request will be an instruction fetch 104 // 105 if ((random() & 0x1) == 0) { 106 flags.set(Request::INST_FETCH); 107 } 108 } else { 109 cmd = MemCmd::WriteReq; 110 flags.set(Request::PF_EXCLUSIVE); 111 } 112 113 PacketPtr pkt = new Packet(req, cmd, port->idx); 114 115 // 116 // push the subblock onto the sender state. The sequencer will update the 117 // subblock on the return 118 // 119 pkt->senderState = new RubyTester::SenderState(m_address, 120 req->getSize(), 121 pkt->senderState); 122 123 if (port->sendTiming(pkt)) { 124 DPRINTF(RubyTest, "successfully initiated prefetch.\n"); 125 } else { 126 // 127 // If the packet did not issue, must delete 128 // 129 RubyTester::SenderState* senderState = 130 safe_cast<RubyTester::SenderState*>(pkt->senderState); 131 pkt->senderState = senderState->saved; 132 delete senderState; 133 delete pkt->req; 134 delete pkt; 135 136 DPRINTF(RubyTest, "prefetch initiation failed because Port was busy.\n"); 137 } 138} 139 140void Check::initiateAction() 141{ 142 DPRINTF(RubyTest, "initiating Action\n"); 143 assert(m_status == TesterStatus_Idle); 144 145 RubyTester::CpuPort* port 146 = safe_cast<RubyTester::CpuPort*> \ 147 (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers)); 148 149 Request::Flags flags; 150 151 // 152 // Create the particular address for the next byte to be written 153 // 154 Address writeAddr(m_address.getAddress() + m_store_count); 155 156 // 157 // Stores are assumed to be 1 byte-sized 158 // 159 Request *req = new Request(writeAddr.getAddress(), 160 1, 161 flags, 162 curTick, 163 m_pc.getAddress()); 164 165 Packet::Command cmd; 166 167 // 168 // 1 out of 8 chance, issue an atomic rather than a write 169 // 170// if ((random() & 0x7) == 0) { 171// cmd = MemCmd::SwapReq; 172// } else { 173 cmd = MemCmd::WriteReq; 174// } 175 176 PacketPtr pkt = new Packet(req, cmd, port->idx); 177 uint8_t* writeData = new uint8_t; 178 *writeData = m_value + m_store_count; 179 pkt->dataDynamic(writeData); 180 181 DPRINTF(RubyTest, 182 "data 0x%x check 0x%x\n", 183 *(pkt->getPtr<uint8_t>()), 184 *writeData); 185 186 // 187 // push the subblock onto the sender state. The sequencer will update the 188 // subblock on the return 189 // 190 pkt->senderState = new RubyTester::SenderState(writeAddr, 191 req->getSize(), 192 pkt->senderState); 193 194 if (port->sendTiming(pkt)) { 195 DPRINTF(RubyTest, "initiating action - successful\n"); 196 DPRINTF(RubyTest, 197 "status before action update: %s\n", 198 (TesterStatus_to_string(m_status)).c_str()); 199 m_status = TesterStatus_Action_Pending; 200 } else { 201 // 202 // If the packet did not issue, must delete 203 // Note: No need to delete the data, the packet destructor will delete it 204 // 205 RubyTester::SenderState* senderState = 206 safe_cast<RubyTester::SenderState*>(pkt->senderState); 207 pkt->senderState = senderState->saved; 208 delete senderState; 209 delete pkt->req; 210 delete pkt; 211 212 DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); 213 } 214 215 DPRINTF(RubyTest, 216 "status after action update: %s\n", 217 (TesterStatus_to_string(m_status)).c_str()); 218} 219 220void Check::initiateCheck() 221{ 222 DPRINTF(RubyTest, "Initiating Check\n"); 223 assert(m_status == TesterStatus_Ready); 224 225 RubyTester::CpuPort* port 226 = safe_cast<RubyTester::CpuPort*> \ 227 (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers)); 228 229 Request::Flags flags; 230 231 // 232 // Checks are sized depending on the number of bytes written 233 // 234 Request *req = new Request(m_address.getAddress(), 235 CHECK_SIZE, 236 flags, 237 curTick, 238 m_pc.getAddress()); 239 240 // 241 // 50% chance that the request will be an instruction fetch 242 // 243 if ((random() & 0x1) == 0) { 244 flags.set(Request::INST_FETCH); 245 } 246 247 PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx); 248 uint8_t* dataArray = new uint8_t[CHECK_SIZE]; 249 pkt->dataDynamicArray(dataArray); 250 251 // 252 // push the subblock onto the sender state. The sequencer will update the 253 // subblock on the return 254 // 255 pkt->senderState = new RubyTester::SenderState(m_address, 256 req->getSize(), 257 pkt->senderState); 258 259 if (port->sendTiming(pkt)) { 260 DPRINTF(RubyTest, "initiating check - successful\n"); 261 DPRINTF(RubyTest, 262 "status before check update: %s\n", 263 (TesterStatus_to_string(m_status)).c_str()); 264 m_status = TesterStatus_Check_Pending; 265 } else { 266 // 267 // If the packet did not issue, must delete 268 // Note: No need to delete the data, the packet destructor will delete it 269 // 270 RubyTester::SenderState* senderState = 271 safe_cast<RubyTester::SenderState*>(pkt->senderState); 272 pkt->senderState = senderState->saved; 273 delete senderState; 274 delete pkt->req; 275 delete pkt; 276 277 DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); 278 } 279 280 DPRINTF(RubyTest, 281 "status after check update: %s\n", 282 (TesterStatus_to_string(m_status)).c_str()); 283} 284 285void Check::performCallback(NodeID proc, SubBlock* data) 286{ 287 Address address = data->getAddress(); 288 // assert(getAddress() == address); // This isn't exactly right since we now have multi-byte checks 289 assert(getAddress().getLineAddress() == address.getLineAddress()); 290 assert(data != NULL); 291 292 DPRINTF(RubyTest, "RubyTester Callback\n"); 293 debugPrint(); 294 295 if (m_status == TesterStatus_Action_Pending) { 296 DPRINTF(RubyTest, 297 "Action callback write value: %d, currently %d\n", 298 (m_value + m_store_count), 299 data->getByte(0)); 300 // 301 // Perform store one byte at a time 302 // 303 data->setByte(0, (m_value + m_store_count)); 304 m_store_count++; 305 if (m_store_count == CHECK_SIZE) { 306 m_status = TesterStatus_Ready; 307 } else { 308 m_status = TesterStatus_Idle; 309 } 310 DPRINTF(RubyTest, 311 "Action callback return data now %d\n", 312 data->getByte(0)); 313 } else if (m_status == TesterStatus_Check_Pending) { 314 DPRINTF(RubyTest, "Check callback\n"); 315 // Perform load/check 316 for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { 317 if (uint8(m_value+byte_number) != data->getByte(byte_number)) { 318 WARN_EXPR(proc); 319 WARN_EXPR(address); 320 WARN_EXPR(data); 321 WARN_EXPR(byte_number); 322 WARN_EXPR((int)m_value+byte_number); 323 WARN_EXPR((int)data->getByte(byte_number)); 324 WARN_EXPR(*this); 325 WARN_EXPR(g_eventQueue_ptr->getTime()); 326 ERROR_MSG("Action/check failure"); 327 } 328 } 329 DPRINTF(RubyTest, "Action/check success\n"); 330 debugPrint(); 331 332 // successful check complete, increment complete 333 m_tester_ptr->incrementCheckCompletions(); 334 335 m_status = TesterStatus_Idle; 336 pickValue(); 337 338 } else { 339 WARN_EXPR(*this); 340 WARN_EXPR(proc); 341 WARN_EXPR(data); 342 WARN_EXPR(m_status); 343 WARN_EXPR(g_eventQueue_ptr->getTime()); 344 ERROR_MSG("Unexpected TesterStatus"); 345 } 346 347 DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, getAddress().getLineAddress()); 348 DPRINTF(RubyTest, "Callback done\n"); 349 debugPrint(); 350} 351 352void Check::changeAddress(const Address& address) 353{ 354 assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready)); 355 m_status = TesterStatus_Idle; 356 m_address = address; 357 m_store_count = 0; 358} 359 360void Check::pickValue() 361{ 362 assert(m_status == TesterStatus_Idle); 363 m_status = TesterStatus_Idle; 364 m_value = random() & 0xff; // One byte 365 m_store_count = 0; 366} 367 368void Check::pickInitiatingNode() 369{ 370 assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready)); 371 m_status = TesterStatus_Idle; 372 m_initiatingNode = (random() % m_num_cpu_sequencers); 373 DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); 374 m_store_count = 0; 375} 376 377void Check::print(ostream& out) const 378{ 379 out << "[" 380 << m_address << ", value: " 381 << (int) m_value << ", status: " 382 << m_status << ", initiating node: " 383 << m_initiatingNode << ", store_count: " 384 << m_store_count 385 << "]" << flush; 386} 387 388void Check::debugPrint() 389{ 390 DPRINTF(RubyTest, 391 "[0x%x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", 392 m_address.getAddress(), 393 (int)m_value, 394 (TesterStatus_to_string(m_status)).c_str(), 395 m_initiatingNode, 396 m_store_count); 397} 398