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