diff options
Diffstat (limited to 'src/cpu/inorder/resources/cache_unit.cc')
-rw-r--r-- | src/cpu/inorder/resources/cache_unit.cc | 650 |
1 files changed, 547 insertions, 103 deletions
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index eb66e10f8..cb1861ea9 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -40,6 +40,7 @@ #include "cpu/inorder/resources/cache_unit.hh" #include "cpu/inorder/pipeline_traits.hh" #include "cpu/inorder/cpu.hh" +#include "cpu/inorder/resource_pool.hh" #include "mem/request.hh" using namespace std; @@ -49,14 +50,14 @@ using namespace ThePipeline; Tick CacheUnit::CachePort::recvAtomic(PacketPtr pkt) { - panic("DefaultFetch doesn't expect recvAtomic callback!"); + panic("CacheUnit::CachePort doesn't expect recvAtomic callback!"); return curTick; } void CacheUnit::CachePort::recvFunctional(PacketPtr pkt) { - panic("DefaultFetch doesn't expect recvFunctional callback!"); + panic("CacheUnit::CachePort doesn't expect recvFunctional callback!"); } void @@ -65,7 +66,7 @@ CacheUnit::CachePort::recvStatusChange(Status status) if (status == RangeChange) return; - panic("DefaultFetch doesn't expect recvStatusChange callback!"); + panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!"); } bool @@ -84,8 +85,7 @@ CacheUnit::CachePort::recvRetry() CacheUnit::CacheUnit(string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), - retryPkt(NULL), retrySlot(-1), cacheBlocked(false), - predecoder(NULL) + cachePortBlocked(false), predecoder(NULL) { cachePort = new CachePort(this); @@ -131,18 +131,24 @@ CacheUnit::init() int CacheUnit::getSlot(DynInstPtr inst) { + ThreadID tid = inst->readTid(); + if (tlbBlocked[inst->threadNumber]) { return -1; } - if (!inst->validMemAddr()) { - panic("Mem. Addr. must be set before requesting cache access\n"); + // 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); } Addr req_addr = inst->getMemAddr(); if (resName == "icache_port" || - find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) { + find(addrList[tid].begin(), addrList[tid].end(), req_addr) == + addrList[tid].end()) { int new_slot = Resource::getSlot(inst); @@ -150,37 +156,115 @@ CacheUnit::getSlot(DynInstPtr inst) return -1; inst->memTime = curTick; - addrList.push_back(req_addr); - addrMap[req_addr] = inst->seqNum; - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", - inst->readTid(), inst->seqNum, req_addr); + setAddrDependency(inst); return new_slot; } else { - DPRINTF(InOrderCachePort, - "Denying request because there is an outstanding" + // Allow same instruction multiple accesses to same address + // should only happen maybe after a squashed inst. needs to replay + if (addrMap[tid][req_addr] == inst->seqNum) { + int new_slot = Resource::getSlot(inst); + + if (new_slot == -1) + return -1; + + return new_slot; + } else { + DPRINTF(InOrderCachePort, + "[tid:%i] Denying request because there is an outstanding" " request to/for addr. %08p. by [sn:%i] @ tick %i\n", - req_addr, addrMap[req_addr], inst->memTime); - return -1; + inst->readTid(), req_addr, addrMap[tid][req_addr], inst->memTime); + return -1; + } } + + return -1; } void -CacheUnit::freeSlot(int slot_num) +CacheUnit::setAddrDependency(DynInstPtr inst) { - vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(), - reqMap[slot_num]->inst->getMemAddr()); - assert(vect_it != addrList.end()); + Addr req_addr = inst->getMemAddr(); + ThreadID tid = inst->readTid(); + addrList[tid].push_back(req_addr); + addrMap[tid][req_addr] = inst->seqNum; DPRINTF(InOrderCachePort, - "[tid:%i]: Address %08p removed from dependency list\n", - reqMap[slot_num]->inst->readTid(), (*vect_it)); + "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", + inst->readTid(), inst->seqNum, req_addr); + DPRINTF(AddrDep, + "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", + inst->readTid(), inst->seqNum, req_addr); +} + +void +CacheUnit::removeAddrDependency(DynInstPtr inst) +{ + ThreadID tid = inst->readTid(); + + Addr mem_addr = inst->getMemAddr(); + + // Erase from Address List + vector<Addr>::iterator vect_it = find(addrList[tid].begin(), addrList[tid].end(), + mem_addr); + assert(vect_it != addrList[tid].end() || inst->splitInst); + + if (vect_it != addrList[tid].end()) { + DPRINTF(AddrDep, + "[tid:%i]: [sn:%i] Address %08p removed from dependency list\n", + inst->readTid(), inst->seqNum, (*vect_it)); + + addrList[tid].erase(vect_it); + + // Erase From Address Map (Used for Debugging) + addrMap[tid].erase(addrMap[tid].find(mem_addr)); + } + + +} + +ResReqPtr +CacheUnit::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + CacheRequest* cache_req = dynamic_cast<CacheRequest*>((*map_it).second); + assert(cache_req); + + if (cache_req && + cache_req->getInst() == inst && + cache_req->instIdx == inst->resSched.top()->idx) { + return cache_req; + } + map_it++; + } + + return NULL; +} + +ResReqPtr +CacheUnit::findSplitRequest(DynInstPtr inst, int idx) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + CacheRequest* cache_req = dynamic_cast<CacheRequest*>((*map_it).second); + assert(cache_req); - addrList.erase(vect_it); + if (cache_req && + cache_req->getInst() == inst && + cache_req->instIdx == idx) { + return cache_req; + } + map_it++; + } - Resource::freeSlot(slot_num); + return NULL; } + ResReqPtr CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) @@ -195,6 +279,14 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, 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; @@ -203,6 +295,14 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, 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; @@ -226,7 +326,8 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, return new CacheRequest(this, inst, stage_num, id, slot_num, sched_entry->cmd, 0, pkt_cmd, - 0/*flags*/, this->cpu->readCpuId()); + 0/*flags*/, this->cpu->readCpuId(), + inst->resSched.top()->idx); } void @@ -237,15 +338,17 @@ CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) // Check to see if this instruction is requesting the same command // or a different one - if (cache_req->cmd != inst->resSched.top()->cmd) { + if (cache_req->cmd != inst->resSched.top()->cmd && + cache_req->instIdx == inst->resSched.top()->idx) { // If different, then update command in the request cache_req->cmd = inst->resSched.top()->cmd; DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Updating the command for this instruction\n", - inst->readTid(), inst->seqNum); + "[tid:%i]: [sn:%i]: Updating the command for this " + "instruction\n ", inst->readTid(), inst->seqNum); service_request = true; - } else { + } else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead && + inst->resSched.top()->idx != CacheUnit::InitSecondSplitWrite) { // If same command, just check to see if memory access was completed // but dont try to re-execute DPRINTF(InOrderCachePort, @@ -271,12 +374,25 @@ CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size, cpu->readCpuId(), inst->readTid()); cache_req->memReq = inst->fetchMemReq; } else { - inst->dataMemReq = new Request(inst->readTid(), aligned_addr, + if (!cache_req->is2ndSplit()) { + inst->dataMemReq = new Request(cpu->asid[tid], aligned_addr, acc_size, flags, inst->readPC(), cpu->readCpuId(), inst->readTid()); cache_req->memReq = inst->dataMemReq; + } else { + assert(inst->splitInst); + + inst->splitMemReq = new Request(cpu->asid[tid], + inst->split2ndAddr, + acc_size, + flags, + inst->readPC(), + cpu->readCpuId(), + tid); + cache_req->memReq = inst->splitMemReq; + } } - + cache_req->fault = _tlb->translateAtomic(cache_req->memReq, @@ -311,14 +427,93 @@ Fault CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags) { CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); - assert(cache_req); + assert(cache_req && "Can't Find Instruction for Read!"); + + // The block size of our peer + unsigned blockSize = this->cachePort->peerBlockSize(); + + //The size of the data we're trying to read. + int dataSize = sizeof(T); + + if (inst->split2ndAccess) { + dataSize = inst->split2ndSize; + cache_req->splitAccess = true; + cache_req->split2ndAccess = true; + + DPRINTF(InOrderCachePort, "[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 + dataSize - 1, blockSize); + + + if (secondAddr > addr && !inst->split2ndAccess) { + DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (1 of 2) for (%#x, %#x).\n", curTick, inst->seqNum, + addr, secondAddr); + + // Save All "Total" Split Information + // ============================== + inst->splitInst = true; + inst->splitMemData = new uint8_t[dataSize]; + inst->splitTotalSize = dataSize; + + if (!inst->splitInstSked) { + // Schedule Split Read/Complete for Instruction + // ============================== + int stage_num = cache_req->getStageNum(); + + int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + + inst->resSched.push(new ScheduleEntry(stage_num, + stage_pri, + cpu->resPool->getResIdx(DCache), + CacheUnit::InitSecondSplitRead, + 1) + ); + + inst->resSched.push(new ScheduleEntry(stage_num + 1, + 1/*stage_pri*/, + cpu->resPool->getResIdx(DCache), + CacheUnit::CompleteSecondSplitRead, + 1) + ); + 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); + } - int acc_size = sizeof(T); - doTLBAccess(inst, cache_req, acc_size, flags, TheISA::TLB::Read); + // Split Information for First Access + // ============================== + dataSize = secondAddr - addr; + cache_req->splitAccess = true; + + // Split Information for Second Access + // ============================== + inst->split2ndSize = addr + sizeof(T) - secondAddr; + inst->split2ndAddr = secondAddr; + inst->split2ndDataPtr = inst->splitMemData + dataSize; + inst->split2ndFlags = flags; + } + + doTLBAccess(inst, cache_req, dataSize, flags, TheISA::TLB::Read); if (cache_req->fault == NoFault) { - cache_req->reqData = new uint8_t[acc_size]; - doCacheAccess(inst, NULL); + if (!cache_req->splitAccess) { + cache_req->reqData = new uint8_t[dataSize]; + doCacheAccess(inst, NULL); + } else { + if (!inst->split2ndAccess) { + cache_req->reqData = inst->splitMemData; + } else { + cache_req->reqData = inst->split2ndDataPtr; + } + + doCacheAccess(inst, NULL, cache_req); + } } return cache_req->fault; @@ -330,16 +525,93 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags, uint64_t *write_res) { CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); - assert(cache_req); - - int acc_size = sizeof(T); - doTLBAccess(inst, cache_req, acc_size, flags, TheISA::TLB::Write); + assert(cache_req && "Can't Find Instruction for Write!"); + + // The block size of our peer + unsigned blockSize = this->cachePort->peerBlockSize(); + + //The size of the data we're trying to read. + int dataSize = sizeof(T); + + if (inst->split2ndAccess) { + dataSize = inst->split2ndSize; + cache_req->splitAccess = true; + cache_req->split2ndAccess = true; + + DPRINTF(InOrderCachePort, "[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 + dataSize - 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; + inst->splitTotalSize = dataSize; + + if (!inst->splitInstSked) { + // Schedule Split Read/Complete for Instruction + // ============================== + int stage_num = cache_req->getStageNum(); + + int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + + inst->resSched.push(new ScheduleEntry(stage_num, + stage_pri, + cpu->resPool->getResIdx(DCache), + CacheUnit::InitSecondSplitWrite, + 1) + ); + + inst->resSched.push(new ScheduleEntry(stage_num + 1, + 1/*stage_pri*/, + cpu->resPool->getResIdx(DCache), + CacheUnit::CompleteSecondSplitWrite, + 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 + // ============================== + dataSize = secondAddr - addr; + cache_req->splitAccess = true; + + // Split Information for Second Access + // ============================== + inst->split2ndSize = addr + sizeof(T) - secondAddr; + inst->split2ndAddr = secondAddr; + inst->split2ndStoreDataPtr = &cache_req->inst->storeData; + inst->split2ndStoreDataPtr += dataSize; + inst->split2ndFlags = flags; + inst->splitInstSked = true; + } + + doTLBAccess(inst, cache_req, dataSize, flags, TheISA::TLB::Write); if (cache_req->fault == NoFault) { - cache_req->reqData = new uint8_t[acc_size]; - doCacheAccess(inst, write_res); + if (!cache_req->splitAccess) { + // Remove this line since storeData is saved in INST? + cache_req->reqData = new uint8_t[dataSize]; + doCacheAccess(inst, write_res); + } else { + doCacheAccess(inst, write_res, cache_req); + } + } - + return cache_req->fault; } @@ -347,8 +619,8 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags, void CacheUnit::execute(int slot_num) { - if (cacheBlocked) { - DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access\n"); + if (cachePortBlocked) { + DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); return; } @@ -359,6 +631,8 @@ CacheUnit::execute(int slot_num) #if TRACING_ON ThreadID tid = inst->readTid(); int seq_num = inst->seqNum; + std::string acc_type = "write"; + #endif cache_req->fault = NoFault; @@ -390,10 +664,14 @@ CacheUnit::execute(int slot_num) } case InitiateReadData: +#if TRACING_ON + acc_type = "read"; +#endif case InitiateWriteData: + DPRINTF(InOrderCachePort, - "[tid:%u]: Initiating data access to %s for addr. %08p\n", - tid, name(), cache_req->inst->getMemAddr()); + "[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); @@ -402,9 +680,29 @@ CacheUnit::execute(int slot_num) } 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->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->split2ndAddr, inst->split2ndData, inst->split2ndFlags, NULL); break; + case CompleteFetch: if (cache_req->isMemAccComplete()) { DPRINTF(InOrderCachePort, @@ -415,16 +713,24 @@ CacheUnit::execute(int slot_num) DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n", tid, seq_num, inst->staticInst->disassemble(inst->PC)); + removeAddrDependency(inst); + delete cache_req->dataPkt; + + // Do not stall and switch threads for fetch... for now.. + // TODO: We need to detect cache misses for latencies > 1 + // cache_req->setMemStall(false); + cache_req->done(); } else { DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n", + "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n", tid, inst->seqNum); DPRINTF(InOrderStall, "STALL: [tid:%i]: Fetch miss from %08p\n", tid, cache_req->inst->readPC()); cache_req->setCompleted(false); + //cache_req->setMemStall(true); } break; @@ -437,14 +743,55 @@ CacheUnit::execute(int slot_num) if (cache_req->isMemAccComplete() || inst->isDataPrefetch() || inst->isInstPrefetch()) { + removeAddrDependency(inst); + cache_req->setMemStall(false); cache_req->done(); } else { DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", tid, cache_req->inst->getMemAddr()); cache_req->setCompleted(false); + cache_req->setMemStall(true); } break; + case CompleteSecondSplitRead: + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read Access\n", + tid, inst->seqNum); + + if (cache_req->isMemAccComplete() || + inst->isDataPrefetch() || + inst->isInstPrefetch()) { + removeAddrDependency(inst); + cache_req->setMemStall(false); + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->split2ndAddr); + cache_req->setCompleted(false); + cache_req->setMemStall(true); + } + break; + + case CompleteSecondSplitWrite: + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write Access\n", + tid, inst->seqNum); + + if (cache_req->isMemAccComplete() || + inst->isDataPrefetch() || + inst->isInstPrefetch()) { + removeAddrDependency(inst); + cache_req->setMemStall(false); + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->split2ndAddr); + cache_req->setCompleted(false); + cache_req->setMemStall(true); + } + break; + default: fatal("Unrecognized command to %s", resName); } @@ -462,8 +809,7 @@ CacheUnit::prefetch(DynInstPtr inst) // Clean-Up cache resource request so // other memory insts. can use them cache_req->setCompleted(); - cacheStatus = cacheAccessComplete; - cacheBlocked = false; + cachePortBlocked = false; cache_req->setMemAccPending(false); cache_req->setMemAccCompleted(); inst->unsetMemAddr(); @@ -482,8 +828,7 @@ CacheUnit::writeHint(DynInstPtr inst) // Clean-Up cache resource request so // other memory insts. can use them cache_req->setCompleted(); - cacheStatus = cacheAccessComplete; - cacheBlocked = false; + cachePortBlocked = false; cache_req->setMemAccPending(false); cache_req->setMemAccCompleted(); inst->unsetMemAddr(); @@ -491,15 +836,21 @@ CacheUnit::writeHint(DynInstPtr inst) // @TODO: Split into doCacheRead() and doCacheWrite() Fault -CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res) +CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, CacheReqPtr split_req) { Fault fault = NoFault; #if TRACING_ON ThreadID tid = inst->readTid(); #endif - CacheReqPtr cache_req - = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]); + CacheReqPtr cache_req; + + if (split_req == NULL) { + cache_req = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]); + } else{ + cache_req = split_req; + } + assert(cache_req); // Check for LL/SC and if so change command @@ -510,25 +861,28 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res) if (cache_req->pktCmd == MemCmd::WriteReq) { cache_req->pktCmd = cache_req->memReq->isSwap() ? MemCmd::SwapReq : - (cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq : MemCmd::WriteReq); + (cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq + : MemCmd::WriteReq); } cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd, - Packet::Broadcast); + Packet::Broadcast, cache_req->instIdx); if (cache_req->dataPkt->isRead()) { cache_req->dataPkt->dataStatic(cache_req->reqData); - } else if (cache_req->dataPkt->isWrite()) { - cache_req->dataPkt->dataStatic(&cache_req->inst->storeData); - + } else if (cache_req->dataPkt->isWrite()) { + if (inst->split2ndAccess) { + cache_req->dataPkt->dataStatic(inst->split2ndStoreDataPtr); + } else { + cache_req->dataPkt->dataStatic(&cache_req->inst->storeData); + } + if (cache_req->memReq->isCondSwap()) { assert(write_res); cache_req->memReq->setExtraData(*write_res); } } - cache_req->dataPkt->time = curTick; - bool do_access = true; // flag to suppress cache access Request *memReq = cache_req->dataPkt->req; @@ -546,28 +900,18 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res) if (do_access) { if (!cachePort->sendTiming(cache_req->dataPkt)) { DPRINTF(InOrderCachePort, - "[tid:%i] [sn:%i] is waiting to retry request\n", - tid, inst->seqNum); - - retrySlot = cache_req->getSlot(); - retryReq = cache_req; - retryPkt = cache_req->dataPkt; - - cacheStatus = cacheWaitRetry; - - //cacheBlocked = true; - - DPRINTF(InOrderStall, "STALL: \n"); - + "[tid:%i] [sn:%i] cannot access cache, because port " + "is blocked. now waiting to retry request\n", tid, + inst->seqNum); cache_req->setCompleted(false); + cachePortBlocked = true; } else { DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is now waiting for cache response\n", tid, inst->seqNum); cache_req->setCompleted(); cache_req->setMemAccPending(); - cacheStatus = cacheWaitResponse; - cacheBlocked = false; + cachePortBlocked = false; } } else if (!do_access && memReq->isLLSC()){ // Store-Conditional instructions complete even if they "failed" @@ -594,6 +938,7 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) { // Cast to correct packet type CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt); + assert(cache_pkt); if (cache_pkt->cacheReq->isSquashed()) { @@ -601,9 +946,16 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n", cache_pkt->cacheReq->getInst()->readTid(), cache_pkt->cacheReq->getInst()->seqNum); + DPRINTF(RefCount, + "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n", + cache_pkt->cacheReq->getTid(), + cache_pkt->cacheReq->seqNum); cache_pkt->cacheReq->done(); delete cache_pkt; + + cpu->wakeCPU(); + return; } @@ -615,7 +967,16 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) // Cast to correct request type CacheRequest *cache_req = dynamic_cast<CacheReqPtr>( - findRequest(cache_pkt->cacheReq->getInst())); + findSplitRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx)); + + if (!cache_req) { + warn( + "[tid:%u]: [sn:%i]: Can't find slot for cache access to addr. %08p\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum, + cache_pkt->cacheReq->getInst()->getMemAddr()); + } + assert(cache_req); @@ -641,8 +1002,9 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) ExtMachInst ext_inst; StaticInstPtr staticInst = NULL; Addr inst_pc = inst->readPC(); - MachInst mach_inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *> - (cache_pkt->getPtr<uint8_t>())); + MachInst mach_inst = + TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *> + (cache_pkt->getPtr<uint8_t>())); predecoder.setTC(cpu->thread[tid]->getTC()); predecoder.moreBytes(inst_pc, inst_pc, mach_inst); @@ -660,9 +1022,33 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) DPRINTF(InOrderCachePort, "[tid:%u]: [sn:%i]: Processing cache access\n", tid, inst->seqNum); - - inst->completeAcc(pkt); - + + if (inst->splitInst) { + inst->splitFinishCnt++; + + if (inst->splitFinishCnt == 2) { + cache_req->memReq->setVirt(0/*inst->tid*/, + inst->getMemAddr(), + inst->splitTotalSize, + 0, + 0); + + Packet split_pkt(cache_req->memReq, cache_req->pktCmd, + Packet::Broadcast); + + + if (inst->isLoad()) { + split_pkt.dataStatic(inst->splitMemData); + } else { + split_pkt.dataStatic(&inst->storeData); + } + + inst->completeAcc(&split_pkt); + } + } else { + inst->completeAcc(pkt); + } + if (inst->isLoad()) { assert(cache_pkt->isRead()); @@ -696,6 +1082,16 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) cache_req->setMemAccPending(false); cache_req->setMemAccCompleted(); + if (cache_req->isMemStall() && + cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) { + DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n", tid); + + cpu->activateContext(tid); + + DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache" + "miss.\n", tid); + } + // Wake up the CPU (if it went to sleep and was waiting on this // completion event). cpu->wakeCPU(); @@ -717,22 +1113,14 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) void CacheUnit::recvRetry() { - DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i]\n", - retryReq->inst->readTid(), retryReq->inst->seqNum); + DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n"); + + assert(cachePortBlocked); - assert(retryPkt != NULL); - assert(cacheBlocked); - assert(cacheStatus == cacheWaitRetry); + // Clear the cache port for use again + cachePortBlocked = false; - if (cachePort->sendTiming(retryPkt)) { - cacheStatus = cacheWaitResponse; - retryPkt = NULL; - cacheBlocked = false; - } else { - DPRINTF(InOrderCachePort, - "Retry Request for [tid:%i] [sn:%i] failed\n", - retryReq->inst->readTid(), retryReq->inst->seqNum); - } + cpu->wakeCPU(); } CacheUnitEvent::CacheUnitEvent() @@ -755,7 +1143,8 @@ CacheUnitEvent::process() tlb_res->tlbBlocked[tid] = false; - tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(tlb_res->reqMap[slotIdx], tid); + tlb_res->cpu->pipelineStage[stage_num]-> + unsetResStall(tlb_res->reqMap[slotIdx], tid); req_ptr->tlbStall = false; @@ -765,6 +1154,26 @@ CacheUnitEvent::process() } void +CacheUnit::squashDueToMemStall(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, ThreadID tid) +{ + // If squashing due to memory stall, then we do NOT want to + // squash the instruction that caused the stall so we + // increment the sequence number here to prevent that. + // + // NOTE: This is only for the SwitchOnCacheMiss Model + // NOTE: If you have multiple outstanding misses from the same + // thread then you need to reevaluate this code + // NOTE: squash should originate from + // pipeline_stage.cc:processInstSchedule + DPRINTF(InOrderCachePort, "Squashing above [sn:%u]\n", + squash_seq_num + 1); + + squash(inst, stage_num, squash_seq_num + 1, tid); +} + + +void CacheUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, ThreadID tid) { @@ -784,6 +1193,14 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, "[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); + map_it++; + continue; + } + req_ptr->setSquashed(); req_ptr->getInst()->setSquashed(); @@ -798,7 +1215,8 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, int stall_stage = reqMap[req_slot_num]->getStageNum(); - cpu->pipelineStage[stall_stage]->unsetResStall(reqMap[req_slot_num], tid); + cpu->pipelineStage[stall_stage]-> + unsetResStall(reqMap[req_slot_num], tid); } if (!cache_req->tlbStall && !cache_req->isMemAccPending()) { @@ -807,7 +1225,29 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, // Mark slot for removal from resource slot_remove_list.push_back(req_ptr->getSlot()); + + DPRINTF(InOrderCachePort, + "[tid:%i] Squashing request from [sn:%i]\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i] Request from [sn:%i] squashed, but still pending completion.\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); + DPRINTF(RefCount, + "[tid:%i] Request from [sn:%i] squashed (split:%i), but still pending completion.\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum, + req_ptr->getInst()->splitInst); } + + if (req_ptr->getInst()->validMemAddr()) { + DPRINTF(AddrDep, "Squash of [tid:%i] [sn:%i], attempting to remove addr. %08p dependencies.\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum, + req_ptr->getInst()->getMemAddr()); + + removeAddrDependency(req_ptr->getInst()); + } + } map_it++; @@ -927,14 +1367,16 @@ CacheUnit::write(DynInstPtr inst, uint8_t data, Addr addr, template<> Fault -CacheUnit::write(DynInstPtr inst, double data, Addr addr, unsigned flags, uint64_t *res) +CacheUnit::write(DynInstPtr inst, double data, Addr addr, unsigned flags, + uint64_t *res) { return write(inst, *(uint64_t*)&data, addr, flags, res); } template<> Fault -CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags, uint64_t *res) +CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags, + uint64_t *res) { return write(inst, *(uint32_t*)&data, addr, flags, res); } @@ -942,7 +1384,9 @@ CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags, uint64_ template<> Fault -CacheUnit::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags, uint64_t *res) +CacheUnit::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags, + uint64_t *res) { return write(inst, (uint32_t)data, addr, flags, res); } + |