When the scoreboard checks RAW dependency, it determines whether the source registers can be forwarded or not to evaluate relative latency. To do that, fuIndices[index] should be used as an index for accessing cant_forward_from_fu_indices, not register index itself. Moreover, since fuIndices[index] is cleared as -1 by clearInstDests(), the first compare should be fuIndices[index] != -1 instead of 1. Change-Id: Ic62546855a8ad5365064d2ea2e2a0fbc1ccc6f41 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50287 Reviewed-by: ZHENGRONG WANG <seanyukigeek@gmail.com> Maintainer: ZHENGRONG WANG <seanyukigeek@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
315 lines
10 KiB
C++
315 lines
10 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "cpu/minor/scoreboard.hh"
|
|
|
|
#include "cpu/reg_class.hh"
|
|
#include "debug/MinorScoreboard.hh"
|
|
#include "debug/MinorTiming.hh"
|
|
|
|
namespace gem5
|
|
{
|
|
|
|
GEM5_DEPRECATED_NAMESPACE(Minor, minor);
|
|
namespace minor
|
|
{
|
|
|
|
bool
|
|
Scoreboard::findIndex(const RegId& reg, Index &scoreboard_index)
|
|
{
|
|
bool ret = false;
|
|
|
|
switch (reg.classValue()) {
|
|
case IntRegClass:
|
|
if (reg.index() == zeroReg) {
|
|
/* Don't bother with the zero register */
|
|
ret = false;
|
|
} else {
|
|
scoreboard_index = reg.index();
|
|
ret = true;
|
|
}
|
|
break;
|
|
case FloatRegClass:
|
|
scoreboard_index = floatRegOffset + reg.index();
|
|
ret = true;
|
|
break;
|
|
case VecRegClass:
|
|
case VecElemClass:
|
|
scoreboard_index = vecRegOffset + reg.index();
|
|
ret = true;
|
|
break;
|
|
case VecPredRegClass:
|
|
scoreboard_index = vecPredRegOffset + reg.index();
|
|
ret = true;
|
|
break;
|
|
case CCRegClass:
|
|
scoreboard_index = ccRegOffset + reg.index();
|
|
ret = true;
|
|
break;
|
|
case MiscRegClass:
|
|
/* Don't bother with Misc registers */
|
|
ret = false;
|
|
break;
|
|
default:
|
|
panic("Unknown register class: %d", 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, 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] = invalidFUIndex;
|
|
}
|
|
|
|
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)) {
|
|
int src_reg_fu = fuIndices[index];
|
|
bool cant_forward = src_reg_fu != invalidFUIndex &&
|
|
cant_forward_from_fu_indices &&
|
|
src_reg_fu < cant_forward_from_fu_indices->size() &&
|
|
(*cant_forward_from_fu_indices)[src_reg_fu];
|
|
|
|
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 (debug::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++;
|
|
}
|
|
|
|
minor::minorTrace("busy=%s\n", result_stream.str());
|
|
}
|
|
|
|
} // namespace minor
|
|
} // namespace gem5
|