2009-02-11 00:49:29 +01:00
|
|
|
/*
|
|
|
|
* 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>
|
2009-09-23 17:34:21 +02:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
#include "arch/isa_traits.hh"
|
2009-05-12 21:01:13 +02:00
|
|
|
#include "arch/locked_mem.hh"
|
2009-02-11 00:49:29 +01:00
|
|
|
#include "arch/utility.hh"
|
2009-05-12 21:01:15 +02:00
|
|
|
#include "arch/predecoder.hh"
|
2009-09-23 17:34:21 +02:00
|
|
|
#include "config/the_isa.hh"
|
2009-02-11 00:49:29 +01:00
|
|
|
#include "cpu/inorder/resources/cache_unit.hh"
|
|
|
|
#include "cpu/inorder/pipeline_traits.hh"
|
|
|
|
#include "cpu/inorder/cpu.hh"
|
2010-02-01 00:30:35 +01:00
|
|
|
#include "cpu/inorder/resource_pool.hh"
|
2009-02-11 00:49:29 +01:00
|
|
|
#include "mem/request.hh"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace TheISA;
|
|
|
|
using namespace ThePipeline;
|
|
|
|
|
|
|
|
Tick
|
|
|
|
CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
|
|
|
|
{
|
2010-02-01 00:27:49 +01:00
|
|
|
panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
|
2009-02-11 00:49:29 +01:00
|
|
|
return curTick;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
|
|
|
|
{
|
2010-02-01 00:27:49 +01:00
|
|
|
panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CacheUnit::CachePort::recvStatusChange(Status status)
|
|
|
|
{
|
|
|
|
if (status == RangeChange)
|
|
|
|
return;
|
|
|
|
|
2010-02-01 00:27:49 +01:00
|
|
|
panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2009-02-11 00:49:29 +01:00
|
|
|
int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
|
2009-02-11 00:49:29 +01:00
|
|
|
: Resource(res_name, res_id, res_width, res_latency, _cpu),
|
2010-02-01 00:29:18 +01:00
|
|
|
cachePortBlocked(false), predecoder(NULL)
|
2009-02-11 00:49:29 +01:00
|
|
|
{
|
|
|
|
cachePort = new CachePort(this);
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Port *
|
2009-02-11 00:49:29 +01:00
|
|
|
CacheUnit::getPort(const string &if_name, int idx)
|
2009-02-11 00:49:29 +01:00
|
|
|
{
|
|
|
|
if (if_name == resName)
|
|
|
|
return cachePort;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
void
|
|
|
|
CacheUnit::init()
|
|
|
|
{
|
|
|
|
// Currently Used to Model TLB Latency. Eventually
|
|
|
|
// Switch to Timing TLB translations.
|
|
|
|
resourceEvent = new CacheUnitEvent[width];
|
|
|
|
|
|
|
|
initSlots();
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
int
|
|
|
|
CacheUnit::getSlot(DynInstPtr inst)
|
|
|
|
{
|
2010-02-01 00:27:12 +01:00
|
|
|
ThreadID tid = inst->readTid();
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
if (tlbBlocked[inst->threadNumber]) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
// For a Split-Load, the instruction would have processed once already
|
|
|
|
// causing the address to be unset.
|
|
|
|
if (!inst->validMemAddr() && !inst->splitInst) {
|
2009-02-11 00:49:29 +01:00
|
|
|
panic("Mem. Addr. must be set before requesting cache access\n");
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Addr req_addr = inst->getMemAddr();
|
|
|
|
|
|
|
|
if (resName == "icache_port" ||
|
2010-02-01 00:30:24 +01:00
|
|
|
find(addrList[tid].begin(), addrList[tid].end(), req_addr) ==
|
|
|
|
addrList[tid].end()) {
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
int new_slot = Resource::getSlot(inst);
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
if (new_slot == -1)
|
2009-02-11 00:49:29 +01:00
|
|
|
return -1;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
inst->memTime = curTick;
|
2010-02-01 00:27:12 +01:00
|
|
|
addrList[tid].push_back(req_addr);
|
|
|
|
addrMap[tid][req_addr] = inst->seqNum;
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: [sn:%i]: Address %08p added to dependency list\n",
|
|
|
|
inst->readTid(), inst->seqNum, req_addr);
|
|
|
|
return new_slot;
|
2009-02-11 00:49:29 +01:00
|
|
|
} else {
|
2010-02-01 00:30:35 +01:00
|
|
|
// Allow same instruction multiple accesses to same address
|
|
|
|
if (addrMap[tid][req_addr] == inst->seqNum) {
|
|
|
|
int new_slot = Resource::getSlot(inst);
|
|
|
|
|
|
|
|
if (new_slot == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return new_slot;
|
|
|
|
} else {
|
|
|
|
DPRINTF(InOrderCachePort,
|
2010-02-01 00:27:02 +01:00
|
|
|
"[tid:%i] Denying request because there is an outstanding"
|
2009-02-11 00:49:29 +01:00
|
|
|
" request to/for addr. %08p. by [sn:%i] @ tick %i\n",
|
2010-02-01 00:27:12 +01:00
|
|
|
inst->readTid(), req_addr, addrMap[tid][req_addr], inst->memTime);
|
2010-02-01 00:30:35 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
2010-02-01 00:30:35 +01:00
|
|
|
|
|
|
|
return -1;
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CacheUnit::freeSlot(int slot_num)
|
|
|
|
{
|
2010-02-01 00:27:12 +01:00
|
|
|
ThreadID tid = reqMap[slot_num]->inst->readTid();
|
|
|
|
|
2010-02-01 00:30:24 +01:00
|
|
|
vector<Addr>::iterator vect_it =
|
|
|
|
find(addrList[tid].begin(), addrList[tid].end(),
|
|
|
|
reqMap[slot_num]->inst->getMemAddr());
|
2010-02-01 00:30:35 +01:00
|
|
|
|
|
|
|
assert(vect_it != addrList[tid].end() ||
|
|
|
|
reqMap[slot_num]->inst->splitInst);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: Address %08p removed from dependency list\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
reqMap[slot_num]->inst->readTid(), (*vect_it));
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
if (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);
|
|
|
|
}
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
Resource::freeSlot(slot_num);
|
|
|
|
}
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
ResReqPtr
|
|
|
|
CacheUnit::findRequest(DynInstPtr inst)
|
|
|
|
{
|
|
|
|
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
|
|
|
|
map<int, ResReqPtr>::iterator map_end = reqMap.end();
|
|
|
|
|
|
|
|
while (map_it != map_end) {
|
|
|
|
CacheRequest* cache_req = dynamic_cast<CacheRequest*>((*map_it).second);
|
|
|
|
assert(cache_req);
|
|
|
|
|
|
|
|
if (cache_req &&
|
|
|
|
cache_req->getInst() == inst &&
|
|
|
|
cache_req->instIdx == inst->resSched.top()->idx) {
|
|
|
|
return cache_req;
|
|
|
|
}
|
|
|
|
map_it++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResReqPtr
|
|
|
|
CacheUnit::findSplitRequest(DynInstPtr inst, int idx)
|
|
|
|
{
|
|
|
|
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
|
|
|
|
map<int, ResReqPtr>::iterator map_end = reqMap.end();
|
|
|
|
|
|
|
|
while (map_it != map_end) {
|
|
|
|
CacheRequest* cache_req = dynamic_cast<CacheRequest*>((*map_it).second);
|
|
|
|
assert(cache_req);
|
|
|
|
|
|
|
|
if (cache_req &&
|
|
|
|
cache_req->getInst() == inst &&
|
|
|
|
cache_req->instIdx == idx) {
|
|
|
|
return cache_req;
|
|
|
|
}
|
|
|
|
map_it++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
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()) {
|
2009-02-11 00:49:29 +01:00
|
|
|
panic("Mem. Addr. must be set before requesting cache access\n");
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MemCmd::Command pkt_cmd;
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
switch (sched_entry->cmd)
|
|
|
|
{
|
2010-02-01 00:30:35 +01:00
|
|
|
case InitSecondSplitRead:
|
|
|
|
pkt_cmd = MemCmd::ReadReq;
|
|
|
|
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: Read request from [sn:%i] for addr %08p\n",
|
|
|
|
inst->readTid(), inst->seqNum, inst->split2ndAddr);
|
|
|
|
break;
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
case InitiateReadData:
|
2009-02-11 00:49:29 +01:00
|
|
|
pkt_cmd = MemCmd::ReadReq;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2009-05-12 21:01:16 +02:00
|
|
|
"[tid:%i]: Read request from [sn:%i] for addr %08p\n",
|
|
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case InitiateWriteData:
|
2009-02-11 00:49:29 +01:00
|
|
|
pkt_cmd = MemCmd::WriteReq;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2009-05-12 21:01:16 +02:00
|
|
|
"[tid:%i]: Write request from [sn:%i] for addr %08p\n",
|
|
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case InitiateFetch:
|
2009-02-11 00:49:29 +01:00
|
|
|
pkt_cmd = MemCmd::ReadReq;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2009-05-12 21:01:16 +02:00
|
|
|
"[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
|
|
|
|
inst->readTid(), inst->seqNum, inst->getMemAddr());
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-02-11 00:49:29 +01:00
|
|
|
panic("%i: Unexpected request type (%i) to %s", curTick,
|
|
|
|
sched_entry->cmd, name());
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return new CacheRequest(this, inst, stage_num, id, slot_num,
|
2009-05-12 21:01:16 +02:00
|
|
|
sched_entry->cmd, 0, pkt_cmd,
|
2010-02-01 00:30:35 +01:00
|
|
|
0/*flags*/, this->cpu->readCpuId(),
|
|
|
|
inst->resSched.top()->idx);
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2010-02-01 00:30:35 +01:00
|
|
|
if (cache_req->cmd != inst->resSched.top()->cmd &&
|
|
|
|
cache_req->instIdx == inst->resSched.top()->idx) {
|
2009-02-11 00:49:29 +01:00
|
|
|
// If different, then update command in the request
|
|
|
|
cache_req->cmd = inst->resSched.top()->cmd;
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2010-02-01 00:26:13 +01:00
|
|
|
"[tid:%i]: [sn:%i]: Updating the command for this "
|
|
|
|
"instruction\n ", inst->readTid(), inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
service_request = true;
|
2010-02-01 00:30:35 +01:00
|
|
|
} else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead) {
|
2009-02-11 00:49:29 +01:00
|
|
|
// If same command, just check to see if memory access was completed
|
|
|
|
// but dont try to re-execute
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: [sn:%i]: requesting this resource again\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
inst->readTid(), inst->seqNum);
|
|
|
|
|
|
|
|
service_request = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
Fault
|
|
|
|
CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
|
|
|
|
int flags, TheISA::TLB::Mode tlb_mode)
|
|
|
|
{
|
2009-05-26 18:23:13 +02:00
|
|
|
ThreadID tid = inst->readTid();
|
|
|
|
Addr aligned_addr = inst->getMemAddr();
|
|
|
|
unsigned stage_num = cache_req->getStageNum();
|
|
|
|
unsigned slot_idx = cache_req->getSlot();
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
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 {
|
2010-02-01 00:30:35 +01:00
|
|
|
if (!cache_req->is2ndSplit()) {
|
|
|
|
inst->dataMemReq = new Request(cpu->asid[tid], aligned_addr,
|
2009-05-12 21:01:16 +02:00
|
|
|
acc_size, flags, inst->readPC(),
|
|
|
|
cpu->readCpuId(), inst->readTid());
|
|
|
|
cache_req->memReq = inst->dataMemReq;
|
2010-02-01 00:30:35 +01:00
|
|
|
} else {
|
|
|
|
assert(inst->splitInst);
|
|
|
|
|
|
|
|
inst->splitMemReq = new Request(cpu->asid[tid],
|
|
|
|
inst->split2ndAddr,
|
|
|
|
acc_size,
|
|
|
|
flags,
|
|
|
|
inst->readPC(),
|
|
|
|
cpu->readCpuId(),
|
|
|
|
tid);
|
|
|
|
cache_req->memReq = inst->splitMemReq;
|
|
|
|
}
|
2009-05-12 21:01:16 +02:00
|
|
|
}
|
2010-02-01 00:30:35 +01:00
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
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(),
|
2009-05-26 18:23:13 +02:00
|
|
|
cache_req->memReq->getVaddr(), inst->seqNum);
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
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 "
|
2009-05-26 18:23:13 +02:00
|
|
|
"to phys. addr:%08p.\n", tid, inst->seqNum,
|
2009-05-12 21:01:16 +02:00
|
|
|
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);
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
// The block size of our peer
|
|
|
|
unsigned blockSize = this->cachePort->peerBlockSize();
|
|
|
|
|
|
|
|
//The size of the data we're trying to read.
|
|
|
|
int dataSize = sizeof(T);
|
|
|
|
|
|
|
|
if (inst->split2ndAccess) {
|
|
|
|
dataSize = inst->split2ndSize;
|
|
|
|
cache_req->splitAccess = true;
|
|
|
|
cache_req->split2ndAccess = true;
|
|
|
|
|
|
|
|
DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (2 of 2) for (%#x, %#x).\n", curTick, inst->seqNum,
|
|
|
|
inst->getMemAddr(), inst->split2ndAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//The address of the second part of this access if it needs to be split
|
|
|
|
//across a cache line boundary.
|
|
|
|
Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
|
|
|
|
|
|
|
|
|
|
|
|
if (secondAddr > addr && !inst->split2ndAccess) {
|
|
|
|
DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (1 of 2) for (%#x, %#x).\n", curTick, inst->seqNum,
|
|
|
|
addr, secondAddr);
|
|
|
|
|
|
|
|
// Save All "Total" Split Information
|
|
|
|
// ==============================
|
|
|
|
inst->splitInst = true;
|
|
|
|
inst->splitMemData = new uint8_t[dataSize];
|
|
|
|
inst->splitTotalSize = dataSize;
|
|
|
|
|
|
|
|
|
|
|
|
// Schedule Split Read/Complete for Instruction
|
|
|
|
// ==============================
|
|
|
|
int stage_num = cache_req->getStageNum();
|
|
|
|
|
|
|
|
int stage_pri = ThePipeline::getNextPriority(inst, stage_num);
|
|
|
|
|
|
|
|
inst->resSched.push(new ScheduleEntry(stage_num,
|
|
|
|
stage_pri,
|
|
|
|
cpu->resPool->getResIdx(DCache),
|
|
|
|
CacheUnit::InitSecondSplitRead,
|
|
|
|
1)
|
|
|
|
);
|
|
|
|
|
|
|
|
inst->resSched.push(new ScheduleEntry(stage_num + 1,
|
|
|
|
1/*stage_pri*/,
|
|
|
|
cpu->resPool->getResIdx(DCache),
|
|
|
|
CacheUnit::CompleteSecondSplitRead, 1)
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Split Information for First Access
|
|
|
|
// ==============================
|
|
|
|
dataSize = secondAddr - addr;
|
|
|
|
cache_req->splitAccess = true;
|
|
|
|
|
|
|
|
// Split Information for Second Access
|
|
|
|
// ==============================
|
|
|
|
inst->split2ndSize = addr + sizeof(T) - secondAddr;
|
|
|
|
inst->split2ndAddr = secondAddr;
|
|
|
|
inst->split2ndDataPtr = inst->splitMemData + dataSize;
|
|
|
|
inst->split2ndFlags = flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
//cout << "h1" << endl;
|
|
|
|
|
|
|
|
doTLBAccess(inst, cache_req, dataSize, flags, TheISA::TLB::Read);
|
|
|
|
|
|
|
|
//cout << "h2" << endl;
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
if (cache_req->fault == NoFault) {
|
2010-02-01 00:30:35 +01:00
|
|
|
if (!cache_req->splitAccess) {
|
|
|
|
cache_req->reqData = new uint8_t[dataSize];
|
|
|
|
doCacheAccess(inst, NULL);
|
|
|
|
} else {
|
|
|
|
if (!inst->split2ndAccess) {
|
|
|
|
cache_req->reqData = inst->splitMemData;
|
|
|
|
} else {
|
|
|
|
cache_req->reqData = inst->split2ndDataPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
doCacheAccess(inst, NULL, cache_req);
|
|
|
|
}
|
2009-05-12 21:01:16 +02:00
|
|
|
}
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
//cout << "h3" << endl;
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
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);
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
// The block size of our peer
|
|
|
|
unsigned blockSize = this->cachePort->peerBlockSize();
|
|
|
|
|
|
|
|
//The size of the data we're trying to read.
|
|
|
|
int dataSize = sizeof(T);
|
|
|
|
|
|
|
|
//The address of the second part of this access if it needs to be split
|
|
|
|
//across a cache line boundary.
|
|
|
|
Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
|
|
|
|
|
|
|
|
if (secondAddr > addr) {
|
|
|
|
assert(0 && "Need Split Write Code!");
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
void
|
|
|
|
CacheUnit::execute(int slot_num)
|
|
|
|
{
|
2010-02-01 00:29:18 +01:00
|
|
|
if (cachePortBlocked) {
|
|
|
|
DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
|
2009-02-11 00:49:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
|
|
|
|
assert(cache_req);
|
|
|
|
|
|
|
|
DynInstPtr inst = cache_req->inst;
|
2009-05-26 18:23:13 +02:00
|
|
|
#if TRACING_ON
|
|
|
|
ThreadID tid = inst->readTid();
|
|
|
|
int seq_num = inst->seqNum;
|
2010-02-01 00:30:35 +01:00
|
|
|
std::string acc_type = "write";
|
|
|
|
|
2009-05-26 18:23:13 +02:00
|
|
|
#endif
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
cache_req->fault = NoFault;
|
|
|
|
|
|
|
|
switch (cache_req->cmd)
|
|
|
|
{
|
|
|
|
case InitiateFetch:
|
2009-05-12 21:01:16 +02:00
|
|
|
{
|
|
|
|
//@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,
|
2009-05-26 18:23:13 +02:00
|
|
|
"[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
|
|
|
|
tid, name(), cache_req->inst->getMemAddr());
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
cache_req->reqData = new uint8_t[acc_size];
|
|
|
|
|
|
|
|
inst->setCurResSlot(slot_num);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
doCacheAccess(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case InitiateReadData:
|
2010-02-01 00:30:35 +01:00
|
|
|
#if TRACING_ON
|
|
|
|
acc_type = "read";
|
|
|
|
#endif
|
2009-05-12 21:01:16 +02:00
|
|
|
case InitiateWriteData:
|
2010-02-01 00:30:35 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2010-02-01 00:30:35 +01:00
|
|
|
"[tid:%u]: [sn:%i] Initiating data %s access to %s for addr. %08p\n",
|
|
|
|
tid, inst->seqNum, acc_type, name(), cache_req->inst->getMemAddr());
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
inst->setCurResSlot(slot_num);
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
|
|
|
|
inst->execute();
|
|
|
|
} else {
|
|
|
|
inst->initiateAcc();
|
2010-02-01 00:30:35 +01:00
|
|
|
//if (inst->splitAccess) {
|
|
|
|
// assert(0 && " Marked as spill inst");
|
|
|
|
//}
|
2009-05-12 21:01:16 +02:00
|
|
|
}
|
2010-02-01 00:30:35 +01:00
|
|
|
|
|
|
|
break;
|
2009-05-12 21:01:16 +02:00
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
case InitSecondSplitRead:
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%u]: [sn:%i] Initiating split data read access to %s for addr. %08p\n",
|
|
|
|
tid, inst->seqNum, name(), cache_req->inst->split2ndAddr);
|
|
|
|
inst->split2ndAccess = true;
|
|
|
|
read(inst, inst->split2ndAddr, inst->split2ndData, inst->split2ndFlags);
|
2009-02-11 00:49:29 +01:00
|
|
|
break;
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
case InitSecondSplitWrite:
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%u]: [sn:%i] Initiating split data write access to %s for addr. %08p\n",
|
|
|
|
tid, inst->seqNum, name(), cache_req->inst->getMemAddr());
|
|
|
|
assert(0);
|
|
|
|
inst->split2ndAccess = true;
|
|
|
|
//write(inst, inst->split2ndAddr, inst->split2ndData, inst->split2ndFlags);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
case CompleteFetch:
|
2009-02-11 00:49:29 +01:00
|
|
|
if (cache_req->isMemAccComplete()) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: Completing Fetch Access for [sn:%i]\n",
|
|
|
|
tid, inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
tid, seq_num, inst->staticInst->disassemble(inst->PC));
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
delete cache_req->dataPkt;
|
2010-02-01 00:26:13 +01:00
|
|
|
//cache_req->setMemStall(false);
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->done();
|
|
|
|
} else {
|
|
|
|
DPRINTF(InOrderCachePort,
|
2010-02-01 00:30:35 +01:00
|
|
|
"[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
tid, inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderStall,
|
|
|
|
"STALL: [tid:%i]: Fetch miss from %08p\n",
|
|
|
|
tid, cache_req->inst->readPC());
|
|
|
|
cache_req->setCompleted(false);
|
2010-02-01 00:26:13 +01:00
|
|
|
//cache_req->setMemStall(true);
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CompleteReadData:
|
|
|
|
case CompleteWriteData:
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
|
|
|
|
tid, inst->seqNum);
|
2009-05-12 21:01:15 +02:00
|
|
|
|
|
|
|
if (cache_req->isMemAccComplete() ||
|
|
|
|
inst->isDataPrefetch() ||
|
|
|
|
inst->isInstPrefetch()) {
|
2010-02-01 00:26:13 +01:00
|
|
|
cache_req->setMemStall(false);
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->done();
|
|
|
|
} else {
|
|
|
|
DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
|
|
|
|
tid, cache_req->inst->getMemAddr());
|
|
|
|
cache_req->setCompleted(false);
|
2010-02-01 00:26:13 +01:00
|
|
|
cache_req->setMemStall(true);
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
case CompleteSecondSplitRead:
|
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i]: [sn:%i]: Trying to Complete Split Data Read 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->split2ndAddr);
|
|
|
|
cache_req->setCompleted(false);
|
|
|
|
cache_req->setMemStall(true);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
default:
|
|
|
|
fatal("Unrecognized command to %s", resName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
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();
|
2010-02-01 00:29:18 +01:00
|
|
|
cachePortBlocked = false;
|
2009-05-12 21:01:15 +02:00
|
|
|
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();
|
2010-02-01 00:29:18 +01:00
|
|
|
cachePortBlocked = false;
|
2009-05-12 21:01:15 +02:00
|
|
|
cache_req->setMemAccPending(false);
|
|
|
|
cache_req->setMemAccCompleted();
|
|
|
|
inst->unsetMemAddr();
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
// @TODO: Split into doCacheRead() and doCacheWrite()
|
2009-02-11 00:49:29 +01:00
|
|
|
Fault
|
2010-02-01 00:30:35 +01:00
|
|
|
CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, CacheReqPtr split_req)
|
2009-02-11 00:49:29 +01:00
|
|
|
{
|
|
|
|
Fault fault = NoFault;
|
2009-05-26 18:23:13 +02:00
|
|
|
#if TRACING_ON
|
|
|
|
ThreadID tid = inst->readTid();
|
|
|
|
#endif
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2010-02-01 00:30:35 +01:00
|
|
|
CacheReqPtr cache_req;
|
|
|
|
|
|
|
|
if (split_req == NULL) {
|
|
|
|
cache_req = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
|
|
|
|
} else{
|
|
|
|
cache_req = split_req;
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
assert(cache_req);
|
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
// 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 :
|
2010-02-01 00:26:13 +01:00
|
|
|
(cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq
|
|
|
|
: MemCmd::WriteReq);
|
2009-05-12 21:01:15 +02:00
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd,
|
2010-02-01 00:30:35 +01:00
|
|
|
Packet::Broadcast, cache_req->instIdx);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
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);
|
2009-05-12 21:01:15 +02:00
|
|
|
|
|
|
|
if (cache_req->memReq->isCondSwap()) {
|
|
|
|
assert(write_res);
|
|
|
|
cache_req->memReq->setExtraData(*write_res);
|
|
|
|
}
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool do_access = true; // flag to suppress cache access
|
|
|
|
|
|
|
|
Request *memReq = cache_req->dataPkt->req;
|
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
if (cache_req->dataPkt->isWrite() && cache_req->memReq->isLLSC()) {
|
2009-02-11 00:49:29 +01:00
|
|
|
assert(cache_req->inst->isStoreConditional());
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
|
2009-02-11 00:49:29 +01:00
|
|
|
do_access = TheISA::handleLockedWrite(cpu, memReq);
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i] [sn:%i] attempting to access cache\n",
|
|
|
|
tid, inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
if (do_access) {
|
2009-02-11 00:49:29 +01:00
|
|
|
if (!cachePort->sendTiming(cache_req->dataPkt)) {
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
2010-02-01 00:29:18 +01:00
|
|
|
"[tid:%i] [sn:%i] cannot access cache, because port "
|
|
|
|
"is blocked. now waiting to retry request\n", tid,
|
|
|
|
inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->setCompleted(false);
|
2010-02-01 00:29:18 +01:00
|
|
|
cachePortBlocked = true;
|
2009-02-11 00:49:29 +01:00
|
|
|
} else {
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%i] [sn:%i] is now waiting for cache response\n",
|
|
|
|
tid, inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->setCompleted();
|
|
|
|
cache_req->setMemAccPending();
|
2010-02-01 00:29:18 +01:00
|
|
|
cachePortBlocked = false;
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
2009-04-20 06:44:15 +02:00
|
|
|
} else if (!do_access && memReq->isLLSC()){
|
2009-02-11 00:49:29 +01:00
|
|
|
// Store-Conditional instructions complete even if they "failed"
|
|
|
|
assert(cache_req->inst->isStoreConditional());
|
|
|
|
cache_req->setCompleted(true);
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(LLSC,
|
|
|
|
"[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
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);
|
2010-02-01 00:30:24 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
assert(cache_pkt);
|
|
|
|
|
|
|
|
if (cache_pkt->cacheReq->isSquashed()) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
2009-02-11 00:49:29 +01:00
|
|
|
"Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_pkt->cacheReq->getInst()->readTid(),
|
|
|
|
cache_pkt->cacheReq->getInst()->seqNum);
|
|
|
|
|
|
|
|
cache_pkt->cacheReq->done();
|
2009-05-12 21:01:15 +02:00
|
|
|
delete cache_pkt;
|
2010-02-01 00:30:24 +01:00
|
|
|
|
|
|
|
cpu->wakeCPU();
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
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());
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
// Cast to correct request type
|
|
|
|
CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
|
2010-02-01 00:30:35 +01:00
|
|
|
findSplitRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx));
|
|
|
|
|
|
|
|
if (!cache_req) {
|
|
|
|
warn(
|
|
|
|
"[tid:%u]: [sn:%i]: Can't find slot for cache access to addr. %08p\n",
|
|
|
|
cache_pkt->cacheReq->getInst()->readTid(),
|
|
|
|
cache_pkt->cacheReq->getInst()->seqNum,
|
|
|
|
cache_pkt->cacheReq->getInst()->getMemAddr());
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
assert(cache_req);
|
|
|
|
|
2009-03-04 19:17:08 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
// Get resource request info
|
|
|
|
unsigned stage_num = cache_req->getStageNum();
|
|
|
|
DynInstPtr inst = cache_req->inst;
|
2009-05-26 18:23:13 +02:00
|
|
|
ThreadID tid = cache_req->inst->readTid();
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
if (!cache_req->isSquashed()) {
|
|
|
|
if (inst->resSched.top()->cmd == CompleteFetch) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
2009-02-11 00:49:29 +01:00
|
|
|
"[tid:%u]: [sn:%i]: Processing fetch access\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
tid, inst->seqNum);
|
2009-05-12 21:01:15 +02:00
|
|
|
|
|
|
|
// 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();
|
2010-02-01 00:26:13 +01:00
|
|
|
MachInst mach_inst =
|
|
|
|
TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
|
|
|
|
(cache_pkt->getPtr<uint8_t>()));
|
2009-05-12 21:01:15 +02:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
} else if (inst->staticInst && inst->isMemRef()) {
|
|
|
|
DPRINTF(InOrderCachePort,
|
2009-02-11 00:49:29 +01:00
|
|
|
"[tid:%u]: [sn:%i]: Processing cache access\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
tid, inst->seqNum);
|
2010-02-01 00:30:35 +01:00
|
|
|
|
|
|
|
if (inst->splitInst) {
|
|
|
|
inst->splitFinishCnt++;
|
|
|
|
|
|
|
|
if (inst->splitFinishCnt == 2) {
|
|
|
|
|
|
|
|
cache_req->memReq->setVirt(0/*inst->tid*/,
|
|
|
|
inst->getMemAddr(),
|
|
|
|
inst->splitTotalSize,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
|
|
|
|
Packet split_pkt(cache_req->memReq, cache_req->pktCmd,
|
|
|
|
Packet::Broadcast);
|
|
|
|
split_pkt.dataStatic(inst->splitMemData);
|
|
|
|
inst->completeAcc(&split_pkt);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
inst->completeAcc(pkt);
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
if (inst->isLoad()) {
|
|
|
|
assert(cache_pkt->isRead());
|
|
|
|
|
2009-04-20 06:44:15 +02:00
|
|
|
if (cache_pkt->req->isLLSC()) {
|
2009-02-11 00:49:29 +01:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%u]: Handling Load-Linked for [sn:%u]\n",
|
|
|
|
tid, inst->seqNum);
|
2009-02-11 00:49:29 +01:00
|
|
|
TheISA::handleLockedRead(cpu, cache_pkt->req);
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:15 +02:00
|
|
|
// @NOTE: Hardcoded to for load instructions. Assumes that
|
2009-02-11 00:49:29 +01:00
|
|
|
// the dest. idx 0 is always where the data is loaded to.
|
|
|
|
DPRINTF(InOrderCachePort,
|
2009-02-11 00:49:29 +01:00
|
|
|
"[tid:%u]: [sn:%i]: Data loaded was: %08p\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
tid, inst->seqNum, inst->readIntResult(0));
|
2009-05-12 21:01:14 +02:00
|
|
|
DPRINTF(InOrderCachePort,
|
|
|
|
"[tid:%u]: [sn:%i]: FP Data loaded was: %08p\n",
|
|
|
|
tid, inst->seqNum, inst->readFloatResult(0));
|
2009-02-11 00:49:29 +01:00
|
|
|
} else if(inst->isStore()) {
|
|
|
|
assert(cache_pkt->isWrite());
|
|
|
|
|
|
|
|
DPRINTF(InOrderCachePort,
|
2009-05-12 21:01:15 +02:00
|
|
|
"[tid:%u]: [sn:%i]: Data stored was: FIX ME\n",
|
|
|
|
tid, inst->seqNum/*,
|
|
|
|
getMemData(cache_pkt)*/);
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
2009-05-12 21:01:15 +02:00
|
|
|
|
|
|
|
delete cache_pkt;
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cache_req->setMemAccPending(false);
|
|
|
|
cache_req->setMemAccCompleted();
|
|
|
|
|
2010-02-01 00:27:02 +01:00
|
|
|
if (cache_req->isMemStall() &&
|
|
|
|
cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
|
2010-02-01 00:27:38 +01:00
|
|
|
DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n", tid);
|
2010-02-01 00:27:02 +01:00
|
|
|
|
|
|
|
cpu->activateContext(tid);
|
2010-02-01 00:27:38 +01:00
|
|
|
|
|
|
|
DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
|
|
|
|
"miss.\n", tid);
|
2010-02-01 00:27:02 +01:00
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
// 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,
|
2009-02-11 00:49:29 +01:00
|
|
|
"[tid:%u] Miss on block @ %08p completed, but squashed\n",
|
|
|
|
tid, cache_req->inst->readPC());
|
2009-02-11 00:49:29 +01:00
|
|
|
cache_req->setMemAccCompleted();
|
|
|
|
}
|
|
|
|
|
|
|
|
inst->unsetMemAddr();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CacheUnit::recvRetry()
|
|
|
|
{
|
2010-02-01 00:29:18 +01:00
|
|
|
DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n");
|
|
|
|
|
|
|
|
assert(cachePortBlocked);
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2010-02-01 00:29:18 +01:00
|
|
|
// Clear the cache port for use again
|
|
|
|
cachePortBlocked = false;
|
2010-02-01 00:30:24 +01:00
|
|
|
|
|
|
|
cpu->wakeCPU();
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
CacheUnitEvent::CacheUnitEvent()
|
|
|
|
: ResourceEvent()
|
|
|
|
{ }
|
|
|
|
|
|
|
|
void
|
|
|
|
CacheUnitEvent::process()
|
|
|
|
{
|
|
|
|
DynInstPtr inst = resource->reqMap[slotIdx]->inst;
|
|
|
|
int stage_num = resource->reqMap[slotIdx]->getStageNum();
|
2009-05-26 18:23:13 +02:00
|
|
|
ThreadID tid = inst->threadNumber;
|
2009-05-12 21:01:16 +02:00
|
|
|
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;
|
|
|
|
|
2010-02-01 00:26:13 +01:00
|
|
|
tlb_res->cpu->pipelineStage[stage_num]->
|
|
|
|
unsetResStall(tlb_res->reqMap[slotIdx], tid);
|
2009-05-12 21:01:16 +02:00
|
|
|
|
|
|
|
req_ptr->tlbStall = false;
|
|
|
|
|
|
|
|
if (req_ptr->isSquashed()) {
|
|
|
|
req_ptr->done();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-01 00:26:13 +01:00
|
|
|
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
|
2010-02-01 00:27:02 +01:00
|
|
|
DPRINTF(InOrderCachePort, "Squashing above [sn:%u]\n",
|
|
|
|
squash_seq_num + 1);
|
|
|
|
|
2010-02-01 00:26:13 +01:00
|
|
|
squash(inst, stage_num, squash_seq_num + 1, tid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
void
|
|
|
|
CacheUnit::squash(DynInstPtr inst, int stage_num,
|
2009-05-26 18:23:13 +02:00
|
|
|
InstSeqNum squash_seq_num, ThreadID tid)
|
2009-02-11 00:49:29 +01:00
|
|
|
{
|
2009-02-11 00:49:29 +01:00
|
|
|
vector<int> slot_remove_list;
|
2009-02-11 00:49:29 +01:00
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
map<int, ResReqPtr>::iterator map_it = reqMap.begin();
|
|
|
|
map<int, ResReqPtr>::iterator map_end = reqMap.end();
|
2009-02-11 00:49:29 +01:00
|
|
|
|
|
|
|
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,
|
2009-02-11 00:49:29 +01:00
|
|
|
"[tid:%i] Squashing request from [sn:%i]\n",
|
2009-02-11 00:49:29 +01:00
|
|
|
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);
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
int req_slot_num = req_ptr->getSlot();
|
|
|
|
|
|
|
|
if (cache_req->tlbStall) {
|
|
|
|
tlbBlocked[tid] = false;
|
|
|
|
|
|
|
|
int stall_stage = reqMap[req_slot_num]->getStageNum();
|
|
|
|
|
2010-02-01 00:26:13 +01:00
|
|
|
cpu->pipelineStage[stall_stage]->
|
|
|
|
unsetResStall(reqMap[req_slot_num], tid);
|
2009-05-12 21:01:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cache_req->tlbStall && !cache_req->isMemAccPending()) {
|
2009-02-11 00:49:29 +01:00
|
|
|
// 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
|
2009-02-11 00:49:29 +01:00
|
|
|
for (int i = 0; i < slot_remove_list.size(); i++)
|
2009-02-11 00:49:29 +01:00
|
|
|
freeSlot(slot_remove_list[i]);
|
|
|
|
}
|
|
|
|
|
2009-02-11 00:49:29 +01:00
|
|
|
uint64_t
|
|
|
|
CacheUnit::getMemData(Packet *packet)
|
|
|
|
{
|
2009-02-11 00:49:29 +01:00
|
|
|
switch (packet->getSize())
|
|
|
|
{
|
|
|
|
case 8:
|
|
|
|
return packet->get<uint8_t>();
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
return packet->get<uint16_t>();
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
return packet->get<uint32_t>();
|
|
|
|
|
2009-05-12 21:01:14 +02:00
|
|
|
case 64:
|
2009-02-11 00:49:29 +01:00
|
|
|
return packet->get<uint64_t>();
|
|
|
|
|
|
|
|
default:
|
2009-02-11 00:49:29 +01:00
|
|
|
panic("bad store data size = %d\n", packet->getSize());
|
2009-02-11 00:49:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-12 21:01:16 +02:00
|
|
|
// 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
|
2010-02-01 00:26:13 +01:00
|
|
|
CacheUnit::write(DynInstPtr inst, double data, Addr addr, unsigned flags,
|
|
|
|
uint64_t *res)
|
2009-05-12 21:01:16 +02:00
|
|
|
{
|
|
|
|
return write(inst, *(uint64_t*)&data, addr, flags, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
Fault
|
2010-02-01 00:26:13 +01:00
|
|
|
CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags,
|
|
|
|
uint64_t *res)
|
2009-05-12 21:01:16 +02:00
|
|
|
{
|
|
|
|
return write(inst, *(uint32_t*)&data, addr, flags, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
Fault
|
2010-02-01 00:26:13 +01:00
|
|
|
CacheUnit::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags,
|
|
|
|
uint64_t *res)
|
2009-05-12 21:01:16 +02:00
|
|
|
{
|
|
|
|
return write(inst, (uint32_t)data, addr, flags, res);
|
|
|
|
}
|