At the same time, rename the trace flags to debug flags since they have broader usage than simply tracing. This means that --trace-flags is now --debug-flags and --trace-help is now --debug-help
280 lines
8.7 KiB
C++
280 lines
8.7 KiB
C++
/*
|
|
* Copyright (c) 2007 MIPS Technologies, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* 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: Korey Sewell
|
|
*
|
|
*/
|
|
|
|
#include "base/str.hh"
|
|
#include "cpu/inorder/resources/resource_list.hh"
|
|
#include "cpu/inorder/cpu.hh"
|
|
#include "cpu/inorder/first_stage.hh"
|
|
#include "cpu/inorder/resource_pool.hh"
|
|
#include "debug/InOrderStage.hh"
|
|
#include "params/InOrderTrace.hh"
|
|
|
|
using namespace std;
|
|
using namespace ThePipeline;
|
|
|
|
FirstStage::FirstStage(Params *params, unsigned stage_num)
|
|
: PipelineStage(params, stage_num), numFetchingThreads(1),
|
|
fetchPolicy(FirstStage::RoundRobin)
|
|
{
|
|
for(ThreadID tid = 0; tid < this->numThreads; tid++) {
|
|
stageStatus[tid] = Running;
|
|
}
|
|
}
|
|
|
|
void
|
|
FirstStage::setCPU(InOrderCPU *cpu_ptr)
|
|
{
|
|
cpu = cpu_ptr;
|
|
|
|
fetchPriorityList = &cpu->fetchPriorityList;
|
|
|
|
DPRINTF(InOrderStage, "Set CPU pointer.\n");
|
|
}
|
|
|
|
|
|
void
|
|
FirstStage::squash(InstSeqNum squash_seq_num, ThreadID tid)
|
|
{
|
|
// Set status to squashing.
|
|
//stageStatus[tid] = Squashing;
|
|
|
|
// Clear the instruction list and skid buffer in case they have any
|
|
// insts in them.
|
|
DPRINTF(InOrderStage, "Removing instructions from stage instruction "
|
|
"list.\n");
|
|
while (!skidBuffer[tid].empty()) {
|
|
if (skidBuffer[tid].front()->seqNum <= squash_seq_num) {
|
|
DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because "
|
|
"it's <= squashing seqNum %i.\n",
|
|
tid,
|
|
skidBuffer[tid].front()->seqNum,
|
|
squash_seq_num);
|
|
|
|
DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
|
|
"instructions before delay slot [sn:%i]. %i insts"
|
|
"left.\n", tid, squash_seq_num,
|
|
skidBuffer[tid].size());
|
|
break;
|
|
}
|
|
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
|
|
"PC %s.\n", tid, skidBuffer[tid].front()->seqNum,
|
|
skidBuffer[tid].front()->pc);
|
|
skidBuffer[tid].pop_front();
|
|
}
|
|
|
|
// Now that squash has propagated to the first stage,
|
|
// Alert CPU to remove instructions from the CPU instruction list.
|
|
// @todo: Move this to the CPU object.
|
|
cpu->removeInstsUntil(squash_seq_num, tid);
|
|
}
|
|
|
|
void
|
|
FirstStage::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
|
|
{
|
|
// Need to preserve the stalling instruction in first-stage
|
|
// since the squash() from first stage also removes
|
|
// the instruction from the CPU (removeInstsUntil). If that
|
|
// functionality gets changed then you can move this offset.
|
|
// (stalling instruction = seq_num + 1)
|
|
squash(seq_num+1, tid);
|
|
}
|
|
|
|
|
|
void
|
|
FirstStage::processStage(bool &status_change)
|
|
{
|
|
list<ThreadID>::iterator threads = activeThreads->begin();
|
|
|
|
//Check stall and squash signals.
|
|
while (threads != activeThreads->end()) {
|
|
ThreadID tid = *threads++;
|
|
status_change = checkSignalsAndUpdate(tid) || status_change;
|
|
}
|
|
|
|
while (instsProcessed < stageWidth) {
|
|
ThreadID tid = getFetchingThread(fetchPolicy);
|
|
|
|
if (tid >= 0) {
|
|
DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
|
|
processThread(status_change, tid);
|
|
DPRINTF(InOrderStage, "Done Processing [tid:%i]\n",tid);
|
|
} else {
|
|
DPRINTF(InOrderStage, "No more threads to fetch from.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (instsProcessed > 0) {
|
|
++runCycles;
|
|
idle = false;
|
|
} else {
|
|
++idleCycles;
|
|
idle = true;
|
|
}
|
|
|
|
}
|
|
|
|
//@TODO: Note in documentation, that when you make a pipeline stage change,
|
|
//then make sure you change the first stage too
|
|
void
|
|
FirstStage::processInsts(ThreadID tid)
|
|
{
|
|
bool all_reqs_completed = true;
|
|
|
|
for (int insts_fetched = instsProcessed;
|
|
insts_fetched < stageWidth;
|
|
insts_fetched++) {
|
|
|
|
DynInstPtr inst;
|
|
bool new_inst = false;
|
|
|
|
if (!skidBuffer[tid].empty()) {
|
|
inst = skidBuffer[tid].front();
|
|
} else {
|
|
// Get new instruction.
|
|
new_inst = true;
|
|
|
|
inst = new InOrderDynInst(cpu,
|
|
cpu->thread[tid],
|
|
cpu->nextInstSeqNum(tid),
|
|
tid,
|
|
tid);
|
|
|
|
#if TRACING_ON
|
|
inst->traceData =
|
|
tracer->getInstRecord(ThePipeline::NumStages,
|
|
cpu->stageTracing,
|
|
cpu->thread[tid]->getTC());
|
|
|
|
#else
|
|
inst->traceData = NULL;
|
|
#endif // TRACING_ON
|
|
|
|
// Add instruction to the CPU's list of instructions.
|
|
inst->setInstListIt(cpu->addInst(inst));
|
|
|
|
// Create Front-End Resource Schedule For Instruction
|
|
inst->setFrontSked(cpu->frontEndSked);
|
|
}
|
|
|
|
int reqs_processed = 0;
|
|
all_reqs_completed = processInstSchedule(inst, reqs_processed);
|
|
|
|
// If the instruction isnt squashed & we've completed one request
|
|
// Then we can officially count this instruction toward the stage's
|
|
// bandwidth count
|
|
if (reqs_processed > 0)
|
|
instsProcessed++;
|
|
|
|
if (!all_reqs_completed || !sendInstToNextStage(inst)) {
|
|
if (new_inst) {
|
|
DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
|
|
"requests for this stage. Keep in stage inst. "
|
|
"list.\n", tid, inst->seqNum);
|
|
skidBuffer[tid].push_back(inst);
|
|
}
|
|
block(tid);
|
|
break;
|
|
} else if (!skidBuffer[tid].empty()){
|
|
DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Finished all "
|
|
"requests for this stage.\n", tid, inst->seqNum);
|
|
skidBuffer[tid].pop_front();
|
|
}
|
|
|
|
}
|
|
|
|
// Record that stage has written to the time buffer for activity
|
|
// tracking.
|
|
if (instsProcessed) {
|
|
wroteToTimeBuffer = true;
|
|
}
|
|
}
|
|
|
|
ThreadID
|
|
FirstStage::getFetchingThread(FetchPriority &fetch_priority)
|
|
{
|
|
ThreadID num_active_threads = cpu->numActiveThreads();
|
|
|
|
if (num_active_threads > 1) {
|
|
switch (fetch_priority) {
|
|
case SingleThread:
|
|
return cpu->activeThreadId();
|
|
|
|
case RoundRobin:
|
|
return roundRobin();
|
|
|
|
default:
|
|
return InvalidThreadID;
|
|
}
|
|
} else if (num_active_threads == 1) {
|
|
ThreadID tid = *activeThreads->begin();
|
|
|
|
if (stageStatus[tid] == Running ||
|
|
stageStatus[tid] == Idle ||
|
|
stageStatus[tid] == Unblocking) {
|
|
return tid;
|
|
} else {
|
|
return InvalidThreadID;
|
|
}
|
|
} else {
|
|
return InvalidThreadID;
|
|
}
|
|
}
|
|
|
|
ThreadID
|
|
FirstStage::roundRobin()
|
|
{
|
|
list<ThreadID>::iterator pri_iter = fetchPriorityList->begin();
|
|
list<ThreadID>::iterator end = fetchPriorityList->end();
|
|
|
|
ThreadID high_pri;
|
|
|
|
while (pri_iter != end) {
|
|
high_pri = *pri_iter;
|
|
|
|
assert(high_pri <= numThreads);
|
|
|
|
if (stageStatus[high_pri] == Running ||
|
|
stageStatus[high_pri] == Idle ||
|
|
stageStatus[high_pri] == Unblocking){
|
|
|
|
fetchPriorityList->erase(pri_iter);
|
|
fetchPriorityList->push_back(high_pri);
|
|
|
|
return high_pri;
|
|
}
|
|
|
|
pri_iter++;
|
|
}
|
|
|
|
return InvalidThreadID;
|
|
}
|