251 lines
8.3 KiB
C++
251 lines
8.3 KiB
C++
|
/*
|
||
|
* 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 <algorithm>
|
||
|
|
||
|
#include "cpu/minor/decode.hh"
|
||
|
#include "cpu/minor/execute.hh"
|
||
|
#include "cpu/minor/fetch1.hh"
|
||
|
#include "cpu/minor/fetch2.hh"
|
||
|
#include "cpu/minor/pipeline.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::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()
|
||
|
{
|
||
|
execute.wakeupFetch();
|
||
|
}
|
||
|
|
||
|
unsigned int
|
||
|
Pipeline::drain(DrainManager *manager)
|
||
|
{
|
||
|
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 ? 0 : 1);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
Pipeline::drainResume()
|
||
|
{
|
||
|
DPRINTF(Drain, "Drain resume\n");
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
}
|