📄 issue.cc
字号:
if (fu_lat == -2) fatal("Function unit type not available!"); if (!dcacheInterface->isBlocked()) { if (fu_lat >= 0) { stat_issued_inst_type[i->thread_number()][MemWriteOp]++; MemReqPtr req = new MemReq(); req->thread_num = i->thread_number(); req->asid = i->asid; if (i->isCopy) { req->cmd = Copy; req->vaddr = i->srcVirtAddr; req->paddr = i->srcPhysAddr; req->dest = i->phys_addr; } else { req->cmd = Write; req->vaddr = i->virt_addr; req->paddr = i->phys_addr; Event *completion_event = new SimCompleteStoreEvent(storebuffer, i, req); req->completionEvent = completion_event; } req->flags = i->mem_req_flags; req->size = i->size; req->time = curTick; req->data = new uint8_t[i->size]; if (i->data) { memcpy(req->data, i->data, i->size); } req->xc = i->xc; assert((req->paddr & ((Addr)req->size-1)) == 0); dcacheInterface->access(req); i->issued = true; } else { // // This problem is accounted for when the store-buffer // fills up. // stat_fu_busy[MemWriteOp]++; stat_fuBusy[pool_num][MemWriteOp]++; fu_busy[i->thread_number()]++; } } return i->issued;}// //// Issue an instruction from the IQ//boolFullCPU::iq_issue(BaseIQ::iterator i, unsigned fu_pool_num){ bool issued = false; int fu_lat; /* * check to make sure that the instruction has spent enough time * in the "issue stage" to be issued */ if (curTick < (i->dispatch_timestamp + dispatch_to_issue_latency)) { if (floss_state.issue_end_cause[0] == ISSUE_CAUSE_NOT_SET) floss_state.issue_end_cause[0] = ISSUE_AGE; // note the reason this inst didn't issue dist_unissued[UNISSUED_TOO_YOUNG]++; return false; } OpClass fu_type = i->opClass(); // instructions that don't need a function unit usually don't make // it out of dispatch... the "faulting no-op" introduced on an // ifetch TLB miss is the exception. Route it through an integer // ALU just to get it to WB. if (fu_type == No_OpClass) { assert(i->inst->fault != No_Fault); fu_type = IntAluOp; } unsigned thread = i->thread_number(); fu_lat = FUPools[fu_pool_num]->getUnit(fu_type); assert(!i->inst->isInstPrefetch() && "Issued instruction prefetch! (should never do so)"); if (fu_lat == -2) panic("Function unit type not available!"); if (fu_lat >= 0) { issued = true; stat_issued_inst_type[i->thread_number()][i->opClass()]++; assert(!i->inst->isInstPrefetch() && "Instruction prefetch in issue stage!"); } else { // // No FU available // // Indicate that we couldn't issue because no fu available stat_fu_busy[fu_type]++; stat_fuBusy[fu_pool_num][fu_type]++; fu_busy[thread]++; if (floss_state.issue_end_cause[0] == ISSUE_CAUSE_NOT_SET) { floss_state.issue_end_cause[0] = ISSUE_FU; // only use element zero for ISSUE_FU floss_state.issue_fu[0][0] = fu_type; } // note the reason this inst didn't issue dist_unissued[fu_type]++; } if (issued) { // Inform the LSQ that this instruction is issuing LSQ->inform_issue(i); i->rob_entry->issued = true; /* Schedule writeback event after i->latency cycles unless: * - it's a store (which completes immediately), indicated by * i->rob_entry->completed already being set * or * - it's a cache miss load (for which the writeback event will * be scheduled on a later callback from the memory system), * indicated by a negative value for latency */ /* queue up the rob entry, since we're going to delete * the iq entry * * even stores need to go through writeback... * (they need to have their entry removed from the lsq * and mark the rob entry as ready for the storebuffer) */ if (!i->rob_entry->completed && (fu_lat >= 0)) { WritebackEvent *wb_event = new WritebackEvent(this, i->rob_entry); // so we can invalidate on a squash i->rob_entry->wb_event = wb_event; wb_event->schedule(curTick + cycles(fu_lat)); } (i->rob_entry)->iq_entry = NULL; /* ROB ptr to IQ */ } return issued;}// boolFullCPU::lsq_issue(BaseIQ::iterator i, unsigned fu_pool_num){ bool issued = false; int fu_lat = 0; int latency = 0; bool store_inst = false; /* * check to make sure that the instruction has spent enough time * in the "issue stage" to be issued */ if (curTick < (i->dispatch_timestamp + dispatch_to_issue_latency)) { if (floss_state.issue_end_cause[0] == ISSUE_CAUSE_NOT_SET) floss_state.issue_end_cause[0] = ISSUE_AGE; // note the reason this inst didn't issue dist_unissued[UNISSUED_TOO_YOUNG]++; return false; } unsigned thread = i->thread_number(); OpClass fu_type = i->opClass(); // // If this is the LSQ portion of a STORE. // // (All stores pass through this code) // if (i->in_LSQ && i->inst->isStore()) { issued = true; latency = cycles(1); store_inst = true; } else if (fu_type != No_OpClass) { // this "if" is probably a waste... // // Load instructions require a functional unit // fu_type = i->opClass(); fu_lat = FUPools[fu_pool_num]->getUnit(fu_type); if (fu_lat == -2) { fatal("Function unit type not available!"); } if (fu_lat >= 0) { // the default... latency = cycles(fu_lat); if (i->inst->isLoad()) { // // Don't do anything if the cache is blocked // bool isPrefetch = i->inst->isDataPrefetch(); if (!dcacheInterface->isBlocked()) { // Actually, unless the ALAT is being used, this op // will ALWAYS issue... // LSQ part of load: May or may not issue. // "latency" is returned via arg list... negative value // indicates that issue should not generate a WB event if (isPrefetch) issued = issue_prefetch(i, &latency); else issued = issue_load(i, &latency); } else { // // Set cause the first time through only // if (floss_state.issue_end_cause[0] == ISSUE_CAUSE_NOT_SET) { floss_state.issue_end_cause[0] = ISSUE_MEM_BLOCKED; // FIXME! // This information needs to come out of the cache floss_state.issue_mem_result[0] = MA_MSHRS_FULL; } // note the reason this inst didn't issue dist_unissued[UNISSUED_CACHE_BLOCKED]++; } } else { // // Store instruction... Issue to FU // issued = true; } if (issued) { // reserve the functional unit stat_issued_inst_type[i->thread_number()][i->opClass()]++; } } else { // // No FU available // // Indicate that we couldn't issue because no fu available stat_fu_busy[fu_type]++; stat_fuBusy[fu_pool_num][fu_type]++; fu_busy[thread]++; if (floss_state.issue_end_cause[0] == ISSUE_CAUSE_NOT_SET) { floss_state.issue_end_cause[0] = ISSUE_FU; // only use element zero for ISSUE_FU floss_state.issue_fu[0][0] = fu_type; } // note the reason this inst didn't issue dist_unissued[fu_type]++; } } else { issued = true; latency = cycles(1); } // // If the instruction was issued... // if (issued) { // Inform the IQ that this instruction is issuing // // NOTE: Store instructions whose data value is ready prior to // the EA will NOT pass through here! // // we do this later, when we inform all clusters // that this inst issued... // IQ[i->rob_entry->queue_num]->inform_issue(i); i->rob_entry->issued = true; // Schedule writeback event after i->latency cycles unless: // - it's a cache miss load // (for which the writeback event will be scheduled on a later // callback from the memory system) // ==> indicated by a negative value for latency // - it's a load prefetch (these get marked completed when issued) // (note that store prefetches that potentially modify cache data, // e.g. wh64, still get writeback events, as they need to be // ordered w.r.t. other stores) // // even stores need to go through writeback... // (they need to have their entry removed from the lsq // and mark the rob entry as ready for the storebuffer) // if (latency < 0 || (i->inst->isDataPrefetch() && i->inst->isLoad())) { // // Do not create a writeback event // } else { WritebackEvent *wb_event = new WritebackEvent(this, i->rob_entry); // so we can invalidate on a squash i->rob_entry->wb_event = wb_event; assert(latency >= clock); wb_event->schedule(curTick + latency); } if (DTRACE(Pipeline)) { string s; i->inst->dump(s); DPRINTF(Pipeline, "Issue %s\n", s); } } return issued;}// //// Find the Input Dependants that are not ready... not the type of// function unit that produces the operand//boolFullCPU::find_idep_to_blame(BaseIQ::iterator inst, int thread){ bool found_fu = false; if (!inst->in_LSQ) { for (int i = 0; i < inst->num_ideps; ++i) { if (!inst->idep_ready[i]) { found_fu = true; ROBStation *rob = inst->idep_ptr[i]->rob_producer; OpClass op_class = rob->inst->opClass(); assert(op_class != No_OpClass); floss_state.issue_fu[thread][i] = op_class; } else { floss_state.issue_fu[thread][i] = No_OpClass; } } } else { // // If the problem is an instruction from the LSQ // if (inst->inst->isStore() && !inst->idep_ready[STORE_DATA_INDEX]) { // store is waiting for its data... ROBStation *rob = inst->idep_ptr[STORE_DATA_INDEX]->rob_producer; floss_state.issue_fu[thread][STORE_DATA_INDEX] = rob->inst->opClass(); found_fu = true; } // This works for both loads & stores if (!inst->idep_ready[MEM_ADDR_INDEX]) { floss_state.issue_fu[thread][MEM_ADDR_INDEX] = IntAluOp; found_fu = true; } } return found_fu;}// class IQList{ private: unsigned number_of_queues; vector<bool> done_with_queue; unsigned num_done; public: IQList(unsigned num_iq) { number_of_queues = num_iq; done_with_queue.resize(number_of_queues, false); num_done = 0; } bool allDone() {return num_done == number_of_queues;} bool markDone(unsigned q) { assert(q < number_of_queues); if (!done_with_queue[q]) { done_with_queue[q] = true; ++num_done; } return allDone(); } bool done(unsigned q) { assert(q < number_of_queues); return done_with_queue[q]; } // find the next NOT Done queue // return false if there's a problem bool next(unsigned &q) { assert(q < number_of_queues); assert(num_done < number_of_queues); if (number_of_queues == 1) { return false; } bool done = false; bool rv = true; unsigned next_queue = q; do { // increment to the NEXT index (w/ wrap) next_queue = (next_queue + 1) % number_of_queues; // if we've wrapped all the way around, deal with it if (next_queue == q) { done = true; rv = false; } else { // haven't wrapped yet ... // if this queue is not done, return it... if (!done_with_queue[next_queue]) { q = next_queue; done = true; } } } while (!done); return rv; }};// attempt to issue all operations in the ready queue; insts in the// ready instruction queue have all register dependencies satisfied,// this function must then 1) ensure the instructions memory// dependencies have been satisfied (see lsq_refresh() for details// on this process) and 2) a function unit is available in this// cycle to commence execution of the operation; if all goes well,// the function unit is allocated, a writeback event is scheduled,// and the instruction begins executionvoidFullCPU::issue(){ int n_issued; bool done_with_sb = false; bool done_with_iq = false; bool done_with_lsq = false; unsigned issued_by_thread[SMT_MAX_THREADS]; unsigned iq_count = 0; unsigned lsq_count = 0; unsigned sb_count = 0; enum inst_source {none, iq, lsq, sb}; inst_source source; BaseIQ::iterator evil_inst = 0; BaseIQ::rq_iterator *iq_rq_iterator = new BaseIQ::rq_iterator[numIQueues];#ifdef DEBUG_ISSUE std::cerr << "-------------------------------" << std::endl; std::cerr << " ISSUE cycle: " << curTick << std::endl; std::cerr << "-------------------------------" << std::endl;#endif // for each queue, the list of RQ iterators to instructions belonging // to the high-priority thread list<BaseIQ::rq_iterator> *hp_rq_it_list = new list<BaseIQ::rq_iterator>[numIQueues]; for (int i = 0; i < SMT_MAX_THREADS; ++i) issued_by_thread[i] = 0; BaseIQ::rq_iterator lsq_rq_iterator = LSQ->issuable_list(); StoreBuffer::rq_iterator sb_rq_iterator = storebuffer->issuable_list(); // We will start issuing out of this IQ unsigned current_iq = issue_starting_iqueue; unsigned current_fu_pool = issue_starting_fu_pool; // Increment the last_iq index (RR fashion) for next cycle issue_starting_iqueue = (++issue_starting_iqueue % numIQueues); issue_starting_fu_pool = (++issue_starting_fu_pool % numFUPools); // visit all ready instructions (i.e., insts whose register input // dependencies have been satisfied, stop issue when no more instructions // are available or issue bandwidth is exhausted n_issued = 0; // // Check to see if we need to change HP thread // if (prioritize_issue && (hp_thread_change <= curTick)) { hp_thread = ++hp_thread % number_of_threads; // schedule the next change hp_thread_change = curTick + issue_thread_weights[hp_thread]; }#if DUMP_ISSUE cerr << "@" << curTick << endl; list<issue_info> issued_list;#endif // // If there are no ready instructions, blame the stopage on the oldest // instruction found in the IQ or LSQ. // // THERE ARE THREE SUB-CASES: // (a) No instructions anywhere ==> ISSUE_NO_INSN // (a) The oldest instruction has not-ready operands // => ISSUE_DEPS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -