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