diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/resources/graduation_unit.cc --- a/src/cpu/inorder/resources/graduation_unit.cc Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/resources/graduation_unit.cc Sun Apr 01 20:45:12 2012 -0400 @@ -81,7 +81,7 @@ case CheckFault: { // Handle Any Faults Before Graduating Instruction - if (inst->fault != NoFault) { + if (inst->fault != NoFault && !inst->isDataPrefetch()) { DPRINTF(InOrderGraduation, "[tid:%i]: [sn:%i]: fault %s found for %s\n", tid, inst->seqNum, inst->fault->name(), inst->instName()); @@ -89,10 +89,15 @@ lastFaultTick[tid] = cur_tick; grad_req->done(false); return; + } else if (inst->fault != NoFault && inst->isDataPrefetch()) { + DPRINTF(InOrderGraduation, "[tid:%i]: [sn:%i]: Ignoring prefetch fault %s found for %s\n", + tid, inst->seqNum, inst->fault->name(), + inst->instName()); + } else { + DPRINTF(InOrderGraduation, "[tid:%i] [sn:%i]: No fault found for %s\n", + tid, inst->seqNum, inst->instName()); } - DPRINTF(InOrderGraduation, "[tid:%i] [sn:%i]: No fault found for %s\n", - tid, inst->seqNum, inst->instName()); grad_req->done(); } break; diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/resources/inorder_translation.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/inorder/resources/inorder_translation.hh Sun Apr 01 20:45:12 2012 -0400 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012 The University of Edinburgh + * 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. + * + * Author: Erik Tomusk + */ + +#ifndef __CPU_INORDER_TRANSLATION__ +#define __CPU_INORDER_TRANSLATION__ + +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/translation.hh" +#include "sim/faults.hh" +#include "sim/tlb.hh" + +/** + * @todo: describe the class + */ +//class CacheUnit; +//class CacheRequestPtr; +class InOrderTranslationState : public WholeTranslationState +{ + protected: + ThreadID tid; + + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + DynInstPtr inst; + CacheReqPtr cacheReq; + bool translationStarted; + bool translationFinished; + + InOrderTranslationState(RequestPtr _req, uint8_t *_data, uint64_t *_res, + BaseTLB::Mode _mode) + : WholeTranslationState(_req, _data, _res, _mode), + translationStarted(false), translationFinished(false) + { } + + InOrderTranslationState(RequestPtr _req, RequestPtr _sreqLow, + RequestPtr _sreqHigh, uint8_t *_data, uint64_t *_res, + BaseTLB::Mode _mode) + : WholeTranslationState(_req, _sreqLow, _sreqHigh, _data, _res, _mode), + translationStarted(false), translationFinished(false) + { } + + inline bool isDelayed() { return delay; } + inline bool isStarted() { return translationStarted; } + inline bool isFinished() { return translationFinished; } + inline bool isRead() { return (mode == BaseTLB::Read); } + inline bool isWrite() { return (mode == BaseTLB::Write); } +}; + +#endif // __CPU_INORDER_TRANSLATION__ diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/translation.hh --- a/src/cpu/translation.hh Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/translation.hh Sun Apr 01 20:45:12 2012 -0400 @@ -103,6 +103,7 @@ assert(mode == BaseTLB::Read || mode == BaseTLB::Write); } + virtual ~WholeTranslationState() {} /** * Finish part of a translation. If there is only one request then this * translation is completed. If the request has been split in two then diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/cpu.hh --- a/src/cpu/inorder/cpu.hh Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/cpu.hh Sun Apr 01 20:45:12 2012 -0400 @@ -67,6 +67,7 @@ #include "cpu/base.hh" #include "cpu/simple_thread.hh" #include "cpu/timebuf.hh" +#include "cpu/translation.hh" #include "mem/packet.hh" #include "mem/port.hh" #include "mem/request.hh" diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/cpu.cc --- a/src/cpu/inorder/cpu.cc Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/cpu.cc Sun Apr 01 20:45:12 2012 -0400 @@ -1798,3 +1798,4 @@ return resPool->getDataUnit()->write(inst, data, size, addr, flags, write_res); } + diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/inorder_dyn_inst.hh --- a/src/cpu/inorder/inorder_dyn_inst.hh Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/inorder_dyn_inst.hh Sun Apr 01 20:45:12 2012 -0400 @@ -49,6 +49,7 @@ #include "cpu/inorder/pipeline_traits.hh" #include "cpu/inorder/resource.hh" #include "cpu/inorder/resource_sked.hh" +#include "cpu/inorder/resources/inorder_translation.hh" #include "cpu/inorder/thread_state.hh" #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" @@ -177,6 +178,10 @@ /** Pointer to the thread state. */ InOrderThreadState *thread; + /** Pointer to translation information */ + //@note: do we need separate states for inst/data translation? + InOrderTranslationState *state; + /** The kind of fault this instruction has generated. */ Fault fault; diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/resources/cache_unit.hh --- a/src/cpu/inorder/resources/cache_unit.hh Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/resources/cache_unit.hh Sun Apr 01 20:45:12 2012 -0400 @@ -50,6 +50,7 @@ #include "sim/sim_object.hh" class CacheReqPacket; +class WholeTranslationState; typedef CacheReqPacket* CacheReqPktPtr; class CacheUnit : public Resource @@ -126,6 +127,9 @@ void doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size, int flags, TheISA::TLB::Mode tlb_mode); + /** Finish a DTB translation */ + void finishTranslation(WholeTranslationState *state); + /** Read/Write on behalf of an instruction. * curResSlot needs to be a valid value in instruction. */ @@ -234,6 +238,7 @@ RequestPtr memReq; PacketDataPtr reqData; CacheReqPacket *dataPkt; + uint64_t *writeRes; bool memAccComplete; bool memAccPending; diff -r 6df06e5975c6 -r d6bee96281fc src/cpu/inorder/resources/cache_unit.cc --- a/src/cpu/inorder/resources/cache_unit.cc Sun Mar 11 16:51:38 2012 -0500 +++ b/src/cpu/inorder/resources/cache_unit.cc Sun Apr 01 20:45:12 2012 -0400 @@ -38,9 +38,11 @@ #include "arch/utility.hh" #include "config/the_isa.hh" #include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/resources/inorder_translation.hh" #include "cpu/inorder/cpu.hh" #include "cpu/inorder/pipeline_traits.hh" #include "cpu/inorder/resource_pool.hh" +#include "cpu/translation.hh" #include "debug/Activity.hh" #include "debug/AddrDep.hh" #include "debug/InOrderCachePort.hh" @@ -355,7 +357,6 @@ 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 @@ -365,8 +366,38 @@ PCState old_pc = tc->pcState(); tc->pcState() = inst->pcState(); - inst->fault = - _tlb->translateAtomic(cache_req->memReq, tc, tlb_mode); + // Set up Translation object similarly to simple/timing.cc + // The data and res values in WholeTranslationState should not be needed + // as that is handled in doCacheAccess() later + if (cache_req->splitAccess) { + assert(0 && "Timing Translation for Split Access Not Working Yet."); + /*RequestPtr req1, req2; + cache_req->memReq->splitOnVaddr(inst->split2ndAddr, req1, req2); + inst->state = new InOrderTranslationState(cache_req->memReq, req1, req2, NULL, NULL, tlb_mode); + DataTranslation *trans1 = + new InOrderTranslation(cpu, inst->state, 0, tid, this); + DataTranslation *trans2 = + new InOrderTranslation(cpu, inst->state, 1, tid, this); + + inst->state->translationStarted = true; + inst->fault = _tlb->translateTiming(req1, tc, trans1, tlb_mode); + //@note: Is it realistic for the CPU to get the TLB response fast enough + // to know if it can be *another* TLB request in the same cycle? + if (inst->fault == NoFault){ + inst->fault = _tlb->translateTiming(req2, tc, trans2, tlb_mode); + }*/ + } else { + inst->state = new InOrderTranslationState(cache_req->memReq, NULL, NULL, tlb_mode); + inst->state->translationStarted = true; + + //@note: Is there anything different here for InstTranslation? + DataTranslation *trans = new DataTranslation(this, inst->state); + + //@note: Why is ARM the only ISA that returns a fault from translateTiming? + _tlb->translateTiming(cache_req->memReq, tc, trans, tlb_mode); + } + + // reset PC due to above hack tc->pcState() = old_pc; if (inst->fault != NoFault) { @@ -393,9 +424,69 @@ } void +CacheUnit::finishTranslation(WholeTranslationState *state) +{ + InOrderTranslationState *trans_state = dynamic_cast(state); + assert(trans_state); + CacheReqPtr cache_req = trans_state->cacheReq; + DynInstPtr inst = trans_state->inst; + ThreadID tid = inst->readTid(); + int size = cache_req->dataPkt->getSize(); + + //Now that the translation is done, go ahead and do the cache access + //@note: ok to mark finished here if split access? maybe count finishes? + trans_state->translationFinished = true; + if (state->getFault() != NoFault) { + if (!state->isPrefetch()) { + 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(); + } else { + DPRINTF(InOrderTLB, "[tid:%i]: Ignoring %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, inst->fault->name(), + cache_req->memReq->getVaddr(), inst->seqNum); + } + // Mark it as complete so it can pass through next stage. + // Fault Handling will happen at commit/graduation + cache_req->setCompleted(); + } else { + if (trans_state->isRead()) { + 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); + } + } else if (trans_state->isWrite()) { + if (!cache_req->splitAccess) { + cache_req->reqData = new uint8_t[size]; + memcpy(cache_req->reqData, data, size); + doCacheAccess(inst, cache_req->writeRes); + } else { + doCacheAccess(inst, cache_req->writeRes, cache_req); + } + } + } +} + +void CacheUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst) { - tlbBlocked[tid] = false; + // Unblocking is done by InOrderDataTranslation + //tlbBlocked[tid] = false; } Fault @@ -475,21 +566,7 @@ 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); - } - } - + //@note: is it possible to have a fault here w/timing translation? return inst->fault; } @@ -583,24 +660,11 @@ inst->split2ndFlags = flags; inst->splitInstSked = true; } - + + cache_req->writeRes = write_res; 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); - } - - } - + //@note: is it possible to have a fault here w/timing translation? return inst->fault; } @@ -670,7 +734,7 @@ } else { inst->initiateAcc(); } - + break; case InitSecondSplitRead: @@ -702,7 +766,13 @@ tid, inst->seqNum); - //@todo: timing translations need to check here... + if (tlbBlocked[tid] || !inst->state->translationFinished) + { + DPRINTF(InOrderCachePort, " Failed because ", + "translation ongoing\n"); + break; + } + assert(!inst->isInstPrefetch() && "Can't Handle Inst. Prefecthes"); if (cache_req->isMemAccComplete() || inst->isDataPrefetch()) { finishCacheUnitReq(inst, cache_req); @@ -721,7 +791,13 @@ tid, inst->seqNum); - //@todo: check that timing translation is finished here + if (tlbBlocked[tid] || !inst->state->translationFinished) + { + DPRINTF(InOrderCachePort, " Failed because ", + "translation ongoing\n"); + break; + } + RequestPtr mem_req = cache_req->memReq; if (mem_req->isCondSwap() || mem_req->isLLSC() || mem_req->isSwap()) { DPRINTF(InOrderCachePort, "Detected Conditional Store Inst.\n"); @@ -754,7 +830,13 @@ "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read " "Access\n", tid, inst->seqNum); - //@todo: check that timing translation is finished here + if (tlbBlocked[tid] || !inst->state->translationFinished) + { + DPRINTF(InOrderCachePort, " Failed because ", + "translation ongoing\n"); + break; + } + assert(!inst->isInstPrefetch() && "Can't Handle Inst. Prefecthes"); if (cache_req->isMemAccComplete() || inst->isDataPrefetch()) { finishCacheUnitReq(inst, cache_req); @@ -779,10 +861,16 @@ cache_req->dataPkt->memReq = cache_req->memReq; } - //@todo: check that timing translation is finished here + if (tlbBlocked[tid] || !inst->state->translationFinished) + { + DPRINTF(InOrderCachePort, " Failed because ", + "translation ongoing\n"); + break; + } + finishCacheUnitReq(inst, cache_req); break; - + default: fatal("Unrecognized command to %s", resName); } @@ -892,6 +980,8 @@ "[tid:%i] [sn:%i] is now waiting for cache response\n", tid, inst->seqNum); cache_req->setCompleted(); + + //@todo: Set Pending on Timing TLB Access cache_req->setMemAccPending(); cachePortBlocked = false; } @@ -998,7 +1088,7 @@ cache_pkt->cacheReq->getInst()->seqNum, cache_pkt->cacheReq->getInst()->getMemAddr()); } - + assert(cache_req); assert(cache_req == cache_pkt->cacheReq); @@ -1090,13 +1180,13 @@ 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(); @@ -1111,7 +1201,7 @@ CacheUnit::recvRetry() { DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n"); - + assert(cachePortBlocked); // Clear the cache port for use again @@ -1127,6 +1217,11 @@ void CacheUnitEvent::process() { + // CacheUnitEvent is apparently deprecated, and process() shouldn't be + // called. + // process() can unset tlbBlocked[tid], which could be bad. + assert(0); + DynInstPtr inst = resource->reqs[slotIdx]->inst; int stage_num = resource->reqs[slotIdx]->getStageNum(); ThreadID tid = inst->threadNumber; @@ -1277,6 +1372,7 @@ memReq = NULL; reqData = NULL; + writeRes = NULL; dataPkt = NULL; memAccComplete = false; memAccPending = false;