base.cc revision 2420
11689SN/A/* 21689SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 31689SN/A * All rights reserved. 41689SN/A * 51689SN/A * Redistribution and use in source and binary forms, with or without 61689SN/A * modification, are permitted provided that the following conditions are 71689SN/A * met: redistributions of source code must retain the above copyright 81689SN/A * notice, this list of conditions and the following disclaimer; 91689SN/A * redistributions in binary form must reproduce the above copyright 101689SN/A * notice, this list of conditions and the following disclaimer in the 111689SN/A * documentation and/or other materials provided with the distribution; 121689SN/A * neither the name of the copyright holders nor the names of its 131689SN/A * contributors may be used to endorse or promote products derived from 141689SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292756Sksewell@umich.edu#include <cmath> 301689SN/A#include <cstdio> 311689SN/A#include <cstdlib> 322325SN/A#include <iostream> 332325SN/A#include <iomanip> 341060SN/A#include <list> 351060SN/A#include <sstream> 361060SN/A#include <string> 372292SN/A 382292SN/A#include "base/cprintf.hh" 391681SN/A#include "base/inifile.hh" 401060SN/A#include "base/loader/symtab.hh" 412980Sgblack@eecs.umich.edu#include "base/misc.hh" 421060SN/A#include "base/pollevent.hh" 431060SN/A#include "base/range.hh" 441858SN/A#include "base/stats/events.hh" 454598Sbinkertn@umich.edu#include "base/trace.hh" 462325SN/A#include "cpu/base.hh" 471717SN/A#include "cpu/exec_context.hh" 482683Sktlim@umich.edu#include "cpu/exetrace.hh" 491717SN/A#include "cpu/profile.hh" 501717SN/A#include "cpu/sampler/sampler.hh" 512292SN/A#include "cpu/simple/cpu.hh" 522292SN/A#include "cpu/smt.hh" 532817Sksewell@umich.edu#include "cpu/static_inst.hh" 541060SN/A#include "kern/kernel_stats.hh" 551060SN/A#include "sim/builder.hh" 565529Snate@binkert.org#include "sim/debug.hh" 575529Snate@binkert.org#include "sim/host.hh" 582316SN/A#include "sim/sim_events.hh" 592316SN/A#include "sim/sim_object.hh" 602680Sktlim@umich.edu#include "sim/stats.hh" 612817Sksewell@umich.edu 622817Sksewell@umich.edu#if FULL_SYSTEM 632843Sktlim@umich.edu#include "base/remote_gdb.hh" 642843Sktlim@umich.edu#include "mem/functional/memory_control.hh" 652669Sktlim@umich.edu#include "mem/functional/physical.hh" 661060SN/A#include "sim/system.hh" 671060SN/A#include "targetarch/alpha_memory.hh" 685529Snate@binkert.org#include "targetarch/stacktrace.hh" 695529Snate@binkert.org#include "targetarch/vtophys.hh" 702733Sktlim@umich.edu#else // !FULL_SYSTEM 711060SN/A#include "mem/memory.hh" 721060SN/A#endif // FULL_SYSTEM 731060SN/A 745529Snate@binkert.orgusing namespace std; 752292SN/A 762292SN/A 772632Sstever@eecs.umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) 782817Sksewell@umich.edu : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) 792817Sksewell@umich.edu{ 802817Sksewell@umich.edu} 812817Sksewell@umich.edu 822669Sktlim@umich.eduvoid 831681SN/ASimpleCPU::TickEvent::process() 841685SN/A{ 851681SN/A int count = width; 861060SN/A do { 871060SN/A cpu->tick(); 882348SN/A } while (--count > 0 && cpu->status() == Running); 892348SN/A} 902348SN/A 912348SN/Aconst char * 922348SN/ASimpleCPU::TickEvent::description() 931060SN/A{ 942733Sktlim@umich.edu return "SimpleCPU tick event"; 951060SN/A} 961060SN/A 972325SN/A 981060SN/Abool 991061SN/ASimpleCPU::CpuPort::recvTiming(Packet &pkt) 1004329Sktlim@umich.edu{ 1011060SN/A cpu->processResponse(pkt); 1022292SN/A return true; 1032292SN/A} 1042292SN/A 1052292SN/ATick 1062817Sksewell@umich.eduSimpleCPU::CpuPort::recvAtomic(Packet &pkt) 1072829Sksewell@umich.edu{ 1081060SN/A panic("CPU doesn't expect callback!"); 1091060SN/A return curTick; 1101060SN/A} 1111060SN/A 1121060SN/Avoid 1132307SN/ASimpleCPU::CpuPort::recvFunctional(Packet &pkt) 1142307SN/A{ 1151060SN/A panic("CPU doesn't expect callback!"); 1161060SN/A} 1173781Sgblack@eecs.umich.edu 1183781Sgblack@eecs.umich.eduvoid 1193781Sgblack@eecs.umich.eduSimpleCPU::CpuPort::recvStatusChange(Status status) 1202292SN/A{ 1211060SN/A cpu->recvStatusChange(status); 1221060SN/A} 1232829Sksewell@umich.edu 1242829Sksewell@umich.eduPacket * 1252829Sksewell@umich.eduSimpleCPU::CpuPort::recvRetry() 1261060SN/A{ 1271060SN/A return cpu->processRetry(); 1281060SN/A} 1291060SN/A 1302292SN/ASimpleCPU::SimpleCPU(Params *p) 1311755SN/A : BaseCPU(p), icachePort(this), 1321060SN/A dcachePort(this), tickEvent(this, p->width), xc(NULL) 1331060SN/A{ 1342292SN/A _status = Idle; 1351755SN/A 1362292SN/A //Create Memory Ports (conect them up) 1372292SN/A p->mem->addPort("DCACHE"); 1381060SN/A dcachePort.setPeer(p->mem->getPort("DCACHE")); 1392292SN/A (p->mem->getPort("DCACHE"))->setPeer(&dcachePort); 1405336Shines@cs.fsu.edu 1411060SN/A p->mem->addPort("ICACHE"); 1421060SN/A icachePort.setPeer(p->mem->getPort("ICACHE")); 1432292SN/A (p->mem->getPort("ICACHE"))->setPeer(&icachePort); 1441060SN/A 1451060SN/A#if FULL_SYSTEM 1462292SN/A xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); 1471060SN/A 1481060SN/A // initialize CPU, including PC 1491060SN/A TheISA::initCPU(&xc->regs); 1505100Ssaidi@eecs.umich.edu#else 1511060SN/A xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0, 1525100Ssaidi@eecs.umich.edu &dcachePort); 1531060SN/A#endif // !FULL_SYSTEM 1541060SN/A 1552292SN/A#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE 1561060SN/A ifetch_req = new CpuRequest; 1571060SN/A ifetch_req->asid = 0; 1581060SN/A ifetch_req->size = sizeof(MachInst); 1591060SN/A ifetch_pkt = new Packet; 1601060SN/A ifetch_pkt->cmd = Read; 1611060SN/A ifetch_pkt->data = (uint8_t *)&inst; 1622829Sksewell@umich.edu ifetch_pkt->req = ifetch_req; 1632829Sksewell@umich.edu ifetch_pkt->size = sizeof(MachInst); 1642829Sksewell@umich.edu 1652829Sksewell@umich.edu data_read_req = new CpuRequest; 1662829Sksewell@umich.edu data_read_req->asid = 0; 1672829Sksewell@umich.edu data_read_pkt = new Packet; 1682829Sksewell@umich.edu data_read_pkt->cmd = Read; 1692829Sksewell@umich.edu data_read_pkt->data = new uint8_t[8]; 1702829Sksewell@umich.edu data_read_pkt->req = data_read_req; 1712829Sksewell@umich.edu 1722829Sksewell@umich.edu data_write_req = new CpuRequest; 1732829Sksewell@umich.edu data_write_req->asid = 0; 1742829Sksewell@umich.edu data_write_pkt = new Packet; 1752829Sksewell@umich.edu data_write_pkt->cmd = Write; 1762829Sksewell@umich.edu data_write_pkt->req = data_write_req; 1772829Sksewell@umich.edu#endif 1782829Sksewell@umich.edu 1792829Sksewell@umich.edu numInst = 0; 1802829Sksewell@umich.edu startNumInst = 0; 1812829Sksewell@umich.edu numLoad = 0; 1825336Shines@cs.fsu.edu startNumLoad = 0; 1832829Sksewell@umich.edu lastIcacheStall = 0; 1842829Sksewell@umich.edu lastDcacheStall = 0; 1852829Sksewell@umich.edu 1862829Sksewell@umich.edu execContexts.push_back(xc); 1872829Sksewell@umich.edu} 1882829Sksewell@umich.edu 1892829Sksewell@umich.eduSimpleCPU::~SimpleCPU() 1904030Sktlim@umich.edu{ 1915100Ssaidi@eecs.umich.edu} 1922829Sksewell@umich.edu 1934030Sktlim@umich.eduvoid 1945100Ssaidi@eecs.umich.eduSimpleCPU::switchOut(Sampler *s) 1952829Sksewell@umich.edu{ 1962829Sksewell@umich.edu sampler = s; 1972829Sksewell@umich.edu if (status() == DcacheWaitResponse) { 1982829Sksewell@umich.edu DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); 1992829Sksewell@umich.edu _status = DcacheWaitSwitch; 2002829Sksewell@umich.edu } 2012829Sksewell@umich.edu else { 2022829Sksewell@umich.edu _status = SwitchedOut; 2032829Sksewell@umich.edu 2042829Sksewell@umich.edu if (tickEvent.scheduled()) 2052829Sksewell@umich.edu tickEvent.squash(); 2062829Sksewell@umich.edu 2072875Sksewell@umich.edu sampler->signalSwitched(); 2082875Sksewell@umich.edu } 2092875Sksewell@umich.edu} 2103221Sktlim@umich.edu 2112875Sksewell@umich.edu 2122875Sksewell@umich.eduvoid 2133221Sktlim@umich.eduSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 2143221Sktlim@umich.edu{ 2153221Sktlim@umich.edu BaseCPU::takeOverFrom(oldCPU); 2162875Sksewell@umich.edu 2172875Sksewell@umich.edu assert(!tickEvent.scheduled()); 2182875Sksewell@umich.edu 2192875Sksewell@umich.edu // if any of this CPU's ExecContexts are active, mark the CPU as 2202875Sksewell@umich.edu // running and schedule its tick event. 2212875Sksewell@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2222875Sksewell@umich.edu ExecContext *xc = execContexts[i]; 2232875Sksewell@umich.edu if (xc->status() == ExecContext::Active && _status != Running) { 2242875Sksewell@umich.edu _status = Running; 2252875Sksewell@umich.edu tickEvent.schedule(curTick); 2262875Sksewell@umich.edu } 2272875Sksewell@umich.edu } 2282875Sksewell@umich.edu} 2293221Sktlim@umich.edu 2303221Sktlim@umich.edu 2313221Sktlim@umich.eduvoid 2322875Sksewell@umich.eduSimpleCPU::activateContext(int thread_num, int delay) 2335336Shines@cs.fsu.edu{ 2342875Sksewell@umich.edu assert(thread_num == 0); 2352875Sksewell@umich.edu assert(xc); 2362875Sksewell@umich.edu 2373221Sktlim@umich.edu assert(_status == Idle); 2382875Sksewell@umich.edu notIdleFraction++; 2392875Sksewell@umich.edu scheduleTickEvent(delay); 2402875Sksewell@umich.edu _status = Running; 2414030Sktlim@umich.edu} 2425100Ssaidi@eecs.umich.edu 2432875Sksewell@umich.edu 2444030Sktlim@umich.eduvoid 2455100Ssaidi@eecs.umich.eduSimpleCPU::suspendContext(int thread_num) 2462875Sksewell@umich.edu{ 2472875Sksewell@umich.edu assert(thread_num == 0); 2482875Sksewell@umich.edu assert(xc); 2492875Sksewell@umich.edu 2502875Sksewell@umich.edu assert(_status == Running); 2512875Sksewell@umich.edu notIdleFraction--; 2522875Sksewell@umich.edu unscheduleTickEvent(); 2532875Sksewell@umich.edu _status = Idle; 2542875Sksewell@umich.edu} 2552875Sksewell@umich.edu 2562875Sksewell@umich.edu 2572875Sksewell@umich.eduvoid 2581060SN/ASimpleCPU::deallocateContext(int thread_num) 2592292SN/A{ 2605529Snate@binkert.org // for now, these are equivalent 2612292SN/A suspendContext(thread_num); 2621755SN/A} 2631060SN/A 2642292SN/A 2651684SN/Avoid 2661684SN/ASimpleCPU::haltContext(int thread_num) 2675358Sgblack@eecs.umich.edu{ 2685358Sgblack@eecs.umich.edu // for now, these are equivalent 2695358Sgblack@eecs.umich.edu suspendContext(thread_num); 2705358Sgblack@eecs.umich.edu} 2715358Sgblack@eecs.umich.edu 2725358Sgblack@eecs.umich.edu 2735358Sgblack@eecs.umich.eduvoid 2745358Sgblack@eecs.umich.eduSimpleCPU::regStats() 2755358Sgblack@eecs.umich.edu{ 2765358Sgblack@eecs.umich.edu using namespace Stats; 2775358Sgblack@eecs.umich.edu 2785358Sgblack@eecs.umich.edu BaseCPU::regStats(); 2795358Sgblack@eecs.umich.edu 2805358Sgblack@eecs.umich.edu numInsts 2815358Sgblack@eecs.umich.edu .name(name() + ".num_insts") 2825358Sgblack@eecs.umich.edu .desc("Number of instructions executed") 2834988Sgblack@eecs.umich.edu ; 2844988Sgblack@eecs.umich.edu 2854988Sgblack@eecs.umich.edu numMemRefs 2864988Sgblack@eecs.umich.edu .name(name() + ".num_refs") 2874988Sgblack@eecs.umich.edu .desc("Number of memory references") 2884988Sgblack@eecs.umich.edu ; 2894988Sgblack@eecs.umich.edu 2904988Sgblack@eecs.umich.edu notIdleFraction 2914988Sgblack@eecs.umich.edu .name(name() + ".not_idle_fraction") 2924988Sgblack@eecs.umich.edu .desc("Percentage of non-idle cycles") 2934988Sgblack@eecs.umich.edu ; 2944988Sgblack@eecs.umich.edu 2954988Sgblack@eecs.umich.edu idleFraction 2964988Sgblack@eecs.umich.edu .name(name() + ".idle_fraction") 2974988Sgblack@eecs.umich.edu .desc("Percentage of idle cycles") 2984988Sgblack@eecs.umich.edu ; 2994988Sgblack@eecs.umich.edu 3004988Sgblack@eecs.umich.edu icacheStallCycles 3012871Sktlim@umich.edu .name(name() + ".icache_stall_cycles") 3022871Sktlim@umich.edu .desc("ICache total stall cycles") 3032871Sktlim@umich.edu .prereq(icacheStallCycles) 3042292SN/A ; 3052292SN/A 3062292SN/A dcacheStallCycles 3071684SN/A .name(name() + ".dcache_stall_cycles") 3081684SN/A .desc("DCache total stall cycles") 3092292SN/A .prereq(dcacheStallCycles) 3101060SN/A ; 3111060SN/A 3122834Sksewell@umich.edu icacheRetryCycles 3132834Sksewell@umich.edu .name(name() + ".icache_retry_cycles") 3142834Sksewell@umich.edu .desc("ICache total retry cycles") 3152834Sksewell@umich.edu .prereq(icacheRetryCycles) 3162829Sksewell@umich.edu ; 3172875Sksewell@umich.edu 3182875Sksewell@umich.edu dcacheRetryCycles 3192875Sksewell@umich.edu .name(name() + ".dcache_retry_cycles") 3202875Sksewell@umich.edu .desc("DCache total retry cycles") 3212829Sksewell@umich.edu .prereq(dcacheRetryCycles) 3222292SN/A ; 3232292SN/A 3241060SN/A idleFraction = constant(1.0) - notIdleFraction; 3252292SN/A} 3262292SN/A 3272292SN/Avoid 3282292SN/ASimpleCPU::resetStats() 3292292SN/A{ 3302292SN/A startNumInst = numInst; 3312292SN/A notIdleFraction = (_status != Idle); 3322292SN/A} 3332292SN/A 3342292SN/Avoid 3352292SN/ASimpleCPU::serialize(ostream &os) 3362292SN/A{ 3372292SN/A BaseCPU::serialize(os); 3382292SN/A SERIALIZE_ENUM(_status); 3392292SN/A SERIALIZE_SCALAR(inst); 3402292SN/A nameOut(os, csprintf("%s.xc", name())); 3412292SN/A xc->serialize(os); 3422292SN/A nameOut(os, csprintf("%s.tickEvent", name())); 3432292SN/A tickEvent.serialize(os); 3442292SN/A nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 3452292SN/A} 3463221Sktlim@umich.edu 3472292SN/Avoid 3483221Sktlim@umich.eduSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 3492292SN/A{ 3502292SN/A BaseCPU::unserialize(cp, section); 3512292SN/A UNSERIALIZE_ENUM(_status); 3522292SN/A UNSERIALIZE_SCALAR(inst); 3532292SN/A xc->unserialize(cp, csprintf("%s.xc", section)); 3542292SN/A tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 3552292SN/A} 3562292SN/A 3572292SN/Avoid 3582292SN/Achange_thread_state(int thread_number, int activate, int priority) 3592292SN/A{ 3602292SN/A} 3612292SN/A 3622292SN/AFault 3632292SN/ASimpleCPU::copySrcTranslate(Addr src) 3642864Sktlim@umich.edu{ 3652864Sktlim@umich.edu#if 0 3662864Sktlim@umich.edu static bool no_warn = true; 3672864Sktlim@umich.edu int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3682864Sktlim@umich.edu // Only support block sizes of 64 atm. 3692864Sktlim@umich.edu assert(blk_size == 64); 3702864Sktlim@umich.edu int offset = src & (blk_size - 1); 3712292SN/A 3722292SN/A // Make sure block doesn't span page 3732292SN/A if (no_warn && 3742292SN/A (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && 3752292SN/A (src >> 40) != 0xfffffc) { 3762325SN/A warn("Copied block source spans pages %x.", src); 3772292SN/A no_warn = false; 3782843Sktlim@umich.edu } 3792843Sktlim@umich.edu 3802905Sktlim@umich.edu memReq->reset(src & ~(blk_size - 1), blk_size); 3812843Sktlim@umich.edu 3822843Sktlim@umich.edu // translate to physical address 3832843Sktlim@umich.edu Fault fault = xc->translateDataReadReq(req); 3842292SN/A 3852348SN/A assert(fault != Alignment_Fault); 3862843Sktlim@umich.edu 3872843Sktlim@umich.edu if (fault == No_Fault) { 3882843Sktlim@umich.edu xc->copySrcAddr = src; 3892843Sktlim@umich.edu xc->copySrcPhysAddr = memReq->paddr + offset; 3902316SN/A } else { 3912348SN/A xc->copySrcAddr = 0; 3922843Sktlim@umich.edu xc->copySrcPhysAddr = 0; 3931060SN/A } 3941060SN/A return fault; 3952316SN/A#else 3962316SN/A return No_Fault; 3971060SN/A#endif 3981858SN/A} 3994192Sktlim@umich.edu 4004192Sktlim@umich.eduFault 4014192Sktlim@umich.eduSimpleCPU::copy(Addr dest) 4024192Sktlim@umich.edu{ 4031060SN/A#if 0 4041060SN/A static bool no_warn = true; 4051060SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 4061060SN/A // Only support block sizes of 64 atm. 4071060SN/A assert(blk_size == 64); 4081060SN/A uint8_t data[blk_size]; 4091060SN/A //assert(xc->copySrcAddr); 4102292SN/A int offset = dest & (blk_size - 1); 4112292SN/A 4121060SN/A // Make sure block doesn't span page 4131060SN/A if (no_warn && 4142292SN/A (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && 4152292SN/A (dest >> 40) != 0xfffffc) { 4161060SN/A no_warn = false; 4172292SN/A warn("Copied block destination spans pages %x. ", dest); 4182292SN/A } 4192683Sktlim@umich.edu 4201060SN/A memReq->reset(dest & ~(blk_size -1), blk_size); 4212292SN/A // translate to physical address 4222292SN/A Fault fault = xc->translateDataWriteReq(req); 4232683Sktlim@umich.edu 4241060SN/A assert(fault != Alignment_Fault); 4251060SN/A 4261060SN/A if (fault == No_Fault) { 4272348SN/A Addr dest_addr = memReq->paddr + offset; 4281060SN/A // Need to read straight from memory since we have more than 8 bytes. 4291060SN/A memReq->paddr = xc->copySrcPhysAddr; 4303781Sgblack@eecs.umich.edu xc->mem->read(memReq, data); 4311060SN/A memReq->paddr = dest_addr; 4323781Sgblack@eecs.umich.edu xc->mem->write(memReq, data); 4331060SN/A if (dcacheInterface) { 4343781Sgblack@eecs.umich.edu memReq->cmd = Copy; 4352455SN/A memReq->completionEvent = NULL; 4363781Sgblack@eecs.umich.edu memReq->paddr = xc->copySrcPhysAddr; 4371060SN/A memReq->dest = dest_addr; 4381060SN/A memReq->size = 64; 4391060SN/A memReq->time = curTick; 4403781Sgblack@eecs.umich.edu memReq->flags &= ~INST_READ; 4411060SN/A dcacheInterface->access(memReq); 4423781Sgblack@eecs.umich.edu } 4431060SN/A } 4443781Sgblack@eecs.umich.edu return fault; 4452455SN/A#else 4463781Sgblack@eecs.umich.edu panic("copy not implemented"); 4471060SN/A return No_Fault; 4482292SN/A#endif 4491060SN/A} 4502292SN/A 4511060SN/A// precise architected memory state accessor macros 4522292SN/Atemplate <class T> 4532292SN/AFault 4542292SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags) 4552292SN/A{ 4562348SN/A if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) { 4572348SN/A// Fault fault = xc->read(memReq,data); 4582348SN/A // Not sure what to check for no fault... 4592348SN/A if (data_read_pkt->result == Success) { 4602348SN/A memcpy(&data, data_read_pkt->data, sizeof(T)); 4612292SN/A } 4622292SN/A 4632292SN/A if (traceData) { 4642292SN/A traceData->setAddr(addr); 4652292SN/A } 4662292SN/A 4672292SN/A // @todo: Figure out a way to create a Fault from the packet result. 4682292SN/A return No_Fault; 4692348SN/A } 4704636Sgblack@eecs.umich.edu 4712292SN/A// memReq->reset(addr, sizeof(T), flags); 4722348SN/A 4732348SN/A#if SIMPLE_CPU_MEM_TIMING 4742292SN/A CpuRequest *data_read_req = new CpuRequest; 4754636Sgblack@eecs.umich.edu#endif 4764636Sgblack@eecs.umich.edu 4774636Sgblack@eecs.umich.edu data_read_req->vaddr = addr; 4784636Sgblack@eecs.umich.edu data_read_req->size = sizeof(T); 4794636Sgblack@eecs.umich.edu data_read_req->flags = flags; 4804636Sgblack@eecs.umich.edu data_read_req->time = curTick; 4812348SN/A 4824636Sgblack@eecs.umich.edu // translate to physical address 4832292SN/A Fault fault = xc->translateDataReadReq(data_read_req); 4842348SN/A 4854636Sgblack@eecs.umich.edu // Now do the access. 4861060SN/A if (fault == No_Fault) { 4872756Sksewell@umich.edu#if SIMPLE_CPU_MEM_TIMING 4884636Sgblack@eecs.umich.edu data_read_pkt = new Packet; 4892756Sksewell@umich.edu data_read_pkt->cmd = Read; 4902756Sksewell@umich.edu data_read_pkt->req = data_read_req; 4914636Sgblack@eecs.umich.edu data_read_pkt->data = new uint8_t[8]; 4924636Sgblack@eecs.umich.edu#endif 4934636Sgblack@eecs.umich.edu data_read_pkt->addr = data_read_req->paddr; 4944636Sgblack@eecs.umich.edu data_read_pkt->size = sizeof(T); 4954636Sgblack@eecs.umich.edu 4964636Sgblack@eecs.umich.edu sendDcacheRequest(data_read_pkt); 4974636Sgblack@eecs.umich.edu 4982756Sksewell@umich.edu#if SIMPLE_CPU_MEM_IMMEDIATE 4991060SN/A // Need to find a way to not duplicate code above. 5001060SN/A 5011060SN/A if (data_read_pkt->result == Success) { 5022292SN/A memcpy(&data, data_read_pkt->data, sizeof(T)); 5031060SN/A } 5041060SN/A 5052292SN/A if (traceData) { 5061060SN/A traceData->setAddr(addr); 5072292SN/A } 5082292SN/A 5091060SN/A // @todo: Figure out a way to create a Fault from the packet result. 5102325SN/A return No_Fault; 5112325SN/A#endif 5121060SN/A } 5131061SN/A/* 5141060SN/A memReq->cmd = Read; 5152935Sksewell@umich.edu memReq->completionEvent = NULL; 5162935Sksewell@umich.edu memReq->time = curTick; 5174632Sgblack@eecs.umich.edu memReq->flags &= ~INST_READ; 5181060SN/A MemAccessResult result = dcacheInterface->access(memReq); 5191062SN/A 5202292SN/A // Ugly hack to get an event scheduled *only* if the access is 5212292SN/A // a miss. We really should add first-class support for this 5222348SN/A // at some point. 5232292SN/A if (result != MA_HIT && dcacheInterface->doEvents()) { 5242292SN/A memReq->completionEvent = &cacheCompletionEvent; 5252348SN/A lastDcacheStall = curTick; 5262292SN/A unscheduleTickEvent(); 5271062SN/A _status = DcacheMissStall; 5282348SN/A } else { 5291060SN/A // do functional access 5301060SN/A fault = xc->read(memReq, data); 5311060SN/A 5321060SN/A } 5332292SN/A 5341060SN/A } else if(fault == No_Fault) { 5352292SN/A // do functional access 5362292SN/A fault = xc->read(memReq, data); 5372292SN/A 5382292SN/A } 5392292SN/A*/ 5402325SN/A // This will need a new way to tell if it has a dcache attached. 5412348SN/A if (data_read_req->flags & UNCACHEABLE) 5422348SN/A recordEvent("Uncached Read"); 5432348SN/A 5442292SN/A return fault; 5452325SN/A} 5462292SN/A 5472325SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS 5482325SN/A 5492292SN/Atemplate 5502292SN/AFault 5512292SN/ASimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 5521060SN/A 5531060SN/Atemplate 5541060SN/AFault 5551060SN/ASimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 5561060SN/A 5571060SN/Atemplate 5581060SN/AFault 5591060SN/ASimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 5601060SN/A 5611060SN/Atemplate 5621060SN/AFault 5631060SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 5641060SN/A 5651060SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 5661060SN/A 5671060SN/Atemplate<> 5681060SN/AFault 5691060SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags) 5701060SN/A{ 5711060SN/A return read(addr, *(uint64_t*)&data, flags); 5721060SN/A} 5731060SN/A 5741060SN/Atemplate<> 5752292SN/AFault 5762292SN/ASimpleCPU::read(Addr addr, float &data, unsigned flags) 5772292SN/A{ 5782292SN/A return read(addr, *(uint32_t*)&data, flags); 5791060SN/A} 5801060SN/A 5811060SN/A 5821060SN/Atemplate<> 5832292SN/AFault 5842292SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 5852292SN/A{ 5862292SN/A return read(addr, (uint32_t&)data, flags); 5872292SN/A} 5882292SN/A 5891060SN/A 5902292SN/Atemplate <class T> 5912292SN/AFault 5922292SN/ASimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 5932292SN/A{ 5942292SN/A data_write_req->vaddr = addr; 5952292SN/A data_write_req->time = curTick; 5962292SN/A data_write_req->size = sizeof(T); 5972292SN/A data_write_req->flags = flags; 5982292SN/A 5992292SN/A // translate to physical address 6002292SN/A Fault fault = xc->translateDataWriteReq(data_write_req); 6012292SN/A 6021060SN/A // Now do the access. 6031060SN/A if (fault == No_Fault) { 6041060SN/A#if SIMPLE_CPU_MEM_TIMING 6051061SN/A data_write_pkt = new Packet; 6061060SN/A data_write_pkt->cmd = Write; 6071061SN/A data_write_pkt->req = data_write_req; 6081060SN/A data_write_pkt->data = new uint8_t[64]; 6091061SN/A memcpy(data_write_pkt->data, &data, sizeof(T)); 6101060SN/A#else 6111061SN/A data_write_pkt->data = (uint8_t *)&data; 6121060SN/A#endif 6131061SN/A data_write_pkt->addr = data_write_req->paddr; 6141060SN/A data_write_pkt->size = sizeof(T); 6151060SN/A 6161060SN/A sendDcacheRequest(data_write_pkt); 6171060SN/A } 6181060SN/A 6191060SN/A/* 6201060SN/A // do functional access 6211060SN/A if (fault == No_Fault) 6221060SN/A fault = xc->write(memReq, data); 6231060SN/A 6241060SN/A if (fault == No_Fault && dcacheInterface) { 6251060SN/A memReq->cmd = Write; 6261060SN/A memcpy(memReq->data,(uint8_t *)&data,memReq->size); 6271060SN/A memReq->completionEvent = NULL; 6281060SN/A memReq->time = curTick; 6291060SN/A memReq->flags &= ~INST_READ; 6302348SN/A MemAccessResult result = dcacheInterface->access(memReq); 6312348SN/A 6322348SN/A // Ugly hack to get an event scheduled *only* if the access is 6332348SN/A // a miss. We really should add first-class support for this 6342348SN/A // at some point. 6352325SN/A if (result != MA_HIT && dcacheInterface->doEvents()) { 6361060SN/A memReq->completionEvent = &cacheCompletionEvent; 6372348SN/A lastDcacheStall = curTick; 6382348SN/A unscheduleTickEvent(); 6392325SN/A _status = DcacheMissStall; 6402292SN/A } 6412348SN/A } 6422325SN/A*/ 6432325SN/A if (res && (fault == No_Fault)) 6442292SN/A *res = data_write_pkt->result; 6452348SN/A 6462325SN/A // This will need a new way to tell if it's hooked up to a cache or not. 6472325SN/A if (data_write_req->flags & UNCACHEABLE) 6482292SN/A recordEvent("Uncached Write"); 6492292SN/A 6502292SN/A // If the write needs to have a fault on the access, consider calling 6512260SN/A // changeStatus() and changing it to "bad addr write" or something. 6522292SN/A return fault; 6532292SN/A} 6542292SN/A 6552292SN/A 6562680Sktlim@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 6572680Sktlim@umich.edutemplate 6581681SN/AFault 6592680Sktlim@umich.eduSimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 6602190SN/A 6612190SN/Atemplate 6622292SN/AFault 6633093Sksewell@umich.eduSimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 6641060SN/A 6654598Sbinkertn@umich.edutemplate 6662348SN/AFault 6672348SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 6682348SN/A 6692348SN/Atemplate 6702316SN/AFault 6714598Sbinkertn@umich.eduSimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 6722316SN/A 6731858SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 6742292SN/A 6751060SN/Atemplate<> 6761060SN/AFault 6772292SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 6781060SN/A{ 6792292SN/A return write(*(uint64_t*)&data, addr, flags, res); 6801060SN/A} 6812843Sktlim@umich.edu 6822843Sktlim@umich.edutemplate<> 6832843Sktlim@umich.eduFault 6842843Sktlim@umich.eduSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 6852843Sktlim@umich.edu{ 6862316SN/A return write(*(uint32_t*)&data, addr, flags, res); 6872348SN/A} 6882292SN/A 6892260SN/A 6902292SN/Atemplate<> 6911060SN/AFault 6921060SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 6932292SN/A{ 6942292SN/A return write((uint32_t)data, addr, flags, res); 6951060SN/A} 6962292SN/A 6972292SN/A 6982292SN/A#if FULL_SYSTEM 6992292SN/AAddr 7002292SN/ASimpleCPU::dbg_vtophys(Addr addr) 7012292SN/A{ 7022829Sksewell@umich.edu return vtophys(xc, addr); 7032829Sksewell@umich.edu} 7042829Sksewell@umich.edu#endif // FULL_SYSTEM 7052292SN/A 7062292SN/Avoid 7072292SN/ASimpleCPU::sendIcacheRequest(Packet *pkt) 7082292SN/A{ 7092292SN/A assert(!tickEvent.scheduled()); 7102292SN/A#if SIMPLE_CPU_MEM_TIMING 7112292SN/A retry_pkt = pkt; 7122292SN/A bool success = icachePort.sendTiming(*pkt); 7132292SN/A 7142292SN/A unscheduleTickEvent(); 7152292SN/A 7162292SN/A lastIcacheStall = curTick; 7172292SN/A 7182292SN/A if (!success) { 7192292SN/A // Need to wait for retry 7202292SN/A _status = IcacheRetry; 7212292SN/A } else { 7222292SN/A // Need to wait for cache to respond 7232292SN/A _status = IcacheWaitResponse; 7242292SN/A } 7252292SN/A#elif SIMPLE_CPU_MEM_ATOMIC 7262292SN/A Tick latency = icachePort.sendAtomic(*pkt); 7272292SN/A 7282292SN/A unscheduleTickEvent(); 7292292SN/A scheduleTickEvent(latency); 7301060SN/A 7311060SN/A // Note that Icache miss cycles will be incorrect. Unless 7322325SN/A // we check the status of the packet sent (is this valid?), 733 // we won't know if the latency is a hit or a miss. 734 icacheStallCycles += latency; 735 736 _status = IcacheAccessComplete; 737#elif SIMPLE_CPU_MEM_IMMEDIATE 738 icachePort.sendAtomic(*pkt); 739#else 740#error "SimpleCPU has no mem model set" 741#endif 742} 743 744void 745SimpleCPU::sendDcacheRequest(Packet *pkt) 746{ 747 assert(!tickEvent.scheduled()); 748#if SIMPLE_CPU_MEM_TIMING 749 unscheduleTickEvent(); 750 751 retry_pkt = pkt; 752 bool success = dcachePort.sendTiming(*pkt); 753 754 lastDcacheStall = curTick; 755 756 if (!success) { 757 _status = DcacheRetry; 758 } else { 759 _status = DcacheWaitResponse; 760 } 761#elif SIMPLE_CPU_MEM_ATOMIC 762 unscheduleTickEvent(); 763 764 Tick latency = dcachePort.sendAtomic(*pkt); 765 766 scheduleTickEvent(latency); 767 768 // Note that Dcache miss cycles will be incorrect. Unless 769 // we check the status of the packet sent (is this valid?), 770 // we won't know if the latency is a hit or a miss. 771 dcacheStallCycles += latency; 772#elif SIMPLE_CPU_MEM_IMMEDIATE 773 dcachePort.sendAtomic(*pkt); 774#else 775#error "SimpleCPU has no mem model set" 776#endif 777} 778 779void 780SimpleCPU::processResponse(Packet &response) 781{ 782 assert(SIMPLE_CPU_MEM_TIMING); 783 784 // For what things is the CPU the consumer of the packet it sent 785 // out? This may create a memory leak if that's the case and it's 786 // expected of the SimpleCPU to delete its own packet. 787 Packet *pkt = &response; 788 789 switch (status()) { 790 case IcacheWaitResponse: 791 icacheStallCycles += curTick - lastIcacheStall; 792 793 _status = IcacheAccessComplete; 794 scheduleTickEvent(1); 795 796 // Copy the icache data into the instruction itself. 797 memcpy(&inst, pkt->data, sizeof(inst)); 798 799 delete pkt; 800 break; 801 case DcacheWaitResponse: 802 if (pkt->cmd == Read) { 803 curStaticInst->execute(this,traceData); 804 if (traceData) 805 traceData->finalize(); 806 } 807 808 delete pkt; 809 810 dcacheStallCycles += curTick - lastDcacheStall; 811 _status = Running; 812 scheduleTickEvent(1); 813 break; 814 case DcacheWaitSwitch: 815 if (pkt->cmd == Read) { 816 curStaticInst->execute(this,traceData); 817 if (traceData) 818 traceData->finalize(); 819 } 820 821 delete pkt; 822 823 _status = SwitchedOut; 824 sampler->signalSwitched(); 825 case SwitchedOut: 826 // If this CPU has been switched out due to sampling/warm-up, 827 // ignore any further status changes (e.g., due to cache 828 // misses outstanding at the time of the switch). 829 delete pkt; 830 831 return; 832 default: 833 panic("SimpleCPU::processCacheCompletion: bad state"); 834 break; 835 } 836} 837 838Packet * 839SimpleCPU::processRetry() 840{ 841#if SIMPLE_CPU_MEM_TIMING 842 switch(status()) { 843 case IcacheRetry: 844 icacheRetryCycles += curTick - lastIcacheStall; 845 return retry_pkt; 846 break; 847 case DcacheRetry: 848 dcacheRetryCycles += curTick - lastDcacheStall; 849 return retry_pkt; 850 break; 851 default: 852 panic("SimpleCPU::processRetry: bad state"); 853 break; 854 } 855#else 856 panic("shouldn't be here"); 857#endif 858} 859 860#if FULL_SYSTEM 861void 862SimpleCPU::post_interrupt(int int_num, int index) 863{ 864 BaseCPU::post_interrupt(int_num, index); 865 866 if (xc->status() == ExecContext::Suspended) { 867 DPRINTF(IPI,"Suspended Processor awoke\n"); 868 xc->activate(); 869 } 870} 871#endif // FULL_SYSTEM 872 873/* start simulation, program loaded, processor precise state initialized */ 874void 875SimpleCPU::tick() 876{ 877 numCycles++; 878 879 traceData = NULL; 880 881 Fault fault = No_Fault; 882 883#if FULL_SYSTEM 884 if (checkInterrupts && check_interrupts() && !xc->inPalMode() && 885 status() != IcacheMissComplete) { 886 int ipl = 0; 887 int summary = 0; 888 checkInterrupts = false; 889 IntReg *ipr = xc->regs.ipr; 890 891 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 892 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 893 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 894 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 895 // See table 4-19 of 21164 hardware reference 896 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 897 summary |= (ULL(1) << i); 898 } 899 } 900 } 901 902 uint64_t interrupts = xc->cpu->intr_status(); 903 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 904 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 905 if (interrupts & (ULL(1) << i)) { 906 // See table 4-19 of 21164 hardware reference 907 ipl = i; 908 summary |= (ULL(1) << i); 909 } 910 } 911 912 if (ipr[TheISA::IPR_ASTRR]) 913 panic("asynchronous traps not implemented\n"); 914 915 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 916 ipr[TheISA::IPR_ISR] = summary; 917 ipr[TheISA::IPR_INTID] = ipl; 918 xc->ev5_trap(Interrupt_Fault); 919 920 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 921 ipr[TheISA::IPR_IPLR], ipl, summary); 922 } 923 } 924#endif 925 926 // maintain $r0 semantics 927 xc->regs.intRegFile[ZeroReg] = 0; 928#ifdef TARGET_ALPHA 929 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 930#endif // TARGET_ALPHA 931 932 if (status() == IcacheAccessComplete) { 933 // We've already fetched an instruction and were stalled on an 934 // I-cache miss. No need to fetch it again. 935 936 // Set status to running; tick event will get rescheduled if 937 // necessary at end of tick() function. 938 _status = Running; 939 } else { 940 // Try to fetch an instruction 941 942 // set up memory request for instruction fetch 943#if FULL_SYSTEM 944#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 945#else 946#define IFETCH_FLAGS(pc) 0 947#endif 948 949#if SIMPLE_CPU_MEM_TIMING 950 CpuRequest *ifetch_req = new CpuRequest(); 951 ifetch_req->size = sizeof(MachInst); 952#endif 953 954 ifetch_req->vaddr = xc->regs.pc & ~3; 955 ifetch_req->time = curTick; 956 957/* memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 958 IFETCH_FLAGS(xc->regs.pc)); 959*/ 960 961 fault = xc->translateInstReq(ifetch_req); 962 963 if (fault == No_Fault) { 964#if SIMPLE_CPU_MEM_TIMING 965 Packet *ifetch_pkt = new Packet; 966 ifetch_pkt->cmd = Read; 967 ifetch_pkt->data = (uint8_t *)&inst; 968 ifetch_pkt->req = ifetch_req; 969 ifetch_pkt->size = sizeof(MachInst); 970#endif 971 ifetch_pkt->addr = ifetch_req->paddr; 972 973 sendIcacheRequest(ifetch_pkt); 974#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC 975 return; 976#endif 977/* 978 if (icacheInterface && fault == No_Fault) { 979 memReq->completionEvent = NULL; 980 981 memReq->time = curTick; 982 memReq->flags |= INST_READ; 983 MemAccessResult result = icacheInterface->access(memReq); 984 985 // Ugly hack to get an event scheduled *only* if the access is 986 // a miss. We really should add first-class support for this 987 // at some point. 988 if (result != MA_HIT && icacheInterface->doEvents()) { 989 memReq->completionEvent = &cacheCompletionEvent; 990 lastIcacheStall = curTick; 991 unscheduleTickEvent(); 992 _status = IcacheMissStall; 993 return; 994 } 995 } 996*/ 997 } 998 } 999 1000 // If we've got a valid instruction (i.e., no fault on instruction 1001 // fetch), then execute it. 1002 if (fault == No_Fault) { 1003 1004 // keep an instruction count 1005 numInst++; 1006 numInsts++; 1007 1008 // check for instruction-count-based events 1009 comInstEventQueue[0]->serviceEvents(numInst); 1010 1011 // decode the instruction 1012 inst = gtoh(inst); 1013 curStaticInst = StaticInst<TheISA>::decode(inst); 1014 1015 traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst, 1016 xc->regs.pc); 1017 1018#if FULL_SYSTEM 1019 xc->setInst(inst); 1020#endif // FULL_SYSTEM 1021 1022 xc->func_exe_inst++; 1023 1024 fault = curStaticInst->execute(this, traceData); 1025 1026#if FULL_SYSTEM 1027 if (xc->fnbin) { 1028 assert(xc->kernelStats); 1029 system->kernelBinning->execute(xc, inst); 1030 } 1031 1032 if (xc->profile) { 1033 bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0; 1034 xc->profilePC = usermode ? 1 : xc->regs.pc; 1035 ProfileNode *node = xc->profile->consume(xc, inst); 1036 if (node) 1037 xc->profileNode = node; 1038 } 1039#endif 1040 1041 if (curStaticInst->isMemRef()) { 1042 numMemRefs++; 1043 } 1044 1045 if (curStaticInst->isLoad()) { 1046 ++numLoad; 1047 comLoadEventQueue[0]->serviceEvents(numLoad); 1048 } 1049 1050 // If we have a dcache miss, then we can't finialize the instruction 1051 // trace yet because we want to populate it with the data later 1052 if (traceData && (status() != DcacheWaitResponse)) { 1053 traceData->finalize(); 1054 } 1055 1056 traceFunctions(xc->regs.pc); 1057 1058 } // if (fault == No_Fault) 1059 1060 if (fault != No_Fault) { 1061#if FULL_SYSTEM 1062 xc->ev5_trap(fault); 1063#else // !FULL_SYSTEM 1064 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 1065#endif // FULL_SYSTEM 1066 } 1067 else { 1068 // go to the next instruction 1069 xc->regs.pc = xc->regs.npc; 1070 xc->regs.npc += sizeof(MachInst); 1071 } 1072 1073#if FULL_SYSTEM 1074 Addr oldpc; 1075 do { 1076 oldpc = xc->regs.pc; 1077 system->pcEventQueue.service(xc); 1078 } while (oldpc != xc->regs.pc); 1079#endif 1080 1081 assert(status() == Running || 1082 status() == Idle || 1083 status() == DcacheWaitResponse); 1084 1085 if (status() == Running && !tickEvent.scheduled()) 1086 tickEvent.schedule(curTick + cycles(1)); 1087} 1088 1089//////////////////////////////////////////////////////////////////////// 1090// 1091// SimpleCPU Simulation Object 1092// 1093BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 1094 1095 Param<Counter> max_insts_any_thread; 1096 Param<Counter> max_insts_all_threads; 1097 Param<Counter> max_loads_any_thread; 1098 Param<Counter> max_loads_all_threads; 1099 1100#if FULL_SYSTEM 1101 SimObjectParam<AlphaITB *> itb; 1102 SimObjectParam<AlphaDTB *> dtb; 1103 SimObjectParam<System *> system; 1104 Param<int> cpu_id; 1105 Param<Tick> profile; 1106#else 1107 SimObjectParam<Memory *> mem; 1108 SimObjectParam<Process *> workload; 1109#endif // FULL_SYSTEM 1110 1111 Param<int> clock; 1112 1113 Param<bool> defer_registration; 1114 Param<int> width; 1115 Param<bool> function_trace; 1116 Param<Tick> function_trace_start; 1117 1118END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 1119 1120BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 1121 1122 INIT_PARAM(max_insts_any_thread, 1123 "terminate when any thread reaches this inst count"), 1124 INIT_PARAM(max_insts_all_threads, 1125 "terminate when all threads have reached this inst count"), 1126 INIT_PARAM(max_loads_any_thread, 1127 "terminate when any thread reaches this load count"), 1128 INIT_PARAM(max_loads_all_threads, 1129 "terminate when all threads have reached this load count"), 1130 1131#if FULL_SYSTEM 1132 INIT_PARAM(itb, "Instruction TLB"), 1133 INIT_PARAM(dtb, "Data TLB"), 1134 INIT_PARAM(system, "system object"), 1135 INIT_PARAM(cpu_id, "processor ID"), 1136 INIT_PARAM(profile, ""), 1137#else 1138 INIT_PARAM(mem, "memory"), 1139 INIT_PARAM(workload, "processes to run"), 1140#endif // FULL_SYSTEM 1141 1142 INIT_PARAM(clock, "clock speed"), 1143 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 1144 INIT_PARAM(width, "cpu width"), 1145 INIT_PARAM(function_trace, "Enable function trace"), 1146 INIT_PARAM(function_trace_start, "Cycle to start function trace") 1147 1148END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 1149 1150 1151CREATE_SIM_OBJECT(SimpleCPU) 1152{ 1153 SimpleCPU::Params *params = new SimpleCPU::Params(); 1154 params->name = getInstanceName(); 1155 params->numberOfThreads = 1; 1156 params->max_insts_any_thread = max_insts_any_thread; 1157 params->max_insts_all_threads = max_insts_all_threads; 1158 params->max_loads_any_thread = max_loads_any_thread; 1159 params->max_loads_all_threads = max_loads_all_threads; 1160 params->deferRegistration = defer_registration; 1161 params->clock = clock; 1162 params->functionTrace = function_trace; 1163 params->functionTraceStart = function_trace_start; 1164 params->width = width; 1165 1166#if FULL_SYSTEM 1167 params->itb = itb; 1168 params->dtb = dtb; 1169 params->system = system; 1170 params->cpu_id = cpu_id; 1171 params->profile = profile; 1172#else 1173 params->mem = mem; 1174 params->process = workload; 1175#endif 1176 1177 SimpleCPU *cpu = new SimpleCPU(params); 1178 return cpu; 1179} 1180 1181REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 1182 1183