?? iq_seg.cc
字號:
/* * Copyright (c) 2001, 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator, developed by Nathan Binkert, * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions * from Ron Dreslinski, Dave Greene, Lisa Hsu, Kevin Lim, Ali Saidi, * and Andrew Schultz. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. */#include <iomanip>#include <iostream>#include <map>#include <sstream>#include "base/cprintf.hh"#include "base/statistics.hh"#include "encumbered/cpu/full/cpu.hh"#include "encumbered/cpu/full/create_vector.hh"#include "encumbered/cpu/full/dep_link.hh"#include "encumbered/cpu/full/iq/iqueue.hh"#include "encumbered/cpu/full/iq/segmented/iq_seg.hh"#include "encumbered/cpu/full/iq/segmented/iq_segmented.hh"#include "encumbered/cpu/full/iq/segmented/seg_chain.hh"#include "encumbered/cpu/full/issue.hh"#include "encumbered/cpu/full/ls_queue.hh"#include "encumbered/cpu/full/reg_info.hh"#include "sim/eventq.hh"#include "sim/stats.hh"using namespace std;#define use_dest_sort 1#define use_pushdown 1//==========================================================================//// The segment implementation////==========================================================================//// Constructor//segment_t::segment_t(SegmentedIQ *iq, string n, unsigned seg_num, unsigned num_segs, unsigned sz, unsigned n_chains, unsigned thresh, bool pipelined, bool en_pri){ // Allows us to reference our own queue data seg_queue = iq; name_string = n; segment_number = seg_num; num_segments = num_segs; size = sz; num_chains = n_chains; threshold = thresh; // we need to set this after the chain info table gets built chain_info = 0; // // The list of iterators to the instructions we're tracking // // ["size" elements, allocated, doesn't grow] // queue = new iq_iterator_list(size, true, 0); chains = new iq_iterator_list * [num_chains]; for (int i = 0; i < num_chains; ++i) chains[i] = new iq_iterator_list(20, true, 2); self_timed_list = new iq_iterator_list(20, true, 2); // Keep track of which instructions are "ready" to promote (or issue) // // NOTE: Segment zero uses a different ready-list policy! string seg_name = name() + ":RQ"; if (seg_num != 0) { ready_list = new ready_queue_t<IQStation, RQ_Seg_Policy> (&(seg_queue->cpu), seg_name, size, en_pri); } else { ready_list = new ready_queue_t<IQStation, RQ_Issue_Policy> (&(seg_queue->cpu), seg_name, size, en_pri); } // // Initilize statistics, etc // total_insts = 0; segment_full = 0; segment_empty = 0; cycles_low_ready = 0; insts_fanout_loads = 0; insts_waiting_for_loads = 0; insts_waiting_for_unissued = 0; for (int i = 0; i < SMT_MAX_THREADS; ++i) { insts[i] = 0; }}//// Copy an instruction into this segment. Add this instruction to// the correct specified chain.//// The instruction is checked to see if it is in the "right" segment// and if not, is automatically marked as ready to promote. This assumes// that the queue _forward_of_this_segment_ is in a consistent state.//// This allows instructions that have not reached their correct segment// to move forward, even though their chain-head isn't moving.//segment_t::iq_iteratorsegment_t::add(segment_t::iq_iterator &p){ unsigned n_chains = 0; // Add this iterator to this segment's queue iq_it_list_iterator q = queue->add_tail(p); if (q.isnull()) return 0; // So we can remove it from the segment queue p->queue_entry = q; p->queued = false; p->rq_entry = 0; p->segment_number = segment_number; // // Add this instruction to it's chain(s) // for (int i = 0; i < TheISA::MaxInstSrcRegs; ++i) { if (p->idep_info[i].chained) { unsigned c_num = p->idep_info[i].follows_chain; bool duplicate = false; for (int j = 0; j < i; ++j) { if (p->idep_info[j].chained && (p->idep_info[j].follows_chain == c_num)) { duplicate = true; break; } } if (! duplicate) { p->idep_info[i].chain_entry = chains[c_num]->add_tail(p); ++n_chains; } else { p->idep_info[i].chain_entry = 0; } } } // // Only if this instruction is completely unchained, do we add it // to the self-timed list // if (n_chains == 0) p->idep_info[0].chain_entry = self_timed_list->add_tail(p); // Has this instruction reached the "right" segment yet? if (segment_number != 0 && promotable(p)) enqueue(p); ++insts[p->thread_number()]; ++total_insts; // // SEGMENT 0: Enqueue incoming instructions if their input // dependencies have been met. // if ((segment_number == 0) && p->ops_ready()) { // we shouldn't become ready too early // assert(p->delay == 0); enqueue(p); } return p;}//// Removing an instruction (actually an iterator to an instruction) from// this queue segment//// (1) Remove the inst from the chain it's following (or the unchained list)// (2) Remove the inst from the chain it's the head of// (3) Remove the inst from the ready-queue (if queued)// (4) Remove the iterator from the queue//segment_t::iq_iteratorsegment_t::remove(segment_t::iq_iterator &e){ iq_iterator next = e.next(); unsigned n_chains = 0; if (e.notnull()) { --insts[e->thread_number()]; --total_insts; for (int i = 0; i < TheISA::MaxInstSrcRegs; ++i) { // // Remove it from the correct chain... // if (e->idep_info[i].chained) { unsigned chain = e->idep_info[i].follows_chain; chains[chain]->remove(e->idep_info[i].chain_entry); ++n_chains; } } if (n_chains == 0) self_timed_list->remove(e->idep_info[0].chain_entry); // // If this inst was queued // if (e->queued) ready_list->remove(e->rq_entry); // // Finally, remove it from the segment queue list // queue->remove(e->queue_entry); } return next;}//// When the head instruction issues, we leave the instructions on// the chain, but tell it to self-time.//// We may want to stop the self-time operation later...//voidsegment_t::self_time(ROBStation *rob){ if (rob->seq == (*chain_info)[rob->head_chain].creator) (*chain_info)[rob->head_chain].self_timed = true;}//// Stop the chain from self-timing//voidsegment_t::stop_self_time(ROBStation *rob){ if (rob->seq == (*chain_info)[rob->head_chain].creator) (*chain_info)[rob->head_chain].self_timed = false;}//// When the head instruction writes-back, we'll free the chain,// Allowing the individual instructions to sit on the self_timed_list//voidsegment_t::release_chain(ROBStation *rob_entry){ iq_it_list_iterator n; unsigned t_count = 0; unsigned chain_num = rob_entry->head_chain;#if 0 // We don't want to free a chain that really belongs to someone else! if (rob_entry->seq != seg_queue->chain_info[chain_num]->creator) return;#endif // // Walk the list of instructions on this chain // iq_it_list_iterator i = chains[chain_num]->head(); for (; i.notnull(); i = n) { unsigned n_chains = 0; n = i.next(); for (int j = 0; j < TheISA::MaxInstSrcRegs; ++j) { if ((*i)->idep_info[j].chained) { if ((*i)->idep_info[j].follows_chain == chain_num) { (*i)->idep_info[j].chained = false; //chains[chain_num]->remove(i); ++t_count; } else { ++n_chains; } } } // If this inst is no longer on _any_ chain... put it on the // self-timed list if (n_chains == 0) { (*i)->idep_info[0].chain_entry = self_timed_list->add_tail(*i); // We need to set the self-timed flag in any register produced // by this instruction ROBStation *rob = (*i)->rob_entry; for (int j = 0; j < rob->num_outputs; ++j) { RegInfoElement &r = (*reg_info_table)[rob->thread_number][rob->onames[j]]; // // If this ROB entry is responsible for producing this // arch register result... // if (r.producer() && (r.producer()->seq == rob->seq)) { // Clear the chained flag so that future consumers // will know not to wait on the chain head r.unChain(); } } } } // instead of the individual removes above... assert(chains[chain_num]->count() == t_count); chains[chain_num]->clear();}voidsegment_t::check_promotable(){ // // All segments except segment 0 need to determine which instructions are // promotable. // // Segment zero instructions are enqueued either on entry // (if no outstanding ideps) or when an instruction writes-back. // // // Walk the entire list of instructions... // (1) Decrement the delay values as necessary // (2) Enqueue instructions that are promotable // iq_it_list_iterator i = queue->head(); for (; i.notnull(); i = i.next()) { bool recalc_position = false; // // Do the easy case first // // (this works because any instruction that is ops-ready MUST be // self-timed) // if ((*i)->ops_ready() && !(*i)->queued) enqueue(*i); // // Decrement the delay counters depending on the state of the chain // for (int j = 0; j < TheISA::MaxInstSrcRegs; ++j) { if (!(*i)->idep_ready[j]) { if ((*i)->idep_info[j].chained) { unsigned c_num = (*i)->idep_info[j].follows_chain; // If the head of this chain was promoted, // or is self-timed, then we need to see if we are // promotable if (chain_info->head_was_promoted(c_num, segment_number) || (*chain_info)[c_num].self_timed) { if ((*chain_info)[c_num].self_timed) { decrement_delay(*i, j); recalc_position = true; } // Don't enqueue for segment zero
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -