cpu_impl.hh revision 3126
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Kevin Lim 29 */ 30 31#include <list> 32#include <string> 33 34#include "base/refcnt.hh" 35#include "cpu/base_dyn_inst.hh" 36#include "cpu/checker/cpu.hh" 37#include "cpu/simple_thread.hh" 38#include "cpu/thread_context.hh" 39#include "cpu/static_inst.hh" 40#include "mem/packet_impl.hh" 41#include "sim/byteswap.hh" 42#include "sim/sim_object.hh" 43#include "sim/stats.hh" 44 45#if FULL_SYSTEM 46#include "arch/vtophys.hh" 47#endif // FULL_SYSTEM 48 49using namespace std; 50//The CheckerCPU does alpha only 51using namespace AlphaISA; 52 53template <class DynInstPtr> 54void 55Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) 56{ 57 DynInstPtr inst; 58 59 // Either check this instruction, or add it to a list of 60 // instructions waiting to be checked. Instructions must be 61 // checked in program order, so if a store has committed yet not 62 // completed, there may be some instructions that are waiting 63 // behind it that have completed and must be checked. 64 if (!instList.empty()) { 65 if (youngestSN < completed_inst->seqNum) { 66 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 67 completed_inst->seqNum, completed_inst->readPC()); 68 instList.push_back(completed_inst); 69 youngestSN = completed_inst->seqNum; 70 } 71 72 if (!instList.front()->isCompleted()) { 73 return; 74 } else { 75 inst = instList.front(); 76 instList.pop_front(); 77 } 78 } else { 79 if (!completed_inst->isCompleted()) { 80 if (youngestSN < completed_inst->seqNum) { 81 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 82 completed_inst->seqNum, completed_inst->readPC()); 83 instList.push_back(completed_inst); 84 youngestSN = completed_inst->seqNum; 85 } 86 return; 87 } else { 88 if (youngestSN < completed_inst->seqNum) { 89 inst = completed_inst; 90 youngestSN = completed_inst->seqNum; 91 } else { 92 return; 93 } 94 } 95 } 96 97 unverifiedInst = inst; 98 99 // Try to check all instructions that are completed, ending if we 100 // run out of instructions to check or if an instruction is not 101 // yet completed. 102 while (1) { 103 DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n", 104 inst->seqNum, inst->readPC()); 105 unverifiedResult.integer = inst->readIntResult(); 106 unverifiedReq = inst->req; 107 unverifiedMemData = inst->memData; 108 numCycles++; 109 110 Fault fault = NoFault; 111 112 // maintain $r0 semantics 113 thread->setIntReg(ZeroReg, 0); 114#ifdef TARGET_ALPHA 115 thread->setFloatRegDouble(ZeroReg, 0.0); 116#endif // TARGET_ALPHA 117 118 // Check if any recent PC changes match up with anything we 119 // expect to happen. This is mostly to check if traps or 120 // PC-based events have occurred in both the checker and CPU. 121 if (changedPC) { 122 DPRINTF(Checker, "Changed PC recently to %#x\n", 123 thread->readPC()); 124 if (willChangePC) { 125 if (newPC == thread->readPC()) { 126 DPRINTF(Checker, "Changed PC matches expected PC\n"); 127 } else { 128 warn("%lli: Changed PC does not match expected PC, " 129 "changed: %#x, expected: %#x", 130 curTick, thread->readPC(), newPC); 131 CheckerCPU::handleError(); 132 } 133 willChangePC = false; 134 } 135 changedPC = false; 136 } 137 if (changedNextPC) { 138 DPRINTF(Checker, "Changed NextPC recently to %#x\n", 139 thread->readNextPC()); 140 changedNextPC = false; 141 } 142 143 // Try to fetch the instruction 144 145#if FULL_SYSTEM 146#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 147#else 148#define IFETCH_FLAGS(pc) 0 149#endif 150 151 uint64_t fetch_PC = thread->readPC() & ~3; 152 153 // set up memory request for instruction fetch 154 memReq = new Request(inst->threadNumber, fetch_PC, 155 sizeof(uint32_t), 156 IFETCH_FLAGS(thread->readPC()), 157 fetch_PC, thread->readCpuId(), inst->threadNumber); 158 159 bool succeeded = translateInstReq(memReq); 160 161 if (!succeeded) { 162 if (inst->getFault() == NoFault) { 163 // In this case the instruction was not a dummy 164 // instruction carrying an ITB fault. In the single 165 // threaded case the ITB should still be able to 166 // translate this instruction; in the SMT case it's 167 // possible that its ITB entry was kicked out. 168 warn("%lli: Instruction PC %#x was not found in the ITB!", 169 curTick, thread->readPC()); 170 handleError(inst); 171 172 // go to the next instruction 173 thread->setPC(thread->readNextPC()); 174 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 175 176 break; 177 } else { 178 // The instruction is carrying an ITB fault. Handle 179 // the fault and see if our results match the CPU on 180 // the next tick(). 181 fault = inst->getFault(); 182 } 183 } 184 185 if (fault == NoFault) { 186 Packet *pkt = new Packet(memReq, Packet::ReadReq, 187 Packet::Broadcast); 188 189 pkt->dataStatic(&machInst); 190 191 icachePort->sendFunctional(pkt); 192 193 delete pkt; 194 195 // keep an instruction count 196 numInst++; 197 198 // decode the instruction 199 machInst = gtoh(machInst); 200 // Checks that the instruction matches what we expected it to be. 201 // Checks both the machine instruction and the PC. 202 validateInst(inst); 203 204 curStaticInst = StaticInst::decode(makeExtMI(machInst, 205 thread->readPC())); 206 207#if FULL_SYSTEM 208 thread->setInst(machInst); 209#endif // FULL_SYSTEM 210 211 fault = inst->getFault(); 212 } 213 214 // Discard fetch's memReq. 215 delete memReq; 216 memReq = NULL; 217 218 // Either the instruction was a fault and we should process the fault, 219 // or we should just go ahead execute the instruction. This assumes 220 // that the instruction is properly marked as a fault. 221 if (fault == NoFault) { 222 223 thread->funcExeInst++; 224 225 if (!inst->isUnverifiable()) 226 fault = curStaticInst->execute(this, NULL); 227 228 // Checks to make sure instrution results are correct. 229 validateExecution(inst); 230 231 if (curStaticInst->isLoad()) { 232 ++numLoad; 233 } 234 } 235 236 if (fault != NoFault) { 237#if FULL_SYSTEM 238 fault->invoke(tc); 239 willChangePC = true; 240 newPC = thread->readPC(); 241 DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); 242#endif 243 } else { 244#if THE_ISA != MIPS_ISA 245 // go to the next instruction 246 thread->setPC(thread->readNextPC()); 247 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 248#else 249 // go to the next instruction 250 thread->setPC(thread->readNextPC()); 251 thread->setNextPC(thread->readNextNPC()); 252 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 253#endif 254 255 } 256 257#if FULL_SYSTEM 258 // @todo: Determine if these should happen only if the 259 // instruction hasn't faulted. In the SimpleCPU case this may 260 // not be true, but in the O3 or Ozone case this may be true. 261 Addr oldpc; 262 int count = 0; 263 do { 264 oldpc = thread->readPC(); 265 system->pcEventQueue.service(tc); 266 count++; 267 } while (oldpc != thread->readPC()); 268 if (count > 1) { 269 willChangePC = true; 270 newPC = thread->readPC(); 271 DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); 272 } 273#endif 274 275 // @todo: Optionally can check all registers. (Or just those 276 // that have been modified). 277 validateState(); 278 279 if (memReq) { 280 delete memReq; 281 memReq = NULL; 282 } 283 284 // Continue verifying instructions if there's another completed 285 // instruction waiting to be verified. 286 if (instList.empty()) { 287 break; 288 } else if (instList.front()->isCompleted()) { 289 inst = instList.front(); 290 instList.pop_front(); 291 } else { 292 break; 293 } 294 } 295 unverifiedInst = NULL; 296} 297 298template <class DynInstPtr> 299void 300Checker<DynInstPtr>::switchOut() 301{ 302 instList.clear(); 303} 304 305template <class DynInstPtr> 306void 307Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) 308{ 309} 310 311template <class DynInstPtr> 312void 313Checker<DynInstPtr>::validateInst(DynInstPtr &inst) 314{ 315 if (inst->readPC() != thread->readPC()) { 316 warn("%lli: PCs do not match! Inst: %#x, checker: %#x", 317 curTick, inst->readPC(), thread->readPC()); 318 if (changedPC) { 319 warn("%lli: Changed PCs recently, may not be an error", 320 curTick); 321 } else { 322 handleError(inst); 323 } 324 } 325 326 MachInst mi = static_cast<MachInst>(inst->staticInst->machInst); 327 328 if (mi != machInst) { 329 warn("%lli: Binary instructions do not match! Inst: %#x, " 330 "checker: %#x", 331 curTick, mi, machInst); 332 handleError(inst); 333 } 334} 335 336template <class DynInstPtr> 337void 338Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) 339{ 340 bool result_mismatch = false; 341 if (inst->numDestRegs()) { 342 // @todo: Support more destination registers. 343 if (inst->isUnverifiable()) { 344 // Unverifiable instructions assume they were executed 345 // properly by the CPU. Grab the result from the 346 // instruction and write it to the register. 347 copyResult(inst); 348 } else if (result.integer != inst->readIntResult()) { 349 result_mismatch = true; 350 } 351 } 352 353 if (result_mismatch) { 354 warn("%lli: Instruction results do not match! (Values may not " 355 "actually be integers) Inst: %#x, checker: %#x", 356 curTick, inst->readIntResult(), result.integer); 357 358 // It's useful to verify load values from memory, but in MP 359 // systems the value obtained at execute may be different than 360 // the value obtained at completion. Similarly DMA can 361 // present the same problem on even UP systems. Thus there is 362 // the option to only warn on loads having a result error. 363 if (inst->isLoad() && warnOnlyOnLoadError) { 364 copyResult(inst); 365 } else { 366 handleError(inst); 367 } 368 } 369 370 if (inst->readNextPC() != thread->readNextPC()) { 371 warn("%lli: Instruction next PCs do not match! Inst: %#x, " 372 "checker: %#x", 373 curTick, inst->readNextPC(), thread->readNextPC()); 374 handleError(inst); 375 } 376 377 // Checking side effect registers can be difficult if they are not 378 // checked simultaneously with the execution of the instruction. 379 // This is because other valid instructions may have modified 380 // these registers in the meantime, and their values are not 381 // stored within the DynInst. 382 while (!miscRegIdxs.empty()) { 383 int misc_reg_idx = miscRegIdxs.front(); 384 miscRegIdxs.pop(); 385 386 if (inst->tcBase()->readMiscReg(misc_reg_idx) != 387 thread->readMiscReg(misc_reg_idx)) { 388 warn("%lli: Misc reg idx %i (side effect) does not match! " 389 "Inst: %#x, checker: %#x", 390 curTick, misc_reg_idx, 391 inst->tcBase()->readMiscReg(misc_reg_idx), 392 thread->readMiscReg(misc_reg_idx)); 393 handleError(inst); 394 } 395 } 396} 397 398template <class DynInstPtr> 399void 400Checker<DynInstPtr>::validateState() 401{ 402 if (updateThisCycle) { 403 warn("%lli: Instruction PC %#x results didn't match up, copying all " 404 "registers from main CPU", curTick, unverifiedInst->readPC()); 405 // Heavy-weight copying of all registers 406 thread->copyArchRegs(unverifiedInst->tcBase()); 407 // Also advance the PC. Hopefully no PC-based events happened. 408#if THE_ISA != MIPS_ISA 409 // go to the next instruction 410 thread->setPC(thread->readNextPC()); 411 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 412#else 413 // go to the next instruction 414 thread->setPC(thread->readNextPC()); 415 thread->setNextPC(thread->readNextNPC()); 416 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 417#endif 418 updateThisCycle = false; 419 } 420} 421 422template <class DynInstPtr> 423void 424Checker<DynInstPtr>::copyResult(DynInstPtr &inst) 425{ 426 RegIndex idx = inst->destRegIdx(0); 427 if (idx < TheISA::FP_Base_DepTag) { 428 thread->setIntReg(idx, inst->readIntResult()); 429 } else if (idx < TheISA::Fpcr_DepTag) { 430 thread->setFloatRegBits(idx, inst->readIntResult()); 431 } else { 432 thread->setMiscReg(idx, inst->readIntResult()); 433 } 434} 435 436template <class DynInstPtr> 437void 438Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst) 439{ 440 cprintf("Error detected, instruction information:\n"); 441 cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n" 442 "Completed:%i\n", 443 inst->readPC(), 444 inst->readNextPC(), 445 inst->seqNum, 446 inst->threadNumber, 447 inst->isCompleted()); 448 inst->dump(); 449 CheckerCPU::dumpAndExit(); 450} 451 452template <class DynInstPtr> 453void 454Checker<DynInstPtr>::dumpInsts() 455{ 456 int num = 0; 457 458 InstListIt inst_list_it = --(instList.end()); 459 460 cprintf("Inst list size: %i\n", instList.size()); 461 462 while (inst_list_it != instList.end()) 463 { 464 cprintf("Instruction:%i\n", 465 num); 466 467 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" 468 "Completed:%i\n", 469 (*inst_list_it)->readPC(), 470 (*inst_list_it)->seqNum, 471 (*inst_list_it)->threadNumber, 472 (*inst_list_it)->isCompleted()); 473 474 cprintf("\n"); 475 476 inst_list_it--; 477 ++num; 478 } 479 480} 481