gem5/src/cpu/inorder/first_stage.cc

252 lines
7.7 KiB
C++
Raw Normal View History

/*
* 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/first_stage.hh"
#include "cpu/inorder/resources/resource_list.hh"
#include "cpu/inorder/resource_pool.hh"
#include "cpu/inorder/cpu.hh"
#include "params/InOrderTrace.hh"
using namespace std;
using namespace ThePipeline;
FirstStage::FirstStage(Params *params, unsigned stage_num)
: PipelineStage(params, stage_num)
{
for(int tid=0; tid < this->numThreads; tid++) {
stageStatus[tid] = Running;
}
numFetchingThreads = 1;
fetchPolicy = RoundRobin;
}
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, unsigned 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 (!insts[tid].empty()) {
if (insts[tid].front()->seqNum <= squash_seq_num) {
DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= "
"squashing seqNum %i.\n",
tid,
insts[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,
insts[tid].size());
break;
}
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
tid, insts[tid].front()->seqNum, insts[tid].front()->PC);
insts[tid].pop();
}
// 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::processStage(bool &status_change)
{
list<unsigned>::iterator threads = (*activeThreads).begin();
//Check stall and squash signals.
while (threads != (*activeThreads).end()) {
unsigned tid = *threads++;
status_change = checkSignalsAndUpdate(tid) || status_change;
}
for (int threadFetched = 0; threadFetched < numFetchingThreads;
threadFetched++) {
int tid = getFetchingThread(fetchPolicy);
if (tid >= 0) {
DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
processThread(status_change, tid);
} else {
DPRINTF(InOrderStage, "No more threads to fetch from.\n");
}
}
}
//@TODO: Note in documentation, that when you make a pipeline stage change, then
//make sure you change the first stage too
void
FirstStage::processInsts(unsigned tid)
{
bool all_reqs_completed = true;
for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) {
DynInstPtr inst;
bool new_inst = false;
if (!insts[tid].empty()) {
inst = insts[tid].front();
} else {
// Get new instruction.
new_inst = true;
inst = new InOrderDynInst(cpu,
cpu->thread[tid],
cpu->nextInstSeqNum(tid),
tid);
#if TRACING_ON
inst->traceData =
tracer->getInstRecord(ThePipeline::NumStages,
cpu->stageTracing,
cpu->thread[tid]->getTC());
#endif // TRACING_ON
DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n",
inst->readTid(),
inst->seqNum,
0/*inst->curCount()*/);
// Add instruction to the CPU's list of instructions.
inst->setInstListIt(cpu->addInst(inst));
DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n",
inst->readTid(),
inst->seqNum,
0/*inst->curCount()*/);
// Create Front-End Resource Schedule For Instruction
ThePipeline::createFrontEndSchedule(inst);
}
// Don't let instruction pass to next stage if it hasnt completed
// all of it's requests for this stage.
all_reqs_completed = processInstSchedule(inst);
if (!all_reqs_completed) {
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);
insts[tid].push(inst);
}
break;
} else if (!insts[tid].empty()){
insts[tid].pop();
}
sendInstToNextStage(inst);
//++stageProcessedInsts;
}
// Record that stage has written to the time buffer for activity
// tracking.
if (toNextStageIndex) {
wroteToTimeBuffer = true;
}
}
int
FirstStage::getFetchingThread(FetchPriority &fetch_priority)
{
if (numThreads > 1) {
switch (fetch_priority) {
case SingleThread:
return 0;
case RoundRobin:
return roundRobin();
default:
return -1;
}
} else {
int tid = *((*activeThreads).begin());
if (stageStatus[tid] == Running ||
stageStatus[tid] == Idle) {
return tid;
} else {
return -1;
}
}
}
int
FirstStage::roundRobin()
{
list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin();
list<unsigned>::iterator end = (*fetchPriorityList).end();
int high_pri;
while (pri_iter != end) {
high_pri = *pri_iter;
assert(high_pri <= numThreads);
if (stageStatus[high_pri] == Running ||
stageStatus[high_pri] == Idle) {
(*fetchPriorityList).erase(pri_iter);
(*fetchPriorityList).push_back(high_pri);
return high_pri;
}
pri_iter++;
}
return -1;
}