cpu.cc revision 2690:f4337c0d9e6f
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.hh" 36#include "cpu/base_dyn_inst.hh" 37#include "cpu/checker/cpu.hh" 38#include "cpu/simple_thread.hh" 39#include "cpu/thread_context.hh" 40#include "cpu/static_inst.hh" 41#include "sim/byteswap.hh" 42#include "sim/sim_object.hh" 43#include "sim/stats.hh" 44 45#include "cpu/o3/alpha_dyn_inst.hh" 46#include "cpu/o3/alpha_impl.hh" 47 48//#include "cpu/ozone/dyn_inst.hh" 49//#include "cpu/ozone/ozone_impl.hh" 50//#include "cpu/ozone/simple_impl.hh" 51 52#if FULL_SYSTEM 53#include "sim/system.hh" 54#include "arch/vtophys.hh" 55#endif // FULL_SYSTEM 56 57using namespace std; 58//The CheckerCPU does alpha only 59using namespace AlphaISA; 60 61void 62CheckerCPU::init() 63{ 64} 65 66CheckerCPU::CheckerCPU(Params *p) 67 : BaseCPU(p), thread(NULL), tc(NULL) 68{ 69 memReq = NULL; 70 71 numInst = 0; 72 startNumInst = 0; 73 numLoad = 0; 74 startNumLoad = 0; 75 youngestSN = 0; 76 77 changedPC = willChangePC = changedNextPC = false; 78 79 exitOnError = p->exitOnError; 80#if FULL_SYSTEM 81 itb = p->itb; 82 dtb = p->dtb; 83 systemPtr = NULL; 84#else 85 process = p->process; 86#endif 87} 88 89CheckerCPU::~CheckerCPU() 90{ 91} 92 93void 94CheckerCPU::setMemory(MemObject *mem) 95{ 96#if !FULL_SYSTEM 97 memPtr = mem; 98 thread = new SimpleThread(this, /* thread_num */ 0, process, 99 /* asid */ 0, mem); 100 101 thread->setStatus(ThreadContext::Suspended); 102 tc = thread->getTC(); 103 threadContexts.push_back(tc); 104#endif 105} 106 107void 108CheckerCPU::setSystem(System *system) 109{ 110#if FULL_SYSTEM 111 systemPtr = system; 112 113 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 114 115 thread->setStatus(ThreadContext::Suspended); 116 tc = thread->getTC(); 117 threadContexts.push_back(tc); 118 delete thread->kernelStats; 119 thread->kernelStats = NULL; 120#endif 121} 122 123void 124CheckerCPU::setIcachePort(Port *icache_port) 125{ 126 icachePort = icache_port; 127} 128 129void 130CheckerCPU::setDcachePort(Port *dcache_port) 131{ 132 dcachePort = dcache_port; 133} 134 135void 136CheckerCPU::serialize(ostream &os) 137{ 138/* 139 BaseCPU::serialize(os); 140 SERIALIZE_SCALAR(inst); 141 nameOut(os, csprintf("%s.xc", name())); 142 thread->serialize(os); 143 cacheCompletionEvent.serialize(os); 144*/ 145} 146 147void 148CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 149{ 150/* 151 BaseCPU::unserialize(cp, section); 152 UNSERIALIZE_SCALAR(inst); 153 thread->unserialize(cp, csprintf("%s.xc", section)); 154*/ 155} 156 157Fault 158CheckerCPU::copySrcTranslate(Addr src) 159{ 160 panic("Unimplemented!"); 161} 162 163Fault 164CheckerCPU::copy(Addr dest) 165{ 166 panic("Unimplemented!"); 167} 168 169template <class T> 170Fault 171CheckerCPU::read(Addr addr, T &data, unsigned flags) 172{ 173 // need to fill in CPU & thread IDs here 174 memReq = new Request(); 175 176 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 177 178 // translate to physical address 179 translateDataReadReq(memReq); 180 181 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 182 183 pkt->dataStatic(&data); 184 185 if (!(memReq->getFlags() & UNCACHEABLE)) { 186 // Access memory to see if we have the same data 187 dcachePort->sendFunctional(pkt); 188 } else { 189 // Assume the data is correct if it's an uncached access 190 memcpy(&data, &unverifiedResult.integer, sizeof(T)); 191 } 192 193 delete pkt; 194 195 return NoFault; 196} 197 198#ifndef DOXYGEN_SHOULD_SKIP_THIS 199 200template 201Fault 202CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); 203 204template 205Fault 206CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); 207 208template 209Fault 210CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); 211 212template 213Fault 214CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); 215 216#endif //DOXYGEN_SHOULD_SKIP_THIS 217 218template<> 219Fault 220CheckerCPU::read(Addr addr, double &data, unsigned flags) 221{ 222 return read(addr, *(uint64_t*)&data, flags); 223} 224 225template<> 226Fault 227CheckerCPU::read(Addr addr, float &data, unsigned flags) 228{ 229 return read(addr, *(uint32_t*)&data, flags); 230} 231 232template<> 233Fault 234CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) 235{ 236 return read(addr, (uint32_t&)data, flags); 237} 238 239template <class T> 240Fault 241CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 242{ 243 // need to fill in CPU & thread IDs here 244 memReq = new Request(); 245 246 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 247 248 // translate to physical address 249 thread->translateDataWriteReq(memReq); 250 251 // Can compare the write data and result only if it's cacheable, 252 // not a store conditional, or is a store conditional that 253 // succeeded. 254 // @todo: Verify that actual memory matches up with these values. 255 // Right now it only verifies that the instruction data is the 256 // same as what was in the request that got sent to memory; there 257 // is no verification that it is the same as what is in memory. 258 // This is because the LSQ would have to be snooped in the CPU to 259 // verify this data. 260 if (unverifiedReq && 261 !(unverifiedReq->getFlags() & UNCACHEABLE) && 262 (!(unverifiedReq->getFlags() & LOCKED) || 263 ((unverifiedReq->getFlags() & LOCKED) && 264 unverifiedReq->getScResult() == 1))) { 265 T inst_data; 266/* 267 // This code would work if the LSQ allowed for snooping. 268 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 269 pkt.dataStatic(&inst_data); 270 271 dcachePort->sendFunctional(pkt); 272 273 delete pkt; 274*/ 275 memcpy(&inst_data, unverifiedMemData, sizeof(T)); 276 277 if (data != inst_data) { 278 warn("%lli: Store value does not match value in memory! " 279 "Instruction: %#x, memory: %#x", 280 curTick, inst_data, data); 281 handleError(); 282 } 283 } 284 285 // Assume the result was the same as the one passed in. This checker 286 // doesn't check if the SC should succeed or fail, it just checks the 287 // value. 288 if (res && unverifiedReq->scResultValid()) 289 *res = unverifiedReq->getScResult(); 290 291 return NoFault; 292} 293 294 295#ifndef DOXYGEN_SHOULD_SKIP_THIS 296template 297Fault 298CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 299 300template 301Fault 302CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 303 304template 305Fault 306CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 307 308template 309Fault 310CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 311 312#endif //DOXYGEN_SHOULD_SKIP_THIS 313 314template<> 315Fault 316CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 317{ 318 return write(*(uint64_t*)&data, addr, flags, res); 319} 320 321template<> 322Fault 323CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 324{ 325 return write(*(uint32_t*)&data, addr, flags, res); 326} 327 328template<> 329Fault 330CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 331{ 332 return write((uint32_t)data, addr, flags, res); 333} 334 335 336#if FULL_SYSTEM 337Addr 338CheckerCPU::dbg_vtophys(Addr addr) 339{ 340 return vtophys(tc, addr); 341} 342#endif // FULL_SYSTEM 343 344bool 345CheckerCPU::translateInstReq(Request *req) 346{ 347#if FULL_SYSTEM 348 return (thread->translateInstReq(req) == NoFault); 349#else 350 thread->translateInstReq(req); 351 return true; 352#endif 353} 354 355void 356CheckerCPU::translateDataReadReq(Request *req) 357{ 358 thread->translateDataReadReq(req); 359 360 if (req->getVaddr() != unverifiedReq->getVaddr()) { 361 warn("%lli: Request virtual addresses do not match! Inst: %#x, " 362 "checker: %#x", 363 curTick, unverifiedReq->getVaddr(), req->getVaddr()); 364 handleError(); 365 } 366 req->setPaddr(unverifiedReq->getPaddr()); 367 368 if (checkFlags(req)) { 369 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", 370 curTick, unverifiedReq->getFlags(), req->getFlags()); 371 handleError(); 372 } 373} 374 375void 376CheckerCPU::translateDataWriteReq(Request *req) 377{ 378 thread->translateDataWriteReq(req); 379 380 if (req->getVaddr() != unverifiedReq->getVaddr()) { 381 warn("%lli: Request virtual addresses do not match! Inst: %#x, " 382 "checker: %#x", 383 curTick, unverifiedReq->getVaddr(), req->getVaddr()); 384 handleError(); 385 } 386 req->setPaddr(unverifiedReq->getPaddr()); 387 388 if (checkFlags(req)) { 389 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", 390 curTick, unverifiedReq->getFlags(), req->getFlags()); 391 handleError(); 392 } 393} 394 395bool 396CheckerCPU::checkFlags(Request *req) 397{ 398 // Remove any dynamic flags that don't have to do with the request itself. 399 unsigned flags = unverifiedReq->getFlags(); 400 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; 401 flags = flags & (mask); 402 if (flags == req->getFlags()) { 403 return false; 404 } else { 405 return true; 406 } 407} 408 409template <class DynInstPtr> 410void 411Checker<DynInstPtr>::tick(DynInstPtr &completed_inst) 412{ 413 DynInstPtr inst; 414 415 // Either check this instruction, or add it to a list of 416 // instructions waiting to be checked. Instructions must be 417 // checked in program order, so if a store has committed yet not 418 // completed, there may be some instructions that are waiting 419 // behind it that have completed and must be checked. 420 if (!instList.empty()) { 421 if (youngestSN < completed_inst->seqNum) { 422 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 423 completed_inst->seqNum, completed_inst->readPC()); 424 instList.push_back(completed_inst); 425 youngestSN = completed_inst->seqNum; 426 } 427 428 if (!instList.front()->isCompleted()) { 429 return; 430 } else { 431 inst = instList.front(); 432 instList.pop_front(); 433 } 434 } else { 435 if (!completed_inst->isCompleted()) { 436 if (youngestSN < completed_inst->seqNum) { 437 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 438 completed_inst->seqNum, completed_inst->readPC()); 439 instList.push_back(completed_inst); 440 youngestSN = completed_inst->seqNum; 441 } 442 return; 443 } else { 444 if (youngestSN < completed_inst->seqNum) { 445 inst = completed_inst; 446 youngestSN = completed_inst->seqNum; 447 } else { 448 return; 449 } 450 } 451 } 452 453 // Try to check all instructions that are completed, ending if we 454 // run out of instructions to check or if an instruction is not 455 // yet completed. 456 while (1) { 457 DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n", 458 inst->seqNum, inst->readPC()); 459 unverifiedResult.integer = inst->readIntResult(); 460 unverifiedReq = inst->req; 461 unverifiedMemData = inst->memData; 462 numCycles++; 463 464 Fault fault = NoFault; 465 466 // maintain $r0 semantics 467 thread->setIntReg(ZeroReg, 0); 468#ifdef TARGET_ALPHA 469 thread->setFloatRegDouble(ZeroReg, 0.0); 470#endif // TARGET_ALPHA 471 472 // Check if any recent PC changes match up with anything we 473 // expect to happen. This is mostly to check if traps or 474 // PC-based events have occurred in both the checker and CPU. 475 if (changedPC) { 476 DPRINTF(Checker, "Changed PC recently to %#x\n", 477 thread->readPC()); 478 if (willChangePC) { 479 if (newPC == thread->readPC()) { 480 DPRINTF(Checker, "Changed PC matches expected PC\n"); 481 } else { 482 warn("%lli: Changed PC does not match expected PC, " 483 "changed: %#x, expected: %#x", 484 curTick, thread->readPC(), newPC); 485 handleError(); 486 } 487 willChangePC = false; 488 } 489 changedPC = false; 490 } 491 if (changedNextPC) { 492 DPRINTF(Checker, "Changed NextPC recently to %#x\n", 493 thread->readNextPC()); 494 changedNextPC = false; 495 } 496 497 // Try to fetch the instruction 498 499#if FULL_SYSTEM 500#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 501#else 502#define IFETCH_FLAGS(pc) 0 503#endif 504 505 uint64_t fetch_PC = thread->readPC() & ~3; 506 507 // set up memory request for instruction fetch 508 memReq = new Request(inst->threadNumber, fetch_PC, 509 sizeof(uint32_t), 510 IFETCH_FLAGS(thread->readPC()), 511 fetch_PC, thread->readCpuId(), inst->threadNumber); 512 513 bool succeeded = translateInstReq(memReq); 514 515 if (!succeeded) { 516 if (inst->getFault() == NoFault) { 517 // In this case the instruction was not a dummy 518 // instruction carrying an ITB fault. In the single 519 // threaded case the ITB should still be able to 520 // translate this instruction; in the SMT case it's 521 // possible that its ITB entry was kicked out. 522 warn("%lli: Instruction PC %#x was not found in the ITB!", 523 curTick, thread->readPC()); 524 handleError(); 525 526 // go to the next instruction 527 thread->setPC(thread->readNextPC()); 528 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 529 530 return; 531 } else { 532 // The instruction is carrying an ITB fault. Handle 533 // the fault and see if our results match the CPU on 534 // the next tick(). 535 fault = inst->getFault(); 536 } 537 } 538 539 if (fault == NoFault) { 540 Packet *pkt = new Packet(memReq, Packet::ReadReq, 541 Packet::Broadcast); 542 543 pkt->dataStatic(&machInst); 544 545 icachePort->sendFunctional(pkt); 546 547 delete pkt; 548 549 // keep an instruction count 550 numInst++; 551 552 // decode the instruction 553 machInst = gtoh(machInst); 554 // Checks that the instruction matches what we expected it to be. 555 // Checks both the machine instruction and the PC. 556 validateInst(inst); 557 558 curStaticInst = StaticInst::decode(makeExtMI(machInst, 559 thread->readPC())); 560 561#if FULL_SYSTEM 562 thread->setInst(machInst); 563#endif // FULL_SYSTEM 564 565 fault = inst->getFault(); 566 } 567 568 // Discard fetch's memReq. 569 delete memReq; 570 memReq = NULL; 571 572 // Either the instruction was a fault and we should process the fault, 573 // or we should just go ahead execute the instruction. This assumes 574 // that the instruction is properly marked as a fault. 575 if (fault == NoFault) { 576 577 thread->funcExeInst++; 578 579 fault = curStaticInst->execute(this, NULL); 580 581 // Checks to make sure instrution results are correct. 582 validateExecution(inst); 583 584 if (curStaticInst->isLoad()) { 585 ++numLoad; 586 } 587 } 588 589 if (fault != NoFault) { 590#if FULL_SYSTEM 591 fault->invoke(tc); 592 willChangePC = true; 593 newPC = thread->readPC(); 594 DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); 595#else // !FULL_SYSTEM 596 fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC()); 597#endif // FULL_SYSTEM 598 } else { 599#if THE_ISA != MIPS_ISA 600 // go to the next instruction 601 thread->setPC(thread->readNextPC()); 602 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 603#else 604 // go to the next instruction 605 thread->setPC(thread->readNextPC()); 606 thread->setNextPC(thread->readNextNPC()); 607 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 608#endif 609 610 } 611 612#if FULL_SYSTEM 613 // @todo: Determine if these should happen only if the 614 // instruction hasn't faulted. In the SimpleCPU case this may 615 // not be true, but in the O3 or Ozone case this may be true. 616 Addr oldpc; 617 int count = 0; 618 do { 619 oldpc = thread->readPC(); 620 system->pcEventQueue.service(tc); 621 count++; 622 } while (oldpc != thread->readPC()); 623 if (count > 1) { 624 willChangePC = true; 625 newPC = thread->readPC(); 626 DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); 627 } 628#endif 629 630 // @todo: Optionally can check all registers. (Or just those 631 // that have been modified). 632 validateState(); 633 634 if (memReq) { 635 delete memReq; 636 memReq = NULL; 637 } 638 639 // Continue verifying instructions if there's another completed 640 // instruction waiting to be verified. 641 if (instList.empty()) { 642 break; 643 } else if (instList.front()->isCompleted()) { 644 inst = instList.front(); 645 instList.pop_front(); 646 } else { 647 break; 648 } 649 } 650} 651 652template <class DynInstPtr> 653void 654Checker<DynInstPtr>::switchOut(Sampler *s) 655{ 656 instList.clear(); 657} 658 659template <class DynInstPtr> 660void 661Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) 662{ 663} 664 665template <class DynInstPtr> 666void 667Checker<DynInstPtr>::validateInst(DynInstPtr &inst) 668{ 669 if (inst->readPC() != thread->readPC()) { 670 warn("%lli: PCs do not match! Inst: %#x, checker: %#x", 671 curTick, inst->readPC(), thread->readPC()); 672 if (changedPC) { 673 warn("%lli: Changed PCs recently, may not be an error", 674 curTick); 675 } else { 676 handleError(); 677 } 678 } 679 680 MachInst mi = static_cast<MachInst>(inst->staticInst->machInst); 681 682 if (mi != machInst) { 683 warn("%lli: Binary instructions do not match! Inst: %#x, " 684 "checker: %#x", 685 curTick, mi, machInst); 686 handleError(); 687 } 688} 689 690template <class DynInstPtr> 691void 692Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) 693{ 694 if (inst->numDestRegs()) { 695 // @todo: Support more destination registers. 696 if (inst->isUnverifiable()) { 697 // Unverifiable instructions assume they were executed 698 // properly by the CPU. Grab the result from the 699 // instruction and write it to the register. 700 RegIndex idx = inst->destRegIdx(0); 701 if (idx < TheISA::FP_Base_DepTag) { 702 thread->setIntReg(idx, inst->readIntResult()); 703 } else if (idx < TheISA::Fpcr_DepTag) { 704 thread->setFloatRegBits(idx, inst->readIntResult()); 705 } else { 706 thread->setMiscReg(idx, inst->readIntResult()); 707 } 708 } else if (result.integer != inst->readIntResult()) { 709 warn("%lli: Instruction results do not match! (Values may not " 710 "actually be integers) Inst: %#x, checker: %#x", 711 curTick, inst->readIntResult(), result.integer); 712 handleError(); 713 } 714 } 715 716 if (inst->readNextPC() != thread->readNextPC()) { 717 warn("%lli: Instruction next PCs do not match! Inst: %#x, " 718 "checker: %#x", 719 curTick, inst->readNextPC(), thread->readNextPC()); 720 handleError(); 721 } 722 723 // Checking side effect registers can be difficult if they are not 724 // checked simultaneously with the execution of the instruction. 725 // This is because other valid instructions may have modified 726 // these registers in the meantime, and their values are not 727 // stored within the DynInst. 728 while (!miscRegIdxs.empty()) { 729 int misc_reg_idx = miscRegIdxs.front(); 730 miscRegIdxs.pop(); 731 732 if (inst->tcBase()->readMiscReg(misc_reg_idx) != 733 thread->readMiscReg(misc_reg_idx)) { 734 warn("%lli: Misc reg idx %i (side effect) does not match! " 735 "Inst: %#x, checker: %#x", 736 curTick, misc_reg_idx, 737 inst->tcBase()->readMiscReg(misc_reg_idx), 738 thread->readMiscReg(misc_reg_idx)); 739 handleError(); 740 } 741 } 742} 743 744template <class DynInstPtr> 745void 746Checker<DynInstPtr>::validateState() 747{ 748} 749 750template <class DynInstPtr> 751void 752Checker<DynInstPtr>::dumpInsts() 753{ 754 int num = 0; 755 756 InstListIt inst_list_it = --(instList.end()); 757 758 cprintf("Inst list size: %i\n", instList.size()); 759 760 while (inst_list_it != instList.end()) 761 { 762 cprintf("Instruction:%i\n", 763 num); 764 765 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" 766 "Completed:%i\n", 767 (*inst_list_it)->readPC(), 768 (*inst_list_it)->seqNum, 769 (*inst_list_it)->threadNumber, 770 (*inst_list_it)->isCompleted()); 771 772 cprintf("\n"); 773 774 inst_list_it--; 775 ++num; 776 } 777 778} 779 780//template 781//class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >; 782 783template 784class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >; 785