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 &section)
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