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