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