blob: 5c0e86a673d780cdf088b1ccbc31e297b36cade7 [file] [log] [blame]
/*
* Copyright (c) 2013-2014, 2016-2017 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/scoreboard.hh"
#include "arch/registers.hh"
#include "cpu/reg_class.hh"
#include "debug/MinorScoreboard.hh"
#include "debug/MinorTiming.hh"
namespace Minor
{
bool
Scoreboard::findIndex(const RegId& reg, Index &scoreboard_index)
{
bool ret = false;
if (reg.isZeroReg()) {
/* Don't bother with the zero register */
ret = false;
} else {
switch (reg.classValue())
{
case IntRegClass:
scoreboard_index = reg.index();
ret = true;
break;
case FloatRegClass:
scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
reg.index();
ret = true;
break;
case VecRegClass:
scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
TheISA::NumFloatRegs + reg.index();
ret = true;
break;
case VecElemClass:
scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
TheISA::NumFloatRegs + reg.flatIndex();
ret = true;
break;
case VecPredRegClass:
scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
TheISA::NumFloatRegs + TheISA::NumVecRegs + reg.index();
ret = true;
break;
case CCRegClass:
scoreboard_index = TheISA::NumIntRegs + reg.index();
ret = true;
break;
case MiscRegClass:
/* Don't bother with Misc registers */
ret = false;
break;
default:
panic("Unknown register class: %d",
static_cast<int>(reg.classValue()));
}
}
return ret;
}
/** Flatten a RegId, irrespective of what reg type it's pointing to */
static RegId
flattenRegIndex(const RegId& reg, ThreadContext *thread_context)
{
return thread_context->flattenRegId(reg);
}
void
Scoreboard::markupInstDests(MinorDynInstPtr inst, Cycles retire_time,
ThreadContext *thread_context, bool mark_unpredictable)
{
if (inst->isFault())
return;
StaticInstPtr staticInst = inst->staticInst;
unsigned int num_dests = staticInst->numDestRegs();
/** Mark each destination register */
for (unsigned int dest_index = 0; dest_index < num_dests;
dest_index++)
{
RegId reg = flattenRegIndex(
staticInst->destRegIdx(dest_index), thread_context);
Index index;
if (findIndex(reg, index)) {
if (mark_unpredictable)
numUnpredictableResults[index]++;
inst->flatDestRegIdx[dest_index] = reg;
numResults[index]++;
returnCycle[index] = retire_time;
/* We should be able to rely on only being given accending
* execSeqNums, but sanity check */
if (inst->id.execSeqNum > writingInst[index]) {
writingInst[index] = inst->id.execSeqNum;
fuIndices[index] = inst->fuIndex;
}
DPRINTF(MinorScoreboard, "Marking up inst: %s"
" regIndex: %d final numResults: %d returnCycle: %d\n",
*inst, index, numResults[index], returnCycle[index]);
} else {
/* Use ZeroReg to mark invalid/untracked dests */
inst->flatDestRegIdx[dest_index] = RegId(IntRegClass,
TheISA::ZeroReg);
}
}
}
InstSeqNum
Scoreboard::execSeqNumToWaitFor(MinorDynInstPtr inst,
ThreadContext *thread_context)
{
InstSeqNum ret = 0;
if (inst->isFault())
return ret;
StaticInstPtr staticInst = inst->staticInst;
unsigned int num_srcs = staticInst->numSrcRegs();
for (unsigned int src_index = 0; src_index < num_srcs; src_index++) {
RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
thread_context);
unsigned short int index;
if (findIndex(reg, index)) {
if (writingInst[index] > ret)
ret = writingInst[index];
}
}
DPRINTF(MinorScoreboard, "Inst: %s depends on execSeqNum: %d\n",
*inst, ret);
return ret;
}
void
Scoreboard::clearInstDests(MinorDynInstPtr inst, bool clear_unpredictable)
{
if (inst->isFault())
return;
StaticInstPtr staticInst = inst->staticInst;
unsigned int num_dests = staticInst->numDestRegs();
/** Mark each destination register */
for (unsigned int dest_index = 0; dest_index < num_dests;
dest_index++)
{
const RegId& reg = inst->flatDestRegIdx[dest_index];
Index index;
if (findIndex(reg, index)) {
if (clear_unpredictable && numUnpredictableResults[index] != 0)
numUnpredictableResults[index] --;
numResults[index] --;
if (numResults[index] == 0) {
returnCycle[index] = Cycles(0);
writingInst[index] = 0;
fuIndices[index] = -1;
}
DPRINTF(MinorScoreboard, "Clearing inst: %s"
" regIndex: %d final numResults: %d\n",
*inst, index, numResults[index]);
}
}
}
bool
Scoreboard::canInstIssue(MinorDynInstPtr inst,
const std::vector<Cycles> *src_reg_relative_latencies,
const std::vector<bool> *cant_forward_from_fu_indices,
Cycles now, ThreadContext *thread_context)
{
/* Always allow fault to be issued */
if (inst->isFault())
return true;
StaticInstPtr staticInst = inst->staticInst;
unsigned int num_srcs = staticInst->numSrcRegs();
/* Default to saying you can issue */
bool ret = true;
unsigned int num_relative_latencies = 0;
Cycles default_relative_latency = Cycles(0);
/* Where relative latencies are given, the default is the last
* one as that allows the rel. lat. list to be shorted than the
* number of src. regs */
if (src_reg_relative_latencies &&
src_reg_relative_latencies->size() != 0)
{
num_relative_latencies = src_reg_relative_latencies->size();
default_relative_latency = (*src_reg_relative_latencies)
[num_relative_latencies-1];
}
/* For each source register, find the latest result */
unsigned int src_index = 0;
while (src_index < num_srcs && /* More registers */
ret /* Still possible */)
{
RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
thread_context);
unsigned short int index;
if (findIndex(reg, index)) {
bool cant_forward = fuIndices[index] != 1 &&
cant_forward_from_fu_indices &&
index < cant_forward_from_fu_indices->size() &&
(*cant_forward_from_fu_indices)[index];
Cycles relative_latency = (cant_forward ? Cycles(0) :
(src_index >= num_relative_latencies ?
default_relative_latency :
(*src_reg_relative_latencies)[src_index]));
if (returnCycle[index] > (now + relative_latency) ||
numUnpredictableResults[index] != 0)
{
ret = false;
}
}
src_index++;
}
if (DTRACE(MinorTiming)) {
if (ret && num_srcs > num_relative_latencies &&
num_relative_latencies != 0)
{
DPRINTF(MinorTiming, "Warning, inst: %s timing extra decode has"
" more src. regs: %d than relative latencies: %d\n",
staticInst->disassemble(0), num_srcs, num_relative_latencies);
}
}
return ret;
}
void
Scoreboard::minorTrace() const
{
std::ostringstream result_stream;
bool printed_element = false;
unsigned int i = 0;
while (i < numRegs) {
unsigned short int num_results = numResults[i];
unsigned short int num_unpredictable_results =
numUnpredictableResults[i];
if (!(num_results == 0 && num_unpredictable_results == Cycles(0))) {
if (printed_element)
result_stream << ',';
result_stream << '(' << i << ','
<< num_results << '/'
<< num_unpredictable_results << '/'
<< returnCycle[i] << '/'
<< writingInst[i] << ')';
printed_element = true;
}
i++;
}
MINORTRACE("busy=%s\n", result_stream.str());
}
}