base.cc revision 224
15347Ssaidi@eecs.umich.edu/* 23395Shsul@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan 33395Shsul@eecs.umich.edu * All rights reserved. 43395Shsul@eecs.umich.edu * 53395Shsul@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 63395Shsul@eecs.umich.edu * modification, are permitted provided that the following conditions are 73395Shsul@eecs.umich.edu * met: redistributions of source code must retain the above copyright 83395Shsul@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 93395Shsul@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 103395Shsul@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 113395Shsul@eecs.umich.edu * documentation and/or other materials provided with the distribution; 123395Shsul@eecs.umich.edu * neither the name of the copyright holders nor the names of its 133395Shsul@eecs.umich.edu * contributors may be used to endorse or promote products derived from 143395Shsul@eecs.umich.edu * this software without specific prior written permission. 153395Shsul@eecs.umich.edu * 163395Shsul@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173395Shsul@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183395Shsul@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193395Shsul@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203395Shsul@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213395Shsul@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223395Shsul@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233395Shsul@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243395Shsul@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253395Shsul@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263395Shsul@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273395Shsul@eecs.umich.edu */ 283395Shsul@eecs.umich.edu 293395Shsul@eecs.umich.edu#include <cmath> 303509Shsul@eecs.umich.edu#include <cstdio> 313395Shsul@eecs.umich.edu#include <cstdlib> 323395Shsul@eecs.umich.edu#include <iostream> 333395Shsul@eecs.umich.edu#include <iomanip> 343448Shsul@eecs.umich.edu#include <list> 353395Shsul@eecs.umich.edu#include <sstream> 363481Shsul@eecs.umich.edu#include <string> 373481Shsul@eecs.umich.edu 383481Shsul@eecs.umich.edu#include "base/cprintf.hh" 393481Shsul@eecs.umich.edu#include "base/inifile.hh" 405347Ssaidi@eecs.umich.edu#include "base/loader/symtab.hh" 413481Shsul@eecs.umich.edu#include "base/misc.hh" 423681Sktlim@umich.edu#include "base/pollevent.hh" 433681Sktlim@umich.edu#include "base/range.hh" 443681Sktlim@umich.edu#include "base/trace.hh" 455347Ssaidi@eecs.umich.edu#include "cpu/base_cpu.hh" 463481Shsul@eecs.umich.edu#include "cpu/exec_context.hh" 475347Ssaidi@eecs.umich.edu#include "cpu/exetrace.hh" 483481Shsul@eecs.umich.edu#include "cpu/full_cpu/smt.hh" 493481Shsul@eecs.umich.edu#include "cpu/simple_cpu/simple_cpu.hh" 503481Shsul@eecs.umich.edu#include "cpu/static_inst.hh" 513481Shsul@eecs.umich.edu#include "mem/base_mem.hh" 523481Shsul@eecs.umich.edu#include "mem/mem_interface.hh" 533481Shsul@eecs.umich.edu#include "sim/annotation.hh" 543481Shsul@eecs.umich.edu#include "sim/builder.hh" 553481Shsul@eecs.umich.edu#include "sim/debug.hh" 565347Ssaidi@eecs.umich.edu#include "sim/host.hh" 573481Shsul@eecs.umich.edu#include "sim/sim_events.hh" 583481Shsul@eecs.umich.edu#include "sim/sim_object.hh" 593481Shsul@eecs.umich.edu#include "sim/sim_stats.hh" 603481Shsul@eecs.umich.edu 613481Shsul@eecs.umich.edu#ifdef FULL_SYSTEM 623481Shsul@eecs.umich.edu#include "base/remote_gdb.hh" 633481Shsul@eecs.umich.edu#include "dev/alpha_access.h" 643395Shsul@eecs.umich.edu#include "dev/pciareg.h" 653395Shsul@eecs.umich.edu#include "mem/functional_mem/memory_control.hh" 663395Shsul@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh" 674167Sbinkertn@umich.edu#include "sim/system.hh" 683395Shsul@eecs.umich.edu#include "targetarch/alpha_memory.hh" 693395Shsul@eecs.umich.edu#include "targetarch/vtophys.hh" 703395Shsul@eecs.umich.edu#else // !FULL_SYSTEM 713511Shsul@eecs.umich.edu#include "eio/eio.hh" 723395Shsul@eecs.umich.edu#include "mem/functional_mem/functional_memory.hh" 733395Shsul@eecs.umich.edu#include "sim/prog.hh" 743395Shsul@eecs.umich.edu#endif // FULL_SYSTEM 755211Ssaidi@eecs.umich.edu 765211Ssaidi@eecs.umich.eduusing namespace std; 773395Shsul@eecs.umich.edu 783395Shsul@eecs.umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c) 793395Shsul@eecs.umich.edu : Event(&mainEventQueue, "SimpleCPU::TickEvent", 100), cpu(c) 803395Shsul@eecs.umich.edu{ 813395Shsul@eecs.umich.edu} 823481Shsul@eecs.umich.edu 833481Shsul@eecs.umich.eduvoid 843481Shsul@eecs.umich.eduSimpleCPU::TickEvent::process() 853481Shsul@eecs.umich.edu{ 863481Shsul@eecs.umich.edu cpu->tick(); 873481Shsul@eecs.umich.edu} 883481Shsul@eecs.umich.edu 893481Shsul@eecs.umich.educonst char * 903481Shsul@eecs.umich.eduSimpleCPU::TickEvent::description() 913481Shsul@eecs.umich.edu{ 923481Shsul@eecs.umich.edu return "SimpleCPU tick event"; 933481Shsul@eecs.umich.edu} 945311Ssaidi@eecs.umich.edu 953481Shsul@eecs.umich.edu 963395Shsul@eecs.umich.eduSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 973395Shsul@eecs.umich.edu : Event(&mainEventQueue, "SimpleCPU::CacheCompletionEvent"), 985353Svilas.sridharan@gmail.com cpu(_cpu) 995353Svilas.sridharan@gmail.com{ 1005353Svilas.sridharan@gmail.com} 1013395Shsul@eecs.umich.edu 1023395Shsul@eecs.umich.eduvoid SimpleCPU::CacheCompletionEvent::process() 1033478Shsul@eecs.umich.edu{ 1043395Shsul@eecs.umich.edu cpu->processCacheCompletion(); 1053478Shsul@eecs.umich.edu} 1063395Shsul@eecs.umich.edu 1073395Shsul@eecs.umich.educonst char * 1083478Shsul@eecs.umich.eduSimpleCPU::CacheCompletionEvent::description() 1093395Shsul@eecs.umich.edu{ 1103395Shsul@eecs.umich.edu return "SimpleCPU cache completion event"; 1113478Shsul@eecs.umich.edu} 1123395Shsul@eecs.umich.edu 1133478Shsul@eecs.umich.edu#ifdef FULL_SYSTEM 1143480Shsul@eecs.umich.eduSimpleCPU::SimpleCPU(const string &_name, 1155353Svilas.sridharan@gmail.com System *_system, 1165353Svilas.sridharan@gmail.com Counter max_insts_any_thread, 1175353Svilas.sridharan@gmail.com Counter max_insts_all_threads, 1185353Svilas.sridharan@gmail.com Counter max_loads_any_thread, 1195353Svilas.sridharan@gmail.com Counter max_loads_all_threads, 1203514Sktlim@umich.edu AlphaItb *itb, AlphaDtb *dtb, 1213481Shsul@eecs.umich.edu FunctionalMemory *mem, 1223480Shsul@eecs.umich.edu MemInterface *icache_interface, 1233480Shsul@eecs.umich.edu MemInterface *dcache_interface, 1243480Shsul@eecs.umich.edu Tick freq) 1253395Shsul@eecs.umich.edu : BaseCPU(_name, /* number_of_threads */ 1, 1263478Shsul@eecs.umich.edu max_insts_any_thread, max_insts_all_threads, 1273514Sktlim@umich.edu max_loads_any_thread, max_loads_all_threads, 1283514Sktlim@umich.edu _system, freq), 1293395Shsul@eecs.umich.edu#else 1303478Shsul@eecs.umich.eduSimpleCPU::SimpleCPU(const string &_name, Process *_process, 1313395Shsul@eecs.umich.edu Counter max_insts_any_thread, 1325353Svilas.sridharan@gmail.com Counter max_insts_all_threads, 1335353Svilas.sridharan@gmail.com Counter max_loads_any_thread, 1345353Svilas.sridharan@gmail.com Counter max_loads_all_threads, 1355353Svilas.sridharan@gmail.com MemInterface *icache_interface, 1363395Shsul@eecs.umich.edu MemInterface *dcache_interface) 1373395Shsul@eecs.umich.edu : BaseCPU(_name, /* number_of_threads */ 1, 1383395Shsul@eecs.umich.edu max_insts_any_thread, max_insts_all_threads, 1393395Shsul@eecs.umich.edu max_loads_any_thread, max_loads_all_threads), 1403395Shsul@eecs.umich.edu#endif 1413395Shsul@eecs.umich.edu tickEvent(this), xc(NULL), cacheCompletionEvent(this) 1423395Shsul@eecs.umich.edu{ 1433395Shsul@eecs.umich.edu _status = Idle; 1443395Shsul@eecs.umich.edu#ifdef FULL_SYSTEM 1453395Shsul@eecs.umich.edu xc = new ExecContext(this, 0, system, itb, dtb, mem); 1463395Shsul@eecs.umich.edu 1475073Ssaidi@eecs.umich.edu // initialize CPU, including PC 1483395Shsul@eecs.umich.edu TheISA::initCPU(&xc->regs); 1493395Shsul@eecs.umich.edu#else 1503395Shsul@eecs.umich.edu xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); 1513395Shsul@eecs.umich.edu#endif // !FULL_SYSTEM 1523395Shsul@eecs.umich.edu 1533395Shsul@eecs.umich.edu icacheInterface = icache_interface; 1543395Shsul@eecs.umich.edu dcacheInterface = dcache_interface; 1553395Shsul@eecs.umich.edu 1563395Shsul@eecs.umich.edu memReq = new MemReq(); 1573395Shsul@eecs.umich.edu memReq->xc = xc; 1583395Shsul@eecs.umich.edu memReq->asid = 0; 1593395Shsul@eecs.umich.edu memReq->data = new uint8_t[64]; 1603395Shsul@eecs.umich.edu 1613999Ssaidi@eecs.umich.edu numInst = 0; 1623999Ssaidi@eecs.umich.edu numLoad = 0; 1633999Ssaidi@eecs.umich.edu last_idle = 0; 1643999Ssaidi@eecs.umich.edu lastIcacheStall = 0; 1653395Shsul@eecs.umich.edu lastDcacheStall = 0; 1663509Shsul@eecs.umich.edu 1673395Shsul@eecs.umich.edu execContexts.push_back(xc); 1683481Shsul@eecs.umich.edu} 1693395Shsul@eecs.umich.edu 1703395Shsul@eecs.umich.eduSimpleCPU::~SimpleCPU() 1713395Shsul@eecs.umich.edu{ 1723395Shsul@eecs.umich.edu} 1733395Shsul@eecs.umich.edu 1743395Shsul@eecs.umich.edu 1753395Shsul@eecs.umich.eduvoid 1763395Shsul@eecs.umich.eduSimpleCPU::switchOut() 1773395Shsul@eecs.umich.edu{ 1783395Shsul@eecs.umich.edu _status = SwitchedOut; 1793395Shsul@eecs.umich.edu if (tickEvent.scheduled()) 1803395Shsul@eecs.umich.edu tickEvent.squash(); 1813481Shsul@eecs.umich.edu} 1825353Svilas.sridharan@gmail.com 1835353Svilas.sridharan@gmail.com 1845353Svilas.sridharan@gmail.comvoid 1855353Svilas.sridharan@gmail.comSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1865072Ssaidi@eecs.umich.edu{ 1873481Shsul@eecs.umich.edu BaseCPU::takeOverFrom(oldCPU); 1885072Ssaidi@eecs.umich.edu 1893395Shsul@eecs.umich.edu assert(!tickEvent.scheduled()); 1905353Svilas.sridharan@gmail.com 1915353Svilas.sridharan@gmail.com // if any of this CPU's ExecContexts are active, mark the CPU as 1925353Svilas.sridharan@gmail.com // running and schedule its tick event. 1935353Svilas.sridharan@gmail.com for (int i = 0; i < execContexts.size(); ++i) { 1945353Svilas.sridharan@gmail.com ExecContext *xc = execContexts[i]; 1955353Svilas.sridharan@gmail.com if (xc->status() == ExecContext::Active && _status != Running) { 1965353Svilas.sridharan@gmail.com _status = Running; 1975353Svilas.sridharan@gmail.com tickEvent.schedule(curTick); 1985353Svilas.sridharan@gmail.com } 1995353Svilas.sridharan@gmail.com } 2005353Svilas.sridharan@gmail.com 2015353Svilas.sridharan@gmail.com oldCPU->switchOut(); 2025353Svilas.sridharan@gmail.com} 2035353Svilas.sridharan@gmail.com 2045353Svilas.sridharan@gmail.com 2055353Svilas.sridharan@gmail.comvoid 2065353Svilas.sridharan@gmail.comSimpleCPU::execCtxStatusChg(int thread_num) { 2075353Svilas.sridharan@gmail.com assert(thread_num == 0); 2083395Shsul@eecs.umich.edu assert(xc); 2093395Shsul@eecs.umich.edu 2103395Shsul@eecs.umich.edu if (xc->status() == ExecContext::Active) 2113410Shsul@eecs.umich.edu setStatus(Running); 2123410Shsul@eecs.umich.edu else 2133410Shsul@eecs.umich.edu setStatus(Idle); 2143395Shsul@eecs.umich.edu} 2153395Shsul@eecs.umich.edu 2163395Shsul@eecs.umich.edu 2173395Shsul@eecs.umich.eduvoid 2183395Shsul@eecs.umich.eduSimpleCPU::regStats() 2193395Shsul@eecs.umich.edu{ 2203395Shsul@eecs.umich.edu BaseCPU::regStats(); 2213395Shsul@eecs.umich.edu 2223395Shsul@eecs.umich.edu numInsts 2233395Shsul@eecs.umich.edu .name(name() + ".num_insts") 2243509Shsul@eecs.umich.edu .desc("Number of instructions executed") 2253395Shsul@eecs.umich.edu ; 2263395Shsul@eecs.umich.edu 2273395Shsul@eecs.umich.edu numMemRefs 2283395Shsul@eecs.umich.edu .name(name() + ".num_refs") 2293999Ssaidi@eecs.umich.edu .desc("Number of memory references") 2305185Ssaidi@eecs.umich.edu ; 2313511Shsul@eecs.umich.edu 2323395Shsul@eecs.umich.edu idleCycles 2333395Shsul@eecs.umich.edu .name(name() + ".idle_cycles") 2343395Shsul@eecs.umich.edu .desc("Number of idle cycles") 2353395Shsul@eecs.umich.edu ; 2363395Shsul@eecs.umich.edu 2373395Shsul@eecs.umich.edu idleFraction 2383395Shsul@eecs.umich.edu .name(name() + ".idle_fraction") 2393395Shsul@eecs.umich.edu .desc("Percentage of idle cycles") 2403395Shsul@eecs.umich.edu ; 2413509Shsul@eecs.umich.edu 2423395Shsul@eecs.umich.edu icacheStallCycles 2433395Shsul@eecs.umich.edu .name(name() + ".icache_stall_cycles") 2445185Ssaidi@eecs.umich.edu .desc("ICache total stall cycles") 2453999Ssaidi@eecs.umich.edu .prereq(icacheStallCycles) 2463999Ssaidi@eecs.umich.edu ; 2473999Ssaidi@eecs.umich.edu 2483395Shsul@eecs.umich.edu dcacheStallCycles 2493395Shsul@eecs.umich.edu .name(name() + ".dcache_stall_cycles") 2503395Shsul@eecs.umich.edu .desc("DCache total stall cycles") 2513395Shsul@eecs.umich.edu .prereq(dcacheStallCycles) 2523509Shsul@eecs.umich.edu ; 2533395Shsul@eecs.umich.edu 2543395Shsul@eecs.umich.edu idleFraction = idleCycles / simTicks; 2553395Shsul@eecs.umich.edu 2563395Shsul@eecs.umich.edu numInsts = Statistics::scalar(numInst); 2573395Shsul@eecs.umich.edu simInsts += numInsts; 2583511Shsul@eecs.umich.edu} 2593395Shsul@eecs.umich.edu 2603395Shsul@eecs.umich.eduvoid 2613395Shsul@eecs.umich.eduSimpleCPU::serialize(ostream &os) 2623395Shsul@eecs.umich.edu{ 2633514Sktlim@umich.edu SERIALIZE_ENUM(_status); 2643395Shsul@eecs.umich.edu SERIALIZE_SCALAR(inst); 265 xc->serialize(os); 266 nameOut(os, csprintf("%s.tickEvent", name())); 267 tickEvent.serialize(os); 268 nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 269 cacheCompletionEvent.serialize(os); 270} 271 272void 273SimpleCPU::unserialize(const IniFile *db, const string §ion) 274{ 275 UNSERIALIZE_ENUM(_status); 276 UNSERIALIZE_SCALAR(inst); 277 xc->unserialize(db, section); 278 tickEvent.unserialize(db, csprintf("%s.tickEvent", name())); 279 cacheCompletionEvent 280 .unserialize(db, csprintf("%s.cacheCompletionEvent", name())); 281} 282 283void 284change_thread_state(int thread_number, int activate, int priority) 285{ 286} 287 288// precise architected memory state accessor macros 289template <class T> 290Fault 291SimpleCPU::read(Addr addr, T& data, unsigned flags) 292{ 293 memReq->reset(addr, sizeof(T), flags); 294 295 // translate to physical address 296 Fault fault = xc->translateDataReadReq(memReq); 297 298 // do functional access 299 if (fault == No_Fault) 300 fault = xc->read(memReq, data); 301 302 if (traceData) { 303 traceData->setAddr(addr); 304 if (fault == No_Fault) 305 traceData->setData(data); 306 } 307 308 // if we have a cache, do cache access too 309 if (fault == No_Fault && dcacheInterface) { 310 memReq->cmd = Read; 311 memReq->completionEvent = NULL; 312 memReq->time = curTick; 313 memReq->flags &= ~UNCACHEABLE; 314 MemAccessResult result = dcacheInterface->access(memReq); 315 316 // Ugly hack to get an event scheduled *only* if the access is 317 // a miss. We really should add first-class support for this 318 // at some point. 319 if (result != MA_HIT && dcacheInterface->doEvents) { 320 memReq->completionEvent = &cacheCompletionEvent; 321 setStatus(DcacheMissStall); 322 } 323 } 324 325 return fault; 326} 327 328#ifndef DOXYGEN_SHOULD_SKIP_THIS 329 330template 331Fault 332SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags); 333 334template 335Fault 336SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags); 337 338template 339Fault 340SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags); 341 342template 343Fault 344SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags); 345 346#endif //DOXYGEN_SHOULD_SKIP_THIS 347 348template<> 349Fault 350SimpleCPU::read(Addr addr, double& data, unsigned flags) 351{ 352 return read(addr, *(uint64_t*)&data, flags); 353} 354 355template<> 356Fault 357SimpleCPU::read(Addr addr, float& data, unsigned flags) 358{ 359 return read(addr, *(uint32_t*)&data, flags); 360} 361 362 363template<> 364Fault 365SimpleCPU::read(Addr addr, int32_t& data, unsigned flags) 366{ 367 return read(addr, (uint32_t&)data, flags); 368} 369 370 371template <class T> 372Fault 373SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 374{ 375 if (traceData) { 376 traceData->setAddr(addr); 377 traceData->setData(data); 378 } 379 380 memReq->reset(addr, sizeof(T), flags); 381 382 // translate to physical address 383 Fault fault = xc->translateDataWriteReq(memReq); 384 385 // do functional access 386 if (fault == No_Fault) 387 fault = xc->write(memReq, data); 388 389 if (fault == No_Fault && dcacheInterface) { 390 memReq->cmd = Write; 391 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 392 memReq->completionEvent = NULL; 393 memReq->time = curTick; 394 memReq->flags &= ~UNCACHEABLE; 395 MemAccessResult result = dcacheInterface->access(memReq); 396 397 // Ugly hack to get an event scheduled *only* if the access is 398 // a miss. We really should add first-class support for this 399 // at some point. 400 if (result != MA_HIT && dcacheInterface->doEvents) { 401 memReq->completionEvent = &cacheCompletionEvent; 402 setStatus(DcacheMissStall); 403 } 404 } 405 406 if (res && (fault == No_Fault)) 407 *res = memReq->result; 408 409 return fault; 410} 411 412 413#ifndef DOXYGEN_SHOULD_SKIP_THIS 414template 415Fault 416SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 417 418template 419Fault 420SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 421 422template 423Fault 424SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 425 426template 427Fault 428SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 429 430#endif //DOXYGEN_SHOULD_SKIP_THIS 431 432template<> 433Fault 434SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 435{ 436 return write(*(uint64_t*)&data, addr, flags, res); 437} 438 439template<> 440Fault 441SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 442{ 443 return write(*(uint32_t*)&data, addr, flags, res); 444} 445 446 447template<> 448Fault 449SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 450{ 451 return write((uint32_t)data, addr, flags, res); 452} 453 454 455#ifdef FULL_SYSTEM 456Addr 457SimpleCPU::dbg_vtophys(Addr addr) 458{ 459 return vtophys(xc, addr); 460} 461#endif // FULL_SYSTEM 462 463Tick save_cycle = 0; 464 465 466void 467SimpleCPU::processCacheCompletion() 468{ 469 switch (status()) { 470 case IcacheMissStall: 471 icacheStallCycles += curTick - lastIcacheStall; 472 setStatus(IcacheMissComplete); 473 break; 474 case DcacheMissStall: 475 dcacheStallCycles += curTick - lastDcacheStall; 476 setStatus(Running); 477 break; 478 case SwitchedOut: 479 // If this CPU has been switched out due to sampling/warm-up, 480 // ignore any further status changes (e.g., due to cache 481 // misses outstanding at the time of the switch). 482 return; 483 default: 484 panic("SimpleCPU::processCacheCompletion: bad state"); 485 break; 486 } 487} 488 489#ifdef FULL_SYSTEM 490void 491SimpleCPU::post_interrupt(int int_num, int index) 492{ 493 BaseCPU::post_interrupt(int_num, index); 494 495 if (xc->status() == ExecContext::Suspended) { 496 DPRINTF(IPI,"Suspended Processor awoke\n"); 497 xc->setStatus(ExecContext::Active); 498 Annotate::Resume(xc); 499 } 500} 501#endif // FULL_SYSTEM 502 503/* start simulation, program loaded, processor precise state initialized */ 504void 505SimpleCPU::tick() 506{ 507 traceData = NULL; 508 509 Fault fault = No_Fault; 510 511#ifdef FULL_SYSTEM 512 if (AlphaISA::check_interrupts && 513 xc->cpu->check_interrupts() && 514 !PC_PAL(xc->regs.pc) && 515 status() != IcacheMissComplete) { 516 int ipl = 0; 517 int summary = 0; 518 AlphaISA::check_interrupts = 0; 519 IntReg *ipr = xc->regs.ipr; 520 521 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 522 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 523 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 524 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 525 // See table 4-19 of 21164 hardware reference 526 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 527 summary |= (ULL(1) << i); 528 } 529 } 530 } 531 532 uint64_t interrupts = xc->cpu->intr_status(); 533 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 534 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 535 if (interrupts & (ULL(1) << i)) { 536 // See table 4-19 of 21164 hardware reference 537 ipl = i; 538 summary |= (ULL(1) << i); 539 } 540 } 541 542 if (ipr[TheISA::IPR_ASTRR]) 543 panic("asynchronous traps not implemented\n"); 544 545 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 546 ipr[TheISA::IPR_ISR] = summary; 547 ipr[TheISA::IPR_INTID] = ipl; 548 xc->ev5_trap(Interrupt_Fault); 549 550 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 551 ipr[TheISA::IPR_IPLR], ipl, summary); 552 } 553 } 554#endif 555 556 // maintain $r0 semantics 557 xc->regs.intRegFile[ZeroReg] = 0; 558#ifdef TARGET_ALPHA 559 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 560#endif // TARGET_ALPHA 561 562 if (status() == IcacheMissComplete) { 563 // We've already fetched an instruction and were stalled on an 564 // I-cache miss. No need to fetch it again. 565 566 setStatus(Running); 567 } 568 else { 569 // Try to fetch an instruction 570 571 // set up memory request for instruction fetch 572#ifdef FULL_SYSTEM 573#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 574#else 575#define IFETCH_FLAGS(pc) 0 576#endif 577 578 memReq->cmd = Read; 579 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 580 IFETCH_FLAGS(xc->regs.pc)); 581 582 fault = xc->translateInstReq(memReq); 583 584 if (fault == No_Fault) 585 fault = xc->mem->read(memReq, inst); 586 587 if (icacheInterface && fault == No_Fault) { 588 memReq->completionEvent = NULL; 589 590 memReq->time = curTick; 591 memReq->flags &= ~UNCACHEABLE; 592 MemAccessResult result = icacheInterface->access(memReq); 593 594 // Ugly hack to get an event scheduled *only* if the access is 595 // a miss. We really should add first-class support for this 596 // at some point. 597 if (result != MA_HIT && icacheInterface->doEvents) { 598 memReq->completionEvent = &cacheCompletionEvent; 599 setStatus(IcacheMissStall); 600 return; 601 } 602 } 603 } 604 605 // If we've got a valid instruction (i.e., no fault on instruction 606 // fetch), then execute it. 607 if (fault == No_Fault) { 608 609 // keep an instruction count 610 numInst++; 611 612 // check for instruction-count-based events 613 comInsnEventQueue[0]->serviceEvents(numInst); 614 615 // decode the instruction 616 StaticInstPtr<TheISA> si(inst); 617 618 traceData = Trace::getInstRecord(curTick, xc, this, si, 619 xc->regs.pc); 620 621#ifdef FULL_SYSTEM 622 xc->regs.opcode = (inst >> 26) & 0x3f; 623 xc->regs.ra = (inst >> 21) & 0x1f; 624#endif // FULL_SYSTEM 625 626 xc->func_exe_insn++; 627 628 fault = si->execute(this, xc, traceData); 629 630 if (si->isMemRef()) { 631 numMemRefs++; 632 } 633 634 if (si->isLoad()) { 635 ++numLoad; 636 comLoadEventQueue[0]->serviceEvents(numLoad); 637 } 638 639 if (traceData) 640 traceData->finalize(); 641 642 } // if (fault == No_Fault) 643 644 if (fault != No_Fault) { 645#ifdef FULL_SYSTEM 646 xc->ev5_trap(fault); 647#else // !FULL_SYSTEM 648 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 649#endif // FULL_SYSTEM 650 } 651 else { 652 // go to the next instruction 653 xc->regs.pc = xc->regs.npc; 654 xc->regs.npc += sizeof(MachInst); 655 } 656 657#ifdef FULL_SYSTEM 658 Addr oldpc; 659 do { 660 oldpc = xc->regs.pc; 661 system->pcEventQueue.service(xc); 662 } while (oldpc != xc->regs.pc); 663#endif 664 665 assert(status() == Running || 666 status() == Idle || 667 status() == DcacheMissStall); 668 669 if (status() == Running && !tickEvent.scheduled()) 670 tickEvent.schedule(curTick + 1); 671} 672 673 674//////////////////////////////////////////////////////////////////////// 675// 676// SimpleCPU Simulation Object 677// 678BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 679 680 Param<Counter> max_insts_any_thread; 681 Param<Counter> max_insts_all_threads; 682 Param<Counter> max_loads_any_thread; 683 Param<Counter> max_loads_all_threads; 684 685#ifdef FULL_SYSTEM 686 SimObjectParam<AlphaItb *> itb; 687 SimObjectParam<AlphaDtb *> dtb; 688 SimObjectParam<FunctionalMemory *> mem; 689 SimObjectParam<System *> system; 690 Param<int> mult; 691#else 692 SimObjectParam<Process *> workload; 693#endif // FULL_SYSTEM 694 695 SimObjectParam<BaseMem *> icache; 696 SimObjectParam<BaseMem *> dcache; 697 698 Param<bool> defer_registration; 699 700END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 701 702BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 703 704 INIT_PARAM_DFLT(max_insts_any_thread, 705 "terminate when any thread reaches this insn count", 706 0), 707 INIT_PARAM_DFLT(max_insts_all_threads, 708 "terminate when all threads have reached this insn count", 709 0), 710 INIT_PARAM_DFLT(max_loads_any_thread, 711 "terminate when any thread reaches this load count", 712 0), 713 INIT_PARAM_DFLT(max_loads_all_threads, 714 "terminate when all threads have reached this load count", 715 0), 716 717#ifdef FULL_SYSTEM 718 INIT_PARAM(itb, "Instruction TLB"), 719 INIT_PARAM(dtb, "Data TLB"), 720 INIT_PARAM(mem, "memory"), 721 INIT_PARAM(system, "system object"), 722 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 723#else 724 INIT_PARAM(workload, "processes to run"), 725#endif // FULL_SYSTEM 726 727 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 728 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), 729 INIT_PARAM_DFLT(defer_registration, "defer registration with system " 730 "(for sampling)", false) 731 732END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 733 734 735CREATE_SIM_OBJECT(SimpleCPU) 736{ 737 SimpleCPU *cpu; 738#ifdef FULL_SYSTEM 739 if (mult != 1) 740 panic("processor clock multiplier must be 1\n"); 741 742 cpu = new SimpleCPU(getInstanceName(), system, 743 max_insts_any_thread, max_insts_all_threads, 744 max_loads_any_thread, max_loads_all_threads, 745 itb, dtb, mem, 746 (icache) ? icache->getInterface() : NULL, 747 (dcache) ? dcache->getInterface() : NULL, 748 ticksPerSecond * mult); 749#else 750 751 cpu = new SimpleCPU(getInstanceName(), workload, 752 max_insts_any_thread, max_insts_all_threads, 753 max_loads_any_thread, max_loads_all_threads, 754 (icache) ? icache->getInterface() : NULL, 755 (dcache) ? dcache->getInterface() : NULL); 756 757#endif // FULL_SYSTEM 758 759 if (!defer_registration) { 760 cpu->registerExecContexts(); 761 } 762 763 return cpu; 764} 765 766REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 767