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

📄 writeback.cc

📁 linux下基于c++的处理器仿真平台。具有处理器流水线
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* * 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. */#include <iostream>#include <string>#include <sstream>#include <vector>#include "base/statistics.hh"#include "encumbered/cpu/full/create_vector.hh"#include "encumbered/cpu/full/dd_queue.hh"#include "encumbered/cpu/full/dep_link.hh"#include "encumbered/cpu/full/fetch.hh"#include "encumbered/cpu/full/cpu.hh"#include "encumbered/cpu/full/iq/iqueue.hh"#include "encumbered/cpu/full/ls_queue.hh"#include "encumbered/cpu/full/readyq.hh"#include "encumbered/cpu/full/rob_station.hh"#include "encumbered/cpu/full/spec_state.hh"#include "encumbered/cpu/full/thread.hh"#include "encumbered/cpu/full/writeback.hh"#include "sim/eventq.hh"#include "sim/stats.hh"using namespace std;InstSeqNum writeback_break = 0;voidwriteback_breakpoint(){    cout << "got to WB break point!\n";}//// simulate the writeback stage of the pipeline//voidFullCPU::writeback(){    writebackEventQueue.serviceEvents();}////  IQ_WRITEBACK() - instruction result writeback pipeline stage//// writeback completed operation results from the functional units to IQ,// at this point, the output dependency chains of completing instructions// are also walked to determine if any dependent instruction now has all// of its register operands, if so the (nearly) ready instruction is inserted// into the ready instruction queue//// The writeback queue holds pointers to the ROB entry for the//   completed instructions The instruction entries in the IQ were//   removed when the instruction was issued.unsignedROBStation::writeback(FullCPU *cpu, unsigned wb_iqueue){    int i;    unsigned wb_events = 0;    if (writeback_break && (writeback_break == seq)) {	writeback_breakpoint();    }    /* RS has completed execution and (possibly) produced a result */    if (!issued || completed)	panic("writeback: inst completed and !issued or completed");    /*  Squashed instructions need to be removed  */    if (squashed) {	/*  We need to remove associated LSQ entries also  */	if (lsq_entry.notnull()) {	    cpu->LSQ->squash(lsq_entry);	    if (cpu->ptrace)		cpu->ptrace->deleteInst(lsq_entry->inst);	}	cpu->remove_ROB_element(this);	return 0;    }    Tick pred_cycle = (eaCompPending ? pred_wb_cycle - 1 : pred_wb_cycle);    cpu->pred_wb_error_dist.sample(curTick - pred_cycle);    //    //  MISPREDICTED Branch    //    //  Clean up if this is the FIRST writeback event for this instruction    //    if (inst->recover_inst) {	wb_events = PipeTrace::MisPredict;        //        //  The idea here is to order recovery events such that        //  once an event of spec-level "n" is scheduled, we do not        //  sechedule an event for spec-level of "m" if m < n        //        //  This means that once an event is scheduled, we don't        //  schedule events for younger recovery-instructions        //  (since these should be blown away by the existing        //  event, anyway)        //	ThreadInfo *threadInfo = &cpu->thread_info[thread_number];        if (!threadInfo->recovery_event_pending ||	    threadInfo->recovery_spec_level > inst->spec_mode) {	    Tick sched_time = curTick + cpu->cycles(cpu->mispred_fixup_penalty);	    //	    //  If we are using multiple IQ's, we schedule a _single_ event	    //  for all of them, but we delay this event by the	    //  IQ communication latency	    //	    if (cpu->numIQueues > 1)		sched_time += cpu->cycles(cpu->iq_comm_latency);            //  Schedule the event that will fix up the Fetch stage, IFQ,            //  FTDQ, and IQ/LSQ            BranchRecoveryEvent *ev =		new BranchRecoveryEvent(cpu, this, thread_number,					spec_state, inst->spec_mode);            ev->schedule(sched_time);	    //	    //  The recovery event will take responsibility for deleting the	    // spec_state information	    //	    spec_state = 0;            //  Grab a pointer to this event in case commit needs it.            recovery_event = ev;            //  Make a note of this event...            cpu->thread_info[thread_number].recovery_event_pending = true;            cpu->thread_info[thread_number].recovery_spec_level		= inst->spec_mode;        }    }    //    //  Writeback the results of this instrution to the specified IQ    //    //    int eff_num_outputs = num_outputs;    unsigned num_consumers = 0;    if (!eaCompPending) {	CreateVector *cv = &cpu->create_vector[thread_number];	//	//  This instruction has written its results back to the register	//  file... update the create vectors to indicate this fact	//	for (i = 0; i < num_outputs; i++) {	    if (inst->spec_mode) {		// update the speculative create vector:		// future operations get value from later creator or		// architected reg file		CVLink link = cv->spec_cv[onames[i]];		if (link.rs == this && link.odep_num == i) {		    // the result can now be read from a physical		    // register, indicate this as so		    cv->spec_cv[onames[i]] = CVLINK_NULL;		    cv->spec_timestamp[onames[i]] = curTick;		}		// else, creator invalidated or there is another		// creator	    } else {		// update the non-speculative create vector, future		// operations get value from later creator or		// architected register file		CVLink link = cv->cv[onames[i]];		if (link.rs == this && link.odep_num == i) {		    // the result can now be read from a physical		    // register, indicate this as so		    cv->cv[onames[i]] = CVLINK_NULL;		    cv->timestamp[onames[i]] = curTick;		}		// else, creator invalidated or there is another		// creator	    }	}		//   for all outputs	//	//  Tell IQ & LSQ that this instruction is complete	//	//  Every non-EA_Comp instruction must walk its output-dependence	//  chains to broadcast its results to other instructions	//	num_consumers =  cpu->IQ[wb_iqueue]->writeback(this, wb_iqueue);	//	//  It's ok to call the LSQ multiple times, since the odep link gets	//  removed once it has been used.	//	//  The queue number argument is unused (ignored) for the LSQ	num_consumers += cpu->LSQ->writeback(this, 0);    } else {	//	//  Address-generation portion of load/store gets special handling	//	//  --> only one op receives the result data	//  --> no create-vectors to mess with	//	assert(seq == lsq_entry->seq);	eff_num_outputs = 1;	num_consumers = 1;	//  Indicate that we've finished with the address generation portion	eaCompPending = false;	lsq_entry->idep_ready[MEM_ADDR_INDEX] = true;	issued = false;	completed = false;	// LSQ operation will be placed on LSQ's ready list in	// lsq_refresh(), depending on things like address	// disambiguation and memory barriers.    }    if (cpu->ptrace)	cpu->ptrace->moveInst(inst, PipeTrace::Writeback, wb_events, 0, 0);    //    //  Statistics...    //    if (eff_num_outputs > 0) {	++cpu->producer_inst[thread_number];	cpu->consumer_inst[thread_number] += num_consumers;    }    return num_consumers;}//////////////////////////////////////////////////////////////////////  recover processor microarchitecture state back to point of the//  mis-predicted branch at IQ[BRANCH_INDEX]////  This routine is called from the BranchRecoveryEvent//voidFullCPU::recover(ROBStation *ROB_branch_entry, int branch_thread){    BaseIQ::iterator IQ_entry;    BaseIQ::iterator LSQ_entry;    ROBStation *ROB_entry;    // recover from the tail of the ROB towards the head until the branch index    // is reached, this direction ensures that the LSQ can be synchronized with    // the IQ    // traverse to older insts until the mispredicted branch is encountered    // Mark all instructions (from the same thread) FOLLOWING the branch as    // squashed (the branch itself commits as a normal instruction)    //  go to first element to squash (ie. the last element in the list)    for (ROB_entry = ROB.tail();	 (ROB_entry != ROB_branch_entry) && (ROB_entry != NULL);         ROB_entry = ROB.prev(ROB_entry))    {	// the IQ should not drain since the mispredicted branch will remain	assert(ROB.num_active());	// should meet up with the branch index first	assert(ROB_entry);	if (!ROB_entry->squashed &&	    (ROB_entry->thread_number == branch_thread)) {	    if (ptrace) {		ptrace->deleteInst(ROB_entry->inst);	    }#if 0	    if (chainGenerator) {		chainGenerator->squashInstruction(ROB_entry);	    }#endif	    //	    //  Inform the IQ and LSQ that an instruction is being squashed	    //	    for (int i=0; i<numIQueues; ++i) {		IQ[i]->inform_squash(ROB_entry);	    }	    LSQ->inform_squash(ROB_entry);	    //	    //  Remove any associated IQ or LSQ entries	    //	    if (ROB_entry->lsq_entry.notnull()) {		LSQ_entry = ROB_entry->lsq_entry;		// squash this LSQ entry		LSQ_entry->tag++;		LSQ_entry->squashed = true;		LSQ->squash(LSQ_entry);	    }	    if (ROB_entry->iq_entry.notnull()) {		IQ_entry = ROB_entry->iq_entry;		// squash this IQ entry		IQ_entry->tag++;		IQ_entry->squashed = true;		//  remove the instruction from it's home IQ		IQ[ROB_entry->queue_num]->squash(IQ_entry);		ROB_entry->iq_entry = 0;		//  tell the remaining clusters that it's gone		for (int q = 0; q < numIQueues; ++q)		    if (q != ROB_entry->queue_num)			IQ[q]->inform_squash(ROB_entry);	    }	    //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -