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