?? fetch.cc
字號:
/* itterate through the fetch list */ for (int j = 0; j < SMT_MAX_THREADS; j++) { int thread = fetch_list[j].thread_number; /* look for this thread number in the active list */ for (int i = 0; i < active_index; i++) { /* If it's in the active list, * Put it into the temporary list so we can sort it */ if (active_list[i] == thread) { temp_list[templist_index] = fetch_list[j]; /* Must make sure that we have the latest priority information */ temp_list[templist_index].priority = thread_info[thread].priority; templist_index++; } } } /* RR policy requires these threads to be sorted into * descending priority order */ if (fetch_policy == RR) qsort(temp_list,templist_index, sizeof(ThreadListElement),rr_compare); /* put the inactive entries into the temp list */ for (int i = 0; i < inactive_index; i++) for (int j = 0; j < SMT_MAX_THREADS; j++) if (fetch_list[j].thread_number == inactive_list[i]) temp_list[templist_index++] = fetch_list[j]; /* copy back to the real list */ for (int i = 0; i < SMT_MAX_THREADS; i++) fetch_list[i] = temp_list[i]; }}voidFullCPU::change_thread_state(int thread_number, int activate, int priority){ // override specified priority if prioritization disabled via option if (!fetch_priority_enable) priority = 100; thread_info[thread_number].priority = priority; /* look for thread in the fetch list */ int ptr = -1; for (int i = 0; i < number_of_threads; i++) if (fetch_list[i].thread_number == thread_number) ptr = i; /* ptr >= 0 if we found it */ if (ptr >= 0) { thread_info[thread_number].active = activate; thread_info[thread_number].priority = priority; fetch_list[ptr].priority = priority; if (fetch_policy == RR) fetch_list[ptr].sort_key = priority; } else panic("fetch list is screwed up!"); /* make sure that the fetch list is kosher */ initialize_fetch_list(false);}/* Remove all instructions from a specific thread from the fetch queue */voidFullCPU::fetch_squash(int thread_number){ icache_output_buffer[thread_number]->squash(thread_number); // free ifq slots reserved for icache_output_buffer insts if (mt_frontend) ifq[thread_number].squash(); else ifq[0].squash(thread_number); icacheInterface->squash(thread_number);}/* initialize the instruction fetch pipeline stage */voidFullCPU::fetch_init(){ icache_block_size = icacheInterface->getBlockSize(); insts_per_block = icache_block_size / TheISA::fetchInstSize(); for (int i = 0; i < number_of_threads; i++) { /* allocate the IFETCH -> DISPATCH instruction queue */ if (!mt_frontend) { if (i == 0) ifq[0].init(this, ifq_size, number_of_threads); } else ifq[i].init(this, ifq_size, i); icache_output_buffer[i] = new IcacheOutputBuffer; icache_output_buffer[i]->init(fetch_width, i); fetch_stall[i] = 0; fetch_fault_count[i] = 0; }}voidFullCPU::clear_fetch_stall(Tick when, int thread_number, int stall_type){ if (fetch_stall[thread_number] == stall_type) { fetch_stall[thread_number] = 0; }}// ===========================================================================//// Events used here//voidClearFetchStallEvent::process(){ cpu->clear_fetch_stall(curTick, thread_number, stall_type); delete this;}const char *ClearFetchStallEvent::description(){ return "clear fetch stall";}voidFetchCompleteEvent::process(){ IcacheOutputBuffer *bufferp; IcacheOutputBufferEntry *entryp; int index = first_index; bufferp = cpu->icache_output_buffer[thread_number]; // checkmshrp->targets[target_idx]. to see if first instruction is // still valid entryp = &(bufferp->insts[first_index]); if (!entryp->inst || entryp->inst->fetch_seq != first_seq_num) { // squashed! no point in continuing, as any squash will // eliminate the whole group of instrs goto done; } // are the instrs we fetched at the head of the buffer? if so, // we'll want to copy them to the ifq as we go. if we allow // multiple fetches on the same thread and they complete out of // order, this may not be the case. if (first_index == bufferp->head) { for (int i = 0; i < num_insts; ++i) { entryp = &bufferp->insts[index]; if (cpu->mt_frontend) { cpu->ifq[entryp->inst->thread_number].append(entryp->inst); } else { cpu->ifq[0].append(entryp->inst); } entryp->inst = NULL; index = bufferp->incr(index); } // now copy any succeeding ready instrs (that were the result // of an out-of-order fetch completion) to the ifq while (entryp = &bufferp->insts[index], entryp->ready) { if (cpu->mt_frontend) { cpu->ifq[entryp->inst->thread_number].append(entryp->inst); } else { cpu->ifq[0].append(entryp->inst); } entryp->ready = false; entryp->inst = NULL; ++num_insts; index = bufferp->incr(index); } // update head & num_insts to reflect instrs copied to ifq bufferp->head = index; bufferp->num_insts -= num_insts; assert(bufferp->num_insts >= 0); } else { // just mak instrs as ready until preceding instrs complete fetch for (int i = 0; i < num_insts; ++i) { entryp = &(bufferp->insts[index]); entryp->ready = true; index = bufferp->incr(index); } } done: delete this;}const char *FetchCompleteEvent::description(){ return "fetch complete";}// ===========================================================================/** * Fetch one instruction from functional memory and execute it * functionally. * * @param thread_number Thread ID to fetch from. * @return A pair consisting of a pointer to a newly * allocated DynInst record and a fault code. The DynInst pointer may * be NULL if the fetch was unsuccessful. The fault code may reflect a * fault caused by the fetch itself (e.g., ITLB miss trap), or on the * functional execution. The fault code will be No_Fault if no * fault was encountered. */pair<DynInst *, Fault>FullCPU::fetchOneInst(int thread_number){ SpecExecContext *xc = thread[thread_number]; Addr pc = xc->regs.pc; // fetch instruction from *functional* memory into IR so we can // look at it MachInst IR; // instruction register#if FULL_SYSTEM#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0#else#define IFETCH_FLAGS(pc) 0#endif MemReqPtr req = new MemReq(pc & ~(Addr)3, xc, sizeof(MachInst), IFETCH_FLAGS(pc)); req->flags |= INST_READ; req->pc = pc; /** * @todo * Need to set asid correctly once we put in a unified memory system. */ // Need to make sure asid is 0 so functional memory works correctly req->asid = 0; Fault fetch_fault = xc->translateInstReq(req);#if FULL_SYSTEM if (xc->spec_mode && (fetch_fault != No_Fault || (req->flags & UNCACHEABLE) || xc->memctrl->badaddr(req->paddr))) { // Bad things can happen on misspeculated accesses to bad // or uncached addresses... stop now before it's too late return make_pair((DynInst *)NULL, No_Fault); }#endif if (fetch_fault == No_Fault) { // translation succeeded... attempt access fetch_fault = xc->mem->read(req, IR); } if (fetch_fault != No_Fault) {#if FULL_SYSTEM assert(!xc->spec_mode); xc->ev5_trap(fetch_fault); // couldn't fetch real instruction, so replace it with a noop IR = TheISA::NoopMachInst;#else fatal("Bad translation on instruction fetch, vaddr = 0x%x", req->vaddr);#endif } StaticInstPtr<TheISA> si(IR); // If SWP_SQUASH is set, filter out SW prefetch instructions right // away; we don't want them to even count against our fetch // bandwidth limit. if (softwarePrefetchPolicy == SWP_SQUASH && si->isDataPrefetch()) { xc->regs.pc += sizeof(MachInst); // need this for EIO syscall checking if (!xc->spec_mode) xc->func_exe_inst++; exe_swp[thread_number]++; // next instruction instead by calling fetchOneInst() // again recursively return fetchOneInst(thread_number); } // // Allocate a DynInst object and populate it // DynInst *inst = new DynInst(si); inst->fetch_seq = next_fetch_seq++; inst->PC = pc; inst->thread_number = thread_number; inst->asid = thread[thread_number]->getDataAsid(); inst->cpu = this; inst->xc = xc; inst->fault = fetch_fault; inst->spec_mode = xc->spec_mode; inst->trace_data = Trace::getInstRecord(curTick, xc, this, inst->staticInst, xc->regs.pc, thread_number); inst->correctPathSeq = (xc->spec_mode == 0) ? correctPathSeq[thread_number]++ : 0; // Predict next PC to fetch. // default guess: sequential inst->Pred_PC = pc + sizeof(MachInst); if (inst->isControl()) { // it's a control-flow instruction: check with predictor // FIXME: This should be a compressed fetch_address BranchPred::LookupResult result; if (branch_pred) { result = branch_pred->lookup(thread_number, pc, inst->staticInst, &inst->Pred_PC, &inst->dir_update); // The old branch predictor interface used a predicted PC of 0 // to indicate Predict_Not_Taken. In some rare cases (e.g., // underflow of an uninitialized return address stack), the // predictor will predict taken but provided a predicted // target of 0. With the old interface, this was // misinterpreted as a not-taken prediction. Since the new // predictor interface actually distinguishes these cases, it // gets slightly different misspeculation behavior, leading to // slightly different results. For exact emulation of the old // behavior, uncomment the code below. // // if (inst->Pred_PC == 0) { // inst->Pred_PC = pc + sizeof(MachInst); // result = BranchPred::Predict_Not_Taken; // } inst->btb_missed = (result == BranchPred::Predict_Taken_No_Target); } else { // Do perfect branch prediction // We can't set this yet. //inst->Pred_PC = inst->Next_PC; inst->btb_missed = false; } } /********************************************************/ /* */ /* Fill in the fetch queue entry */ /* */ /********************************************************/ IcacheOutputBufferEntry *buf_entry = icache_output_buffer[thread_number]->new_tail(); buf_entry->inst = inst; buf_entry->ready = false; if (mt_frontend) { ifq[thread_number].reserve(thread_number); assert(ifq[thread_number].num_total() <= ifq_size); } else { ifq[0].reserve(thread_number); assert(ifq[0].num_total() <= ifq_size); } /**********************************************************/ /* */ /* Execute this instruction. */ /* */ /**********************************************************/ if (inst->fault == No_Fault) inst->fault = execute_instruction(inst, thread_number); if (inst->fault != No_Fault) return make_pair(inst, inst->fault); if (!branch_pred) { // Do perfect branch prediction inst->Pred_PC = inst->Next_PC; } // // Update execution context's PC to point to next instruction to // fetch (based on predicted next PC). // // // Pipe-tracing... // // This doesn't quite work the way we might want it: // - The fourth parameter (latency) is supposed to indicate the // cache miss delay... // - The fifth parameter (longest latency event) is designed // to indicate which of several events took the longest... // since our model doesn't generate events, this // isn't used here either. // if (ptrace) { ptrace->newInst(inst); ptrace->moveInst(inst, PipeTrace::Fetch, 0, 0, 0); } /* * Handle the transition "into" mis-speculative mode * (note that we may _already_ be misspeculating) * * There are two "forms" of misspeculation that we have to * deal with: * (1) Mispredicting the direction of a branch * (2) Mispredicting the */ if (inst->Pred_PC != inst->Next_PC) { // Conflicting maps are also recover insts, but why? Perhaps // because all of the aliased registers are updated? But // that shouldn't matter for a renaming machine with the LRT. // Ah, except the LRT won't be updated until the map executes, // which is too late. inst->recover_inst = true; xc->spec_mode++; } return make_pair(inst, No_Fault);}/** * Fetch several instructions (up to a full cache line) from * functional memory and execute them functionally (by calling * fetchOneInst()). Fetching will cease if the end of the current * cache line is reached, a predicted-taken branch is encountered, a * fault occurs, the fetch queue fills up, or the CPU parameter limits * on instructions or branches per cycle are reached. In the first * two cases, fetching can continue for this thread in this cycle in * another block; in the remaining cases, fetching for this thread * must be terminated for this cycle. * * @param thread_number Thread ID to fetch from. * @param max_to_fetch Maximum number of instructions to fetch. * @param branch_cnt Reference to number of branches fetched this cycle * for the current thread. This value will be updated if any branches * are fetched. * @return A pair combining an integer indicating * the number of instructions fetched and a boolean indicating whether * fetching on the current thread should continue. */pair<int, bool>FullCPU::fetchOneLine(int thread_number, int max_to_fetch, int &branch_cnt, bool entering_interrupt){ SpecExecContext *xc = thread[thread_number]; int num_fetched = 0; // remember start address of current line, so we can tell if we
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -