82c5a754e6
- on certain retry requests you can get an assertion failure - fix by allowing the request to literally "Retry" itself if it wasnt successful before, and then block any requests through cache port while waiting for the cache to be made available for access
970 lines
29 KiB
C++
970 lines
29 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 <vector>
|
|
#include <list>
|
|
|
|
#include "arch/isa_traits.hh"
|
|
#include "arch/locked_mem.hh"
|
|
#include "arch/utility.hh"
|
|
#include "arch/predecoder.hh"
|
|
#include "config/the_isa.hh"
|
|
#include "cpu/inorder/resources/cache_unit.hh"
|
|
#include "cpu/inorder/pipeline_traits.hh"
|
|
#include "cpu/inorder/cpu.hh"
|
|
#include "mem/request.hh"
|
|
|
|
using namespace std;
|
|
using namespace TheISA;
|
|
using namespace ThePipeline;
|
|
|
|
Tick
|
|
CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
|
|
{
|
|
panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
|
|
return curTick;
|
|
}
|
|
|
|
void
|
|
CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
|
|
{
|
|
panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
|
|
}
|
|
|
|
void
|
|
CacheUnit::CachePort::recvStatusChange(Status status)
|
|
{
|
|
if (status == RangeChange)
|
|
return;
|
|
|
|
panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
|
|
}
|
|
|
|
bool
|
|
CacheUnit::CachePort::recvTiming(Packet *pkt)
|
|
{
|
|
cachePortUnit->processCacheCompletion(pkt);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
CacheUnit::CachePort::recvRetry()
|
|
{
|
|
cachePortUnit->recvRetry();
|
|
}
|
|
|
|
CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
|
|
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
|
|
: Resource(res_name, res_id, res_width, res_latency, _cpu),
|
|
cachePortBlocked(false), predecoder(NULL)
|
|
{
|
|
cachePort = new CachePort(this);
|
|
|
|
// Hard-Code Selection For Now
|
|
if (res_name == "icache_port")
|
|
_tlb = params->itb;
|
|
else if (res_name == "dcache_port")
|
|
_tlb = params->dtb;
|
|
else
|
|
fatal("Unrecognized TLB name passed by user");
|
|
|
|
for (int i=0; i < MaxThreads; i++) {
|
|
tlbBlocked[i] = false;
|
|
}
|
|
}
|
|
|
|
TheISA::TLB*
|
|
CacheUnit::tlb()
|
|
{
|
|
return _tlb;
|
|
|
|
}
|
|
|
|
Port *
|
|
CacheUnit::getPort(const string &if_name, int idx)
|
|
{
|
|
if (if_name == resName)
|
|
return cachePort;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
CacheUnit::init()
|
|
{
|
|
// Currently Used to Model TLB Latency. Eventually
|
|
// Switch to Timing TLB translations.
|
|
resourceEvent = new CacheUnitEvent[width];
|
|
|
|
initSlots();
|
|
}
|
|
|
|
int
|
|
CacheUnit::getSlot(DynInstPtr inst)
|
|
{
|
|
ThreadID tid = inst->readTid();
|
|
|
|
if (tlbBlocked[inst->threadNumber]) {
|
|
return -1;
|
|
}
|
|
|
|
if (!inst->validMemAddr()) {
|
|
panic("Mem. Addr. must be set before requesting cache access\n");
|
|
}
|
|
|
|
Addr req_addr = inst->getMemAddr();
|
|
|
|
if (resName == "icache_port" ||
|
|
find(addrList[tid].begin(), addrList[tid].end(), req_addr) == addrList[tid].end()) {
|
|
|
|
int new_slot = Resource::getSlot(inst);
|
|
|
|
if (new_slot == -1)
|
|
return -1;
|
|
|
|
inst->memTime = curTick;
|
|
addrList[tid].push_back(req_addr);
|
|
addrMap[tid][req_addr] = inst->seqNum;
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: [sn:%i]: Address %08p added to dependency list\n",
|
|
inst->readTid(), inst->seqNum, req_addr);
|
|
return new_slot;
|
|
} else {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i] Denying request because there is an outstanding"
|
|
" request to/for addr. %08p. by [sn:%i] @ tick %i\n",
|
|
inst->readTid(), req_addr, addrMap[tid][req_addr], inst->memTime);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void
|
|
CacheUnit::freeSlot(int slot_num)
|
|
{
|
|
ThreadID tid = reqMap[slot_num]->inst->readTid();
|
|
|
|
vector<Addr>::iterator vect_it = find(addrList[tid].begin(), addrList[tid].end(),
|
|
reqMap[slot_num]->inst->getMemAddr());
|
|
assert(vect_it != addrList[tid].end());
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: Address %08p removed from dependency list\n",
|
|
reqMap[slot_num]->inst->readTid(), (*vect_it));
|
|
|
|
addrList[tid].erase(vect_it);
|
|
|
|
Resource::freeSlot(slot_num);
|
|
}
|
|
|
|
ResReqPtr
|
|
CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
|
|
int slot_num, unsigned cmd)
|
|
{
|
|
ScheduleEntry* sched_entry = inst->resSched.top();
|
|
|
|
if (!inst->validMemAddr()) {
|
|
panic("Mem. Addr. must be set before requesting cache access\n");
|
|
}
|
|
|
|
MemCmd::Command pkt_cmd;
|
|
|
|
switch (sched_entry->cmd)
|
|
{
|
|
case InitiateReadData:
|
|
pkt_cmd = MemCmd::ReadReq;
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: Read request from [sn:%i] for addr %08p\n",
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
break;
|
|
|
|
case InitiateWriteData:
|
|
pkt_cmd = MemCmd::WriteReq;
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: Write request from [sn:%i] for addr %08p\n",
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
break;
|
|
|
|
case InitiateFetch:
|
|
pkt_cmd = MemCmd::ReadReq;
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
break;
|
|
|
|
default:
|
|
panic("%i: Unexpected request type (%i) to %s", curTick,
|
|
sched_entry->cmd, name());
|
|
}
|
|
|
|
return new CacheRequest(this, inst, stage_num, id, slot_num,
|
|
sched_entry->cmd, 0, pkt_cmd,
|
|
0/*flags*/, this->cpu->readCpuId());
|
|
}
|
|
|
|
void
|
|
CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
|
|
{
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
|
|
assert(cache_req);
|
|
|
|
// Check to see if this instruction is requesting the same command
|
|
// or a different one
|
|
if (cache_req->cmd != inst->resSched.top()->cmd) {
|
|
// If different, then update command in the request
|
|
cache_req->cmd = inst->resSched.top()->cmd;
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: [sn:%i]: Updating the command for this "
|
|
"instruction\n ", inst->readTid(), inst->seqNum);
|
|
|
|
service_request = true;
|
|
} else {
|
|
// If same command, just check to see if memory access was completed
|
|
// but dont try to re-execute
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: [sn:%i]: requesting this resource again\n",
|
|
inst->readTid(), inst->seqNum);
|
|
|
|
service_request = true;
|
|
}
|
|
}
|
|
|
|
Fault
|
|
CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
|
|
int flags, TheISA::TLB::Mode tlb_mode)
|
|
{
|
|
ThreadID tid = inst->readTid();
|
|
Addr aligned_addr = inst->getMemAddr();
|
|
unsigned stage_num = cache_req->getStageNum();
|
|
unsigned slot_idx = cache_req->getSlot();
|
|
|
|
if (tlb_mode == TheISA::TLB::Execute) {
|
|
inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
|
|
acc_size, flags, inst->readPC(),
|
|
cpu->readCpuId(), inst->readTid());
|
|
cache_req->memReq = inst->fetchMemReq;
|
|
} else {
|
|
inst->dataMemReq = new Request(inst->readTid(), aligned_addr,
|
|
acc_size, flags, inst->readPC(),
|
|
cpu->readCpuId(), inst->readTid());
|
|
cache_req->memReq = inst->dataMemReq;
|
|
}
|
|
|
|
|
|
cache_req->fault =
|
|
_tlb->translateAtomic(cache_req->memReq,
|
|
cpu->thread[tid]->getTC(), tlb_mode);
|
|
|
|
if (cache_req->fault != NoFault) {
|
|
DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
|
|
"addr:%08p for [sn:%i].\n", tid, cache_req->fault->name(),
|
|
cache_req->memReq->getVaddr(), inst->seqNum);
|
|
|
|
cpu->pipelineStage[stage_num]->setResStall(cache_req, tid);
|
|
|
|
tlbBlocked[tid] = true;
|
|
|
|
cache_req->tlbStall = true;
|
|
|
|
scheduleEvent(slot_idx, 1);
|
|
|
|
cpu->trap(cache_req->fault, tid);
|
|
} else {
|
|
DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
|
|
"to phys. addr:%08p.\n", tid, inst->seqNum,
|
|
cache_req->memReq->getVaddr(),
|
|
cache_req->memReq->getPaddr());
|
|
}
|
|
|
|
return cache_req->fault;
|
|
}
|
|
|
|
template <class T>
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
|
|
{
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
|
|
assert(cache_req);
|
|
|
|
int acc_size = sizeof(T);
|
|
doTLBAccess(inst, cache_req, acc_size, flags, TheISA::TLB::Read);
|
|
|
|
if (cache_req->fault == NoFault) {
|
|
cache_req->reqData = new uint8_t[acc_size];
|
|
doCacheAccess(inst, NULL);
|
|
}
|
|
|
|
return cache_req->fault;
|
|
}
|
|
|
|
template <class T>
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
|
|
uint64_t *write_res)
|
|
{
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
|
|
assert(cache_req);
|
|
|
|
int acc_size = sizeof(T);
|
|
doTLBAccess(inst, cache_req, acc_size, flags, TheISA::TLB::Write);
|
|
|
|
if (cache_req->fault == NoFault) {
|
|
cache_req->reqData = new uint8_t[acc_size];
|
|
doCacheAccess(inst, write_res);
|
|
}
|
|
|
|
return cache_req->fault;
|
|
}
|
|
|
|
|
|
void
|
|
CacheUnit::execute(int slot_num)
|
|
{
|
|
if (cachePortBlocked) {
|
|
DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
|
|
return;
|
|
}
|
|
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
|
|
assert(cache_req);
|
|
|
|
DynInstPtr inst = cache_req->inst;
|
|
#if TRACING_ON
|
|
ThreadID tid = inst->readTid();
|
|
int seq_num = inst->seqNum;
|
|
#endif
|
|
|
|
cache_req->fault = NoFault;
|
|
|
|
switch (cache_req->cmd)
|
|
{
|
|
case InitiateFetch:
|
|
{
|
|
//@TODO: Switch to size of full cache block. Store in fetch buffer
|
|
int acc_size = sizeof(TheISA::MachInst);
|
|
|
|
doTLBAccess(inst, cache_req, acc_size, 0, TheISA::TLB::Execute);
|
|
|
|
// Only Do Access if no fault from TLB
|
|
if (cache_req->fault == NoFault) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
|
|
tid, name(), cache_req->inst->getMemAddr());
|
|
|
|
cache_req->reqData = new uint8_t[acc_size];
|
|
|
|
inst->setCurResSlot(slot_num);
|
|
|
|
doCacheAccess(inst);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case InitiateReadData:
|
|
case InitiateWriteData:
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: Initiating data access to %s for addr. %08p\n",
|
|
tid, name(), cache_req->inst->getMemAddr());
|
|
|
|
inst->setCurResSlot(slot_num);
|
|
|
|
if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
|
|
inst->execute();
|
|
} else {
|
|
inst->initiateAcc();
|
|
}
|
|
|
|
break;
|
|
|
|
case CompleteFetch:
|
|
if (cache_req->isMemAccComplete()) {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: Completing Fetch Access for [sn:%i]\n",
|
|
tid, inst->seqNum);
|
|
|
|
|
|
DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
|
|
tid, seq_num, inst->staticInst->disassemble(inst->PC));
|
|
|
|
delete cache_req->dataPkt;
|
|
//cache_req->setMemStall(false);
|
|
cache_req->done();
|
|
} else {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n",
|
|
tid, inst->seqNum);
|
|
DPRINTF(InOrderStall,
|
|
"STALL: [tid:%i]: Fetch miss from %08p\n",
|
|
tid, cache_req->inst->readPC());
|
|
cache_req->setCompleted(false);
|
|
//cache_req->setMemStall(true);
|
|
}
|
|
break;
|
|
|
|
case CompleteReadData:
|
|
case CompleteWriteData:
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
|
|
tid, inst->seqNum);
|
|
|
|
if (cache_req->isMemAccComplete() ||
|
|
inst->isDataPrefetch() ||
|
|
inst->isInstPrefetch()) {
|
|
cache_req->setMemStall(false);
|
|
cache_req->done();
|
|
} else {
|
|
DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
|
|
tid, cache_req->inst->getMemAddr());
|
|
cache_req->setCompleted(false);
|
|
cache_req->setMemStall(true);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fatal("Unrecognized command to %s", resName);
|
|
}
|
|
}
|
|
|
|
void
|
|
CacheUnit::prefetch(DynInstPtr inst)
|
|
{
|
|
warn_once("Prefetching currently unimplemented");
|
|
|
|
CacheReqPtr cache_req
|
|
= dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
|
|
assert(cache_req);
|
|
|
|
// Clean-Up cache resource request so
|
|
// other memory insts. can use them
|
|
cache_req->setCompleted();
|
|
cachePortBlocked = false;
|
|
cache_req->setMemAccPending(false);
|
|
cache_req->setMemAccCompleted();
|
|
inst->unsetMemAddr();
|
|
}
|
|
|
|
|
|
void
|
|
CacheUnit::writeHint(DynInstPtr inst)
|
|
{
|
|
warn_once("Write Hints currently unimplemented");
|
|
|
|
CacheReqPtr cache_req
|
|
= dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
|
|
assert(cache_req);
|
|
|
|
// Clean-Up cache resource request so
|
|
// other memory insts. can use them
|
|
cache_req->setCompleted();
|
|
cachePortBlocked = false;
|
|
cache_req->setMemAccPending(false);
|
|
cache_req->setMemAccCompleted();
|
|
inst->unsetMemAddr();
|
|
}
|
|
|
|
// @TODO: Split into doCacheRead() and doCacheWrite()
|
|
Fault
|
|
CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res)
|
|
{
|
|
Fault fault = NoFault;
|
|
#if TRACING_ON
|
|
ThreadID tid = inst->readTid();
|
|
#endif
|
|
|
|
CacheReqPtr cache_req
|
|
= dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
|
|
assert(cache_req);
|
|
|
|
// Check for LL/SC and if so change command
|
|
if (cache_req->memReq->isLLSC() && cache_req->pktCmd == MemCmd::ReadReq) {
|
|
cache_req->pktCmd = MemCmd::LoadLockedReq;
|
|
}
|
|
|
|
if (cache_req->pktCmd == MemCmd::WriteReq) {
|
|
cache_req->pktCmd =
|
|
cache_req->memReq->isSwap() ? MemCmd::SwapReq :
|
|
(cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq
|
|
: MemCmd::WriteReq);
|
|
}
|
|
|
|
cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd,
|
|
Packet::Broadcast);
|
|
|
|
if (cache_req->dataPkt->isRead()) {
|
|
cache_req->dataPkt->dataStatic(cache_req->reqData);
|
|
} else if (cache_req->dataPkt->isWrite()) {
|
|
cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
|
|
|
|
if (cache_req->memReq->isCondSwap()) {
|
|
assert(write_res);
|
|
cache_req->memReq->setExtraData(*write_res);
|
|
}
|
|
}
|
|
|
|
cache_req->dataPkt->time = curTick;
|
|
|
|
bool do_access = true; // flag to suppress cache access
|
|
|
|
Request *memReq = cache_req->dataPkt->req;
|
|
|
|
if (cache_req->dataPkt->isWrite() && cache_req->memReq->isLLSC()) {
|
|
assert(cache_req->inst->isStoreConditional());
|
|
DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
|
|
do_access = TheISA::handleLockedWrite(cpu, memReq);
|
|
}
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i] [sn:%i] attempting to access cache\n",
|
|
tid, inst->seqNum);
|
|
|
|
if (do_access) {
|
|
if (!cachePort->sendTiming(cache_req->dataPkt)) {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i] [sn:%i] cannot access cache, because port "
|
|
"is blocked. now waiting to retry request\n", tid,
|
|
inst->seqNum);
|
|
cache_req->setCompleted(false);
|
|
cachePortBlocked = true;
|
|
} else {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i] [sn:%i] is now waiting for cache response\n",
|
|
tid, inst->seqNum);
|
|
cache_req->setCompleted();
|
|
cache_req->setMemAccPending();
|
|
cachePortBlocked = false;
|
|
}
|
|
} else if (!do_access && memReq->isLLSC()){
|
|
// Store-Conditional instructions complete even if they "failed"
|
|
assert(cache_req->inst->isStoreConditional());
|
|
cache_req->setCompleted(true);
|
|
|
|
DPRINTF(LLSC,
|
|
"[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
|
|
tid, tid);
|
|
|
|
processCacheCompletion(cache_req->dataPkt);
|
|
} else {
|
|
// Make cache request again since access due to
|
|
// inability to access
|
|
DPRINTF(InOrderStall, "STALL: \n");
|
|
cache_req->setCompleted(false);
|
|
}
|
|
|
|
return fault;
|
|
}
|
|
|
|
void
|
|
CacheUnit::processCacheCompletion(PacketPtr pkt)
|
|
{
|
|
// Cast to correct packet type
|
|
CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
|
|
assert(cache_pkt);
|
|
|
|
if (cache_pkt->cacheReq->isSquashed()) {
|
|
DPRINTF(InOrderCachePort,
|
|
"Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
|
|
cache_pkt->cacheReq->getInst()->readTid(),
|
|
cache_pkt->cacheReq->getInst()->seqNum);
|
|
|
|
cache_pkt->cacheReq->done();
|
|
delete cache_pkt;
|
|
return;
|
|
}
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n",
|
|
cache_pkt->cacheReq->getInst()->readTid(),
|
|
cache_pkt->cacheReq->getInst()->seqNum,
|
|
cache_pkt->cacheReq->getInst()->getMemAddr());
|
|
|
|
// Cast to correct request type
|
|
CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
|
|
findRequest(cache_pkt->cacheReq->getInst()));
|
|
assert(cache_req);
|
|
|
|
|
|
// Get resource request info
|
|
unsigned stage_num = cache_req->getStageNum();
|
|
DynInstPtr inst = cache_req->inst;
|
|
ThreadID tid = cache_req->inst->readTid();
|
|
|
|
if (!cache_req->isSquashed()) {
|
|
if (inst->resSched.top()->cmd == CompleteFetch) {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: Processing fetch access\n",
|
|
tid, inst->seqNum);
|
|
|
|
// NOTE: This is only allowing a thread to fetch one line
|
|
// at a time. Re-examine when/if prefetching
|
|
// gets implemented.
|
|
//memcpy(fetchData[tid], cache_pkt->getPtr<uint8_t>(),
|
|
// cache_pkt->getSize());
|
|
|
|
// Get the instruction from the array of the cache line.
|
|
// @todo: update thsi
|
|
ExtMachInst ext_inst;
|
|
StaticInstPtr staticInst = NULL;
|
|
Addr inst_pc = inst->readPC();
|
|
MachInst mach_inst =
|
|
TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
|
|
(cache_pkt->getPtr<uint8_t>()));
|
|
|
|
predecoder.setTC(cpu->thread[tid]->getTC());
|
|
predecoder.moreBytes(inst_pc, inst_pc, mach_inst);
|
|
ext_inst = predecoder.getExtMachInst();
|
|
|
|
inst->setMachInst(ext_inst);
|
|
|
|
// Set Up More TraceData info
|
|
if (inst->traceData) {
|
|
inst->traceData->setStaticInst(inst->staticInst);
|
|
inst->traceData->setPC(inst->readPC());
|
|
}
|
|
|
|
} else if (inst->staticInst && inst->isMemRef()) {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: Processing cache access\n",
|
|
tid, inst->seqNum);
|
|
|
|
inst->completeAcc(pkt);
|
|
|
|
if (inst->isLoad()) {
|
|
assert(cache_pkt->isRead());
|
|
|
|
if (cache_pkt->req->isLLSC()) {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: Handling Load-Linked for [sn:%u]\n",
|
|
tid, inst->seqNum);
|
|
TheISA::handleLockedRead(cpu, cache_pkt->req);
|
|
}
|
|
|
|
// @NOTE: Hardcoded to for load instructions. Assumes that
|
|
// the dest. idx 0 is always where the data is loaded to.
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: Data loaded was: %08p\n",
|
|
tid, inst->seqNum, inst->readIntResult(0));
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: FP Data loaded was: %08p\n",
|
|
tid, inst->seqNum, inst->readFloatResult(0));
|
|
} else if(inst->isStore()) {
|
|
assert(cache_pkt->isWrite());
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u]: [sn:%i]: Data stored was: FIX ME\n",
|
|
tid, inst->seqNum/*,
|
|
getMemData(cache_pkt)*/);
|
|
}
|
|
|
|
delete cache_pkt;
|
|
}
|
|
|
|
cache_req->setMemAccPending(false);
|
|
cache_req->setMemAccCompleted();
|
|
|
|
if (cache_req->isMemStall() &&
|
|
cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
|
|
DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n", tid);
|
|
|
|
cpu->activateContext(tid);
|
|
|
|
DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
|
|
"miss.\n", tid);
|
|
}
|
|
|
|
// Wake up the CPU (if it went to sleep and was waiting on this
|
|
// completion event).
|
|
cpu->wakeCPU();
|
|
|
|
DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
|
|
tid, cpu->pipelineStage[stage_num]->name());
|
|
|
|
cpu->switchToActive(stage_num);
|
|
} else {
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%u] Miss on block @ %08p completed, but squashed\n",
|
|
tid, cache_req->inst->readPC());
|
|
cache_req->setMemAccCompleted();
|
|
}
|
|
|
|
inst->unsetMemAddr();
|
|
}
|
|
|
|
void
|
|
CacheUnit::recvRetry()
|
|
{
|
|
DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n");
|
|
|
|
assert(cachePortBlocked);
|
|
|
|
// Clear the cache port for use again
|
|
cachePortBlocked = false;
|
|
}
|
|
|
|
CacheUnitEvent::CacheUnitEvent()
|
|
: ResourceEvent()
|
|
{ }
|
|
|
|
void
|
|
CacheUnitEvent::process()
|
|
{
|
|
DynInstPtr inst = resource->reqMap[slotIdx]->inst;
|
|
int stage_num = resource->reqMap[slotIdx]->getStageNum();
|
|
ThreadID tid = inst->threadNumber;
|
|
CacheReqPtr req_ptr = dynamic_cast<CacheReqPtr>(resource->reqMap[slotIdx]);
|
|
|
|
DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
|
|
inst->seqNum);
|
|
|
|
CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource);
|
|
assert(tlb_res);
|
|
|
|
tlb_res->tlbBlocked[tid] = false;
|
|
|
|
tlb_res->cpu->pipelineStage[stage_num]->
|
|
unsetResStall(tlb_res->reqMap[slotIdx], tid);
|
|
|
|
req_ptr->tlbStall = false;
|
|
|
|
if (req_ptr->isSquashed()) {
|
|
req_ptr->done();
|
|
}
|
|
}
|
|
|
|
void
|
|
CacheUnit::squashDueToMemStall(DynInstPtr inst, int stage_num,
|
|
InstSeqNum squash_seq_num, ThreadID tid)
|
|
{
|
|
// If squashing due to memory stall, then we do NOT want to
|
|
// squash the instruction that caused the stall so we
|
|
// increment the sequence number here to prevent that.
|
|
//
|
|
// NOTE: This is only for the SwitchOnCacheMiss Model
|
|
// NOTE: If you have multiple outstanding misses from the same
|
|
// thread then you need to reevaluate this code
|
|
// NOTE: squash should originate from
|
|
// pipeline_stage.cc:processInstSchedule
|
|
DPRINTF(InOrderCachePort, "Squashing above [sn:%u]\n",
|
|
squash_seq_num + 1);
|
|
|
|
squash(inst, stage_num, squash_seq_num + 1, tid);
|
|
}
|
|
|
|
|
|
void
|
|
CacheUnit::squash(DynInstPtr inst, int stage_num,
|
|
InstSeqNum squash_seq_num, ThreadID tid)
|
|
{
|
|
vector<int> slot_remove_list;
|
|
|
|
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
|
|
map<int, ResReqPtr>::iterator map_end = reqMap.end();
|
|
|
|
while (map_it != map_end) {
|
|
ResReqPtr req_ptr = (*map_it).second;
|
|
|
|
if (req_ptr &&
|
|
req_ptr->getInst()->readTid() == tid &&
|
|
req_ptr->getInst()->seqNum > squash_seq_num) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
"[tid:%i] Squashing request from [sn:%i]\n",
|
|
req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
|
|
|
|
req_ptr->setSquashed();
|
|
|
|
req_ptr->getInst()->setSquashed();
|
|
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
|
|
assert(cache_req);
|
|
|
|
int req_slot_num = req_ptr->getSlot();
|
|
|
|
if (cache_req->tlbStall) {
|
|
tlbBlocked[tid] = false;
|
|
|
|
int stall_stage = reqMap[req_slot_num]->getStageNum();
|
|
|
|
cpu->pipelineStage[stall_stage]->
|
|
unsetResStall(reqMap[req_slot_num], tid);
|
|
}
|
|
|
|
if (!cache_req->tlbStall && !cache_req->isMemAccPending()) {
|
|
// Mark request for later removal
|
|
cpu->reqRemoveList.push(req_ptr);
|
|
|
|
// Mark slot for removal from resource
|
|
slot_remove_list.push_back(req_ptr->getSlot());
|
|
}
|
|
}
|
|
|
|
map_it++;
|
|
}
|
|
|
|
// Now Delete Slot Entry from Req. Map
|
|
for (int i = 0; i < slot_remove_list.size(); i++)
|
|
freeSlot(slot_remove_list[i]);
|
|
}
|
|
|
|
uint64_t
|
|
CacheUnit::getMemData(Packet *packet)
|
|
{
|
|
switch (packet->getSize())
|
|
{
|
|
case 8:
|
|
return packet->get<uint8_t>();
|
|
|
|
case 16:
|
|
return packet->get<uint16_t>();
|
|
|
|
case 32:
|
|
return packet->get<uint32_t>();
|
|
|
|
case 64:
|
|
return packet->get<uint64_t>();
|
|
|
|
default:
|
|
panic("bad store data size = %d\n", packet->getSize());
|
|
}
|
|
}
|
|
|
|
// Extra Template Definitions
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, Twin32_t &data, unsigned flags);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, Twin64_t &data, unsigned flags);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, uint64_t &data, unsigned flags);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, uint32_t &data, unsigned flags);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, uint16_t &data, unsigned flags);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, uint8_t &data, unsigned flags);
|
|
|
|
#endif //DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, double &data, unsigned flags)
|
|
{
|
|
return read(inst, addr, *(uint64_t*)&data, flags);
|
|
}
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, float &data, unsigned flags)
|
|
{
|
|
return read(inst, addr, *(uint32_t*)&data, flags);
|
|
}
|
|
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::read(DynInstPtr inst, Addr addr, int32_t &data, unsigned flags)
|
|
{
|
|
return read(inst, addr, (uint32_t&)data, flags);
|
|
}
|
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, Twin32_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, Twin64_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, uint64_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, uint32_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, uint16_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
template
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, uint8_t data, Addr addr,
|
|
unsigned flags, uint64_t *res);
|
|
|
|
#endif //DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, double data, Addr addr, unsigned flags,
|
|
uint64_t *res)
|
|
{
|
|
return write(inst, *(uint64_t*)&data, addr, flags, res);
|
|
}
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags,
|
|
uint64_t *res)
|
|
{
|
|
return write(inst, *(uint32_t*)&data, addr, flags, res);
|
|
}
|
|
|
|
|
|
template<>
|
|
Fault
|
|
CacheUnit::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags,
|
|
uint64_t *res)
|
|
{
|
|
return write(inst, (uint32_t)data, addr, flags, res);
|
|
}
|