diff options
Diffstat (limited to 'cpu/simple/cpu.cc')
-rw-r--r-- | cpu/simple/cpu.cc | 399 |
1 files changed, 326 insertions, 73 deletions
diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc index 8db72b77e..fc70df662 100644 --- a/cpu/simple/cpu.cc +++ b/cpu/simple/cpu.cc @@ -53,8 +53,6 @@ #include "cpu/smt.hh" #include "cpu/static_inst.hh" #include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" #include "sim/byteswap.hh" #include "sim/builder.hh" #include "sim/debug.hh" @@ -72,7 +70,7 @@ #include "arch/stacktrace.hh" #include "arch/vtophys.hh" #else // !FULL_SYSTEM -#include "mem/functional/functional.hh" +#include "mem/memory.hh" #endif // FULL_SYSTEM using namespace std; @@ -116,43 +114,85 @@ SimpleCPU::TickEvent::description() } -SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) - : Event(&mainEventQueue), cpu(_cpu) +bool +SimpleCPU::CpuPort::recvTiming(Packet &pkt) { + cpu->processResponse(pkt); + return true; } -void SimpleCPU::CacheCompletionEvent::process() +Tick +SimpleCPU::CpuPort::recvAtomic(Packet &pkt) { - cpu->processCacheCompletion(); + panic("CPU doesn't expect callback!"); + return curTick; } -const char * -SimpleCPU::CacheCompletionEvent::description() +void +SimpleCPU::CpuPort::recvFunctional(Packet &pkt) +{ + panic("CPU doesn't expect callback!"); +} + +void +SimpleCPU::CpuPort::recvStatusChange(Status status) { - return "SimpleCPU cache completion event"; + cpu->recvStatusChange(status); +} + +Packet * +SimpleCPU::CpuPort::recvRetry() +{ + return cpu->processRetry(); } SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL), - cacheCompletionEvent(this) + : BaseCPU(p), icachePort(this), + dcachePort(this), tickEvent(this, p->width), cpuXC(NULL) { _status = Idle; + + //Create Memory Ports (conect them up) + p->mem->addPort("DCACHE"); + dcachePort.setPeer(p->mem->getPort("DCACHE")); + (p->mem->getPort("DCACHE"))->setPeer(&dcachePort); + + p->mem->addPort("ICACHE"); + icachePort.setPeer(p->mem->getPort("ICACHE")); + (p->mem->getPort("ICACHE"))->setPeer(&icachePort); + #if FULL_SYSTEM cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); - #else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0); + cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0, + &dcachePort); #endif // !FULL_SYSTEM - xcProxy = cpuXC->getProxy(); - icacheInterface = p->icache_interface; - dcacheInterface = p->dcache_interface; + xcProxy = cpuXC->getProxy(); - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; +#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE + ifetch_req = new CpuRequest; + ifetch_req->asid = 0; + ifetch_req->size = sizeof(MachInst); + ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->data = (uint8_t *)&inst; + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); + + data_read_req = new CpuRequest; + data_read_req->asid = 0; + data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->data = new uint8_t[8]; + data_read_pkt->req = data_read_req; + + data_write_req = new CpuRequest; + data_write_req->asid = 0; + data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; +#endif numInst = 0; startNumInst = 0; @@ -172,9 +212,9 @@ void SimpleCPU::switchOut(Sampler *s) { sampler = s; - if (status() == DcacheMissStall) { + if (status() == DcacheWaitResponse) { DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheMissSwitch; + _status = DcacheWaitSwitch; } else { _status = SwitchedOut; @@ -287,6 +327,18 @@ SimpleCPU::regStats() .prereq(dcacheStallCycles) ; + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + idleFraction = constant(1.0) - notIdleFraction; } @@ -308,7 +360,6 @@ SimpleCPU::serialize(ostream &os) nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); nameOut(os, csprintf("%s.cacheCompletionEvent", name())); - cacheCompletionEvent.serialize(os); } void @@ -319,8 +370,6 @@ SimpleCPU::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(inst); cpuXC->unserialize(cp, csprintf("%s.xc", section)); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); - cacheCompletionEvent - .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); } void @@ -331,6 +380,7 @@ change_thread_state(int thread_number, int activate, int priority) Fault SimpleCPU::copySrcTranslate(Addr src) { +#if 0 static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. @@ -347,8 +397,7 @@ SimpleCPU::copySrcTranslate(Addr src) memReq->reset(src & ~(blk_size - 1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); + // translate to physical address Fault fault = cpuXC->translateDataReadReq(req); if (fault == NoFault) { cpuXC->copySrcAddr = src; @@ -360,11 +409,15 @@ SimpleCPU::copySrcTranslate(Addr src) cpuXC->copySrcPhysAddr = 0; } return fault; +#else + return No_Fault; +#endif } Fault SimpleCPU::copy(Addr dest) { +#if 0 static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. @@ -383,7 +436,7 @@ SimpleCPU::copy(Addr dest) memReq->reset(dest & ~(blk_size -1), blk_size); // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); + Fault fault = cpuXC->translateDataWriteReq(req); if (fault == NoFault) { Addr dest_addr = memReq->paddr + offset; @@ -407,6 +460,10 @@ SimpleCPU::copy(Addr dest) assert(!fault->isAlignmentFault()); return fault; +#else + panic("copy not implemented"); + return No_Fault; +#endif } // precise architected memory state accessor macros @@ -414,22 +471,64 @@ template <class T> Fault SimpleCPU::read(Addr addr, T &data, unsigned flags) { - if (status() == DcacheMissStall || status() == DcacheMissSwitch) { - Fault fault = cpuXC->read(memReq,data); + if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) { +// Fault fault = xc->read(memReq,data); + // Not sure what to check for no fault... + if (data_read_pkt->result == Success) { + memcpy(&data, data_read_pkt->data, sizeof(T)); + } if (traceData) { traceData->setAddr(addr); } - return fault; + + // @todo: Figure out a way to create a Fault from the packet result. + return No_Fault; } - memReq->reset(addr, sizeof(T), flags); +// memReq->reset(addr, sizeof(T), flags); + +#if SIMPLE_CPU_MEM_TIMING + CpuRequest *data_read_req = new CpuRequest; +#endif + + data_read_req->vaddr = addr; + data_read_req->size = sizeof(T); + data_read_req->flags = flags; + data_read_req->time = curTick; // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == No_Fault) { +#if SIMPLE_CPU_MEM_TIMING + data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->req = data_read_req; + data_read_pkt->data = new uint8_t[8]; +#endif + data_read_pkt->addr = data_read_req->paddr; + data_read_pkt->size = sizeof(T); - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { + sendDcacheRequest(data_read_pkt); + +#if SIMPLE_CPU_MEM_IMMEDIATE + // Need to find a way to not duplicate code above. + + if (data_read_pkt->result == Success) { + memcpy(&data, data_read_pkt->data, sizeof(T)); + } + + if (traceData) { + traceData->setAddr(addr); + } + + // @todo: Figure out a way to create a Fault from the packet result. + return No_Fault; +#endif + } +/* memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; @@ -454,8 +553,9 @@ SimpleCPU::read(Addr addr, T &data, unsigned flags) fault = cpuXC->read(memReq, data); } - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) +*/ + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->flags & UNCACHEABLE) recordEvent("Uncached Read"); return fault; @@ -508,11 +608,31 @@ template <class T> Fault SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { - memReq->reset(addr, sizeof(T), flags); + data_write_req->vaddr = addr; + data_write_req->time = curTick; + data_write_req->size = sizeof(T); + data_write_req->flags = flags; // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + // Now do the access. + if (fault == No_Fault) { +#if SIMPLE_CPU_MEM_TIMING + data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; + data_write_pkt->data = new uint8_t[64]; + memcpy(data_write_pkt->data, &data, sizeof(T)); +#else + data_write_pkt->data = (uint8_t *)&data; +#endif + data_write_pkt->addr = data_write_req->paddr; + data_write_pkt->size = sizeof(T); + + sendDcacheRequest(data_write_pkt); + } +/* // do functional access if (fault == NoFault) fault = cpuXC->write(memReq, data); @@ -535,13 +655,16 @@ SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) _status = DcacheMissStall; } } - +*/ if (res && (fault == NoFault)) - *res = memReq->result; + *res = data_write_pkt->result; - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->flags & UNCACHEABLE) recordEvent("Uncached Write"); + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. return fault; } @@ -597,36 +720,130 @@ SimpleCPU::dbg_vtophys(Addr addr) #endif // FULL_SYSTEM void -SimpleCPU::processCacheCompletion() +SimpleCPU::sendIcacheRequest(Packet *pkt) { + assert(!tickEvent.scheduled()); +#if SIMPLE_CPU_MEM_TIMING + retry_pkt = pkt; + bool success = icachePort.sendTiming(*pkt); + + unscheduleTickEvent(); + + lastIcacheStall = curTick; + + if (!success) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + } +#elif SIMPLE_CPU_MEM_ATOMIC + Tick latency = icachePort.sendAtomic(*pkt); + + unscheduleTickEvent(); + scheduleTickEvent(latency); + + // Note that Icache miss cycles will be incorrect. Unless + // we check the status of the packet sent (is this valid?), + // we won't know if the latency is a hit or a miss. + icacheStallCycles += latency; + + _status = IcacheAccessComplete; +#elif SIMPLE_CPU_MEM_IMMEDIATE + icachePort.sendAtomic(*pkt); +#else +#error "SimpleCPU has no mem model set" +#endif +} + +void +SimpleCPU::sendDcacheRequest(Packet *pkt) +{ + assert(!tickEvent.scheduled()); +#if SIMPLE_CPU_MEM_TIMING + unscheduleTickEvent(); + + retry_pkt = pkt; + bool success = dcachePort.sendTiming(*pkt); + + lastDcacheStall = curTick; + + if (!success) { + _status = DcacheRetry; + } else { + _status = DcacheWaitResponse; + } +#elif SIMPLE_CPU_MEM_ATOMIC + unscheduleTickEvent(); + + Tick latency = dcachePort.sendAtomic(*pkt); + + scheduleTickEvent(latency); + + // Note that Dcache miss cycles will be incorrect. Unless + // we check the status of the packet sent (is this valid?), + // we won't know if the latency is a hit or a miss. + dcacheStallCycles += latency; +#elif SIMPLE_CPU_MEM_IMMEDIATE + dcachePort.sendAtomic(*pkt); +#else +#error "SimpleCPU has no mem model set" +#endif +} + +void +SimpleCPU::processResponse(Packet &response) +{ + assert(SIMPLE_CPU_MEM_TIMING); + + // For what things is the CPU the consumer of the packet it sent + // out? This may create a memory leak if that's the case and it's + // expected of the SimpleCPU to delete its own packet. + Packet *pkt = &response; + switch (status()) { - case IcacheMissStall: + case IcacheWaitResponse: icacheStallCycles += curTick - lastIcacheStall; - _status = IcacheMissComplete; + + _status = IcacheAccessComplete; scheduleTickEvent(1); + + // Copy the icache data into the instruction itself. + memcpy(&inst, pkt->data, sizeof(inst)); + + delete pkt; break; - case DcacheMissStall: - if (memReq->cmd.isRead()) { + case DcacheWaitResponse: + if (pkt->cmd == Read) { curStaticInst->execute(this,traceData); if (traceData) traceData->finalize(); } + + delete pkt; + dcacheStallCycles += curTick - lastDcacheStall; _status = Running; scheduleTickEvent(1); break; - case DcacheMissSwitch: - if (memReq->cmd.isRead()) { + case DcacheWaitSwitch: + if (pkt->cmd == Read) { curStaticInst->execute(this,traceData); if (traceData) traceData->finalize(); } + + delete pkt; + _status = SwitchedOut; sampler->signalSwitched(); case SwitchedOut: // If this CPU has been switched out due to sampling/warm-up, // ignore any further status changes (e.g., due to cache // misses outstanding at the time of the switch). + delete pkt; + return; default: panic("SimpleCPU::processCacheCompletion: bad state"); @@ -634,6 +851,28 @@ SimpleCPU::processCacheCompletion() } } +Packet * +SimpleCPU::processRetry() +{ +#if SIMPLE_CPU_MEM_TIMING + switch(status()) { + case IcacheRetry: + icacheRetryCycles += curTick - lastIcacheStall; + return retry_pkt; + break; + case DcacheRetry: + dcacheRetryCycles += curTick - lastDcacheStall; + return retry_pkt; + break; + default: + panic("SimpleCPU::processRetry: bad state"); + break; + } +#else + panic("shouldn't be here"); +#endif +} + #if FULL_SYSTEM void SimpleCPU::post_interrupt(int int_num, int index) @@ -706,15 +945,14 @@ SimpleCPU::tick() cpuXC->setFloatRegDouble(ZeroReg, 0.0); #endif // TARGET_ALPHA - if (status() == IcacheMissComplete) { + if (status() == IcacheAccessComplete) { // We've already fetched an instruction and were stalled on an // I-cache miss. No need to fetch it again. // Set status to running; tick event will get rescheduled if // necessary at end of tick() function. _status = Running; - } - else { + } else { // Try to fetch an instruction // set up memory request for instruction fetch @@ -724,15 +962,35 @@ SimpleCPU::tick() #define IFETCH_FLAGS(pc) 0 #endif - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); +#if SIMPLE_CPU_MEM_TIMING + CpuRequest *ifetch_req = new CpuRequest(); + ifetch_req->size = sizeof(MachInst); +#endif - fault = cpuXC->translateInstReq(memReq); + ifetch_req->vaddr = cpuXC->readPC() & ~3; + ifetch_req->time = curTick; - if (fault == NoFault) - fault = cpuXC->mem->read(memReq, inst); +/* memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), + IFETCH_FLAGS(xc->regs.pc)); +*/ + + fault = xc->translateInstReq(ifetch_req); + + if (fault == NoFault) { +#if SIMPLE_CPU_MEM_TIMING + Packet *ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->data = (uint8_t *)&inst; + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); +#endif + ifetch_pkt->addr = ifetch_req->paddr; + sendIcacheRequest(ifetch_pkt); +#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC + return; +#endif +/* if (icacheInterface && fault == NoFault) { memReq->completionEvent = NULL; @@ -743,7 +1001,7 @@ SimpleCPU::tick() // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. - if (result != MA_HIT && icacheInterface->doEvents()) { + if (result != MA_HIT && icacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastIcacheStall = curTick; unscheduleTickEvent(); @@ -751,6 +1009,8 @@ SimpleCPU::tick() return; } } +*/ + } } // If we've got a valid instruction (i.e., no fault on instruction @@ -806,8 +1066,7 @@ SimpleCPU::tick() // If we have a dcache miss, then we can't finialize the instruction // trace yet because we want to populate it with the data later - if (traceData && - !(status() == DcacheMissStall && memReq->cmd.isRead())) { + if (traceData && (status() != DcacheWaitResponse)) { traceData->finalize(); } @@ -846,7 +1105,7 @@ SimpleCPU::tick() assert(status() == Running || status() == Idle || - status() == DcacheMissStall); + status() == DcacheWaitResponse); if (status() == Running && !tickEvent.scheduled()) tickEvent.schedule(curTick + cycles(1)); @@ -866,17 +1125,15 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) #if FULL_SYSTEM SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; SimObjectParam<System *> system; Param<int> cpu_id; Param<Tick> profile; #else + SimObjectParam<Memory *> mem; SimObjectParam<Process *> workload; #endif // FULL_SYSTEM Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; Param<bool> defer_registration; Param<int> width; @@ -899,17 +1156,15 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) #if FULL_SYSTEM INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), INIT_PARAM(system, "system object"), INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(profile, ""), #else + INIT_PARAM(mem, "memory"), INIT_PARAM(workload, "processes to run"), #endif // FULL_SYSTEM INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), INIT_PARAM(defer_registration, "defer system registration (for sampling)"), INIT_PARAM(width, "cpu width"), INIT_PARAM(function_trace, "Enable function trace"), @@ -931,18 +1186,16 @@ CREATE_SIM_OBJECT(SimpleCPU) params->clock = clock; params->functionTrace = function_trace; params->functionTraceStart = function_trace_start; - params->icache_interface = (icache) ? icache->getInterface() : NULL; - params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; params->width = width; #if FULL_SYSTEM params->itb = itb; params->dtb = dtb; - params->mem = mem; params->system = system; params->cpu_id = cpu_id; params->profile = profile; #else + params->mem = mem; params->process = workload; #endif |