/* * Copyright (c) 2013-2014 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Andrew Bardsley */ #include "cpu/minor/pipeline.hh" #include <algorithm> #include "cpu/minor/decode.hh" #include "cpu/minor/execute.hh" #include "cpu/minor/fetch1.hh" #include "cpu/minor/fetch2.hh" #include "debug/Drain.hh" #include "debug/MinorCPU.hh" #include "debug/MinorTrace.hh" #include "debug/Quiesce.hh" namespace Minor { Pipeline::Pipeline(MinorCPU &cpu_, MinorCPUParams ¶ms) : Ticked(cpu_, &(cpu_.BaseCPU::numCycles)), cpu(cpu_), allow_idling(params.enableIdling), f1ToF2(cpu.name() + ".f1ToF2", "lines", params.fetch1ToFetch2ForwardDelay), f2ToF1(cpu.name() + ".f2ToF1", "prediction", params.fetch1ToFetch2BackwardDelay, true), f2ToD(cpu.name() + ".f2ToD", "insts", params.fetch2ToDecodeForwardDelay), dToE(cpu.name() + ".dToE", "insts", params.decodeToExecuteForwardDelay), eToF1(cpu.name() + ".eToF1", "branch", params.executeBranchDelay), execute(cpu.name() + ".execute", cpu, params, dToE.output(), eToF1.input()), decode(cpu.name() + ".decode", cpu, params, f2ToD.output(), dToE.input(), execute.inputBuffer), fetch2(cpu.name() + ".fetch2", cpu, params, f1ToF2.output(), eToF1.output(), f2ToF1.input(), f2ToD.input(), decode.inputBuffer), fetch1(cpu.name() + ".fetch1", cpu, params, eToF1.output(), f1ToF2.input(), f2ToF1.output(), fetch2.inputBuffer), activityRecorder(cpu.name() + ".activity", Num_StageId, /* The max depth of inter-stage FIFOs */ std::max(params.fetch1ToFetch2ForwardDelay, std::max(params.fetch2ToDecodeForwardDelay, std::max(params.decodeToExecuteForwardDelay, params.executeBranchDelay)))), needToSignalDrained(false) { if (params.fetch1ToFetch2ForwardDelay < 1) { fatal("%s: fetch1ToFetch2ForwardDelay must be >= 1 (%d)\n", cpu.name(), params.fetch1ToFetch2ForwardDelay); } if (params.fetch2ToDecodeForwardDelay < 1) { fatal("%s: fetch2ToDecodeForwardDelay must be >= 1 (%d)\n", cpu.name(), params.fetch2ToDecodeForwardDelay); } if (params.decodeToExecuteForwardDelay < 1) { fatal("%s: decodeToExecuteForwardDelay must be >= 1 (%d)\n", cpu.name(), params.decodeToExecuteForwardDelay); } if (params.executeBranchDelay < 1) { fatal("%s: executeBranchDelay must be >= 1\n", cpu.name(), params.executeBranchDelay); } } void Pipeline::regStats() { Ticked::regStats(); fetch2.regStats(); } void Pipeline::minorTrace() const { fetch1.minorTrace(); f1ToF2.minorTrace(); f2ToF1.minorTrace(); fetch2.minorTrace(); f2ToD.minorTrace(); decode.minorTrace(); dToE.minorTrace(); execute.minorTrace(); eToF1.minorTrace(); activityRecorder.minorTrace(); } void Pipeline::evaluate() { /* Note that it's important to evaluate the stages in order to allow * 'immediate', 0-time-offset TimeBuffer activity to be visible from * later stages to earlier ones in the same cycle */ execute.evaluate(); decode.evaluate(); fetch2.evaluate(); fetch1.evaluate(); if (DTRACE(MinorTrace)) minorTrace(); /* Update the time buffers after the stages */ f1ToF2.evaluate(); f2ToF1.evaluate(); f2ToD.evaluate(); dToE.evaluate(); eToF1.evaluate(); /* The activity recorder must be be called after all the stages and * before the idler (which acts on the advice of the activity recorder */ activityRecorder.evaluate(); if (allow_idling) { /* Become idle if we can but are not draining */ if (!activityRecorder.active() && !needToSignalDrained) { DPRINTF(Quiesce, "Suspending as the processor is idle\n"); stop(); } /* Deactivate all stages. Note that the stages *could* * activate and deactivate themselves but that's fraught * with additional difficulty. * As organised herre */ activityRecorder.deactivateStage(Pipeline::CPUStageId); activityRecorder.deactivateStage(Pipeline::Fetch1StageId); activityRecorder.deactivateStage(Pipeline::Fetch2StageId); activityRecorder.deactivateStage(Pipeline::DecodeStageId); activityRecorder.deactivateStage(Pipeline::ExecuteStageId); } if (needToSignalDrained) /* Must be draining */ { DPRINTF(Drain, "Still draining\n"); if (isDrained()) { DPRINTF(Drain, "Signalling end of draining\n"); cpu.signalDrainDone(); needToSignalDrained = false; stop(); } } } MinorCPU::MinorCPUPort & Pipeline::getInstPort() { return fetch1.getIcachePort(); } MinorCPU::MinorCPUPort & Pipeline::getDataPort() { return execute.getDcachePort(); } void Pipeline::wakeupFetch(ThreadID tid) { fetch1.wakeupFetch(tid); } bool Pipeline::drain() { DPRINTF(MinorCPU, "Draining pipeline by halting inst fetches. " " Execution should drain naturally\n"); execute.drain(); /* Make sure that needToSignalDrained isn't accidentally set if we * are 'pre-drained' */ bool drained = isDrained(); needToSignalDrained = !drained; return drained; } void Pipeline::drainResume() { DPRINTF(Drain, "Drain resume\n"); for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { fetch1.wakeupFetch(tid); } execute.drainResume(); } bool Pipeline::isDrained() { bool fetch1_drained = fetch1.isDrained(); bool fetch2_drained = fetch2.isDrained(); bool decode_drained = decode.isDrained(); bool execute_drained = execute.isDrained(); bool f1_to_f2_drained = f1ToF2.empty(); bool f2_to_f1_drained = f2ToF1.empty(); bool f2_to_d_drained = f2ToD.empty(); bool d_to_e_drained = dToE.empty(); bool ret = fetch1_drained && fetch2_drained && decode_drained && execute_drained && f1_to_f2_drained && f2_to_f1_drained && f2_to_d_drained && d_to_e_drained; DPRINTF(MinorCPU, "Pipeline undrained stages state:%s%s%s%s%s%s%s%s\n", (fetch1_drained ? "" : " Fetch1"), (fetch2_drained ? "" : " Fetch2"), (decode_drained ? "" : " Decode"), (execute_drained ? "" : " Execute"), (f1_to_f2_drained ? "" : " F1->F2"), (f2_to_f1_drained ? "" : " F2->F1"), (f2_to_d_drained ? "" : " F2->D"), (d_to_e_drained ? "" : " D->E") ); return ret; } }