?? writeback.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. */#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 + -