?? fetch.cc
字號:
/* * Copyright (c) 2000, 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. *//* * @file * Defines the portions of CPU relating to the fetch stages. */#include <fstream>#include <iostream>#include <iomanip>#include <set>#include <sstream>#include <string>#include <vector>#include "base/cprintf.hh"#include "base/loader/symtab.hh"#include "base/range.hh"#include "encumbered/cpu/full/bpred.hh"#include "encumbered/cpu/full/cpu.hh"#include "encumbered/cpu/full/dd_queue.hh"#include "encumbered/cpu/full/dyn_inst.hh"#include "encumbered/cpu/full/fetch.hh"#include "encumbered/cpu/full/floss_reasons.hh"#include "encumbered/cpu/full/iq/iqueue.hh"#include "encumbered/cpu/full/issue.hh"#include "encumbered/cpu/full/spec_state.hh"#include "encumbered/cpu/full/thread.hh"#include "mem/functional/memory_control.hh"#include "mem/mem_interface.hh"#include "sim/param.hh"#include "sim/sim_exit.hh"#include "sim/stats.hh"#if FULL_SYSTEM#include "sim/system.hh"#include "targetarch/vtophys.hh" // can get rid of this when we fix translation#endifusing namespace std;/* * Local function prototypes */static int rr_compare(const void *first, const void *second);static int icount_compare(const void *first, const void *second);// ==========================================================================//// FetchQueue Implementation////voidFetchQueue::init(FullCPU *cpu, int _size, int _num_threads){ instrs = new fetch_instr_rec_t[_size]; head = tail = 0; size = _size; index_mask = _size - 1; // size must be power of two if ((_size & index_mask) != 0) fatal("fetch_queue: size %d not a power of two!\n", _size); num_threads = _num_threads; mt_frontend = cpu->mt_frontend; num_valid = num_reserved = num_squashed = 0; for (int i = 0; i < SMT_MAX_THREADS; ++i) { num_reserved_thread[i] = 0; num_valid_thread[i] = 0; num_squashed_thread[i] = 0; } for (int i = 0; i < _size; ++i) instrs[i].inst = NULL;}voidFetchQueue::reserve(int thread){ assert(mt_frontend && thread == num_threads || !mt_frontend && thread >= 0 && thread <= num_threads); assert(num_total() < size); num_reserved++; num_reserved_thread[thread]++;}// append an instruction from an IcacheOutputBuffer to the ifq.// a slot should already have been reserved by incrementing the// num_reserved and num_reserved_thread[] countersvoidFetchQueue::append(DynInst *inst){ int thread_number = inst->thread_number; fetch_instr_rec_t *frec = &instrs[tail]; tail = incr(tail); frec->inst = inst; frec->thread_number = thread_number; frec->squashed = false; frec->contents_valid = true; --num_reserved; --num_reserved_thread[thread_number]; ++num_valid; ++num_valid_thread[thread_number]; assert(num_reserved >= 0); // don't need to increment num_valid or num_valid_thread[] // since these counts already include reserved slots}DynInst *FetchQueue::pull(){ DynInst *rv = instrs[head].inst; if (!instrs[head].squashed) { // // instruction was not squashed... // --num_valid; --num_valid_thread[rv->thread_number]; instrs[head].inst = 0; head = incr(head); } else { // // instruction WAS squashed... // --num_squashed; --num_squashed_thread[instrs[head].thread_number]; head = incr(head); } return rv;}//// Overloaded Function ! ! !//// This version squashes everything in this queuevoidFetchQueue::squash(){ assert(mt_frontend); if (num_valid) { int idx = head; do { if (!instrs[idx].squashed) { unsigned t = instrs[idx].thread_number; assert(mt_frontend && t == num_threads); --num_valid; --num_valid_thread[t]; ++num_squashed; ++num_squashed_thread[t]; instrs[idx].squash(); } idx = incr(idx); } while (idx != tail); assert(num_valid == 0); } num_reserved = 0; assert(num_valid_thread[num_threads] == 0); num_reserved_thread[num_threads] = 0;}//// This version squashes instructions from the specified thread in this queue//// should only be used in the non-MT frontend case//voidFetchQueue::squash(int t){ assert(!mt_frontend && t >= 0 && t <= num_threads); if (num_valid) { int idx = head; do { if (!instrs[idx].squashed && (instrs[idx].thread_number == t)) { instrs[idx].squash(); --num_valid; --num_valid_thread[t]; ++num_squashed; ++num_squashed_thread[t]; } idx = incr(idx); } while (idx != tail); assert(num_valid_thread[t] == 0); } num_reserved -= num_reserved_thread[t]; num_reserved_thread[t] = 0;}voidFetchQueue::dump(const string &str){ cprintf("=======================================================\n"); cprintf("Contents Of Fetch Queue%s:\n", str); cprintf("fetch_num: %d (%d valid)(%d reserved)(%d squashed)\n", num_total(), num_valid, num_reserved, num_squashed); cprintf("-------------------------------------------------------\n"); cprintf("fetch_head: %d, fetch_tail: %d\n", head, tail); cprintf("-------------------------------------------------------\n"); for (int i = 0, idx = head; i < num_total(); i++, idx = incr(idx)) { fetch_instr_rec_t *frec = &(instrs[idx]); DynInst *inst = frec->inst; if (frec->squashed) { cprintf("%2d: <squashed>\n", idx); } else { cprintf("%2d: (Thread %d) ", idx, frec->thread_number); if (inst) inst->dump(); else cprintf("RESERVED\n"); } } cprintf("=======================================================\n\n");}// ==========================================================================/* * The icache_output_buffer structures are per-thread structures that * serve as the destination for outstanding icache accesses. We read * the actual instructions from memory when we initiate the fetch (in * order to have perfect prediction information); these buffers hold * those instructions while we wait for the actual icache access * delay. We can't have the ifetch queue serve this purpose, since * icache accesses from different threads may complete out of order, * and we want to put instructions in the ifq in the order they come * back from the icache. The icache fetch completion event * (FetchCompleteEvent) copies the instructions from the * icache_output_buffer to the ifq when it is processed. */struct IcacheOutputBufferEntry{ DynInst *inst; bool ready; // constructor IcacheOutputBufferEntry() { inst = NULL; ready = false; }};struct IcacheOutputBuffer{ IcacheOutputBufferEntry *insts; short head; short tail; short index_mask; short num_insts; short size; int thread; // initialization void init(int _size, int _thread) { head = tail = 0; num_insts = 0; insts = new IcacheOutputBufferEntry[_size]; index_mask = _size - 1; // size must be power of two if ((_size & index_mask) != 0) fatal("icache_output_buffer: size %d not a power of two!\n", _size); size = _size; thread = _thread; } // number of available slots int free_slots() { return size - num_insts; } // increment tail pointer & return tail entry IcacheOutputBufferEntry *new_tail() { IcacheOutputBufferEntry *entryp = &insts[tail]; tail = (tail + 1) & index_mask; num_insts++; return entryp; } // increment a queue index (with wrap) int incr(int index) { return ((index + 1) & index_mask); } // squash all instructions void squash(int thread_number); void dump();};//void fetch_squash_inst(DynInst *inst);voidIcacheOutputBuffer::dump(){ ccprintf(cerr, "=========================================================\n" "I-Cache Output Buffer (Thread %d)\n" "---------------------------------------------------------\n" "Head=%d, Tail=%d\n" "---------------------------------------------------------\n", thread, head, tail); for (int i = 0, idx = head; i < num_insts; ++i, idx = incr(idx)) { DynInst *inst = insts[idx].inst; ccprintf(cerr, "%2d: PC %#08x, Pred_PC %#08x: ", idx, inst->PC, inst->Pred_PC); cerr << inst->staticInst->disassemble(inst->PC); cerr << "\n"; } cerr << "=========================================================\n";}voidIcacheOutputBuffer::squash(int thread_number){ for (int i = 0, idx = head; i < num_insts; ++i, idx = incr(idx)) { IcacheOutputBufferEntry *entryp = &insts[idx]; entryp->inst->squash(); delete entryp->inst; entryp->inst = NULL; entryp->ready = false; } // buffer is now empty head = tail; num_insts = 0;}// ==========================================================================//// This routine does double-duty...// (1) Complete initialization of the fetch-list and thread_info structs// (2) Re-initilizes the fetch-list on a state change//voidFullCPU::initialize_fetch_list(int initial){ int active_list[SMT_MAX_THREADS]; int inactive_list[SMT_MAX_THREADS]; ThreadListElement temp_list[SMT_MAX_THREADS]; // // Initialize the state of the fetch-list & thread_info struct // for (int i = 0; i < SMT_MAX_THREADS; i++) { if (initial) { fetch_list[i].thread_number = i; fetch_list[i].sort_key = 0; fetch_list[i].blocked = 0; fetch_list[i].priority = 0; fetch_list[i].last_fetch = 0; thread_info[i].last_fetch = 0; thread_info[i].blocked = false; thread_info[i].active = false; thread_info[i].fetch_counter = 0; thread_info[i].commit_counter = 0; thread_info[i].base_commit_count = 0; thread_info[i].fetch_average = 0; thread_info[i].current_icount = 0; thread_info[i].cum_icount = 0; thread_info[i].recovery_event_pending = false; thread_info[i].recovery_spec_level = 0; } else { // only need to initialize these for the non-initial case active_list[i] = -1; inactive_list[i] = -1; } } // // This section of code manipulates the fetch-list such that active // threads are at the front of the list, inactive threads are at the // bottom of the list. If the fetch-policy is RR, then the active // threads are also sorted by thread priority // if (!initial) { int active_index = 0; int inactive_index = 0; int templist_index = 0; // // Place each thread into either the active or inactive list // for (int thread = 0; thread < SMT_MAX_THREADS; thread++) { if (thread_info[thread].active) active_list[active_index++] = thread; else inactive_list[inactive_index++] = thread; } /* * We make a copy of the current fetch_list in temp_list * => The orderering from the fetch_list MUST be maintianed!!! */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -