timing.cc revision 2867:cc92d58a3210
16973Stjones1@inf.ed.ac.uk/* 27944SGiacomo.Gabrielli@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 37944SGiacomo.Gabrielli@arm.com * All rights reserved. 47944SGiacomo.Gabrielli@arm.com * 57944SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 67944SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are 77944SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright 87944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 97944SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 107944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 117944SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution; 127944SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its 137944SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from 146973Stjones1@inf.ed.ac.uk * this software without specific prior written permission. 156973Stjones1@inf.ed.ac.uk * 166973Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176973Stjones1@inf.ed.ac.uk * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186973Stjones1@inf.ed.ac.uk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196973Stjones1@inf.ed.ac.uk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206973Stjones1@inf.ed.ac.uk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216973Stjones1@inf.ed.ac.uk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226973Stjones1@inf.ed.ac.uk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236973Stjones1@inf.ed.ac.uk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246973Stjones1@inf.ed.ac.uk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256973Stjones1@inf.ed.ac.uk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266973Stjones1@inf.ed.ac.uk * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276973Stjones1@inf.ed.ac.uk * 286973Stjones1@inf.ed.ac.uk * Authors: Steve Reinhardt 296973Stjones1@inf.ed.ac.uk */ 306973Stjones1@inf.ed.ac.uk 316973Stjones1@inf.ed.ac.uk#include "arch/utility.hh" 326973Stjones1@inf.ed.ac.uk#include "cpu/exetrace.hh" 336973Stjones1@inf.ed.ac.uk#include "cpu/simple/timing.hh" 346973Stjones1@inf.ed.ac.uk#include "mem/packet_impl.hh" 356973Stjones1@inf.ed.ac.uk#include "sim/builder.hh" 366973Stjones1@inf.ed.ac.uk 376973Stjones1@inf.ed.ac.ukusing namespace std; 386973Stjones1@inf.ed.ac.ukusing namespace TheISA; 396973Stjones1@inf.ed.ac.uk 406973Stjones1@inf.ed.ac.uk 416973Stjones1@inf.ed.ac.ukvoid 426973Stjones1@inf.ed.ac.ukTimingSimpleCPU::init() 436973Stjones1@inf.ed.ac.uk{ 446973Stjones1@inf.ed.ac.uk //Create Memory Ports (conect them up) 456973Stjones1@inf.ed.ac.uk Port *mem_dport = mem->getPort(""); 466973Stjones1@inf.ed.ac.uk dcachePort.setPeer(mem_dport); 476973Stjones1@inf.ed.ac.uk mem_dport->setPeer(&dcachePort); 487678Sgblack@eecs.umich.edu 496973Stjones1@inf.ed.ac.uk Port *mem_iport = mem->getPort(""); 506973Stjones1@inf.ed.ac.uk icachePort.setPeer(mem_iport); 517049Stjones1@inf.ed.ac.uk mem_iport->setPeer(&icachePort); 527049Stjones1@inf.ed.ac.uk 537049Stjones1@inf.ed.ac.uk BaseCPU::init(); 547049Stjones1@inf.ed.ac.uk#if FULL_SYSTEM 557049Stjones1@inf.ed.ac.uk for (int i = 0; i < threadContexts.size(); ++i) { 567049Stjones1@inf.ed.ac.uk ThreadContext *tc = threadContexts[i]; 577049Stjones1@inf.ed.ac.uk 587049Stjones1@inf.ed.ac.uk // initialize CPU, including PC 597049Stjones1@inf.ed.ac.uk TheISA::initCPU(tc, tc->readCpuId()); 607049Stjones1@inf.ed.ac.uk } 616973Stjones1@inf.ed.ac.uk#endif 626973Stjones1@inf.ed.ac.uk} 636973Stjones1@inf.ed.ac.uk 646973Stjones1@inf.ed.ac.ukTick 656973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) 666973Stjones1@inf.ed.ac.uk{ 676973Stjones1@inf.ed.ac.uk panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 687944SGiacomo.Gabrielli@arm.com return curTick; 696973Stjones1@inf.ed.ac.uk} 706973Stjones1@inf.ed.ac.uk 716973Stjones1@inf.ed.ac.ukvoid 726973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) 736973Stjones1@inf.ed.ac.uk{ 746973Stjones1@inf.ed.ac.uk panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); 756973Stjones1@inf.ed.ac.uk} 766973Stjones1@inf.ed.ac.uk 777049Stjones1@inf.ed.ac.ukvoid 787049Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 797049Stjones1@inf.ed.ac.uk{ 807049Stjones1@inf.ed.ac.uk if (status == RangeChange) 816973Stjones1@inf.ed.ac.uk return; 826973Stjones1@inf.ed.ac.uk 837944SGiacomo.Gabrielli@arm.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 847944SGiacomo.Gabrielli@arm.com} 856973Stjones1@inf.ed.ac.uk 866973Stjones1@inf.ed.ac.ukTimingSimpleCPU::TimingSimpleCPU(Params *p) 876973Stjones1@inf.ed.ac.uk : BaseSimpleCPU(p), icachePort(this), dcachePort(this) 886973Stjones1@inf.ed.ac.uk{ 896973Stjones1@inf.ed.ac.uk _status = Idle; 907049Stjones1@inf.ed.ac.uk ifetch_pkt = dcache_pkt = NULL; 917049Stjones1@inf.ed.ac.uk drainEvent = NULL; 927049Stjones1@inf.ed.ac.uk fetchEvent = NULL; 937049Stjones1@inf.ed.ac.uk state = SimObject::Timing; 947049Stjones1@inf.ed.ac.uk} 956973Stjones1@inf.ed.ac.uk 966973Stjones1@inf.ed.ac.uk 976973Stjones1@inf.ed.ac.ukTimingSimpleCPU::~TimingSimpleCPU() 987944SGiacomo.Gabrielli@arm.com{ 997944SGiacomo.Gabrielli@arm.com} 1007944SGiacomo.Gabrielli@arm.com 1016973Stjones1@inf.ed.ac.ukvoid 1026973Stjones1@inf.ed.ac.ukTimingSimpleCPU::serialize(ostream &os) 1036973Stjones1@inf.ed.ac.uk{ 1046973Stjones1@inf.ed.ac.uk SERIALIZE_ENUM(_status); 1056973Stjones1@inf.ed.ac.uk BaseSimpleCPU::serialize(os); 1067049Stjones1@inf.ed.ac.uk} 1077049Stjones1@inf.ed.ac.uk 1087049Stjones1@inf.ed.ac.ukvoid 1097049Stjones1@inf.ed.ac.ukTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1107049Stjones1@inf.ed.ac.uk{ 1117049Stjones1@inf.ed.ac.uk UNSERIALIZE_ENUM(_status); 1127049Stjones1@inf.ed.ac.uk BaseSimpleCPU::unserialize(cp, section); 1136973Stjones1@inf.ed.ac.uk} 1146973Stjones1@inf.ed.ac.uk 1156973Stjones1@inf.ed.ac.ukbool 1166973Stjones1@inf.ed.ac.ukTimingSimpleCPU::drain(Event *drain_event) 1176973Stjones1@inf.ed.ac.uk{ 1186973Stjones1@inf.ed.ac.uk // TimingSimpleCPU is ready to drain if it's not waiting for 1196973Stjones1@inf.ed.ac.uk // an access to complete. 1206973Stjones1@inf.ed.ac.uk if (status() == Idle || status() == Running || status() == SwitchedOut) { 1216973Stjones1@inf.ed.ac.uk changeState(SimObject::DrainedTiming); 1226973Stjones1@inf.ed.ac.uk return true; 1236973Stjones1@inf.ed.ac.uk } else { 1246973Stjones1@inf.ed.ac.uk changeState(SimObject::Draining); 1256973Stjones1@inf.ed.ac.uk drainEvent = drain_event; 1266973Stjones1@inf.ed.ac.uk return false; 1276973Stjones1@inf.ed.ac.uk } 1286973Stjones1@inf.ed.ac.uk} 1296973Stjones1@inf.ed.ac.uk 1306973Stjones1@inf.ed.ac.ukvoid 1317049Stjones1@inf.ed.ac.ukTimingSimpleCPU::resume() 1327049Stjones1@inf.ed.ac.uk{ 1337049Stjones1@inf.ed.ac.uk if (_status != SwitchedOut && _status != Idle) { 1347049Stjones1@inf.ed.ac.uk // Delete the old event if it existed. 1356973Stjones1@inf.ed.ac.uk if (fetchEvent) { 1366973Stjones1@inf.ed.ac.uk assert(!fetchEvent->scheduled()); 1376973Stjones1@inf.ed.ac.uk delete fetchEvent; 1386973Stjones1@inf.ed.ac.uk } 1396973Stjones1@inf.ed.ac.uk 1406973Stjones1@inf.ed.ac.uk fetchEvent = 1416973Stjones1@inf.ed.ac.uk new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 1426973Stjones1@inf.ed.ac.uk fetchEvent->schedule(curTick); 1436973Stjones1@inf.ed.ac.uk } 1446973Stjones1@inf.ed.ac.uk} 1456973Stjones1@inf.ed.ac.uk 1466973Stjones1@inf.ed.ac.ukvoid 1476973Stjones1@inf.ed.ac.ukTimingSimpleCPU::setMemoryMode(State new_mode) 1487049Stjones1@inf.ed.ac.uk{ 1496973Stjones1@inf.ed.ac.uk assert(new_mode == SimObject::Timing); 1506973Stjones1@inf.ed.ac.uk} 1516973Stjones1@inf.ed.ac.uk 1526973Stjones1@inf.ed.ac.ukvoid 1536973Stjones1@inf.ed.ac.ukTimingSimpleCPU::switchOut() 1546973Stjones1@inf.ed.ac.uk{ 1557049Stjones1@inf.ed.ac.uk assert(status() == Running || status() == Idle); 1567049Stjones1@inf.ed.ac.uk _status = SwitchedOut; 1577049Stjones1@inf.ed.ac.uk 1587049Stjones1@inf.ed.ac.uk // If we've been scheduled to resume but are then told to switch out, 1597049Stjones1@inf.ed.ac.uk // we'll need to cancel it. 1606973Stjones1@inf.ed.ac.uk if (fetchEvent && fetchEvent->scheduled()) 1616973Stjones1@inf.ed.ac.uk fetchEvent->deschedule(); 1626973Stjones1@inf.ed.ac.uk} 1636973Stjones1@inf.ed.ac.uk 1646973Stjones1@inf.ed.ac.uk 1656973Stjones1@inf.ed.ac.ukvoid 1667049Stjones1@inf.ed.ac.ukTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1677049Stjones1@inf.ed.ac.uk{ 1687049Stjones1@inf.ed.ac.uk BaseCPU::takeOverFrom(oldCPU); 1697049Stjones1@inf.ed.ac.uk 1707049Stjones1@inf.ed.ac.uk // if any of this CPU's ThreadContexts are active, mark the CPU as 1716973Stjones1@inf.ed.ac.uk // running and schedule its tick event. 1726973Stjones1@inf.ed.ac.uk for (int i = 0; i < threadContexts.size(); ++i) { 1736973Stjones1@inf.ed.ac.uk ThreadContext *tc = threadContexts[i]; 1746973Stjones1@inf.ed.ac.uk if (tc->status() == ThreadContext::Active && _status != Running) { 1756973Stjones1@inf.ed.ac.uk _status = Running; 1766973Stjones1@inf.ed.ac.uk break; 1777049Stjones1@inf.ed.ac.uk } 1786973Stjones1@inf.ed.ac.uk } 1796973Stjones1@inf.ed.ac.uk} 1806973Stjones1@inf.ed.ac.uk 1816973Stjones1@inf.ed.ac.uk 1826973Stjones1@inf.ed.ac.ukvoid 1836973Stjones1@inf.ed.ac.ukTimingSimpleCPU::activateContext(int thread_num, int delay) 1847049Stjones1@inf.ed.ac.uk{ 1857049Stjones1@inf.ed.ac.uk assert(thread_num == 0); 1867049Stjones1@inf.ed.ac.uk assert(thread); 1877049Stjones1@inf.ed.ac.uk 1887049Stjones1@inf.ed.ac.uk assert(_status == Idle); 1896973Stjones1@inf.ed.ac.uk 1906973Stjones1@inf.ed.ac.uk notIdleFraction++; 1916973Stjones1@inf.ed.ac.uk _status = Running; 1926973Stjones1@inf.ed.ac.uk // kick things off by initiating the fetch of the next instruction 1936973Stjones1@inf.ed.ac.uk fetchEvent = 1946973Stjones1@inf.ed.ac.uk new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 1957049Stjones1@inf.ed.ac.uk fetchEvent->schedule(curTick + cycles(delay)); 1966973Stjones1@inf.ed.ac.uk} 1976973Stjones1@inf.ed.ac.uk 1986973Stjones1@inf.ed.ac.uk 1996973Stjones1@inf.ed.ac.ukvoid 2006973Stjones1@inf.ed.ac.ukTimingSimpleCPU::suspendContext(int thread_num) 2016973Stjones1@inf.ed.ac.uk{ 2026973Stjones1@inf.ed.ac.uk assert(thread_num == 0); 2036973Stjones1@inf.ed.ac.uk assert(thread); 2046973Stjones1@inf.ed.ac.uk 2056973Stjones1@inf.ed.ac.uk assert(_status == Running); 2066973Stjones1@inf.ed.ac.uk 2077049Stjones1@inf.ed.ac.uk // just change status to Idle... if status != Running, 2087049Stjones1@inf.ed.ac.uk // completeInst() will not initiate fetch of next instruction. 2097049Stjones1@inf.ed.ac.uk 2107049Stjones1@inf.ed.ac.uk notIdleFraction--; 2117049Stjones1@inf.ed.ac.uk _status = Idle; 2127049Stjones1@inf.ed.ac.uk} 2137049Stjones1@inf.ed.ac.uk 2147049Stjones1@inf.ed.ac.uk 2157049Stjones1@inf.ed.ac.uktemplate <class T> 2167049Stjones1@inf.ed.ac.ukFault 2178486Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 2186973Stjones1@inf.ed.ac.uk{ 2196973Stjones1@inf.ed.ac.uk // need to fill in CPU & thread IDs here 2206973Stjones1@inf.ed.ac.uk Request *data_read_req = new Request(); 2218486Sgblack@eecs.umich.edu data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 2226973Stjones1@inf.ed.ac.uk data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 2236973Stjones1@inf.ed.ac.uk 2246973Stjones1@inf.ed.ac.uk if (traceData) { 2256973Stjones1@inf.ed.ac.uk traceData->setAddr(data_read_req->getVaddr()); 2268486Sgblack@eecs.umich.edu } 2276973Stjones1@inf.ed.ac.uk 2286973Stjones1@inf.ed.ac.uk // translate to physical address 2296973Stjones1@inf.ed.ac.uk Fault fault = thread->translateDataReadReq(data_read_req); 2306973Stjones1@inf.ed.ac.uk 2318486Sgblack@eecs.umich.edu // Now do the access. 2326973Stjones1@inf.ed.ac.uk if (fault == NoFault) { 2336973Stjones1@inf.ed.ac.uk Packet *data_read_pkt = 2346973Stjones1@inf.ed.ac.uk new Packet(data_read_req, Packet::ReadReq, Packet::Broadcast); 2356973Stjones1@inf.ed.ac.uk data_read_pkt->dataDynamic<T>(new T); 2366973Stjones1@inf.ed.ac.uk 2377049Stjones1@inf.ed.ac.uk if (!dcachePort.sendTiming(data_read_pkt)) { 2387944SGiacomo.Gabrielli@arm.com _status = DcacheRetry; 2397944SGiacomo.Gabrielli@arm.com dcache_pkt = data_read_pkt; 2407944SGiacomo.Gabrielli@arm.com } else { 2417944SGiacomo.Gabrielli@arm.com _status = DcacheWaitResponse; 2427944SGiacomo.Gabrielli@arm.com dcache_pkt = NULL; 2437944SGiacomo.Gabrielli@arm.com } 2447944SGiacomo.Gabrielli@arm.com } 2457944SGiacomo.Gabrielli@arm.com 2467944SGiacomo.Gabrielli@arm.com // This will need a new way to tell if it has a dcache attached. 2477944SGiacomo.Gabrielli@arm.com if (data_read_req->getFlags() & UNCACHEABLE) 2487049Stjones1@inf.ed.ac.uk recordEvent("Uncached Read"); 2497049Stjones1@inf.ed.ac.uk 2507049Stjones1@inf.ed.ac.uk return fault; 2516973Stjones1@inf.ed.ac.uk} 2526973Stjones1@inf.ed.ac.uk 2536973Stjones1@inf.ed.ac.uk#ifndef DOXYGEN_SHOULD_SKIP_THIS 2546973Stjones1@inf.ed.ac.uk 2556973Stjones1@inf.ed.ac.uktemplate 2566973Stjones1@inf.ed.ac.ukFault 2576973Stjones1@inf.ed.ac.ukTimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 2586973Stjones1@inf.ed.ac.uk 2596973Stjones1@inf.ed.ac.uktemplate 2606973Stjones1@inf.ed.ac.ukFault 2616973Stjones1@inf.ed.ac.ukTimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 2626973Stjones1@inf.ed.ac.uk 2636973Stjones1@inf.ed.ac.uktemplate 2646973Stjones1@inf.ed.ac.ukFault 265TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 266 267template 268Fault 269TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 270 271#endif //DOXYGEN_SHOULD_SKIP_THIS 272 273template<> 274Fault 275TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 276{ 277 return read(addr, *(uint64_t*)&data, flags); 278} 279 280template<> 281Fault 282TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 283{ 284 return read(addr, *(uint32_t*)&data, flags); 285} 286 287 288template<> 289Fault 290TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 291{ 292 return read(addr, (uint32_t&)data, flags); 293} 294 295 296template <class T> 297Fault 298TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 299{ 300 // need to fill in CPU & thread IDs here 301 Request *data_write_req = new Request(); 302 data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 303 data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 304 305 // translate to physical address 306 Fault fault = thread->translateDataWriteReq(data_write_req); 307 // Now do the access. 308 if (fault == NoFault) { 309 Packet *data_write_pkt = 310 new Packet(data_write_req, Packet::WriteReq, Packet::Broadcast); 311 data_write_pkt->allocate(); 312 data_write_pkt->set(data); 313 314 if (!dcachePort.sendTiming(data_write_pkt)) { 315 _status = DcacheRetry; 316 dcache_pkt = data_write_pkt; 317 } else { 318 _status = DcacheWaitResponse; 319 dcache_pkt = NULL; 320 } 321 } 322 323 // This will need a new way to tell if it's hooked up to a cache or not. 324 if (data_write_req->getFlags() & UNCACHEABLE) 325 recordEvent("Uncached Write"); 326 327 // If the write needs to have a fault on the access, consider calling 328 // changeStatus() and changing it to "bad addr write" or something. 329 return fault; 330} 331 332 333#ifndef DOXYGEN_SHOULD_SKIP_THIS 334template 335Fault 336TimingSimpleCPU::write(uint64_t data, Addr addr, 337 unsigned flags, uint64_t *res); 338 339template 340Fault 341TimingSimpleCPU::write(uint32_t data, Addr addr, 342 unsigned flags, uint64_t *res); 343 344template 345Fault 346TimingSimpleCPU::write(uint16_t data, Addr addr, 347 unsigned flags, uint64_t *res); 348 349template 350Fault 351TimingSimpleCPU::write(uint8_t data, Addr addr, 352 unsigned flags, uint64_t *res); 353 354#endif //DOXYGEN_SHOULD_SKIP_THIS 355 356template<> 357Fault 358TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 359{ 360 return write(*(uint64_t*)&data, addr, flags, res); 361} 362 363template<> 364Fault 365TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 366{ 367 return write(*(uint32_t*)&data, addr, flags, res); 368} 369 370 371template<> 372Fault 373TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 374{ 375 return write((uint32_t)data, addr, flags, res); 376} 377 378 379void 380TimingSimpleCPU::fetch() 381{ 382 checkForInterrupts(); 383 384 // need to fill in CPU & thread IDs here 385 Request *ifetch_req = new Request(); 386 ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 387 Fault fault = setupFetchRequest(ifetch_req); 388 389 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 390 ifetch_pkt->dataStatic(&inst); 391 392 if (fault == NoFault) { 393 if (!icachePort.sendTiming(ifetch_pkt)) { 394 // Need to wait for retry 395 _status = IcacheRetry; 396 } else { 397 // Need to wait for cache to respond 398 _status = IcacheWaitResponse; 399 // ownership of packet transferred to memory system 400 ifetch_pkt = NULL; 401 } 402 } else { 403 // fetch fault: advance directly to next instruction (fault handler) 404 advanceInst(fault); 405 } 406} 407 408 409void 410TimingSimpleCPU::advanceInst(Fault fault) 411{ 412 advancePC(fault); 413 414 if (_status == Running) { 415 // kick off fetch of next instruction... callback from icache 416 // response will cause that instruction to be executed, 417 // keeping the CPU running. 418 fetch(); 419 } 420} 421 422 423void 424TimingSimpleCPU::completeIfetch(Packet *pkt) 425{ 426 // received a response from the icache: execute the received 427 // instruction 428 assert(pkt->result == Packet::Success); 429 assert(_status == IcacheWaitResponse); 430 431 _status = Running; 432 433 delete pkt->req; 434 delete pkt; 435 436 if (getState() == SimObject::Draining) { 437 completeDrain(); 438 return; 439 } 440 441 preExecute(); 442 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 443 // load or store: just send to dcache 444 Fault fault = curStaticInst->initiateAcc(this, traceData); 445 if (fault == NoFault) { 446 // successfully initiated access: instruction will 447 // complete in dcache response callback 448 assert(_status == DcacheWaitResponse); 449 } else { 450 // fault: complete now to invoke fault handler 451 postExecute(); 452 advanceInst(fault); 453 } 454 } else { 455 // non-memory instruction: execute completely now 456 Fault fault = curStaticInst->execute(this, traceData); 457 postExecute(); 458 advanceInst(fault); 459 } 460} 461 462 463bool 464TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) 465{ 466 if (cpu->_status == DcacheWaitResponse) 467 cpu->completeDataAccess(pkt); 468 else if (cpu->_status == IcacheWaitResponse) 469 cpu->completeIfetch(pkt); 470 else 471 assert("OOPS" && 0); 472 return true; 473} 474 475void 476TimingSimpleCPU::IcachePort::recvRetry() 477{ 478 // we shouldn't get a retry unless we have a packet that we're 479 // waiting to transmit 480 assert(cpu->ifetch_pkt != NULL); 481 assert(cpu->_status == IcacheRetry); 482 Packet *tmp = cpu->ifetch_pkt; 483 if (sendTiming(tmp)) { 484 cpu->_status = IcacheWaitResponse; 485 cpu->ifetch_pkt = NULL; 486 } 487} 488 489void 490TimingSimpleCPU::completeDataAccess(Packet *pkt) 491{ 492 // received a response from the dcache: complete the load or store 493 // instruction 494 assert(pkt->result == Packet::Success); 495 assert(_status == DcacheWaitResponse); 496 _status = Running; 497 498 if (getState() == SimObject::Draining) { 499 completeDrain(); 500 501 delete pkt->req; 502 delete pkt; 503 504 return; 505 } 506 507 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 508 509 delete pkt->req; 510 delete pkt; 511 512 postExecute(); 513 advanceInst(fault); 514} 515 516 517void 518TimingSimpleCPU::completeDrain() 519{ 520 DPRINTF(Config, "Done draining\n"); 521 changeState(SimObject::DrainedTiming); 522 drainEvent->process(); 523} 524 525bool 526TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) 527{ 528 cpu->completeDataAccess(pkt); 529 return true; 530} 531 532void 533TimingSimpleCPU::DcachePort::recvRetry() 534{ 535 // we shouldn't get a retry unless we have a packet that we're 536 // waiting to transmit 537 assert(cpu->dcache_pkt != NULL); 538 assert(cpu->_status == DcacheRetry); 539 Packet *tmp = cpu->dcache_pkt; 540 if (sendTiming(tmp)) { 541 cpu->_status = DcacheWaitResponse; 542 cpu->dcache_pkt = NULL; 543 } 544} 545 546 547//////////////////////////////////////////////////////////////////////// 548// 549// TimingSimpleCPU Simulation Object 550// 551BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 552 553 Param<Counter> max_insts_any_thread; 554 Param<Counter> max_insts_all_threads; 555 Param<Counter> max_loads_any_thread; 556 Param<Counter> max_loads_all_threads; 557 SimObjectParam<MemObject *> mem; 558 559#if FULL_SYSTEM 560 SimObjectParam<AlphaITB *> itb; 561 SimObjectParam<AlphaDTB *> dtb; 562 SimObjectParam<System *> system; 563 Param<int> cpu_id; 564 Param<Tick> profile; 565#else 566 SimObjectParam<Process *> workload; 567#endif // FULL_SYSTEM 568 569 Param<int> clock; 570 571 Param<bool> defer_registration; 572 Param<int> width; 573 Param<bool> function_trace; 574 Param<Tick> function_trace_start; 575 Param<bool> simulate_stalls; 576 577END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 578 579BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 580 581 INIT_PARAM(max_insts_any_thread, 582 "terminate when any thread reaches this inst count"), 583 INIT_PARAM(max_insts_all_threads, 584 "terminate when all threads have reached this inst count"), 585 INIT_PARAM(max_loads_any_thread, 586 "terminate when any thread reaches this load count"), 587 INIT_PARAM(max_loads_all_threads, 588 "terminate when all threads have reached this load count"), 589 INIT_PARAM(mem, "memory"), 590 591#if FULL_SYSTEM 592 INIT_PARAM(itb, "Instruction TLB"), 593 INIT_PARAM(dtb, "Data TLB"), 594 INIT_PARAM(system, "system object"), 595 INIT_PARAM(cpu_id, "processor ID"), 596 INIT_PARAM(profile, ""), 597#else 598 INIT_PARAM(workload, "processes to run"), 599#endif // FULL_SYSTEM 600 601 INIT_PARAM(clock, "clock speed"), 602 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 603 INIT_PARAM(width, "cpu width"), 604 INIT_PARAM(function_trace, "Enable function trace"), 605 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 606 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 607 608END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 609 610 611CREATE_SIM_OBJECT(TimingSimpleCPU) 612{ 613 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 614 params->name = getInstanceName(); 615 params->numberOfThreads = 1; 616 params->max_insts_any_thread = max_insts_any_thread; 617 params->max_insts_all_threads = max_insts_all_threads; 618 params->max_loads_any_thread = max_loads_any_thread; 619 params->max_loads_all_threads = max_loads_all_threads; 620 params->deferRegistration = defer_registration; 621 params->clock = clock; 622 params->functionTrace = function_trace; 623 params->functionTraceStart = function_trace_start; 624 params->mem = mem; 625 626#if FULL_SYSTEM 627 params->itb = itb; 628 params->dtb = dtb; 629 params->system = system; 630 params->cpu_id = cpu_id; 631 params->profile = profile; 632#else 633 params->process = workload; 634#endif 635 636 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 637 return cpu; 638} 639 640REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 641 642