cpu_impl.hh revision 8733:64a7bf8fa56c
1/*
2 * Copyright (c) 2011 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2006 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Kevin Lim
41 *          Geoffrey Blake
42 */
43
44#include <list>
45#include <string>
46
47#include "base/refcnt.hh"
48#include "config/the_isa.hh"
49#include "cpu/base_dyn_inst.hh"
50#include "cpu/exetrace.hh"
51#include "cpu/simple_thread.hh"
52#include "cpu/static_inst.hh"
53#include "cpu/thread_context.hh"
54#include "cpu/checker/cpu.hh"
55#include "debug/Checker.hh"
56#include "sim/sim_object.hh"
57#include "sim/stats.hh"
58
59#if FULL_SYSTEM
60#include "arch/vtophys.hh"
61#endif // FULL_SYSTEM
62
63using namespace std;
64using namespace TheISA;
65
66template <class Impl>
67void
68Checker<Impl>::advancePC(Fault fault)
69{
70    if (fault != NoFault) {
71        curMacroStaticInst = StaticInst::nullStaticInstPtr;
72        fault->invoke(tc, curStaticInst);
73        predecoder.reset();
74    } else {
75        if (curStaticInst) {
76            if (curStaticInst->isLastMicroop())
77                curMacroStaticInst = StaticInst::nullStaticInstPtr;
78            TheISA::PCState pcState = thread->pcState();
79            TheISA::advancePC(pcState, curStaticInst);
80            thread->pcState(pcState);
81            DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState());
82        }
83    }
84}
85//////////////////////////////////////////////////
86
87template <class Impl>
88void
89Checker<Impl>::handlePendingInt()
90{
91    DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n",
92                     thread->pcState(), instList.size());
93    DynInstPtr boundaryInst = NULL;
94    if (!instList.empty()) {
95        // Set the instructions as completed and verify as much as possible.
96        DynInstPtr inst;
97        typename std::list<DynInstPtr>::iterator itr;
98
99        for (itr = instList.begin(); itr != instList.end(); itr++) {
100            (*itr)->setCompleted();
101        }
102
103        inst = instList.front();
104        boundaryInst = instList.back();
105        verify(inst); // verify the instructions
106        inst = NULL;
107    }
108    if ((!boundaryInst && curMacroStaticInst &&
109          curStaticInst->isDelayedCommit() &&
110          !curStaticInst->isLastMicroop()) ||
111        (boundaryInst && boundaryInst->isDelayedCommit() &&
112         !boundaryInst->isLastMicroop())) {
113        panic("%lli: Trying to take an interrupt in middle of "
114              "a non-interuptable instruction!", curTick());
115    }
116    boundaryInst = NULL;
117    predecoder.reset();
118    curMacroStaticInst = StaticInst::nullStaticInstPtr;
119}
120
121template <class Impl>
122void
123Checker<Impl>::verify(DynInstPtr &completed_inst)
124{
125    DynInstPtr inst;
126
127    // Make sure serializing instructions are actually
128    // seen as serializing to commit. instList should be
129    // empty in these cases.
130    if ((completed_inst->isSerializing() ||
131        completed_inst->isSerializeBefore()) &&
132        (!instList.empty() ?
133         (instList.front()->seqNum != completed_inst->seqNum) : 0)) {
134        panic("%lli: Instruction sn:%lli at PC %s is serializing before but is"
135              " entering instList with other instructions\n", curTick(),
136              completed_inst->seqNum, completed_inst->pcState());
137    }
138
139    // Either check this instruction, or add it to a list of
140    // instructions waiting to be checked.  Instructions must be
141    // checked in program order, so if a store has committed yet not
142    // completed, there may be some instructions that are waiting
143    // behind it that have completed and must be checked.
144    if (!instList.empty()) {
145        if (youngestSN < completed_inst->seqNum) {
146            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
147                    completed_inst->seqNum, completed_inst->pcState());
148            instList.push_back(completed_inst);
149            youngestSN = completed_inst->seqNum;
150        }
151
152        if (!instList.front()->isCompleted()) {
153            return;
154        } else {
155            inst = instList.front();
156            instList.pop_front();
157        }
158    } else {
159        if (!completed_inst->isCompleted()) {
160            if (youngestSN < completed_inst->seqNum) {
161                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
162                        completed_inst->seqNum, completed_inst->pcState());
163                instList.push_back(completed_inst);
164                youngestSN = completed_inst->seqNum;
165            }
166            return;
167        } else {
168            if (youngestSN < completed_inst->seqNum) {
169                inst = completed_inst;
170                youngestSN = completed_inst->seqNum;
171            } else {
172                return;
173            }
174        }
175    }
176
177    // Make sure a serializing instruction is actually seen as
178    // serializing. instList should be empty here
179    if (inst->isSerializeAfter() && !instList.empty()) {
180        panic("%lli: Instruction sn:%lli at PC %s is serializing after but is"
181             " exiting instList with other instructions\n", curTick(),
182             completed_inst->seqNum, completed_inst->pcState());
183    }
184    unverifiedInst = inst;
185    inst = NULL;
186
187    // Try to check all instructions that are completed, ending if we
188    // run out of instructions to check or if an instruction is not
189    // yet completed.
190    while (1) {
191        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%s.\n",
192                unverifiedInst->seqNum, unverifiedInst->pcState());
193        unverifiedReq = NULL;
194        unverifiedReq = unverifiedInst->reqToVerify;
195        unverifiedMemData = unverifiedInst->memData;
196        // Make sure results queue is empty
197        while (!result.empty()) {
198            result.pop();
199        }
200        numCycles++;
201
202        Fault fault = NoFault;
203
204        // maintain $r0 semantics
205        thread->setIntReg(ZeroReg, 0);
206#ifdef TARGET_ALPHA
207        thread->setFloatRegDouble(ZeroReg, 0.0);
208#endif // TARGET_ALPHA
209
210        // Check if any recent PC changes match up with anything we
211        // expect to happen.  This is mostly to check if traps or
212        // PC-based events have occurred in both the checker and CPU.
213        if (changedPC) {
214            DPRINTF(Checker, "Changed PC recently to %s\n",
215                    thread->pcState());
216            if (willChangePC) {
217                if (newPCState == thread->pcState()) {
218                    DPRINTF(Checker, "Changed PC matches expected PC\n");
219                } else {
220                    warn("%lli: Changed PC does not match expected PC, "
221                         "changed: %s, expected: %s",
222                         curTick(), thread->pcState(), newPCState);
223                    CheckerCPU::handleError();
224                }
225                willChangePC = false;
226            }
227            changedPC = false;
228        }
229        if (changedNextPC) {
230            DPRINTF(Checker, "Changed NextPC recently to %#x\n",
231                    thread->nextInstAddr());
232            changedNextPC = false;
233        }
234
235        // Try to fetch the instruction
236        uint64_t fetchOffset = 0;
237        bool fetchDone = false;
238
239        while (!fetchDone) {
240            Addr fetch_PC = thread->instAddr();
241            fetch_PC = (fetch_PC & PCMask) + fetchOffset;
242
243            // If not in the middle of a macro instruction
244            if (!curMacroStaticInst) {
245                // set up memory request for instruction fetch
246                memReq = new Request(unverifiedInst->threadNumber, fetch_PC,
247                                     sizeof(MachInst),
248                                     0,
249                                     fetch_PC, thread->contextId(),
250                                     unverifiedInst->threadNumber);
251                memReq->setVirt(0, fetch_PC, sizeof(MachInst),
252                                Request::INST_FETCH, thread->instAddr());
253
254
255                fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
256
257                if (fault != NoFault) {
258                    if (unverifiedInst->getFault() == NoFault) {
259                        // In this case the instruction was not a dummy
260                        // instruction carrying an ITB fault.  In the single
261                        // threaded case the ITB should still be able to
262                        // translate this instruction; in the SMT case it's
263                        // possible that its ITB entry was kicked out.
264                        warn("%lli: Instruction PC %s was not found in the "
265                             "ITB!", curTick(), thread->pcState());
266                        handleError(unverifiedInst);
267
268                        // go to the next instruction
269                        advancePC(NoFault);
270
271                        // Give up on an ITB fault..
272                        delete memReq;
273                        unverifiedInst = NULL;
274                        return;
275                    } else {
276                        // The instruction is carrying an ITB fault.  Handle
277                        // the fault and see if our results match the CPU on
278                        // the next tick().
279                        fault = unverifiedInst->getFault();
280                        delete memReq;
281                        break;
282                    }
283                } else {
284                    PacketPtr pkt = new Packet(memReq,
285                                               MemCmd::ReadReq,
286                                               Packet::Broadcast);
287
288                    pkt->dataStatic(&machInst);
289                    icachePort->sendFunctional(pkt);
290                    machInst = gtoh(machInst);
291
292                    delete memReq;
293                    delete pkt;
294                }
295            }
296
297            if (fault == NoFault) {
298                TheISA::PCState pcState = thread->pcState();
299
300                if (isRomMicroPC(pcState.microPC())) {
301                    fetchDone = true;
302                    curStaticInst =
303                        microcodeRom.fetchMicroop(pcState.microPC(), NULL);
304                } else if (!curMacroStaticInst) {
305                    //We're not in the middle of a macro instruction
306                    StaticInstPtr instPtr = NULL;
307
308                    //Predecode, ie bundle up an ExtMachInst
309                    predecoder.setTC(thread->getTC());
310                    //If more fetch data is needed, pass it in.
311                    Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
312                    predecoder.moreBytes(pcState, fetchPC, machInst);
313
314                    //If an instruction is ready, decode it.
315                    //Otherwise, we'll have to fetch beyond the
316                    //MachInst at the current pc.
317                    if (predecoder.extMachInstReady()) {
318                        fetchDone = true;
319                        ExtMachInst newMachInst =
320                            predecoder.getExtMachInst(pcState);
321                        thread->pcState(pcState);
322                        instPtr = thread->decoder.decode(newMachInst,
323                                                         pcState.instAddr());
324                        machInst = newMachInst;
325                    } else {
326                        fetchDone = false;
327                        fetchOffset += sizeof(TheISA::MachInst);
328                    }
329
330                    //If we decoded an instruction and it's microcoded,
331                    //start pulling out micro ops
332                    if (instPtr && instPtr->isMacroop()) {
333                        curMacroStaticInst = instPtr;
334                        curStaticInst =
335                            instPtr->fetchMicroop(pcState.microPC());
336                    } else {
337                        curStaticInst = instPtr;
338                    }
339                } else {
340                    // Read the next micro op from the macro-op
341                    curStaticInst =
342                        curMacroStaticInst->fetchMicroop(pcState.microPC());
343                    fetchDone = true;
344                }
345            }
346        }
347        // reset predecoder on Checker
348        predecoder.reset();
349
350        // Check Checker and CPU get same instruction, and record
351        // any faults the CPU may have had.
352        Fault unverifiedFault;
353        if (fault == NoFault) {
354            unverifiedFault = unverifiedInst->getFault();
355
356            // Checks that the instruction matches what we expected it to be.
357            // Checks both the machine instruction and the PC.
358            validateInst(unverifiedInst);
359        }
360
361        // keep an instruction count
362        numInst++;
363
364
365        // Either the instruction was a fault and we should process the fault,
366        // or we should just go ahead execute the instruction.  This assumes
367        // that the instruction is properly marked as a fault.
368        if (fault == NoFault) {
369            // Execute Checker instruction and trace
370            if (!unverifiedInst->isUnverifiable()) {
371                Trace::InstRecord *traceData = tracer->getInstRecord(curTick(),
372                                                           tc,
373                                                           curStaticInst,
374                                                           pcState(),
375                                                           curMacroStaticInst);
376                fault = curStaticInst->execute(this, traceData);
377                if (traceData) {
378                    traceData->dump();
379                    delete traceData;
380                }
381            }
382
383            if (fault == NoFault && unverifiedFault == NoFault) {
384                thread->funcExeInst++;
385                // Checks to make sure instrution results are correct.
386                validateExecution(unverifiedInst);
387
388                if (curStaticInst->isLoad()) {
389                    ++numLoad;
390                }
391            } else if (fault != NoFault && unverifiedFault == NoFault) {
392                panic("%lli: sn: %lli at PC: %s took a fault in checker "
393                      "but not in driver CPU\n", curTick(),
394                      unverifiedInst->seqNum, unverifiedInst->pcState());
395            } else if (fault == NoFault && unverifiedFault != NoFault) {
396                panic("%lli: sn: %lli at PC: %s took a fault in driver "
397                      "CPU but not in checker\n", curTick(),
398                      unverifiedInst->seqNum, unverifiedInst->pcState());
399            }
400        }
401
402        // Take any faults here
403        if (fault != NoFault) {
404#if FULL_SYSTEM
405            fault->invoke(tc, curStaticInst);
406            willChangePC = true;
407            newPCState = thread->pcState();
408            DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
409            curMacroStaticInst = StaticInst::nullStaticInstPtr;
410#endif
411        } else {
412           advancePC(fault);
413        }
414
415#if FULL_SYSTEM
416        // @todo: Determine if these should happen only if the
417        // instruction hasn't faulted.  In the SimpleCPU case this may
418        // not be true, but in the O3 or Ozone case this may be true.
419        Addr oldpc;
420        int count = 0;
421        do {
422            oldpc = thread->instAddr();
423            system->pcEventQueue.service(tc);
424            count++;
425        } while (oldpc != thread->instAddr());
426        if (count > 1) {
427            willChangePC = true;
428            newPCState = thread->pcState();
429            DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
430        }
431#endif
432
433        // @todo:  Optionally can check all registers. (Or just those
434        // that have been modified).
435        validateState();
436
437        // Continue verifying instructions if there's another completed
438        // instruction waiting to be verified.
439        if (instList.empty()) {
440            break;
441        } else if (instList.front()->isCompleted()) {
442            unverifiedInst = NULL;
443            unverifiedInst = instList.front();
444            instList.pop_front();
445        } else {
446            break;
447        }
448    }
449    unverifiedInst = NULL;
450}
451
452template <class Impl>
453void
454Checker<Impl>::switchOut()
455{
456    instList.clear();
457}
458
459template <class Impl>
460void
461Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
462{
463}
464
465template <class Impl>
466void
467Checker<Impl>::validateInst(DynInstPtr &inst)
468{
469    if (inst->instAddr() != thread->instAddr()) {
470        warn("%lli: PCs do not match! Inst: %s, checker: %s",
471             curTick(), inst->pcState(), thread->pcState());
472        if (changedPC) {
473            warn("%lli: Changed PCs recently, may not be an error",
474                 curTick());
475        } else {
476            handleError(inst);
477        }
478    }
479
480    MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
481
482    if (mi != machInst) {
483        panic("%lli: Binary instructions do not match! Inst: %#x, "
484             "checker: %#x",
485             curTick(), mi, machInst);
486        handleError(inst);
487    }
488}
489
490template <class Impl>
491void
492Checker<Impl>::validateExecution(DynInstPtr &inst)
493{
494    uint64_t checker_val;
495    uint64_t inst_val;
496    int idx = -1;
497    bool result_mismatch = false;
498
499    if (inst->isUnverifiable()) {
500        // Unverifiable instructions assume they were executed
501        // properly by the CPU. Grab the result from the
502        // instruction and write it to the register.
503        copyResult(inst, 0, idx);
504    } else if (inst->numDestRegs() > 0 && !result.empty()) {
505        DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
506                         inst->numDestRegs(), result.size());
507        for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
508            result.front().get(checker_val);
509            result.pop();
510            inst_val = 0;
511            inst->template popResult<uint64_t>(inst_val);
512            if (checker_val != inst_val) {
513                result_mismatch = true;
514                idx = i;
515                break;
516            }
517        }
518    } // Checker CPU checks all the saved results in the dyninst passed by
519      // the cpu model being checked against the saved results present in
520      // the static inst executed in the Checker.  Sometimes the number
521      // of saved results differs between the dyninst and static inst, but
522      // this is ok and not a bug.  May be worthwhile to try and correct this.
523
524    if (result_mismatch) {
525        warn("%lli: Instruction results do not match! (Values may not "
526             "actually be integers) Inst: %#x, checker: %#x",
527             curTick(), inst_val, checker_val);
528
529        // It's useful to verify load values from memory, but in MP
530        // systems the value obtained at execute may be different than
531        // the value obtained at completion.  Similarly DMA can
532        // present the same problem on even UP systems.  Thus there is
533        // the option to only warn on loads having a result error.
534        // The load/store queue in Detailed CPU can also cause problems
535        // if load/store forwarding is allowed.
536        if (inst->isLoad() && warnOnlyOnLoadError) {
537            copyResult(inst, inst_val, idx);
538        } else {
539            handleError(inst);
540        }
541    }
542
543    if (inst->nextInstAddr() != thread->nextInstAddr()) {
544        warn("%lli: Instruction next PCs do not match! Inst: %#x, "
545             "checker: %#x",
546             curTick(), inst->nextInstAddr(), thread->nextInstAddr());
547        handleError(inst);
548    }
549
550    // Checking side effect registers can be difficult if they are not
551    // checked simultaneously with the execution of the instruction.
552    // This is because other valid instructions may have modified
553    // these registers in the meantime, and their values are not
554    // stored within the DynInst.
555    while (!miscRegIdxs.empty()) {
556        int misc_reg_idx = miscRegIdxs.front();
557        miscRegIdxs.pop();
558
559        if (inst->tcBase()->readMiscRegNoEffect(misc_reg_idx) !=
560            thread->readMiscRegNoEffect(misc_reg_idx)) {
561            warn("%lli: Misc reg idx %i (side effect) does not match! "
562                 "Inst: %#x, checker: %#x",
563                 curTick(), misc_reg_idx,
564                 inst->tcBase()->readMiscRegNoEffect(misc_reg_idx),
565                 thread->readMiscRegNoEffect(misc_reg_idx));
566            handleError(inst);
567        }
568    }
569}
570
571
572// This function is weird, if it is called it means the Checker and
573// O3 have diverged, so panic is called for now.  It may be useful
574// to resynch states and continue if the divergence is a false positive
575template <class Impl>
576void
577Checker<Impl>::validateState()
578{
579    if (updateThisCycle) {
580        // Change this back to warn if divergences end up being false positives
581        panic("%lli: Instruction PC %#x results didn't match up, copying all "
582             "registers from main CPU", curTick(), unverifiedInst->instAddr());
583
584        // Terribly convoluted way to make sure O3 model does not implode
585        bool inSyscall = unverifiedInst->thread->inSyscall;
586        unverifiedInst->thread->inSyscall = true;
587
588        // Heavy-weight copying of all registers
589        thread->copyArchRegs(unverifiedInst->tcBase());
590        unverifiedInst->thread->inSyscall = inSyscall;
591
592        // Set curStaticInst to unverifiedInst->staticInst
593        curStaticInst = unverifiedInst->staticInst;
594        // Also advance the PC.  Hopefully no PC-based events happened.
595        advancePC(NoFault);
596        updateThisCycle = false;
597    }
598}
599
600template <class Impl>
601void
602Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
603                          int start_idx)
604{
605    // We've already popped one dest off the queue,
606    // so do the fix-up then start with the next dest reg;
607    if (start_idx >= 0) {
608        RegIndex idx = inst->destRegIdx(start_idx);
609        if (idx < TheISA::FP_Base_DepTag) {
610            thread->setIntReg(idx, mismatch_val);
611        } else if (idx < TheISA::Ctrl_Base_DepTag) {
612            thread->setFloatRegBits(idx, mismatch_val);
613        } else if (idx < TheISA::Max_DepTag) {
614            thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag,
615                               mismatch_val);
616        }
617    }
618    start_idx++;
619    uint64_t res = 0;
620    for (int i = start_idx; i < inst->numDestRegs(); i++) {
621        RegIndex idx = inst->destRegIdx(i);
622        inst->template popResult<uint64_t>(res);
623        if (idx < TheISA::FP_Base_DepTag) {
624            thread->setIntReg(idx, res);
625        } else if (idx < TheISA::Ctrl_Base_DepTag) {
626            thread->setFloatRegBits(idx, res);
627        } else if (idx < TheISA::Max_DepTag) {
628            // Try to get the proper misc register index for ARM here...
629            thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, res);
630        } // else Register is out of range...
631    }
632}
633
634template <class Impl>
635void
636Checker<Impl>::dumpAndExit(DynInstPtr &inst)
637{
638    cprintf("Error detected, instruction information:\n");
639    cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
640            "Completed:%i\n",
641            inst->pcState(),
642            inst->nextInstAddr(),
643            inst->seqNum,
644            inst->threadNumber,
645            inst->isCompleted());
646    inst->dump();
647    CheckerCPU::dumpAndExit();
648}
649
650template <class Impl>
651void
652Checker<Impl>::dumpInsts()
653{
654    int num = 0;
655
656    InstListIt inst_list_it = --(instList.end());
657
658    cprintf("Inst list size: %i\n", instList.size());
659
660    while (inst_list_it != instList.end())
661    {
662        cprintf("Instruction:%i\n",
663                num);
664
665        cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
666                "Completed:%i\n",
667                (*inst_list_it)->pcState(),
668                (*inst_list_it)->seqNum,
669                (*inst_list_it)->threadNumber,
670                (*inst_list_it)->isCompleted());
671
672        cprintf("\n");
673
674        inst_list_it--;
675        ++num;
676    }
677
678}
679