?? dispatch.cc
字號:
// If we run out of chains... // case FLOSS_DIS_POLICY: done = true; break; case FLOSS_DIS_CAUSE_NOT_SET: done = false; break; default: warn("need to adjust endCauses for dispatch_thread()"); done = false; } if (queue_endCause == FLOSS_DIS_CAUSE_NOT_SET) { if (decodeQueue->instsAvailable(thread) == 0) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_NO_INSN); done = true; // nothing left to dispatch } } if (dispatched_this_cycle == dispatch_width) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_BW); done = true; // we used all available BW } if (done) SET_FIRST_FLOSS_CAUSE(endCause, queue_endCause); } while (!done); assert(endCause != FLOSS_DIS_CAUSE_NOT_SET); break; case MODULO_N: // // We dispatch A SINGLE thread to as many IQ's as necessary. // // rotate through all the IQ's until: // (1) We run out of instructions to dispatch // (2) We try to dispatch to an IQ, and fail // // ==> This means that we have to check each IQ for caps, etc // as we rotate through... // lastDispatchTime[thread] = curTick; do { DispatchEndCause queue_endCause = FLOSS_DIS_CAUSE_NOT_SET; unsigned dispatched_this_queue = dispatch_thread(thread, iq_idx, dispatch_width, queue_endCause); dispatched_this_cycle += dispatched_this_queue; switch (queue_endCause) { // // The following end-causes indicate that we can't dispatch // any more instructions this cycle // case FLOSS_DIS_ROB_FULL: case FLOSS_DIS_LSQ_FULL: case FLOSS_DIS_IREG_FULL: case FLOSS_DIS_FPREG_FULL: done = true; endCause = queue_endCause; break; // // The following end-causes indicate that we can't continue // dispatching this thread this cycle // case FLOSS_DIS_ROB_CAP: case FLOSS_DIS_NO_INSN: done = true; endCause = queue_endCause; break; // // The following end-causes indicate that we can't continue // dispatching to this Queue, but should try the next one // case FLOSS_DIS_IQ_FULL: case FLOSS_DIS_IQ_CAP: case FLOSS_DIS_BW: case FLOSS_DIS_POLICY: endCause = queue_endCause; // done = false; done = true; break; case FLOSS_DIS_CAUSE_NOT_SET: done = false; break; default: warn("need to adjust endCauses for dispatch_thread()"); done = false; } if (queue_endCause == FLOSS_DIS_CAUSE_NOT_SET) { if (decodeQueue->instsAvailable(thread) == 0) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_NO_INSN); done = true; // nothing left to dispatch } } if (dispatched_this_cycle == dispatch_width) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_BW); done = true; // we used all available BW } if (!done) {#if 0 // Rotate to the next IQ iq_idx = choose_iqueue(thread); if ((iq_idx < 0) || (iq_idx == first)) { done = true; // we call this policy... SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_POLICY); }#endif } else SET_FIRST_FLOSS_CAUSE(endCause, queue_endCause); } while (!done); assert(endCause != FLOSS_DIS_CAUSE_NOT_SET); break; case THREAD_PER_QUEUE: // // Walk the sorted list of threads, dispatching as many insts // from each as possible. // for (unsigned t = 0; t < SMT_MAX_THREADS; ++t) { if (tlist[t].eligable) { unsigned dispatched_this_thread = 0; unsigned iq_idx = tlist[t].iq_idx; unsigned thread = tlist[t].thread_number; unsigned possible_dispatches = dispatch_width - dispatched_this_cycle; dispatched_this_thread = dispatch_thread(thread, iq_idx, possible_dispatches, endCause); dispatched_this_cycle += dispatched_this_thread; bool done; switch (endCause) { // // The following end-causes indicate that we can't dispatch // any more instructions this cycle // case FLOSS_DIS_ROB_FULL: case FLOSS_DIS_LSQ_FULL: case FLOSS_DIS_IREG_FULL: case FLOSS_DIS_FPREG_FULL: done = true; // stop dispatching break; // // The following end-causes indicate that we can't // continue dispatching this thread this cycle // case FLOSS_DIS_ROB_CAP: case FLOSS_DIS_NO_INSN: case FLOSS_DIS_POLICY: done = false; // continue dispatching break; // // The following end-causes indicate that we can't continue // dispatching to this Queue, but should try the next one // case FLOSS_DIS_IQ_FULL: case FLOSS_DIS_IQ_CAP: case FLOSS_DIS_BW: done = false; // continue dispatching break; case FLOSS_DIS_CAUSE_NOT_SET: done = false; break; default: warn("need to adjust endCauses for dispatch_thread()"); done = false; } if (done) break; if (dispatched_this_cycle == dispatch_width) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_BW); break; // we used _all_ available BW } // // If we dispatched all available instructions // for this thread, and the "next" thread is going // to try to dispatch, then reset the endCause // if (dispatched_this_thread == tlist[t].disp_insts && t < (SMT_MAX_THREADS - 1) && tlist[t + 1].eligable) endCause = FLOSS_DIS_CAUSE_NOT_SET; } else { // endCause will have been set earlier, when we assigned // scores break; // no other threads will be eligible } } break; } // // Anything that we didn't set a cause for before this point, MUST // be a thread that we _could_ have dispatched, but chose not to // if (floss_state.dispatch_end_cause == FLOSS_DIS_CAUSE_NOT_SET) floss_state.dispatch_end_cause = FLOSS_DIS_BROKEN;#if DUMP_IQ IQ[0]->dump(0);#endif}//// Return the desired cluster//unsignedFullCPU::choose_dependence_cluster(DynInst *inst){ unsigned thread = inst->thread_number; RegInfoTable * rit = clusterSharedInfo->ri_table; bool chained = false; Tick pred_ready = 0; unsigned pred_cluster = IQLeastFull(); // default if no chained idep for (int i = 0; i < inst->numSrcRegs(); ++i) { unsigned ireg = inst->srcRegIdx(i); // // If we have an input register that is not yet ready and is chained // chained = (*rit)[thread][ireg].isChained(); if (create_vector[thread].entry(ireg).rs != 0) { if ((*rit)[thread][ireg].predReady() > pred_ready) { pred_ready = (*rit)[thread][ireg].predReady(); pred_cluster = (*rit)[thread][ireg].cluster(); } } else { // sanity check: if the input reg does not have a creator, // it had better not be chained... assert(!chained); } } return pred_cluster;}//// Dispatch the next 'max' instructions for thread number 'thread' to// Instruction queue 'iq_idx'.//// Returns:// - The number of instructions actually dispatched// (squashed instructions _do_ count)// - The reason we stopped dispatching// (this value will NOT be set if we stop due to reaching 'max')//// Dispatch End Causes Returned:// FLOSS_DIS_NO_INSN --> No more instructions to dispatch for this thread// FLOSS_DIS_BW --> No BW left for this queue//// FLOSS_DIS_IQ_FULL {via checkThreadForDispatch()}// FLOSS_DIS_IQ_CAP {via checkThreadForDispatch()}// FLOSS_DIS_LSQ_FULL {via checkThreadForDispatch()}// FLOSS_DIS_ROB_FULL {via checkThreadForDispatch()}// FLOSS_DIS_ROB_CAP {via checkThreadForDispatch()}// FLOSS_DIS_IREG_FULL {via checkThreadForDispatch()}// FLOSS_DIS_FPREG_FULL {via checkThreadForDispatch()}//unsignedFullCPU::dispatch_thread(unsigned thread, unsigned iq_idx, unsigned max, DispatchEndCause &endCause){ ROBStation *rob; unsigned dCount = 0; unsigned first_idx; bool using_loose_mod_n = false; DPRINTF(Pipeline, "DISP: dispatch_thread (thread %d) (clust %d)\n", thread, iq_idx); // Default case... no maximum value if (max == 0) { max = dispatch_width; } first_idx = iq_idx; // // Dispatch until: // (1) An instruction fails to dispatch // (2) We dispatch the "max" number of instructions // (3) We run out of decodeQueue bandwidth // do { DynInst * inst = decodeQueue->peek(thread); // // If this inst hasn't been squashed... // if (inst != 0) { // If it's a serializing instruction, flush the pipeline // by stalling here until all older instructions have // committed. Do this before checking for No_OpClass, // since instructions that only serialize (e.g. Alpha // trapb) will have No_OpClass and thus get discarded // before being dispatched once the serialization is // complete. if (inst->isSerializing() && ROB.num_thread(thread) != 0) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_SERIALIZING); ++dispatch_serialize_stall_cycles[thread]; break; } else if (inst->fault == No_Fault && (inst->opClass() == No_OpClass || inst->isNop() || inst->isInstPrefetch())) { // Drop things that don't need to go any farther in the // pipeline. This includes all instructions that do not // use a function unit (i.e. have No_OpClass for their op // class). This should include all instructions that // declare themselves as no-ops (isNop()), but just to be // sure we'll check that too. We're also dropping // instruction prefetches here for historical reasons (in // practice we don't have any, I believe). if (ptrace) { ptrace->moveInst(inst, PipeTrace::Dispatch, 0, 0, 0); ptrace->deleteInst(inst); } // Copied this here from dispatch_one_inst() since // insts that get discarded here never make it to that // function. Causes minor inconsistencies since these // don't get counted in some other stats, but oh well. if (inst->isSerializing()) ++dispatched_serializing[thread]; delete inst; inst = 0; // not going to need this one... decodeQueue->remove(thread); ++dCount; } else { DispatchEndCause cause; unsigned output_reg = 0; bool output_reg_valid = false; if (numIQueues == 1) { cause = checkThreadForDispatch(thread, iq_idx, 1); } else { // // Some dispatch policies require decisions to be made // for each instruction... // switch (dispatch_policy) { case DEPENDENCE: // // Find the output register // (--> assumes only one output register per // instruction) // for (int i = 0; i < inst->numDestRegs(); ++i) { output_reg = inst->destRegIdx(i); output_reg_valid = true; break; } // // Now pick the Cluster... // iq_idx = choose_dependence_cluster(inst); // // Check for available resources // cause = checkThreadForDispatch(thread, iq_idx, 1); // // Just because we can't put the instruction where // we want it doesn't mean that we shouldn't dispatch // it... // if (cause == FLOSS_DIS_BW) { // No IQ bandwidth for our preferred IQ... // --> try to dispatch to the least full IQ, but // if that also fails, blame the original IQ // BW problem unsigned new_idx = IQLeastFull(); DispatchEndCause new_cause = checkThreadForDispatch(thread, new_idx, 1); if (new_cause == FLOSS_DIS_CAUSE_NOT_SET) { // go with the new IQ cause = new_cause; iq_idx = new_idx; } } break; case MODULO_N: cause = checkThreadForDispatch(thread, iq_idx, 1); if (cause == FLOSS_DIS_IQ_FULL || cause == FLOSS_DIS_IQ_CAP || cause == FLOSS_DIS_BW) { DispatchEndCause temp = cause; unsigned n = IQFreeSlotsX(iq_idx); if (n) { ++mod_n_disp_stalls[thread]; mod_n_disp_stall_free[thread] += n; // // Loose Mod-N: // // if we'd normally just quit, try to find a // different cluster for these instructions // if (loose_mod_n_policy) { do { iq_idx = (iq_idx+1) % numIQueues; if (iq_idx == first_idx) { cause = temp; break; } cause = checkThreadForDispatch (thread, iq_idx, 1); } while (cause != FLOSS_DIS_CAUSE_NOT_SET); if (cause == FLOSS_DIS_CAUSE_NOT_SET) using_loose_mod_n = true; } } } break; default: // // "normal case": Just check for available resources // cause = checkThreadForDispatch(thread, iq_idx, 1); break; } } if (cause != FLOSS_DIS_CAUSE_NOT_SET) { SET_FIRST_FLOSS_CAUSE(endCause, cause); break; } // // Dispatch this instruction // rob = dispatch_one_inst(inst, iq_idx); // // Policy-Dependant post-processing // if (numIQueues > 1) { switch (dispatch_policy) { case MODULO_N: if ((rob != 0) && ((dispatch_count[thread]) % MODULO_VAL)) { mod_n_queue_idx = ++mod_n_queue_idx % numIQueues; if (!using_loose_mod_n) { iq_idx = mod_n_queue_idx; first_idx = iq_idx; } } break; default: break; } } // // If we dispatched the instruction... // if (rob != 0) { // remove it from the decode queue decodeQueue->remove(thread); ++dCount; if (dispatch_policy == DEPENDENCE) { if (output_reg_valid) { rob->output_reg = output_reg; (*clusterSharedInfo->ri_table)[thread][output_reg]. setCluster(iq_idx); } } if (decodeQueue->instsAvailable(thread) == 0) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_NO_INSN); break; } } else { // this should really never happen... // ==> It can if the segmented IQ enters deadlock // recovery mode! // warn("dispatch_one_inst() failed @%d!", curTick); endCause = FLOSS_DIS_POLICY; break; } } } else { // // Squashed instruction // decodeQueue->remove(thread); ++dCount; } // // We must have instructions to continue... // if (decodeQueue->instsAvailable(thread) == 0) { SET_FIRST_FLOSS_CAUSE(endCause, FLOSS_DIS_NO_INSN); break; } DispatchEndCause c = checkGlobalResourcesForDispatch(1); if (c != FLOSS_DIS_CAUSE_NOT_SET) { SET_FIRST_FLOSS_CAUSE(endCause, c); break; } // Check to see if we've dispatched the specified maximum number of // instructions if (dCount >= max) break; } while (true); return dCount;}////// Dispatch this instruction to the specified queue////ROBStation *FullCPU::dispatch_one_inst(DynInst *inst, unsigned iq_idx){ if (dispatch_break && (dispatch_break == dispatch_seq)) dispatch_breakpoint(); unsigned thread = inst->thread_number; if (DTRACE(Pipeline)) { string s; inst->dump(s); DPRINTF(Pipeline, "Dispatch %s\n", s); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -