diff options
Diffstat (limited to 'src/cpu/inorder/resources/cache_unit.cc')
-rw-r--r-- | src/cpu/inorder/resources/cache_unit.cc | 1297 |
1 files changed, 0 insertions, 1297 deletions
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc deleted file mode 100644 index 78b803501..000000000 --- a/src/cpu/inorder/resources/cache_unit.cc +++ /dev/null @@ -1,1297 +0,0 @@ -/* - * Copyright (c) 2013 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. - * - * 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 <list> -#include <vector> - -#include "arch/isa_traits.hh" -#include "arch/locked_mem.hh" -#include "arch/utility.hh" -#include "config/the_isa.hh" -#include "cpu/inorder/resources/cache_unit.hh" -#include "cpu/inorder/cpu.hh" -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/resource_pool.hh" -#include "debug/Activity.hh" -#include "debug/AddrDep.hh" -#include "debug/InOrderCachePort.hh" -#include "debug/InOrderStall.hh" -#include "debug/InOrderTLB.hh" -#include "debug/LLSC.hh" -#include "debug/RefCount.hh" -#include "debug/ThreadModel.hh" -#include "mem/request.hh" - -using namespace std; -using namespace TheISA; -using namespace ThePipeline; - -#if TRACING_ON -static std::string -printMemData(const uint8_t *data, unsigned size) -{ - std::stringstream dataStr; - for (unsigned pos = 0; pos < size; pos++) { - ccprintf(dataStr, "%02x", data[pos]); - } - return dataStr.str(); -} -#endif - -CacheUnit::CacheUnit(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), - cachePort(NULL), cachePortBlocked(false) -{ - // Hard-Code Selection For Now - if (res_id == ICache) - _tlb = params->itb; - else if (res_id == DCache) - _tlb = params->dtb; - else - fatal("Unrecognized TLB name passed by user"); - - // Note that the CPU port is not yet instantiated (as it is done - // after the resource pool), we delay setting the cachePort - // pointer until init(). - - for (int i=0; i < MaxThreads; i++) { - tlbBlocked[i] = false; - tlbBlockSeqNum[i] = 0; - } -} - -TheISA::TLB* -CacheUnit::tlb() -{ - return _tlb; - -} - -void -CacheUnit::init() -{ - // Get the appropriate port from the CPU based on the resource name. - if (id == ICache) { - cachePort = &cpu->getInstPort(); - } else if (id == DCache) { - cachePort = &cpu->getDataPort(); - } - assert(cachePort != NULL); - - for (int i = 0; i < width; i++) { - reqs[i] = new CacheRequest(this); - } - - cacheBlkSize = cpu->cacheLineSize(); - cacheBlkMask = cacheBlkSize - 1; - - initSlots(); -} - -int -CacheUnit::getSlot(DynInstPtr inst) -{ - ThreadID tid = inst->readTid(); - if (tlbBlocked[tid]) { - return -1; - } - - // For a Split-Load, the instruction would have processed once already - // causing the address to be unset. - if (!inst->validMemAddr() && !inst->splitInst) { - panic("[tid:%i][sn:%i] Mem. Addr. must be set before requesting " - "cache access\n", inst->readTid(), inst->seqNum); - } - - int new_slot = Resource::getSlot(inst); - inst->memTime = curTick(); - //@note: add back in if you want speculative loads/store capability - //setAddrDependency(inst); - return new_slot; -} - -void -CacheUnit::setAddrDependency(DynInstPtr inst) -{ - Addr req_addr = inst->getMemAddr(); - ThreadID tid = inst->readTid(); - - addrList[tid].push_back(req_addr); - addrMap[tid][req_addr] = inst->seqNum; - - DPRINTF(AddrDep, - "[tid:%i]: [sn:%i]: Address %08p added to dependency list (size=%i)\n", - inst->readTid(), inst->seqNum, req_addr, addrList[tid].size()); - - //@NOTE: 10 is an arbitrarily "high" number, but to be exact - // we would need to know the # of outstanding accesses - // a priori. Information like fetch width, stage width, - // fetch buffer, and the branch resolution stage would be - // useful for the icache_port. For the dcache port, the # - // of outstanding cache accesses (mshrs) would be a good - // sanity check here. - //assert(addrList[tid].size() < 10); -} - -void -CacheUnit::removeAddrDependency(DynInstPtr inst) -{ - ThreadID tid = inst->readTid(); - - Addr mem_addr = inst->getMemAddr(); - - inst->unsetMemAddr(); - - // Erase from Address List - std::list<Addr>::iterator list_it = find(addrList[tid].begin(), - addrList[tid].end(), - mem_addr); - assert(list_it != addrList[tid].end() || inst->splitInst); - - if (list_it != addrList[tid].end()) { - DPRINTF(AddrDep, - "[tid:%i]: [sn:%i] Address %08p removed from dependency " - "list\n", inst->readTid(), inst->seqNum, (*list_it)); - - addrList[tid].erase(list_it); - - // Erase From Address Map (Used for Debugging) - addrMap[tid].erase(addrMap[tid].find(mem_addr)); - } - - -} - -ResReqPtr -CacheUnit::findRequest(DynInstPtr inst) -{ - for (int i = 0; i < width; i++) { - CacheRequest* cache_req = - dynamic_cast<CacheRequest*>(reqs[i]); - assert(cache_req); - - if (cache_req->valid && - cache_req->getInst() == inst && - cache_req->instIdx == inst->curSkedEntry->idx) { - return cache_req; - } - } - - return NULL; -} - -ResReqPtr -CacheUnit::findRequest(DynInstPtr inst, int idx) -{ - for (int i = 0; i < width; i++) { - CacheRequest* cache_req = - dynamic_cast<CacheRequest*>(reqs[i]); - assert(cache_req); - - if (cache_req->valid && - cache_req->getInst() == inst && - cache_req->instIdx == idx) { - return cache_req; - } - } - - return NULL; -} - - -ResReqPtr -CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, - int slot_num, unsigned cmd) -{ - ScheduleEntry* sched_entry = *inst->curSkedEntry; - CacheRequest* cache_req = dynamic_cast<CacheRequest*>(reqs[slot_num]); - - if (!inst->validMemAddr()) { - panic("Mem. Addr. must be set before requesting cache access\n"); - } - - MemCmd::Command pkt_cmd; - - switch (sched_entry->cmd) - { - 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; - - 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 InitSecondSplitWrite: - pkt_cmd = MemCmd::WriteReq; - - DPRINTF(InOrderCachePort, - "[tid:%i]: Write request from [sn:%i] for addr %08p\n", - inst->readTid(), inst->seqNum, inst->split2ndAddr); - 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; - - default: - panic("%i: Unexpected request type (%i) to %s", curTick(), - sched_entry->cmd, name()); - } - - cache_req->setRequest(inst, stage_num, id, slot_num, - sched_entry->cmd, pkt_cmd, - inst->curSkedEntry->idx); - return cache_req; -} - -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->curSkedEntry->cmd && - cache_req->instIdx == inst->curSkedEntry->idx) { - // If different, then update command in the request - cache_req->cmd = inst->curSkedEntry->cmd; - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Updating the command for this " - "instruction\n", inst->readTid(), inst->seqNum); - - service_request = true; - } else if (inst->curSkedEntry->idx != CacheUnit::InitSecondSplitRead && - inst->curSkedEntry->idx != CacheUnit::InitSecondSplitWrite) { - // 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; - } -} - -void -CacheUnit::setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req, - int acc_size, int flags) -{ - ThreadID tid = inst->readTid(); - Addr aligned_addr = inst->getMemAddr(); - - if (!cache_req->is2ndSplit()) { - if (cache_req->memReq == NULL) { - cache_req->memReq = - new Request(cpu->asid[tid], aligned_addr, acc_size, flags, - cpu->dataMasterId(), - inst->instAddr(), - cpu->readCpuId(), //@todo: use context id - tid); - } - } else { - assert(inst->splitInst); - - if (inst->splitMemReq == NULL) { - inst->splitMemReq = new Request(cpu->asid[tid], - inst->split2ndAddr, - acc_size, - flags, - cpu->dataMasterId(), - inst->instAddr(), - cpu->readCpuId(), - tid); - } - - cache_req->memReq = inst->splitMemReq; - } -} - -void -CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size, - int flags, TheISA::TLB::Mode tlb_mode) -{ - ThreadID tid = inst->readTid(); - - setupMemRequest(inst, cache_req, acc_size, flags); - - //@todo: HACK: the DTB expects the correct PC in the ThreadContext - // but how if the memory accesses are speculative? Shouldn't - // we send along the requestor's PC to the translate functions? - ThreadContext *tc = cpu->thread[tid]->getTC(); - PCState old_pc = tc->pcState(); - tc->pcState() = inst->pcState(); - - inst->fault = - _tlb->translateAtomic(cache_req->memReq, tc, tlb_mode); - tc->pcState() = old_pc; - - if (inst->fault != NoFault) { - DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " - "addr:%08p for [sn:%i].\n", tid, inst->fault->name(), - cache_req->memReq->getVaddr(), inst->seqNum); - - tlbBlocked[tid] = true; - tlbBlockSeqNum[tid] = inst->seqNum; - - // Make sure nothing gets executed until after this faulting - // instruction gets handled. - inst->setSerializeAfter(); - - // Mark it as complete so it can pass through next stage. - // Fault Handling will happen at commit/graduation - cache_req->setCompleted(); - } 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()); - } -} - -void -CacheUnit::trap(const Fault &fault, ThreadID tid, DynInstPtr inst) -{ - tlbBlocked[tid] = false; -} - -Fault -CacheUnit::read(DynInstPtr inst, Addr addr, - uint8_t *data, unsigned size, unsigned flags) -{ - CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); - assert(cache_req && "Can't Find Instruction for Read!"); - - // The block size of our peer - unsigned blockSize = cacheBlkSize; - - //The size of the data we're trying to read. - int fullSize = size; - inst->totalSize = size; - - if (inst->traceData) { - inst->traceData->setMem(addr, size, flags); - } - - if (inst->split2ndAccess) { - size = inst->split2ndSize; - cache_req->splitAccess = true; - cache_req->split2ndAccess = true; - - DPRINTF(InOrderCachePort, "[sn:%i] Split Read Access (2 of 2) for " - "(%#x, %#x).\n", 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 + size - 1, blockSize); - - - if (secondAddr > addr && !inst->split2ndAccess) { - - if (!inst->splitInst) { - DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (1 of 2) for " - "(%#x, %#x).\n", curTick(), inst->seqNum, addr, secondAddr); - - unsigned stage_num = cache_req->getStageNum(); - unsigned cmd = inst->curSkedEntry->cmd; - - // 1. Make A New Inst. Schedule w/Split Read/Complete Entered on - // the schedule - // ============================== - // 2. Reassign curSkedPtr to current command (InitiateRead) on new - // schedule - // ============================== - inst->splitInst = true; - inst->setBackSked(cpu->createBackEndSked(inst)); - inst->curSkedEntry = inst->backSked->find(stage_num, cmd); - } else { - DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] Retrying Split Read " - "Access (1 of 2) for (%#x, %#x).\n", inst->readTid(), - inst->seqNum, addr, secondAddr); - } - - // Save All "Total" Split Information - // ============================== - inst->splitMemData = new uint8_t[size]; - - // Split Information for First Access - // ============================== - size = secondAddr - addr; - cache_req->splitAccess = true; - - // Split Information for Second Access - // ============================== - inst->split2ndSize = addr + fullSize - secondAddr; - inst->split2ndAddr = secondAddr; - inst->split2ndDataPtr = inst->splitMemData + size; - inst->split2ndFlags = flags; - } - - doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Read); - - if (inst->fault == NoFault) { - if (!cache_req->splitAccess) { - cache_req->reqData = new uint8_t[size]; - doCacheAccess(inst, NULL); - } else { - if (!inst->split2ndAccess) { - cache_req->reqData = inst->splitMemData; - } else { - cache_req->reqData = inst->split2ndDataPtr; - } - - doCacheAccess(inst, NULL, cache_req); - } - } - - return inst->fault; -} - -Fault -CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size, - Addr addr, unsigned flags, uint64_t *write_res) -{ - CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); - assert(cache_req && "Can't Find Instruction for Write!"); - - // The block size of our peer - unsigned blockSize = cacheBlkSize; - - //The size of the data we're trying to write. - int fullSize = size; - inst->totalSize = size; - - if (inst->traceData) - inst->traceData->setMem(addr, size, flags); - - if (inst->split2ndAccess) { - size = inst->split2ndSize; - cache_req->splitAccess = true; - cache_req->split2ndAccess = true; - - DPRINTF(InOrderCachePort, "[sn:%i] Split Write Access (2 of 2) for " - "(%#x, %#x).\n", 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 + size - 1, blockSize); - - if (secondAddr > addr && !inst->split2ndAccess) { - - DPRINTF(InOrderCachePort, "[sn:%i] Split Write Access (1 of 2) for " - "(%#x, %#x).\n", inst->seqNum, addr, secondAddr); - - // Save All "Total" Split Information - // ============================== - inst->splitInst = true; - - if (!inst->splitInstSked) { - assert(0 && "Split Requests Not Supported for Now..."); - - // Schedule Split Read/Complete for Instruction - // ============================== - int stage_num = cache_req->getStageNum(); - RSkedPtr inst_sked = (stage_num >= ThePipeline::BackEndStartStage) ? - inst->backSked : inst->frontSked; - - // this is just an arbitrarily high priority to ensure that this - // gets pushed to the back of the list - int stage_pri = 20; - - int isplit_cmd = CacheUnit::InitSecondSplitWrite; - inst_sked->push(new - ScheduleEntry(stage_num, - stage_pri, - cpu->resPool->getResIdx(DCache), - isplit_cmd, - 1)); - - int csplit_cmd = CacheUnit::CompleteSecondSplitWrite; - inst_sked->push(new - ScheduleEntry(stage_num + 1, - 1/*stage_pri*/, - cpu->resPool->getResIdx(DCache), - csplit_cmd, - 1)); - inst->splitInstSked = true; - } else { - DPRINTF(InOrderCachePort, "[tid:%i] sn:%i] Retrying Split Read " - "Access (1 of 2) for (%#x, %#x).\n", - inst->readTid(), inst->seqNum, addr, secondAddr); - } - - - - // Split Information for First Access - // ============================== - size = secondAddr - addr; - cache_req->splitAccess = true; - - // Split Information for Second Access - // ============================== - inst->split2ndSize = addr + fullSize - secondAddr; - inst->split2ndAddr = secondAddr; - inst->split2ndFlags = flags; - inst->splitInstSked = true; - } - - doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Write); - - if (inst->fault == NoFault) { - if (!cache_req->splitAccess) { - cache_req->reqData = new uint8_t[size]; - memcpy(cache_req->reqData, data, size); - - //inst->split2ndStoreDataPtr = cache_req->reqData; - //inst->split2ndStoreDataPtr += size; - - doCacheAccess(inst, write_res); - } else { - doCacheAccess(inst, write_res, cache_req); - } - - } - - return inst->fault; -} - - -void -CacheUnit::execute(int slot_num) -{ - CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqs[slot_num]); - assert(cache_req); - - if (cachePortBlocked && - (cache_req->cmd == InitiateReadData || - cache_req->cmd == InitiateWriteData || - cache_req->cmd == InitSecondSplitRead || - cache_req->cmd == InitSecondSplitWrite)) { - DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); - cache_req->done(false); - return; - } - - DynInstPtr inst = cache_req->inst; - if (inst->fault != NoFault) { - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to " - "next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(), - inst->getMemAddr()); - finishCacheUnitReq(inst, cache_req); - return; - } - - if (inst->isSquashed()) { - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Detected squashed instruction " - "next stage.\n", inst->readTid(), inst->seqNum); - finishCacheUnitReq(inst, cache_req); - return; - } - -#if TRACING_ON - ThreadID tid = inst->readTid(); - std::string acc_type = "write"; -#endif - - switch (cache_req->cmd) - { - - case InitiateReadData: -#if TRACING_ON - acc_type = "read"; -#endif - case InitiateWriteData: - if (cachePortBlocked) { - DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); - cache_req->done(false); - return; - } - - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i] Initiating data %s access to %s for " - "addr. %08p\n", tid, inst->seqNum, acc_type, name(), - cache_req->inst->getMemAddr()); - - inst->setCurResSlot(slot_num); - - if (inst->isDataPrefetch() || inst->isInstPrefetch()) { - inst->execute(); - } else { - inst->initiateAcc(); - } - - break; - - 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; - assert(inst->split2ndAddr != 0); - read(inst, inst->split2ndAddr, &inst->split2ndData, - inst->totalSize, inst->split2ndFlags); - break; - - 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()); - - inst->split2ndAccess = true; - assert(inst->split2ndAddr != 0); - write(inst, &inst->split2ndData, inst->totalSize, - inst->split2ndAddr, inst->split2ndFlags, NULL); - break; - - case CompleteReadData: - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Trying to Complete Data Read Access\n", - tid, inst->seqNum); - - - //@todo: timing translations need to check here... - assert(!inst->isInstPrefetch() && "Can't Handle Inst. Prefecthes"); - if (cache_req->isMemAccComplete() || inst->isDataPrefetch()) { - finishCacheUnitReq(inst, cache_req); - } 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; - - case CompleteWriteData: - { - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Trying to Complete Data Write Access\n", - tid, inst->seqNum); - - - //@todo: check that timing translation is finished here - RequestPtr mem_req = cache_req->memReq; - if (mem_req->isCondSwap() || mem_req->isLLSC() || mem_req->isSwap()) { - DPRINTF(InOrderCachePort, "Detected Conditional Store Inst.\n"); - - if (!cache_req->isMemAccComplete()) { - DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", - tid, cache_req->inst->getMemAddr()); - cache_req->setCompleted(false); - cache_req->setMemStall(true); - return; - } else { - DPRINTF(InOrderStall, "Mem Acc Completed\n"); - } - } - - if (cache_req->isMemAccPending()) { - DPRINTF(InOrderCachePort, "Store Instruction Pending Completion.\n"); - cache_req->dataPkt->reqData = cache_req->reqData; - cache_req->dataPkt->memReq = cache_req->memReq; - } else - DPRINTF(InOrderCachePort, "Store Instruction Finished Completion.\n"); - - //@todo: if split inst save data - finishCacheUnitReq(inst, cache_req); - } - break; - - case CompleteSecondSplitRead: - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read " - "Access\n", tid, inst->seqNum); - - //@todo: check that timing translation is finished here - assert(!inst->isInstPrefetch() && "Can't Handle Inst. Prefecthes"); - if (cache_req->isMemAccComplete() || inst->isDataPrefetch()) { - finishCacheUnitReq(inst, cache_req); - } 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; - - case CompleteSecondSplitWrite: - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write " - "Access\n", tid, inst->seqNum); - //@todo: illegal to have a unaligned cond.swap or llsc? - assert(!cache_req->memReq->isSwap() && !cache_req->memReq->isCondSwap() - && !cache_req->memReq->isLLSC()); - - if (cache_req->isMemAccPending()) { - cache_req->dataPkt->reqData = cache_req->reqData; - cache_req->dataPkt->memReq = cache_req->memReq; - } - - //@todo: check that timing translation is finished here - finishCacheUnitReq(inst, cache_req); - break; - - default: - fatal("Unrecognized command to %s", resName); - } -} - -void -CacheUnit::finishCacheUnitReq(DynInstPtr inst, CacheRequest *cache_req) -{ - //@note: add back in for speculative load/store capability - //removeAddrDependency(inst); - cache_req->setMemStall(false); - cache_req->done(); -} - -void -CacheUnit::buildDataPacket(CacheRequest *cache_req) -{ - MemCmd cmd; - - if (cache_req->pktCmd == MemCmd::ReadReq) { - cmd = Packet::makeReadCmd(cache_req->memReq); - } else { - assert(cache_req->pktCmd == MemCmd::WriteReq); - cmd = Packet::makeWriteCmd(cache_req->memReq); - } - - cache_req->dataPkt = new CacheReqPacket(cache_req, cmd, - cache_req->instIdx); - - DPRINTF(InOrderCachePort, "[slot:%i]: Slot marked for %x\n", - cache_req->getSlot(), - cache_req->dataPkt->getAddr()); - - cache_req->dataPkt->hasSlot = true; - cache_req->dataPkt->dataStatic(cache_req->reqData); -} - -void -CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, - CacheReqPtr split_req) -{ - Fault fault = NoFault; -#if TRACING_ON - ThreadID tid = inst->readTid(); -#endif - bool do_access = true; // flag to suppress cache access - - // Special Handling if this is a split request - CacheReqPtr cache_req; - if (split_req == NULL) - cache_req = dynamic_cast<CacheReqPtr>(reqs[inst->getCurResSlot()]); - else { - cache_req = split_req; - assert(0); - } - - // Make a new packet inside the CacheRequest object - assert(cache_req); - buildDataPacket(cache_req); - - // Special Handling for LL/SC or Compare/Swap - bool is_write = cache_req->dataPkt->isWrite(); - RequestPtr mem_req = cache_req->dataPkt->req; - if (is_write) { - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Storing data: %s\n", - tid, inst->seqNum, - printMemData(cache_req->dataPkt->getConstPtr<uint8_t>(), - cache_req->dataPkt->getSize())); - - if (mem_req->isCondSwap()) { - assert(write_res); - cache_req->memReq->setExtraData(*write_res); - } - if (mem_req->isLLSC()) { - assert(cache_req->inst->isStoreConditional()); - DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n"); - do_access = TheISA::handleLockedWrite(inst.get(), mem_req, cacheBlkSize); - } - } - - // Finally, go ahead and make the access if we can... - DPRINTF(InOrderCachePort, - "[tid:%i] [sn:%i] attempting to access cache for addr %08p\n", - tid, inst->seqNum, cache_req->dataPkt->getAddr()); - - if (do_access) { - if (!cachePort->sendTimingReq(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); - delete cache_req->dataPkt; - cache_req->dataPkt = NULL; - - delete cache_req->memReq; - cache_req->memReq = NULL; - - cache_req->done(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 (mem_req->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 { - delete cache_req->dataPkt; - cache_req->dataPkt = NULL; - - delete cache_req->memReq; - cache_req->memReq = NULL; - - // Make cache request again since access due to - // inability to access - DPRINTF(InOrderStall, "STALL: \n"); - cache_req->done(false); - } - -} - -bool -CacheUnit::processSquash(CacheReqPacket *cache_pkt) -{ - // The resource may no longer be actively servicing this - // packet. Scenarios like a store that has been sent to the - // memory system or access that's been squashed. If that's - // the case, we can't access the request slot because it - // will be either invalid or servicing another request. - if (!cache_pkt->hasSlot) { - DPRINTF(InOrderCachePort, - "%x does not have a slot in unit, ignoring.\n", - cache_pkt->getAddr()); - - if (cache_pkt->reqData) { - delete [] cache_pkt->reqData; - cache_pkt->reqData = NULL; - } - - if (cache_pkt->memReq) { - delete cache_pkt->memReq; - cache_pkt->memReq = NULL; - } - - delete cache_pkt; - cache_pkt = NULL; - cpu->wakeCPU(); - return true; - } else { - DPRINTF(InOrderCachePort, "%x has slot %i\n", - cache_pkt->getAddr(), cache_pkt->cacheReq->getSlot()); - } - - - // It's possible that the request is squashed but the - // packet is still acknowledged by the resource. Squashes - // should happen at the end of the cycles and trigger the - // code above, but if not, this would handle any timing - // variations due to diff. user parameters. - 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->setMemAccPending(false); - cache_pkt->cacheReq->freeSlot(); - delete cache_pkt; - cache_pkt = NULL; - cpu->wakeCPU(); - return true; - } - - - return false; -} - -void -CacheUnit::processCacheCompletion(PacketPtr pkt) -{ - //@todo: use packet sender state instead of deriving from packet class to - // get special state - CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt); - assert(cache_pkt); - - DPRINTF(InOrderCachePort, "Finished request for %x\n", pkt->getAddr()); - - if (processSquash(cache_pkt)) - return; - - CacheRequest *cache_req = dynamic_cast<CacheReqPtr>( - findRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx)); - - if (!cache_req) { - panic("[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()); - } - - assert(cache_req); - assert(cache_req == cache_pkt->cacheReq); - - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: [slot:%i] Waking from cache access (vaddr.%08p, paddr:%08p)\n", - cache_pkt->cacheReq->getInst()->readTid(), - cache_pkt->cacheReq->getInst()->seqNum, - cache_req->getSlot(), - cache_pkt->req->getVaddr(), - cache_pkt->req->getPaddr()); - - // Get resource request info - unsigned stage_num = cache_req->getStageNum(); - DynInstPtr inst = cache_req->inst; - ThreadID tid = cache_req->inst->readTid(); - - assert(!cache_req->isSquashed()); - assert(inst->staticInst && inst->isMemRef()); - - - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Processing cache access\n", - tid, inst->seqNum); - - PacketPtr split_pkt = NULL; - if (inst->splitInst) { - inst->splitFinishCnt++; - - if (inst->splitFinishCnt == 2) { - cache_req->memReq->setVirt(0/*inst->tid*/, - inst->getMemAddr(), - inst->totalSize, - 0, - cpu->dataMasterId(), - 0); - - split_pkt = new Packet(cache_req->memReq, cache_req->pktCmd); - split_pkt->dataStatic(inst->splitMemData); - - DPRINTF(InOrderCachePort, "Completing Split Access.\n"); - inst->completeAcc(split_pkt); - } - } else { - inst->completeAcc(cache_pkt); - } - - inst->setExecuted(); - - 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(inst.get(), cache_pkt->req); - } - - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Bytes loaded were: %s\n", - tid, inst->seqNum, - (split_pkt) ? printMemData(split_pkt->getConstPtr<uint8_t>(), - split_pkt->getSize()) : - printMemData(cache_pkt->getConstPtr<uint8_t>(), - cache_pkt->getSize())); - } else if(inst->isStore()) { - assert(cache_pkt->isWrite()); - - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Bytes stored were: %s\n", - tid, inst->seqNum, - (split_pkt) ? printMemData(split_pkt->getConstPtr<uint8_t>(), - split_pkt->getSize()) : - printMemData(cache_pkt->getConstPtr<uint8_t>(), - cache_pkt->getSize())); - } - - - if (split_pkt) { - delete split_pkt; - split_pkt = NULL; - } - - 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); -} - -void -CacheUnit::recvRetry() -{ - DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n"); - - assert(cachePortBlocked); - - // Clear the cache port for use again - cachePortBlocked = false; - - cpu->wakeCPU(); -} - -CacheUnitEvent::CacheUnitEvent() - : ResourceEvent() -{ } - -void -CacheUnitEvent::process() -{ - DynInstPtr inst = resource->reqs[slotIdx]->inst; - int stage_num = resource->reqs[slotIdx]->getStageNum(); - ThreadID tid = inst->threadNumber; - CacheReqPtr req_ptr = dynamic_cast<CacheReqPtr>(resource->reqs[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); - - //@todo: eventually, we should do a timing translation w/ - // hw page table walk on tlb miss - DPRINTF(InOrderTLB, "Handling Fault %s : [sn:%i] %x\n", inst->fault->name(), inst->seqNum, inst->getMemAddr()); - inst->fault->invoke(tlb_res->cpu->tcBase(tid), inst->staticInst); - - tlb_res->tlbBlocked[tid] = false; - - tlb_res->cpu->pipelineStage[stage_num]-> - unsetResStall(tlb_res->reqs[slotIdx], tid); - - req_ptr->tlbStall = false; - - //@todo: timing translation needs to have some type of independent - // info regarding if it's squashed or not so we can - // free up the resource if a request gets squashed in the middle - // of a table walk - if (req_ptr->isSquashed()) { - req_ptr->freeSlot(); - } - - tlb_res->cpu->wakeCPU(); -} - -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::squashCacheRequest(CacheReqPtr req_ptr) -{ - DynInstPtr inst = req_ptr->getInst(); - req_ptr->setSquashed(); - inst->setSquashed(); - - //@note: add back in for speculative load/store capability - /*if (inst->validMemAddr()) { - DPRINTF(AddrDep, "Squash of [tid:%i] [sn:%i], attempting to " - "remove addr. %08p dependencies.\n", - inst->readTid(), - inst->seqNum, - inst->getMemAddr()); - - removeAddrDependency(inst); - }*/ -} - - -void -CacheUnit::squash(DynInstPtr inst, int stage_num, - InstSeqNum squash_seq_num, ThreadID tid) -{ - if (tlbBlocked[tid] && - tlbBlockSeqNum[tid] > squash_seq_num) { - DPRINTF(InOrderCachePort, "Releasing TLB Block due to " - " squash after [sn:%i].\n", squash_seq_num); - tlbBlocked[tid] = false; - } - - for (int i = 0; i < width; i++) { - ResReqPtr req_ptr = reqs[i]; - - if (req_ptr->valid && - 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); - - if (req_ptr->isSquashed()) { - DPRINTF(AddrDep, "Request for [tid:%i] [sn:%i] already " - "squashed, ignoring squash process.\n", - req_ptr->getInst()->readTid(), - req_ptr->getInst()->seqNum); - continue; - } - - CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr); - assert(cache_req); - - squashCacheRequest(cache_req); - - int req_slot_num = req_ptr->getSlot(); - - if (cache_req->tlbStall) { - tlbBlocked[tid] = false; - - int stall_stage = reqs[req_slot_num]->getStageNum(); - - cpu->pipelineStage[stall_stage]-> - unsetResStall(reqs[req_slot_num], tid); - } - - if (cache_req->isMemAccPending()) { - cache_req->dataPkt->reqData = cache_req->reqData; - cache_req->dataPkt->memReq = cache_req->memReq; - } - - if (!cache_req->tlbStall) - freeSlot(req_slot_num); - } - } - -} - -void -CacheRequest::clearRequest() -{ - if (!memAccPending) { - if (reqData && !splitAccess) - delete [] reqData; - - if (memReq) - delete memReq; - - if (dataPkt) - delete dataPkt; - } else { - if (dataPkt) - dataPkt->hasSlot = false; - } - - memReq = NULL; - reqData = NULL; - dataPkt = NULL; - memAccComplete = false; - memAccPending = false; - tlbStall = false; - splitAccess = false; - splitAccessNum = -1; - split2ndAccess = false; - instIdx = 0; - fetchBufferFill = false; - - ResourceRequest::clearRequest(); -} |