base.cc revision 2036
19793Sakash.bagdia@arm.com/* 28706Sandreas.hansson@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 38706Sandreas.hansson@arm.com * All rights reserved. 48706Sandreas.hansson@arm.com * 58706Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68706Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 78706Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 88706Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 98706Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 108706Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 118706Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 128706Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 135369Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 143005Sstever@eecs.umich.edu * this software without specific prior written permission. 153005Sstever@eecs.umich.edu * 163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu */ 283005Sstever@eecs.umich.edu 293005Sstever@eecs.umich.edu#include <cmath> 303005Sstever@eecs.umich.edu#include <cstdio> 313005Sstever@eecs.umich.edu#include <cstdlib> 323005Sstever@eecs.umich.edu#include <iostream> 333005Sstever@eecs.umich.edu#include <iomanip> 343005Sstever@eecs.umich.edu#include <list> 353005Sstever@eecs.umich.edu#include <sstream> 363005Sstever@eecs.umich.edu#include <string> 373005Sstever@eecs.umich.edu 383005Sstever@eecs.umich.edu#include "base/cprintf.hh" 393005Sstever@eecs.umich.edu#include "base/inifile.hh" 403005Sstever@eecs.umich.edu#include "base/loader/symtab.hh" 412710SN/A#include "base/misc.hh" 422710SN/A#include "base/pollevent.hh" 433005Sstever@eecs.umich.edu#include "base/range.hh" 442889SN/A#include "base/stats/events.hh" 4512564Sgabeblack@google.com#include "base/trace.hh" 4613774Sandreas.sandberg@arm.com#include "cpu/base.hh" 4712564Sgabeblack@google.com#include "cpu/exec_context.hh" 486654Snate@binkert.org#include "cpu/exetrace.hh" 496654Snate@binkert.org#include "cpu/profile.hh" 509907Snilay@cs.wisc.edu#include "cpu/sampler/sampler.hh" 516654Snate@binkert.org#include "cpu/simple/cpu.hh" 522667SN/A#include "cpu/smt.hh" 536654Snate@binkert.org#include "cpu/static_inst.hh" 546654Snate@binkert.org#include "kern/kernel_stats.hh" 5512395Sswapnilster@gmail.com#include "mem/base_mem.hh" 565457Ssaidi@eecs.umich.edu#include "mem/mem_interface.hh" 5711670Sandreas.hansson@arm.com#include "sim/byteswap.hh" 5811670Sandreas.hansson@arm.com#include "sim/builder.hh" 5911670Sandreas.hansson@arm.com#include "sim/debug.hh" 608169SLisa.Hsu@amd.com#include "sim/host.hh" 6111682Sandreas.hansson@arm.com#include "sim/sim_events.hh" 6211682Sandreas.hansson@arm.com#include "sim/sim_object.hh" 6311682Sandreas.hansson@arm.com#include "sim/stats.hh" 6411682Sandreas.hansson@arm.com 6513432Spau.cabre@metempsy.com#if FULL_SYSTEM 6611682Sandreas.hansson@arm.com#include "base/remote_gdb.hh" 6713883Sdavid.hashe@amd.com#include "mem/functional/memory_control.hh" 6811682Sandreas.hansson@arm.com#include "mem/functional/physical.hh" 6911682Sandreas.hansson@arm.com#include "sim/system.hh" 703394Shsul@eecs.umich.edu#include "targetarch/alpha_memory.hh" 719197Snilay@cs.wisc.edu#include "targetarch/stacktrace.hh" 729197Snilay@cs.wisc.edu#include "targetarch/vtophys.hh" 739197Snilay@cs.wisc.edu#else // !FULL_SYSTEM 749197Snilay@cs.wisc.edu#include "mem/functional/functional.hh" 759197Snilay@cs.wisc.edu#endif // FULL_SYSTEM 769197Snilay@cs.wisc.edu 779197Snilay@cs.wisc.eduusing namespace std; 789197Snilay@cs.wisc.edu//The SimpleCPU does alpha only 799197Snilay@cs.wisc.eduusing namespace LittleEndianGuest; 809197Snilay@cs.wisc.edu 819197Snilay@cs.wisc.edu 829197Snilay@cs.wisc.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) 839197Snilay@cs.wisc.edu : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) 849197Snilay@cs.wisc.edu{ 859197Snilay@cs.wisc.edu} 869197Snilay@cs.wisc.edu 879197Snilay@cs.wisc.eduvoid 889197Snilay@cs.wisc.eduSimpleCPU::TickEvent::process() 899197Snilay@cs.wisc.edu{ 909197Snilay@cs.wisc.edu int count = width; 919197Snilay@cs.wisc.edu do { 9212146Spau.cabre@metempsy.com cpu->tick(); 939197Snilay@cs.wisc.edu } while (--count > 0 && cpu->status() == Running); 949907Snilay@cs.wisc.edu} 959197Snilay@cs.wisc.edu 9610803Sbrandon.potter@amd.comconst char * 9710803Sbrandon.potter@amd.comSimpleCPU::TickEvent::description() 9810803Sbrandon.potter@amd.com{ 9910803Sbrandon.potter@amd.com return "SimpleCPU tick event"; 1009197Snilay@cs.wisc.edu} 1019217Snilay@cs.wisc.edu 1029197Snilay@cs.wisc.edu 1039197Snilay@cs.wisc.eduSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 1049197Snilay@cs.wisc.edu : Event(&mainEventQueue), cpu(_cpu) 1059197Snilay@cs.wisc.edu{ 1069197Snilay@cs.wisc.edu} 1079197Snilay@cs.wisc.edu 1089197Snilay@cs.wisc.eduvoid SimpleCPU::CacheCompletionEvent::process() 1099197Snilay@cs.wisc.edu{ 1109197Snilay@cs.wisc.edu cpu->processCacheCompletion(); 1119197Snilay@cs.wisc.edu} 1129197Snilay@cs.wisc.edu 1139197Snilay@cs.wisc.educonst char * 1149197Snilay@cs.wisc.eduSimpleCPU::CacheCompletionEvent::description() 1159197Snilay@cs.wisc.edu{ 11612014Sgabeblack@google.com return "SimpleCPU cache completion event"; 1179197Snilay@cs.wisc.edu} 1189197Snilay@cs.wisc.edu 1199197Snilay@cs.wisc.eduSimpleCPU::SimpleCPU(Params *p) 1209197Snilay@cs.wisc.edu : BaseCPU(p), tickEvent(this, p->width), xc(NULL), 1219197Snilay@cs.wisc.edu cacheCompletionEvent(this) 1222957SN/A{ 1238920Snilay@cs.wisc.edu _status = Idle; 1248920Snilay@cs.wisc.edu#if FULL_SYSTEM 1252957SN/A xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); 1268862Snilay@cs.wisc.edu 1278862Snilay@cs.wisc.edu // initialize CPU, including PC 1288467Snilay@cs.wisc.edu TheISA::initCPU(&xc->regs); 1292957SN/A#else 1302957SN/A xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0); 1312957SN/A#endif // !FULL_SYSTEM 13212564Sgabeblack@google.com 1332957SN/A icacheInterface = p->icache_interface; 1342957SN/A dcacheInterface = p->dcache_interface; 1358167SLisa.Hsu@amd.com 1369197Snilay@cs.wisc.edu memReq = new MemReq(); 1378167SLisa.Hsu@amd.com memReq->xc = xc; 1385369Ssaidi@eecs.umich.edu memReq->asid = 0; 1398167SLisa.Hsu@amd.com memReq->data = new uint8_t[64]; 1408167SLisa.Hsu@amd.com 14112564Sgabeblack@google.com numInst = 0; 1428167SLisa.Hsu@amd.com startNumInst = 0; 1438167SLisa.Hsu@amd.com numLoad = 0; 1448167SLisa.Hsu@amd.com startNumLoad = 0; 1458167SLisa.Hsu@amd.com lastIcacheStall = 0; 1468168SLisa.Hsu@amd.com lastDcacheStall = 0; 14710037SARM gem5 Developers 14810037SARM gem5 Developers execContexts.push_back(xc); 14910037SARM gem5 Developers} 15010037SARM gem5 Developers 15110037SARM gem5 DevelopersSimpleCPU::~SimpleCPU() 1528168SLisa.Hsu@amd.com{ 15310037SARM gem5 Developers} 15410037SARM gem5 Developers 15511851Sbrandon.potter@amd.comvoid 1568167SLisa.Hsu@amd.comSimpleCPU::switchOut(Sampler *s) 15712564Sgabeblack@google.com{ 15812564Sgabeblack@google.com sampler = s; 15912564Sgabeblack@google.com if (status() == DcacheMissStall) { 1605369Ssaidi@eecs.umich.edu DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); 1618920Snilay@cs.wisc.edu _status = DcacheMissSwitch; 1629197Snilay@cs.wisc.edu } 1638920Snilay@cs.wisc.edu else { 16412564Sgabeblack@google.com _status = SwitchedOut; 1658920Snilay@cs.wisc.edu 1665369Ssaidi@eecs.umich.edu if (tickEvent.scheduled()) 1675369Ssaidi@eecs.umich.edu tickEvent.squash(); 1688718Snilay@cs.wisc.edu 1699197Snilay@cs.wisc.edu sampler->signalSwitched(); 1709197Snilay@cs.wisc.edu } 1719197Snilay@cs.wisc.edu} 1729197Snilay@cs.wisc.edu 1739197Snilay@cs.wisc.edu 1743005Sstever@eecs.umich.eduvoid 1753395Shsul@eecs.umich.eduSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 17613731Sandreas.sandberg@arm.com{ 1779793Sakash.bagdia@arm.com BaseCPU::takeOverFrom(oldCPU); 1789836Sandreas.hansson@arm.com 1799815SAndreas Hansson <andreas.hansson> assert(!tickEvent.scheduled()); 1809793Sakash.bagdia@arm.com 18111147Smitch.hayenga@arm.com // if any of this CPU's ExecContexts are active, mark the CPU as 18211147Smitch.hayenga@arm.com // running and schedule its tick event. 18311147Smitch.hayenga@arm.com for (int i = 0; i < execContexts.size(); ++i) { 1849827Sakash.bagdia@arm.com ExecContext *xc = execContexts[i]; 1859827Sakash.bagdia@arm.com if (xc->status() == ExecContext::Active && _status != Running) { 1869827Sakash.bagdia@arm.com _status = Running; 1879827Sakash.bagdia@arm.com tickEvent.schedule(curTick); 1889827Sakash.bagdia@arm.com } 1899827Sakash.bagdia@arm.com } 1909827Sakash.bagdia@arm.com} 1919827Sakash.bagdia@arm.com 1929827Sakash.bagdia@arm.com 1939827Sakash.bagdia@arm.comvoid 1949793Sakash.bagdia@arm.comSimpleCPU::activateContext(int thread_num, int delay) 1959827Sakash.bagdia@arm.com{ 1969827Sakash.bagdia@arm.com assert(thread_num == 0); 1979827Sakash.bagdia@arm.com assert(xc); 1989793Sakash.bagdia@arm.com 19911251Sradhika.jagtap@ARM.com assert(_status == Idle); 20011251Sradhika.jagtap@ARM.com notIdleFraction++; 20111251Sradhika.jagtap@ARM.com scheduleTickEvent(delay); 20211251Sradhika.jagtap@ARM.com _status = Running; 20311251Sradhika.jagtap@ARM.com} 2049793Sakash.bagdia@arm.com 2059793Sakash.bagdia@arm.com 2069793Sakash.bagdia@arm.comvoid 2079793Sakash.bagdia@arm.comSimpleCPU::suspendContext(int thread_num) 2083395Shsul@eecs.umich.edu{ 20912941Sandreas.sandberg@arm.com assert(thread_num == 0); 21010555Salexandru.dutu@amd.com assert(xc); 21111839SCurtis.Dunham@arm.com 21210555Salexandru.dutu@amd.com assert(_status == Running); 21310555Salexandru.dutu@amd.com notIdleFraction--; 21410555Salexandru.dutu@amd.com unscheduleTickEvent(); 21510555Salexandru.dutu@amd.com _status = Idle; 21610555Salexandru.dutu@amd.com} 21710555Salexandru.dutu@amd.com 2188926Sandreas.hansson@arm.com 2199647Sdam.sunwoo@arm.comvoid 22013684Sgiacomo.travaglini@arm.comSimpleCPU::deallocateContext(int thread_num) 22113012Sandreas.sandberg@arm.com{ 2229647Sdam.sunwoo@arm.com // for now, these are equivalent 2239647Sdam.sunwoo@arm.com suspendContext(thread_num); 2249647Sdam.sunwoo@arm.com} 22513731Sandreas.sandberg@arm.com 2269197Snilay@cs.wisc.edu 2279197Snilay@cs.wisc.eduvoid 2289197Snilay@cs.wisc.eduSimpleCPU::haltContext(int thread_num) 2298957Sjayneel@cs.wisc.edu{ 2308957Sjayneel@cs.wisc.edu // for now, these are equivalent 2318957Sjayneel@cs.wisc.edu suspendContext(thread_num); 2323005Sstever@eecs.umich.edu} 2339647Sdam.sunwoo@arm.com 23410381Sdam.sunwoo@arm.com 2359647Sdam.sunwoo@arm.comvoid 2368887Sgeoffrey.blake@arm.comSimpleCPU::regStats() 2378887Sgeoffrey.blake@arm.com{ 2388887Sgeoffrey.blake@arm.com using namespace Stats; 23913432Spau.cabre@metempsy.com 24013432Spau.cabre@metempsy.com BaseCPU::regStats(); 24113432Spau.cabre@metempsy.com 24213432Spau.cabre@metempsy.com numInsts 24313958Sjairo.balart@metempsy.com .name(name() + ".num_insts") 24413958Sjairo.balart@metempsy.com .desc("Number of instructions executed") 24513958Sjairo.balart@metempsy.com ; 24613958Sjairo.balart@metempsy.com 2479384SAndreas.Sandberg@arm.com numMemRefs 2489384SAndreas.Sandberg@arm.com .name(name() + ".num_refs") 24913883Sdavid.hashe@amd.com .desc("Number of memory references") 25013883Sdavid.hashe@amd.com ; 25113883Sdavid.hashe@amd.com 2528887Sgeoffrey.blake@arm.com notIdleFraction 25310519Snilay@cs.wisc.edu .name(name() + ".not_idle_fraction") 25410120Snilay@cs.wisc.edu .desc("Percentage of non-idle cycles") 2558896Snilay@cs.wisc.edu ; 25610300Scastilloe@unican.es 25710300Scastilloe@unican.es idleFraction 25813731Sandreas.sandberg@arm.com .name(name() + ".idle_fraction") 25910120Snilay@cs.wisc.edu .desc("Percentage of idle cycles") 2608896Snilay@cs.wisc.edu ; 2618896Snilay@cs.wisc.edu 2629268Smalek.musleh@gmail.com icacheStallCycles 2639268Smalek.musleh@gmail.com .name(name() + ".icache_stall_cycles") 2648896Snilay@cs.wisc.edu .desc("ICache total stall cycles") 2658896Snilay@cs.wisc.edu .prereq(icacheStallCycles) 2668896Snilay@cs.wisc.edu ; 2678896Snilay@cs.wisc.edu 2688896Snilay@cs.wisc.edu dcacheStallCycles 2699222Shestness@cs.wisc.edu .name(name() + ".dcache_stall_cycles") 27011150Smitch.hayenga@arm.com .desc("DCache total stall cycles") 27111150Smitch.hayenga@arm.com .prereq(dcacheStallCycles) 27211150Smitch.hayenga@arm.com ; 2739222Shestness@cs.wisc.edu 2749222Shestness@cs.wisc.edu idleFraction = constant(1.0) - notIdleFraction; 2758887Sgeoffrey.blake@arm.com} 27610150Snilay@cs.wisc.edu 27710720Sandreas.hansson@arm.comvoid 2788887Sgeoffrey.blake@arm.comSimpleCPU::resetStats() 2798887Sgeoffrey.blake@arm.com{ 2809836Sandreas.hansson@arm.com startNumInst = numInst; 2818887Sgeoffrey.blake@arm.com notIdleFraction = (_status != Idle); 2828801Sgblack@eecs.umich.edu} 2833481Shsul@eecs.umich.edu 284void 285SimpleCPU::serialize(ostream &os) 286{ 287 BaseCPU::serialize(os); 288 SERIALIZE_ENUM(_status); 289 SERIALIZE_SCALAR(inst); 290 nameOut(os, csprintf("%s.xc", name())); 291 xc->serialize(os); 292 nameOut(os, csprintf("%s.tickEvent", name())); 293 tickEvent.serialize(os); 294 nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 295 cacheCompletionEvent.serialize(os); 296} 297 298void 299SimpleCPU::unserialize(Checkpoint *cp, const string §ion) 300{ 301 BaseCPU::unserialize(cp, section); 302 UNSERIALIZE_ENUM(_status); 303 UNSERIALIZE_SCALAR(inst); 304 xc->unserialize(cp, csprintf("%s.xc", section)); 305 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 306 cacheCompletionEvent 307 .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); 308} 309 310void 311change_thread_state(int thread_number, int activate, int priority) 312{ 313} 314 315Fault 316SimpleCPU::copySrcTranslate(Addr src) 317{ 318 static bool no_warn = true; 319 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 320 // Only support block sizes of 64 atm. 321 assert(blk_size == 64); 322 int offset = src & (blk_size - 1); 323 324 // Make sure block doesn't span page 325 if (no_warn && 326 (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && 327 (src >> 40) != 0xfffffc) { 328 warn("Copied block source spans pages %x.", src); 329 no_warn = false; 330 } 331 332 memReq->reset(src & ~(blk_size - 1), blk_size); 333 334 // translate to physical address 335 Fault fault = xc->translateDataReadReq(memReq); 336 337 assert(fault != Alignment_Fault); 338 339 if (fault == No_Fault) { 340 xc->copySrcAddr = src; 341 xc->copySrcPhysAddr = memReq->paddr + offset; 342 } else { 343 xc->copySrcAddr = 0; 344 xc->copySrcPhysAddr = 0; 345 } 346 return fault; 347} 348 349Fault 350SimpleCPU::copy(Addr dest) 351{ 352 static bool no_warn = true; 353 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 354 // Only support block sizes of 64 atm. 355 assert(blk_size == 64); 356 uint8_t data[blk_size]; 357 //assert(xc->copySrcAddr); 358 int offset = dest & (blk_size - 1); 359 360 // Make sure block doesn't span page 361 if (no_warn && 362 (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && 363 (dest >> 40) != 0xfffffc) { 364 no_warn = false; 365 warn("Copied block destination spans pages %x. ", dest); 366 } 367 368 memReq->reset(dest & ~(blk_size -1), blk_size); 369 // translate to physical address 370 Fault fault = xc->translateDataWriteReq(memReq); 371 372 assert(fault != Alignment_Fault); 373 374 if (fault == No_Fault) { 375 Addr dest_addr = memReq->paddr + offset; 376 // Need to read straight from memory since we have more than 8 bytes. 377 memReq->paddr = xc->copySrcPhysAddr; 378 xc->mem->read(memReq, data); 379 memReq->paddr = dest_addr; 380 xc->mem->write(memReq, data); 381 if (dcacheInterface) { 382 memReq->cmd = Copy; 383 memReq->completionEvent = NULL; 384 memReq->paddr = xc->copySrcPhysAddr; 385 memReq->dest = dest_addr; 386 memReq->size = 64; 387 memReq->time = curTick; 388 memReq->flags &= ~INST_READ; 389 dcacheInterface->access(memReq); 390 } 391 } 392 return fault; 393} 394 395// precise architected memory state accessor macros 396template <class T> 397Fault 398SimpleCPU::read(Addr addr, T &data, unsigned flags) 399{ 400 if (status() == DcacheMissStall || status() == DcacheMissSwitch) { 401 Fault fault = xc->read(memReq,data); 402 403 if (traceData) { 404 traceData->setAddr(addr); 405 } 406 return fault; 407 } 408 409 memReq->reset(addr, sizeof(T), flags); 410 411 // translate to physical address 412 Fault fault = xc->translateDataReadReq(memReq); 413 414 // if we have a cache, do cache access too 415 if (fault == No_Fault && dcacheInterface) { 416 memReq->cmd = Read; 417 memReq->completionEvent = NULL; 418 memReq->time = curTick; 419 memReq->flags &= ~INST_READ; 420 MemAccessResult result = dcacheInterface->access(memReq); 421 422 // Ugly hack to get an event scheduled *only* if the access is 423 // a miss. We really should add first-class support for this 424 // at some point. 425 if (result != MA_HIT && dcacheInterface->doEvents()) { 426 memReq->completionEvent = &cacheCompletionEvent; 427 lastDcacheStall = curTick; 428 unscheduleTickEvent(); 429 _status = DcacheMissStall; 430 } else { 431 // do functional access 432 fault = xc->read(memReq, data); 433 434 } 435 } else if(fault == No_Fault) { 436 // do functional access 437 fault = xc->read(memReq, data); 438 439 } 440 441 if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 442 recordEvent("Uncached Read"); 443 444 return fault; 445} 446 447#ifndef DOXYGEN_SHOULD_SKIP_THIS 448 449template 450Fault 451SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 452 453template 454Fault 455SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 456 457template 458Fault 459SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 460 461template 462Fault 463SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 464 465#endif //DOXYGEN_SHOULD_SKIP_THIS 466 467template<> 468Fault 469SimpleCPU::read(Addr addr, double &data, unsigned flags) 470{ 471 return read(addr, *(uint64_t*)&data, flags); 472} 473 474template<> 475Fault 476SimpleCPU::read(Addr addr, float &data, unsigned flags) 477{ 478 return read(addr, *(uint32_t*)&data, flags); 479} 480 481 482template<> 483Fault 484SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 485{ 486 return read(addr, (uint32_t&)data, flags); 487} 488 489 490template <class T> 491Fault 492SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 493{ 494 memReq->reset(addr, sizeof(T), flags); 495 496 // translate to physical address 497 Fault fault = xc->translateDataWriteReq(memReq); 498 499 // do functional access 500 if (fault == No_Fault) 501 fault = xc->write(memReq, data); 502 503 if (fault == No_Fault && dcacheInterface) { 504 memReq->cmd = Write; 505 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 506 memReq->completionEvent = NULL; 507 memReq->time = curTick; 508 memReq->flags &= ~INST_READ; 509 MemAccessResult result = dcacheInterface->access(memReq); 510 511 // Ugly hack to get an event scheduled *only* if the access is 512 // a miss. We really should add first-class support for this 513 // at some point. 514 if (result != MA_HIT && dcacheInterface->doEvents()) { 515 memReq->completionEvent = &cacheCompletionEvent; 516 lastDcacheStall = curTick; 517 unscheduleTickEvent(); 518 _status = DcacheMissStall; 519 } 520 } 521 522 if (res && (fault == No_Fault)) 523 *res = memReq->result; 524 525 if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 526 recordEvent("Uncached Write"); 527 528 return fault; 529} 530 531 532#ifndef DOXYGEN_SHOULD_SKIP_THIS 533template 534Fault 535SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 536 537template 538Fault 539SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 540 541template 542Fault 543SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 544 545template 546Fault 547SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 548 549#endif //DOXYGEN_SHOULD_SKIP_THIS 550 551template<> 552Fault 553SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 554{ 555 return write(*(uint64_t*)&data, addr, flags, res); 556} 557 558template<> 559Fault 560SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 561{ 562 return write(*(uint32_t*)&data, addr, flags, res); 563} 564 565 566template<> 567Fault 568SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 569{ 570 return write((uint32_t)data, addr, flags, res); 571} 572 573 574#if FULL_SYSTEM 575Addr 576SimpleCPU::dbg_vtophys(Addr addr) 577{ 578 return vtophys(xc, addr); 579} 580#endif // FULL_SYSTEM 581 582void 583SimpleCPU::processCacheCompletion() 584{ 585 switch (status()) { 586 case IcacheMissStall: 587 icacheStallCycles += curTick - lastIcacheStall; 588 _status = IcacheMissComplete; 589 scheduleTickEvent(1); 590 break; 591 case DcacheMissStall: 592 if (memReq->cmd.isRead()) { 593 curStaticInst->execute(this,traceData); 594 if (traceData) 595 traceData->finalize(); 596 } 597 dcacheStallCycles += curTick - lastDcacheStall; 598 _status = Running; 599 scheduleTickEvent(1); 600 break; 601 case DcacheMissSwitch: 602 if (memReq->cmd.isRead()) { 603 curStaticInst->execute(this,traceData); 604 if (traceData) 605 traceData->finalize(); 606 } 607 _status = SwitchedOut; 608 sampler->signalSwitched(); 609 case SwitchedOut: 610 // If this CPU has been switched out due to sampling/warm-up, 611 // ignore any further status changes (e.g., due to cache 612 // misses outstanding at the time of the switch). 613 return; 614 default: 615 panic("SimpleCPU::processCacheCompletion: bad state"); 616 break; 617 } 618} 619 620#if FULL_SYSTEM 621void 622SimpleCPU::post_interrupt(int int_num, int index) 623{ 624 BaseCPU::post_interrupt(int_num, index); 625 626 if (xc->status() == ExecContext::Suspended) { 627 DPRINTF(IPI,"Suspended Processor awoke\n"); 628 xc->activate(); 629 } 630} 631#endif // FULL_SYSTEM 632 633/* start simulation, program loaded, processor precise state initialized */ 634void 635SimpleCPU::tick() 636{ 637 numCycles++; 638 639 traceData = NULL; 640 641 Fault fault = No_Fault; 642 643#if FULL_SYSTEM 644 if (checkInterrupts && check_interrupts() && !xc->inPalMode() && 645 status() != IcacheMissComplete) { 646 int ipl = 0; 647 int summary = 0; 648 checkInterrupts = false; 649 IntReg *ipr = xc->regs.ipr; 650 651 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 652 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 653 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 654 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 655 // See table 4-19 of 21164 hardware reference 656 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 657 summary |= (ULL(1) << i); 658 } 659 } 660 } 661 662 uint64_t interrupts = xc->cpu->intr_status(); 663 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 664 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 665 if (interrupts & (ULL(1) << i)) { 666 // See table 4-19 of 21164 hardware reference 667 ipl = i; 668 summary |= (ULL(1) << i); 669 } 670 } 671 672 if (ipr[TheISA::IPR_ASTRR]) 673 panic("asynchronous traps not implemented\n"); 674 675 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 676 ipr[TheISA::IPR_ISR] = summary; 677 ipr[TheISA::IPR_INTID] = ipl; 678 xc->ev5_trap(Interrupt_Fault); 679 680 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 681 ipr[TheISA::IPR_IPLR], ipl, summary); 682 } 683 } 684#endif 685 686 // maintain $r0 semantics 687 xc->regs.intRegFile[ZeroReg] = 0; 688#ifdef TARGET_ALPHA 689 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 690#endif // TARGET_ALPHA 691 692 if (status() == IcacheMissComplete) { 693 // We've already fetched an instruction and were stalled on an 694 // I-cache miss. No need to fetch it again. 695 696 // Set status to running; tick event will get rescheduled if 697 // necessary at end of tick() function. 698 _status = Running; 699 } 700 else { 701 // Try to fetch an instruction 702 703 // set up memory request for instruction fetch 704#if FULL_SYSTEM 705#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 706#else 707#define IFETCH_FLAGS(pc) 0 708#endif 709 710 memReq->cmd = Read; 711 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 712 IFETCH_FLAGS(xc->regs.pc)); 713 714 fault = xc->translateInstReq(memReq); 715 716 if (fault == No_Fault) 717 fault = xc->mem->read(memReq, inst); 718 719 if (icacheInterface && fault == No_Fault) { 720 memReq->completionEvent = NULL; 721 722 memReq->time = curTick; 723 memReq->flags |= INST_READ; 724 MemAccessResult result = icacheInterface->access(memReq); 725 726 // Ugly hack to get an event scheduled *only* if the access is 727 // a miss. We really should add first-class support for this 728 // at some point. 729 if (result != MA_HIT && icacheInterface->doEvents()) { 730 memReq->completionEvent = &cacheCompletionEvent; 731 lastIcacheStall = curTick; 732 unscheduleTickEvent(); 733 _status = IcacheMissStall; 734 return; 735 } 736 } 737 } 738 739 // If we've got a valid instruction (i.e., no fault on instruction 740 // fetch), then execute it. 741 if (fault == No_Fault) { 742 743 // keep an instruction count 744 numInst++; 745 numInsts++; 746 747 // check for instruction-count-based events 748 comInstEventQueue[0]->serviceEvents(numInst); 749 750 // decode the instruction 751 inst = gtoh(inst); 752 curStaticInst = StaticInst<TheISA>::decode(inst); 753 754 traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst, 755 xc->regs.pc); 756 757#if FULL_SYSTEM 758 xc->setInst(inst); 759#endif // FULL_SYSTEM 760 761 xc->func_exe_inst++; 762 763 fault = curStaticInst->execute(this, traceData); 764 765#if FULL_SYSTEM 766 if (xc->fnbin) { 767 assert(xc->kernelStats); 768 system->kernelBinning->execute(xc, inst); 769 } 770 771 if (xc->profile) { 772 bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0; 773 xc->profilePC = usermode ? 1 : xc->regs.pc; 774 ProfileNode *node = xc->profile->consume(xc, inst); 775 if (node) 776 xc->profileNode = node; 777 } 778#endif 779 780 if (curStaticInst->isMemRef()) { 781 numMemRefs++; 782 } 783 784 if (curStaticInst->isLoad()) { 785 ++numLoad; 786 comLoadEventQueue[0]->serviceEvents(numLoad); 787 } 788 789 // If we have a dcache miss, then we can't finialize the instruction 790 // trace yet because we want to populate it with the data later 791 if (traceData && 792 !(status() == DcacheMissStall && memReq->cmd.isRead())) { 793 traceData->finalize(); 794 } 795 796 traceFunctions(xc->regs.pc); 797 798 } // if (fault == No_Fault) 799 800 if (fault != No_Fault) { 801#if FULL_SYSTEM 802 xc->ev5_trap(fault); 803#else // !FULL_SYSTEM 804 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 805#endif // FULL_SYSTEM 806 } 807 else { 808 // go to the next instruction 809 xc->regs.pc = xc->regs.npc; 810 xc->regs.npc += sizeof(MachInst); 811 } 812 813#if FULL_SYSTEM 814 Addr oldpc; 815 do { 816 oldpc = xc->regs.pc; 817 system->pcEventQueue.service(xc); 818 } while (oldpc != xc->regs.pc); 819#endif 820 821 assert(status() == Running || 822 status() == Idle || 823 status() == DcacheMissStall); 824 825 if (status() == Running && !tickEvent.scheduled()) 826 tickEvent.schedule(curTick + cycles(1)); 827} 828 829//////////////////////////////////////////////////////////////////////// 830// 831// SimpleCPU Simulation Object 832// 833BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 834 835 Param<Counter> max_insts_any_thread; 836 Param<Counter> max_insts_all_threads; 837 Param<Counter> max_loads_any_thread; 838 Param<Counter> max_loads_all_threads; 839 840#if FULL_SYSTEM 841 SimObjectParam<AlphaITB *> itb; 842 SimObjectParam<AlphaDTB *> dtb; 843 SimObjectParam<FunctionalMemory *> mem; 844 SimObjectParam<System *> system; 845 Param<int> cpu_id; 846 Param<Tick> profile; 847#else 848 SimObjectParam<Process *> workload; 849#endif // FULL_SYSTEM 850 851 Param<int> clock; 852 SimObjectParam<BaseMem *> icache; 853 SimObjectParam<BaseMem *> dcache; 854 855 Param<bool> defer_registration; 856 Param<int> width; 857 Param<bool> function_trace; 858 Param<Tick> function_trace_start; 859 860END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 861 862BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 863 864 INIT_PARAM(max_insts_any_thread, 865 "terminate when any thread reaches this inst count"), 866 INIT_PARAM(max_insts_all_threads, 867 "terminate when all threads have reached this inst count"), 868 INIT_PARAM(max_loads_any_thread, 869 "terminate when any thread reaches this load count"), 870 INIT_PARAM(max_loads_all_threads, 871 "terminate when all threads have reached this load count"), 872 873#if FULL_SYSTEM 874 INIT_PARAM(itb, "Instruction TLB"), 875 INIT_PARAM(dtb, "Data TLB"), 876 INIT_PARAM(mem, "memory"), 877 INIT_PARAM(system, "system object"), 878 INIT_PARAM(cpu_id, "processor ID"), 879 INIT_PARAM(profile, ""), 880#else 881 INIT_PARAM(workload, "processes to run"), 882#endif // FULL_SYSTEM 883 884 INIT_PARAM(clock, "clock speed"), 885 INIT_PARAM(icache, "L1 instruction cache object"), 886 INIT_PARAM(dcache, "L1 data cache object"), 887 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 888 INIT_PARAM(width, "cpu width"), 889 INIT_PARAM(function_trace, "Enable function trace"), 890 INIT_PARAM(function_trace_start, "Cycle to start function trace") 891 892END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 893 894 895CREATE_SIM_OBJECT(SimpleCPU) 896{ 897 SimpleCPU::Params *params = new SimpleCPU::Params(); 898 params->name = getInstanceName(); 899 params->numberOfThreads = 1; 900 params->max_insts_any_thread = max_insts_any_thread; 901 params->max_insts_all_threads = max_insts_all_threads; 902 params->max_loads_any_thread = max_loads_any_thread; 903 params->max_loads_all_threads = max_loads_all_threads; 904 params->deferRegistration = defer_registration; 905 params->clock = clock; 906 params->functionTrace = function_trace; 907 params->functionTraceStart = function_trace_start; 908 params->icache_interface = (icache) ? icache->getInterface() : NULL; 909 params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; 910 params->width = width; 911 912#if FULL_SYSTEM 913 params->itb = itb; 914 params->dtb = dtb; 915 params->mem = mem; 916 params->system = system; 917 params->cpu_id = cpu_id; 918 params->profile = profile; 919#else 920 params->process = workload; 921#endif 922 923 SimpleCPU *cpu = new SimpleCPU(params); 924 return cpu; 925} 926 927REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 928 929