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