blob: 5a871d0d4c6591af236aeedef4b38905cad9cf72 [file] [log] [blame]
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2013 Advanced Micro Devices, 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 <list>
#include <vector>
#include "arch/isa_traits.hh"
#include "config/the_isa.hh"
#include "cpu/inorder/resources/use_def.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "debug/InOrderStall.hh"
#include "debug/InOrderUseDef.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
Cycles res_latency, InOrderCPU *_cpu,
ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
serializeOnNextInst[tid] = false;
serializeAfterSeqNum[tid] = 0;
regDepMap[tid] = &cpu->archRegDepMap[tid];
}
}
void
UseDefUnit::regStats()
{
uniqueRegsPerSwitch
.name(name() + ".uniqueRegsPerSwitch")
.desc("Number of Unique Registers Needed Per Context Switch")
.prereq(uniqueRegsPerSwitch);
intRegFileReads
.name(name() + ".intRegFileReads")
.desc("Number of Reads from Int. Register File");
intRegFileWrites
.name(name() + ".intRegFileWrites")
.desc("Number of Writes to Int. Register File");
intRegFileAccs
.name(name() + ".intRegFileAccesses")
.desc("Total Accesses (Read+Write) to the Int. Register File");
intRegFileAccs = intRegFileReads + intRegFileWrites;
floatRegFileReads
.name(name() + ".floatRegFileReads")
.desc("Number of Reads from FP Register File");
floatRegFileWrites
.name(name() + ".floatRegFileWrites")
.desc("Number of Writes to FP Register File");
floatRegFileAccs
.name(name() + ".floatRegFileAccesses")
.desc("Total Accesses (Read+Write) to the FP Register File");
floatRegFileAccs = floatRegFileReads + floatRegFileWrites;
//@todo: add miscreg reads/writes
// add forwarding by type???
regForwards
.name(name() + ".regForwards")
.desc("Number of Registers Read Through Forwarding Logic");
Resource::regStats();
}
void
UseDefUnit::init()
{
// Set Up Resource Events to Appropriate Resource BandWidth
if (latency > Cycles(0)) {
resourceEvent = new ResourceEvent[width];
} else {
resourceEvent = NULL;
}
for (int i = 0; i < width; i++) {
reqs[i] = new UseDefRequest(this);
}
initSlots();
}
ResReqPtr
UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
UseDefRequest *ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_num]);
ud_req->setRequest(inst, stage_num, id, slot_num, cmd,
inst->curSkedEntry->idx);
return ud_req;
}
ResReqPtr
UseDefUnit::findRequest(DynInstPtr inst)
{
for (int i = 0; i < width; i++) {
UseDefRequest* ud_req =
dynamic_cast<UseDefRequest*>(reqs[i]);
assert(ud_req);
if (ud_req->valid &&
ud_req->getInst() == inst &&
ud_req->cmd == inst->curSkedEntry->cmd &&
ud_req->useDefIdx == inst->curSkedEntry->idx) {
return ud_req;
}
}
return NULL;
}
void
UseDefUnit::execute(int slot_idx)
{
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_idx]);
DynInstPtr inst = ud_req->inst;
ThreadID tid = inst->readTid();
InstSeqNum seq_num = inst->seqNum;
int ud_idx = ud_req->useDefIdx;
if (serializeOnNextInst[tid] &&
seq_num > serializeAfterSeqNum[tid]) {
inst->setSerializeBefore();
serializeOnNextInst[tid] = false;
}
if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
cpu->instList[tid].front() != inst) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize before instruction encountered."
" Blocking until pipeline is clear.\n", tid, seq_num);
ud_req->done(false);
return;
} else if (inst->isStoreConditional() || inst->isSerializeAfter()) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] Serialize after instruction encountered."
" Blocking until pipeline is clear.\n", tid, seq_num);
serializeOnNextInst[tid] = true;
serializeAfterSeqNum[tid] = seq_num;
}
if (inst->fault != NoFault) {
DPRINTF(InOrderUseDef,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->pcState());
ud_req->done();
return;
}
// If there is a non-speculative instruction
// in the pipeline then stall instructions here
// ---
if (*nonSpecInstActive[tid] && seq_num > *nonSpecSeqNum[tid]) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because"
"there is non-speculative instruction [sn:%i] has not "
"graduated.\n", tid, seq_num, *nonSpecSeqNum[tid]);
ud_req->done(false);
return;
} else if (inst->isNonSpeculative()) {
*nonSpecInstActive[tid] = true;
*nonSpecSeqNum[tid] = seq_num;
}
switch (ud_req->cmd)
{
case ReadSrcReg:
{
RegClass reg_type;
RegIndex reg_idx = inst->_srcRegIdx[ud_idx];
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
inst->flattenSrcReg(ud_idx, flat_idx);
if (flat_idx == TheISA::ZeroReg && reg_type == IntRegClass) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Ignoring Reading of ISA-ZeroReg "
"(Int. Reg %i).\n", tid, inst->seqNum, flat_idx);
ud_req->done();
return;
} else {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Attempting to read source "
"register idx %i (reg #%i, flat#%i).\n",
tid, seq_num, ud_idx, reg_idx, flat_idx);
}
if (regDepMap[tid]->canRead(reg_type, flat_idx, inst)) {
switch (reg_type)
{
case IntRegClass:
{
uniqueIntRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Int Reg %i"
" (%i) from Register File:0x%x.\n",
tid, seq_num,
reg_idx, flat_idx,
cpu->readIntReg(flat_idx,inst->readTid()));
inst->setIntSrc(ud_idx,
cpu->readIntReg(flat_idx,
inst->readTid()));
intRegFileReads++;
}
break;
case FloatRegClass:
{
uniqueFloatRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Float Reg %i"
" (%i) from Register File:%x (%08f).\n",
tid, seq_num,
reg_idx - FP_Reg_Base, flat_idx,
cpu->readFloatRegBits(flat_idx,
inst->readTid()),
cpu->readFloatReg(flat_idx,
inst->readTid()));
inst->setFloatSrc(ud_idx,
cpu->readFloatReg(flat_idx,
inst->readTid()));
inst->setFloatRegBitsSrc(ud_idx,
cpu->readFloatRegBits(flat_idx,
inst->readTid()));
floatRegFileReads++;
}
break;
case MiscRegClass:
{
uniqueMiscRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Reading Misc Reg %i "
" (%i) from Register File:0x%x.\n",
tid, seq_num,
reg_idx - Misc_Reg_Base, flat_idx,
cpu->readMiscReg(flat_idx,
inst->readTid()));
inst->setIntSrc(ud_idx,
cpu->readMiscReg(flat_idx,
inst->readTid()));
}
break;
default:
panic("Invalid Register Type: %i", reg_type);
}
ud_req->done();
} else {
// Look for forwarding opportunities
DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_type,
flat_idx,
inst);
if (forward_inst) {
int dest_reg_idx =
forward_inst->getDestIdxNum(flat_idx);
switch (reg_type)
{
case IntRegClass:
{
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
" reg %i (%i), value 0x%x from "
"[sn:%i] to [sn:%i] source #%x.\n",
tid, reg_idx, flat_idx,
forward_inst->readIntResult(dest_reg_idx),
forward_inst->seqNum,
inst->seqNum, ud_idx);
inst->setIntSrc(ud_idx,
forward_inst->
readIntResult(dest_reg_idx));
}
break;
case FloatRegClass:
{
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
" reg %i (%i) value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, reg_idx - FP_Reg_Base, flat_idx,
forward_inst->readFloatResult(dest_reg_idx),
forward_inst->seqNum, inst->seqNum, ud_idx);
inst->setFloatSrc(ud_idx,
forward_inst->
readFloatResult(dest_reg_idx));
}
break;
case MiscRegClass:
{
DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
" reg %i (%i) value 0x%x from "
"[sn:%i] to [sn:%i] source #%i.\n",
tid, reg_idx - Misc_Reg_Base, flat_idx,
forward_inst->readIntResult(dest_reg_idx),
forward_inst->seqNum,
inst->seqNum, ud_idx);
inst->setIntSrc(ud_idx,
forward_inst->
readIntResult(dest_reg_idx));
}
break;
default:
panic("Invalid Register Type: %i", reg_type);
}
regForwards++;
ud_req->done();
} else {
DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i "
"is not ready to read.\n",
tid, reg_idx);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read "
"register (idx=%i)\n",
tid, reg_idx);
ud_req->done(false);
}
}
}
break;
case WriteDestReg:
{
RegClass reg_type;
RegIndex reg_idx = inst->_destRegIdx[ud_idx];
RegIndex flat_idx = cpu->flattenRegIdx(reg_idx, reg_type, tid);
if (flat_idx == TheISA::ZeroReg && reg_type == IntRegClass) {
DPRINTF(IntRegs, "[tid:%i]: Ignoring Writing of ISA-ZeroReg "
"(Int. Reg %i)\n", tid, flat_idx);
ud_req->done();
return;
}
if (regDepMap[tid]->canWrite(reg_type, flat_idx, inst)) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Flattening register idx %i "
"(%i) and Attempting to write to Register File.\n",
tid, seq_num, reg_idx, flat_idx);
switch (reg_type)
{
case IntRegClass:
{
uniqueIntRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Int. Result "
"0x%x to register idx %i (%i).\n",
tid, seq_num, inst->readIntResult(ud_idx),
reg_idx, flat_idx);
// Remove Dependencies
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
cpu->setIntReg(flat_idx,
inst->readIntResult(ud_idx),
inst->readTid());
intRegFileWrites++;
}
break;
case FloatRegClass:
{
uniqueFloatRegMap[flat_idx] = true;
// Remove Reg. Dependecny Block on this Register
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
if (inst->resultType(ud_idx) ==
InOrderDynInst::FloatBits) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing FP-Bits "
"Result %08f (bits:0x%x) to register "
"idx %i (%i).\n",
tid, seq_num,
inst->readFloatResult(ud_idx),
inst->readFloatBitsResult(ud_idx),
reg_idx - FP_Reg_Base, flat_idx);
// Check for FloatRegBits Here
cpu->setFloatRegBits(flat_idx,
inst->readFloatBitsResult(ud_idx),
inst->readTid());
} else if (inst->resultType(ud_idx) ==
InOrderDynInst::Float) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Float "
"Result %08f (bits:0x%x) to register "
"idx %i (%i).\n",
tid, seq_num, inst->readFloatResult(ud_idx),
inst->readIntResult(ud_idx),
reg_idx - FP_Reg_Base, flat_idx);
cpu->setFloatReg(flat_idx,
inst->readFloatResult(ud_idx),
inst->readTid());
} else if (inst->resultType(ud_idx) ==
InOrderDynInst::Double) {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Writing Double "
"Result %08f (bits:0x%x) to register "
"idx %i (%i).\n",
tid, seq_num,
inst->readFloatResult(ud_idx),
inst->readIntResult(ud_idx),
reg_idx - FP_Reg_Base, flat_idx);
cpu->setFloatReg(flat_idx,
inst->readFloatResult(ud_idx),
inst->readTid());
} else {
panic("Result Type Not Set For [sn:%i] %s.\n",
inst->seqNum, inst->instName());
}
floatRegFileWrites++;
}
break;
case MiscRegClass:
{
uniqueMiscRegMap[flat_idx] = true;
DPRINTF(InOrderUseDef, "[tid:%i]: Writing Misc. 0x%x "
"to register idx %i.\n",
tid, inst->readIntResult(ud_idx), reg_idx - Misc_Reg_Base);
// Remove Dependencies
regDepMap[tid]->removeFront(reg_type, flat_idx, inst);
cpu->setMiscReg(flat_idx,
inst->readIntResult(ud_idx),
inst->readTid());
}
break;
default:
panic("Invalid Register Type: %i", reg_type);
}
ud_req->done();
} else {
DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i]: Dest. register idx: %i is "
"not ready to write.\n",
tid, seq_num, reg_idx);
DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write "
"register (idx=%i)\n",
tid, reg_idx);
ud_req->done(false);
}
}
break;
case MarkDestRegs:
{
regDepMap[tid]->insert(inst);
ud_req->done();
}
break;
default:
fatal("Unrecognized command to %s", resName);
}
}
void
UseDefUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
{
uniqueRegsPerSwitch = uniqueIntRegMap.size() + uniqueFloatRegMap.size()
+ uniqueMiscRegMap.size();
uniqueIntRegMap.clear();
uniqueFloatRegMap.clear();
uniqueMiscRegMap.clear();
}