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