summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/resources/cache_unit.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2015-04-20 12:46:35 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2015-04-20 12:46:35 -0400
commitcd76e34056afab83697beef1d1ced94ee671a20d (patch)
tree8adaa80ba72593bdf67103ad5cd0a072b95e8acb /src/cpu/inorder/resources/cache_unit.cc
parent076ea249ae47b935bea424954174f33fdecb7fcc (diff)
downloadgem5-cd76e34056afab83697beef1d1ced94ee671a20d.tar.xz
cpu: Remove the InOrderCPU from the tree
This patch takes the final step in removing the InOrderCPU from the tree. Rest in peace. The MinorCPU is now used to model an in-order microarchitecture, and long term the MinorCPU will eventually be renamed InOrderCPU.
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();
-}