Check.cc revision 10566:c99c8d2a7c31
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#include "mem/ruby/system/Sequencer.hh" 35#include "mem/ruby/system/System.hh" 36 37typedef RubyTester::SenderState SenderState; 38 39Check::Check(const Address& address, const Address& pc, 40 int _num_writers, int _num_readers, RubyTester* _tester) 41 : m_num_writers(_num_writers), m_num_readers(_num_readers), 42 m_tester_ptr(_tester) 43{ 44 m_status = TesterStatus_Idle; 45 46 pickValue(); 47 pickInitiatingNode(); 48 changeAddress(address); 49 m_pc = pc; 50 m_access_mode = RubyAccessMode(random_mt.random(0, 51 RubyAccessMode_NUM - 1)); 52 m_store_count = 0; 53} 54 55void 56Check::initiate() 57{ 58 DPRINTF(RubyTest, "initiating\n"); 59 debugPrint(); 60 61 // currently no protocols support prefetches 62 if (false && (random_mt.random(0, 0xf) == 0)) { 63 initiatePrefetch(); // Prefetch from random processor 64 } 65 66 if (m_tester_ptr->getCheckFlush() && (random_mt.random(0, 0xff) == 0)) { 67 initiateFlush(); // issue a Flush request from random processor 68 } 69 70 if (m_status == TesterStatus_Idle) { 71 initiateAction(); 72 } else if (m_status == TesterStatus_Ready) { 73 initiateCheck(); 74 } else { 75 // Pending - do nothing 76 DPRINTF(RubyTest, 77 "initiating action/check - failed: action/check is pending\n"); 78 } 79} 80 81void 82Check::initiatePrefetch() 83{ 84 DPRINTF(RubyTest, "initiating prefetch\n"); 85 86 int index = random_mt.random(0, m_num_readers - 1); 87 MasterPort* port = m_tester_ptr->getReadableCpuPort(index); 88 89 Request::Flags flags; 90 flags.set(Request::PREFETCH); 91 92 Packet::Command cmd; 93 94 // 1 in 8 chance this will be an exclusive prefetch 95 if (random_mt.random(0, 0x7) != 0) { 96 cmd = MemCmd::ReadReq; 97 98 // if necessary, make the request an instruction fetch 99 if (m_tester_ptr->isInstReadableCpuPort(index)) { 100 flags.set(Request::INST_FETCH); 101 } 102 } else { 103 cmd = MemCmd::WriteReq; 104 flags.set(Request::PF_EXCLUSIVE); 105 } 106 107 // Prefetches are assumed to be 0 sized 108 Request *req = new Request(m_address.getAddress(), 0, flags, 109 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 110 req->setThreadContext(index, 0); 111 112 PacketPtr pkt = new Packet(req, cmd); 113 // despite the oddity of the 0 size (questionable if this should 114 // even be allowed), a prefetch is still a read and as such needs 115 // a place to store the result 116 uint8_t *data = new uint8_t[1]; 117 pkt->dataDynamic(data); 118 119 // push the subblock onto the sender state. The sequencer will 120 // update the subblock on the return 121 pkt->senderState = new SenderState(m_address, req->getSize()); 122 123 if (port->sendTimingReq(pkt)) { 124 DPRINTF(RubyTest, "successfully initiated prefetch.\n"); 125 } else { 126 // If the packet did not issue, must delete 127 delete pkt->senderState; 128 delete pkt->req; 129 delete pkt; 130 131 DPRINTF(RubyTest, 132 "prefetch initiation failed because Port was busy.\n"); 133 } 134} 135 136void 137Check::initiateFlush() 138{ 139 140 DPRINTF(RubyTest, "initiating Flush\n"); 141 142 int index = random_mt.random(0, m_num_writers - 1); 143 MasterPort* port = m_tester_ptr->getWritableCpuPort(index); 144 145 Request::Flags flags; 146 147 Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, 148 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 149 150 Packet::Command cmd; 151 152 cmd = MemCmd::FlushReq; 153 154 PacketPtr pkt = new Packet(req, cmd); 155 156 // push the subblock onto the sender state. The sequencer will 157 // update the subblock on the return 158 pkt->senderState = new SenderState(m_address, req->getSize()); 159 160 if (port->sendTimingReq(pkt)) { 161 DPRINTF(RubyTest, "initiating Flush - successful\n"); 162 } 163} 164 165void 166Check::initiateAction() 167{ 168 DPRINTF(RubyTest, "initiating Action\n"); 169 assert(m_status == TesterStatus_Idle); 170 171 int index = random_mt.random(0, m_num_writers - 1); 172 MasterPort* port = m_tester_ptr->getWritableCpuPort(index); 173 174 Request::Flags flags; 175 176 // Create the particular address for the next byte to be written 177 Address writeAddr(m_address.getAddress() + m_store_count); 178 179 // Stores are assumed to be 1 byte-sized 180 Request *req = new Request(writeAddr.getAddress(), 1, flags, 181 m_tester_ptr->masterId(), curTick(), 182 m_pc.getAddress()); 183 184 req->setThreadContext(index, 0); 185 Packet::Command cmd; 186 187 // 1 out of 8 chance, issue an atomic rather than a write 188 // if ((random() & 0x7) == 0) { 189 // cmd = MemCmd::SwapReq; 190 // } else { 191 cmd = MemCmd::WriteReq; 192 // } 193 194 PacketPtr pkt = new Packet(req, cmd); 195 uint8_t *writeData = new uint8_t[1]; 196 *writeData = m_value + m_store_count; 197 pkt->dataDynamic(writeData); 198 199 DPRINTF(RubyTest, "data 0x%x check 0x%x\n", 200 *(pkt->getConstPtr<uint8_t>()), *writeData); 201 202 // push the subblock onto the sender state. The sequencer will 203 // update the subblock on the return 204 pkt->senderState = new SenderState(writeAddr, req->getSize()); 205 206 if (port->sendTimingReq(pkt)) { 207 DPRINTF(RubyTest, "initiating action - successful\n"); 208 DPRINTF(RubyTest, "status before action update: %s\n", 209 (TesterStatus_to_string(m_status)).c_str()); 210 m_status = TesterStatus_Action_Pending; 211 } else { 212 // If the packet did not issue, must delete 213 // Note: No need to delete the data, the packet destructor 214 // will delete it 215 delete pkt->senderState; 216 delete pkt->req; 217 delete pkt; 218 219 DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); 220 } 221 222 DPRINTF(RubyTest, "status after action update: %s\n", 223 (TesterStatus_to_string(m_status)).c_str()); 224} 225 226void 227Check::initiateCheck() 228{ 229 DPRINTF(RubyTest, "Initiating Check\n"); 230 assert(m_status == TesterStatus_Ready); 231 232 int index = random_mt.random(0, m_num_readers - 1); 233 MasterPort* port = m_tester_ptr->getReadableCpuPort(index); 234 235 Request::Flags flags; 236 237 // If necessary, make the request an instruction fetch 238 if (m_tester_ptr->isInstReadableCpuPort(index)) { 239 flags.set(Request::INST_FETCH); 240 } 241 242 // Checks are sized depending on the number of bytes written 243 Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, 244 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 245 246 req->setThreadContext(index, 0); 247 PacketPtr pkt = new Packet(req, MemCmd::ReadReq); 248 uint8_t *dataArray = new uint8_t[CHECK_SIZE]; 249 pkt->dataDynamic(dataArray); 250 251 // push the subblock onto the sender state. The sequencer will 252 // update the subblock on the return 253 pkt->senderState = new SenderState(m_address, req->getSize()); 254 255 if (port->sendTimingReq(pkt)) { 256 DPRINTF(RubyTest, "initiating check - successful\n"); 257 DPRINTF(RubyTest, "status before check update: %s\n", 258 TesterStatus_to_string(m_status).c_str()); 259 m_status = TesterStatus_Check_Pending; 260 } else { 261 // If the packet did not issue, must delete 262 // Note: No need to delete the data, the packet destructor 263 // will delete it 264 delete pkt->senderState; 265 delete pkt->req; 266 delete pkt; 267 268 DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); 269 } 270 271 DPRINTF(RubyTest, "status after check update: %s\n", 272 TesterStatus_to_string(m_status).c_str()); 273} 274 275void 276Check::performCallback(NodeID proc, SubBlock* data, Cycles curTime) 277{ 278 Address address = data->getAddress(); 279 280 // This isn't exactly right since we now have multi-byte checks 281 // assert(getAddress() == address); 282 283 assert(getAddress().getLineAddress() == address.getLineAddress()); 284 assert(data != NULL); 285 286 DPRINTF(RubyTest, "RubyTester Callback\n"); 287 debugPrint(); 288 289 if (m_status == TesterStatus_Action_Pending) { 290 DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n", 291 (m_value + m_store_count), data->getByte(0)); 292 // Perform store one byte at a time 293 data->setByte(0, (m_value + m_store_count)); 294 m_store_count++; 295 if (m_store_count == CHECK_SIZE) { 296 m_status = TesterStatus_Ready; 297 } else { 298 m_status = TesterStatus_Idle; 299 } 300 DPRINTF(RubyTest, "Action callback return data now %d\n", 301 data->getByte(0)); 302 } else if (m_status == TesterStatus_Check_Pending) { 303 DPRINTF(RubyTest, "Check callback\n"); 304 // Perform load/check 305 for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { 306 if (uint8_t(m_value + byte_number) != data->getByte(byte_number)) { 307 panic("Action/check failure: proc: %d address: %s data: %s " 308 "byte_number: %d m_value+byte_number: %d byte: %d %s" 309 "Time: %d\n", 310 proc, address, data, byte_number, 311 (int)m_value + byte_number, 312 (int)data->getByte(byte_number), *this, curTime); 313 } 314 } 315 DPRINTF(RubyTest, "Action/check success\n"); 316 debugPrint(); 317 318 // successful check complete, increment complete 319 m_tester_ptr->incrementCheckCompletions(); 320 321 m_status = TesterStatus_Idle; 322 pickValue(); 323 324 } else { 325 panic("Unexpected TesterStatus: %s proc: %d data: %s m_status: %s " 326 "time: %d\n", *this, proc, data, m_status, curTime); 327 } 328 329 DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, 330 getAddress().getLineAddress()); 331 DPRINTF(RubyTest, "Callback done\n"); 332 debugPrint(); 333} 334 335void 336Check::changeAddress(const Address& address) 337{ 338 assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 339 m_status = TesterStatus_Idle; 340 m_address = address; 341 m_store_count = 0; 342} 343 344void 345Check::pickValue() 346{ 347 assert(m_status == TesterStatus_Idle); 348 m_status = TesterStatus_Idle; 349 m_value = random_mt.random(0, 0xff); // One byte 350 m_store_count = 0; 351} 352 353void 354Check::pickInitiatingNode() 355{ 356 assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 357 m_status = TesterStatus_Idle; 358 m_initiatingNode = (random_mt.random(0, m_num_writers - 1)); 359 DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); 360 m_store_count = 0; 361} 362 363void 364Check::print(std::ostream& out) const 365{ 366 out << "[" 367 << m_address << ", value: " 368 << (int)m_value << ", status: " 369 << m_status << ", initiating node: " 370 << m_initiatingNode << ", store_count: " 371 << m_store_count 372 << "]" << std::flush; 373} 374 375void 376Check::debugPrint() 377{ 378 DPRINTF(RubyTest, 379 "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", 380 m_address.getAddress(), (int)m_value, 381 TesterStatus_to_string(m_status).c_str(), 382 m_initiatingNode, m_store_count); 383} 384