summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/resources/cache_unit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/inorder/resources/cache_unit.cc')
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc1297
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();
-}