Check.cc revision 11017:6ec228f6c143
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(const Address& address, const Address& pc, 38 int _num_writers, int _num_readers, 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.getAddress(), 0, flags, 107 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 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.getAddress(), CHECK_SIZE, flags, 146 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 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 Address writeAddr(m_address.getAddress() + m_store_count); 176 177 // Stores are assumed to be 1 byte-sized 178 Request *req = new Request(writeAddr.getAddress(), 1, flags, 179 m_tester_ptr->masterId(), curTick(), 180 m_pc.getAddress()); 181 182 req->setThreadContext(index, 0); 183 Packet::Command cmd; 184 185 // 1 out of 8 chance, issue an atomic rather than a write 186 // if ((random() & 0x7) == 0) { 187 // cmd = MemCmd::SwapReq; 188 // } else { 189 cmd = MemCmd::WriteReq; 190 // } 191 192 PacketPtr pkt = new Packet(req, cmd); 193 uint8_t *writeData = new uint8_t[1]; 194 *writeData = m_value + m_store_count; 195 pkt->dataDynamic(writeData); 196 197 DPRINTF(RubyTest, "data 0x%x check 0x%x\n", 198 *(pkt->getConstPtr<uint8_t>()), *writeData); 199 200 // push the subblock onto the sender state. The sequencer will 201 // update the subblock on the return 202 pkt->senderState = new SenderState(writeAddr, req->getSize()); 203 204 if (port->sendTimingReq(pkt)) { 205 DPRINTF(RubyTest, "initiating action - successful\n"); 206 DPRINTF(RubyTest, "status before action update: %s\n", 207 (TesterStatus_to_string(m_status)).c_str()); 208 m_status = TesterStatus_Action_Pending; 209 } else { 210 // If the packet did not issue, must delete 211 // Note: No need to delete the data, the packet destructor 212 // will delete it 213 delete pkt->senderState; 214 delete pkt->req; 215 delete pkt; 216 217 DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); 218 } 219 220 DPRINTF(RubyTest, "status after action update: %s\n", 221 (TesterStatus_to_string(m_status)).c_str()); 222} 223 224void 225Check::initiateCheck() 226{ 227 DPRINTF(RubyTest, "Initiating Check\n"); 228 assert(m_status == TesterStatus_Ready); 229 230 int index = random_mt.random(0, m_num_readers - 1); 231 MasterPort* port = m_tester_ptr->getReadableCpuPort(index); 232 233 Request::Flags flags; 234 235 // If necessary, make the request an instruction fetch 236 if (m_tester_ptr->isInstReadableCpuPort(index)) { 237 flags.set(Request::INST_FETCH); 238 } 239 240 // Checks are sized depending on the number of bytes written 241 Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, 242 m_tester_ptr->masterId(), curTick(), m_pc.getAddress()); 243 244 req->setThreadContext(index, 0); 245 PacketPtr pkt = new Packet(req, MemCmd::ReadReq); 246 uint8_t *dataArray = new uint8_t[CHECK_SIZE]; 247 pkt->dataDynamic(dataArray); 248 249 // push the subblock onto the sender state. The sequencer will 250 // update the subblock on the return 251 pkt->senderState = new SenderState(m_address, req->getSize()); 252 253 if (port->sendTimingReq(pkt)) { 254 DPRINTF(RubyTest, "initiating check - successful\n"); 255 DPRINTF(RubyTest, "status before check update: %s\n", 256 TesterStatus_to_string(m_status).c_str()); 257 m_status = TesterStatus_Check_Pending; 258 } else { 259 // If the packet did not issue, must delete 260 // Note: No need to delete the data, the packet destructor 261 // will delete it 262 delete pkt->senderState; 263 delete pkt->req; 264 delete pkt; 265 266 DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); 267 } 268 269 DPRINTF(RubyTest, "status after check update: %s\n", 270 TesterStatus_to_string(m_status).c_str()); 271} 272 273void 274Check::performCallback(NodeID proc, SubBlock* data, Cycles curTime) 275{ 276 Address address = data->getAddress(); 277 278 // This isn't exactly right since we now have multi-byte checks 279 // assert(getAddress() == address); 280 281 assert(getAddress().getLineAddress() == address.getLineAddress()); 282 assert(data != NULL); 283 284 DPRINTF(RubyTest, "RubyTester Callback\n"); 285 debugPrint(); 286 287 if (m_status == TesterStatus_Action_Pending) { 288 DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n", 289 (m_value + m_store_count), data->getByte(0)); 290 // Perform store one byte at a time 291 data->setByte(0, (m_value + m_store_count)); 292 m_store_count++; 293 if (m_store_count == CHECK_SIZE) { 294 m_status = TesterStatus_Ready; 295 } else { 296 m_status = TesterStatus_Idle; 297 } 298 DPRINTF(RubyTest, "Action callback return data now %d\n", 299 data->getByte(0)); 300 } else if (m_status == TesterStatus_Check_Pending) { 301 DPRINTF(RubyTest, "Check callback\n"); 302 // Perform load/check 303 for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { 304 if (uint8_t(m_value + byte_number) != data->getByte(byte_number)) { 305 panic("Action/check failure: proc: %d address: %s data: %s " 306 "byte_number: %d m_value+byte_number: %d byte: %d %s" 307 "Time: %d\n", 308 proc, address, data, byte_number, 309 (int)m_value + byte_number, 310 (int)data->getByte(byte_number), *this, curTime); 311 } 312 } 313 DPRINTF(RubyTest, "Action/check success\n"); 314 debugPrint(); 315 316 // successful check complete, increment complete 317 m_tester_ptr->incrementCheckCompletions(); 318 319 m_status = TesterStatus_Idle; 320 pickValue(); 321 322 } else { 323 panic("Unexpected TesterStatus: %s proc: %d data: %s m_status: %s " 324 "time: %d\n", *this, proc, data, m_status, curTime); 325 } 326 327 DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, 328 getAddress().getLineAddress()); 329 DPRINTF(RubyTest, "Callback done\n"); 330 debugPrint(); 331} 332 333void 334Check::changeAddress(const Address& address) 335{ 336 assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 337 m_status = TesterStatus_Idle; 338 m_address = address; 339 m_store_count = 0; 340} 341 342void 343Check::pickValue() 344{ 345 assert(m_status == TesterStatus_Idle); 346 m_status = TesterStatus_Idle; 347 m_value = random_mt.random(0, 0xff); // One byte 348 m_store_count = 0; 349} 350 351void 352Check::pickInitiatingNode() 353{ 354 assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 355 m_status = TesterStatus_Idle; 356 m_initiatingNode = (random_mt.random(0, m_num_writers - 1)); 357 DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); 358 m_store_count = 0; 359} 360 361void 362Check::print(std::ostream& out) const 363{ 364 out << "[" 365 << m_address << ", value: " 366 << (int)m_value << ", status: " 367 << m_status << ", initiating node: " 368 << m_initiatingNode << ", store_count: " 369 << m_store_count 370 << "]" << std::flush; 371} 372 373void 374Check::debugPrint() 375{ 376 DPRINTF(RubyTest, 377 "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", 378 m_address.getAddress(), (int)m_value, 379 TesterStatus_to_string(m_status).c_str(), 380 m_initiatingNode, m_store_count); 381} 382