⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fetch.cc

📁 linux下基于c++的处理器仿真平台。具有处理器流水线
💻 CC
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -