timing.cc revision 2948
110497Ssteve.reinhardt@amd.com/* 210497Ssteve.reinhardt@amd.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 310497Ssteve.reinhardt@amd.com * All rights reserved. 410497Ssteve.reinhardt@amd.com * 510497Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without 610497Ssteve.reinhardt@amd.com * modification, are permitted provided that the following conditions are 710497Ssteve.reinhardt@amd.com * met: redistributions of source code must retain the above copyright 810497Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer; 910497Ssteve.reinhardt@amd.com * redistributions in binary form must reproduce the above copyright 1010497Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer in the 1110497Ssteve.reinhardt@amd.com * documentation and/or other materials provided with the distribution; 1210497Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its 1310497Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from 1410497Ssteve.reinhardt@amd.com * this software without specific prior written permission. 1510497Ssteve.reinhardt@amd.com * 1610497Ssteve.reinhardt@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710497Ssteve.reinhardt@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810497Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910497Ssteve.reinhardt@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010497Ssteve.reinhardt@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110497Ssteve.reinhardt@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210497Ssteve.reinhardt@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310497Ssteve.reinhardt@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410497Ssteve.reinhardt@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510497Ssteve.reinhardt@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610497Ssteve.reinhardt@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710497Ssteve.reinhardt@amd.com * 2810497Ssteve.reinhardt@amd.com * Authors: Steve Reinhardt 2910497Ssteve.reinhardt@amd.com */ 3010497Ssteve.reinhardt@amd.com 3110497Ssteve.reinhardt@amd.com#include "arch/utility.hh" 3210497Ssteve.reinhardt@amd.com#include "cpu/exetrace.hh" 3310497Ssteve.reinhardt@amd.com#include "cpu/simple/timing.hh" 3410497Ssteve.reinhardt@amd.com#include "mem/packet_impl.hh" 3510497Ssteve.reinhardt@amd.com#include "sim/builder.hh" 3610497Ssteve.reinhardt@amd.com#include "sim/system.hh" 3710497Ssteve.reinhardt@amd.com 3810497Ssteve.reinhardt@amd.comusing namespace std; 3910497Ssteve.reinhardt@amd.comusing namespace TheISA; 4010497Ssteve.reinhardt@amd.com 4110497Ssteve.reinhardt@amd.comPort * 4210497Ssteve.reinhardt@amd.comTimingSimpleCPU::getPort(const std::string &if_name, int idx) 4310497Ssteve.reinhardt@amd.com{ 4410497Ssteve.reinhardt@amd.com if (if_name == "dcache_port") 4510497Ssteve.reinhardt@amd.com return &dcachePort; 4610497Ssteve.reinhardt@amd.com else if (if_name == "icache_port") 4710497Ssteve.reinhardt@amd.com return &icachePort; 4810497Ssteve.reinhardt@amd.com else 4910497Ssteve.reinhardt@amd.com panic("No Such Port\n"); 5010497Ssteve.reinhardt@amd.com} 5110497Ssteve.reinhardt@amd.com 5210497Ssteve.reinhardt@amd.comvoid 5310497Ssteve.reinhardt@amd.comTimingSimpleCPU::init() 5410497Ssteve.reinhardt@amd.com{ 5510497Ssteve.reinhardt@amd.com BaseCPU::init(); 5610497Ssteve.reinhardt@amd.com#if FULL_SYSTEM 5710497Ssteve.reinhardt@amd.com for (int i = 0; i < threadContexts.size(); ++i) { 5810497Ssteve.reinhardt@amd.com ThreadContext *tc = threadContexts[i]; 5910497Ssteve.reinhardt@amd.com 6010497Ssteve.reinhardt@amd.com // initialize CPU, including PC 6110497Ssteve.reinhardt@amd.com TheISA::initCPU(tc, tc->readCpuId()); 6210497Ssteve.reinhardt@amd.com } 6310497Ssteve.reinhardt@amd.com#endif 6410497Ssteve.reinhardt@amd.com} 6510497Ssteve.reinhardt@amd.com 6610497Ssteve.reinhardt@amd.comTick 6710497Ssteve.reinhardt@amd.comTimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) 6810497Ssteve.reinhardt@amd.com{ 6910497Ssteve.reinhardt@amd.com panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 7010497Ssteve.reinhardt@amd.com return curTick; 7110497Ssteve.reinhardt@amd.com} 7210497Ssteve.reinhardt@amd.com 7310497Ssteve.reinhardt@amd.comvoid 7410497Ssteve.reinhardt@amd.comTimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) 7510497Ssteve.reinhardt@amd.com{ 7610497Ssteve.reinhardt@amd.com panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); 7710497Ssteve.reinhardt@amd.com} 7810497Ssteve.reinhardt@amd.com 7910497Ssteve.reinhardt@amd.comvoid 8010497Ssteve.reinhardt@amd.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 8110497Ssteve.reinhardt@amd.com{ 8210497Ssteve.reinhardt@amd.com if (status == RangeChange) 8310497Ssteve.reinhardt@amd.com return; 8410497Ssteve.reinhardt@amd.com 8510497Ssteve.reinhardt@amd.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 8610497Ssteve.reinhardt@amd.com} 8710497Ssteve.reinhardt@amd.com 8810497Ssteve.reinhardt@amd.com 8910497Ssteve.reinhardt@amd.comvoid 9010497Ssteve.reinhardt@amd.comTimingSimpleCPU::CpuPort::TickEvent::schedule(Packet *_pkt, Tick t) 9110497Ssteve.reinhardt@amd.com{ 9210497Ssteve.reinhardt@amd.com pkt = _pkt; 9310497Ssteve.reinhardt@amd.com Event::schedule(t); 9410497Ssteve.reinhardt@amd.com} 9510497Ssteve.reinhardt@amd.com 9610497Ssteve.reinhardt@amd.comTimingSimpleCPU::TimingSimpleCPU(Params *p) 9710497Ssteve.reinhardt@amd.com : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) 9810497Ssteve.reinhardt@amd.com{ 9910497Ssteve.reinhardt@amd.com _status = Idle; 10010497Ssteve.reinhardt@amd.com ifetch_pkt = dcache_pkt = NULL; 10110497Ssteve.reinhardt@amd.com drainEvent = NULL; 10210497Ssteve.reinhardt@amd.com fetchEvent = NULL; 10310497Ssteve.reinhardt@amd.com changeState(SimObject::Running); 10410497Ssteve.reinhardt@amd.com} 10510497Ssteve.reinhardt@amd.com 10610497Ssteve.reinhardt@amd.com 10710497Ssteve.reinhardt@amd.comTimingSimpleCPU::~TimingSimpleCPU() 10810497Ssteve.reinhardt@amd.com{ 10910497Ssteve.reinhardt@amd.com} 11010497Ssteve.reinhardt@amd.com 11110497Ssteve.reinhardt@amd.comvoid 11210497Ssteve.reinhardt@amd.comTimingSimpleCPU::serialize(ostream &os) 11310497Ssteve.reinhardt@amd.com{ 11410497Ssteve.reinhardt@amd.com SimObject::State so_state = SimObject::getState(); 11510497Ssteve.reinhardt@amd.com SERIALIZE_ENUM(so_state); 11610497Ssteve.reinhardt@amd.com BaseSimpleCPU::serialize(os); 11710497Ssteve.reinhardt@amd.com} 11810497Ssteve.reinhardt@amd.com 11910497Ssteve.reinhardt@amd.comvoid 12010497Ssteve.reinhardt@amd.comTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 12110497Ssteve.reinhardt@amd.com{ 12210497Ssteve.reinhardt@amd.com SimObject::State so_state; 12310497Ssteve.reinhardt@amd.com UNSERIALIZE_ENUM(so_state); 12410497Ssteve.reinhardt@amd.com BaseSimpleCPU::unserialize(cp, section); 12510497Ssteve.reinhardt@amd.com} 12610497Ssteve.reinhardt@amd.com 12710497Ssteve.reinhardt@amd.comunsigned int 12810497Ssteve.reinhardt@amd.comTimingSimpleCPU::drain(Event *drain_event) 12910497Ssteve.reinhardt@amd.com{ 13010497Ssteve.reinhardt@amd.com // TimingSimpleCPU is ready to drain if it's not waiting for 13110497Ssteve.reinhardt@amd.com // an access to complete. 13210497Ssteve.reinhardt@amd.com if (status() == Idle || status() == Running || status() == SwitchedOut) { 13310497Ssteve.reinhardt@amd.com changeState(SimObject::Drained); 13410497Ssteve.reinhardt@amd.com return 0; 13510497Ssteve.reinhardt@amd.com } else { 13610497Ssteve.reinhardt@amd.com changeState(SimObject::Draining); 13710497Ssteve.reinhardt@amd.com drainEvent = drain_event; 13810497Ssteve.reinhardt@amd.com return 1; 13910497Ssteve.reinhardt@amd.com } 14010497Ssteve.reinhardt@amd.com} 14110497Ssteve.reinhardt@amd.com 14210497Ssteve.reinhardt@amd.comvoid 14310497Ssteve.reinhardt@amd.comTimingSimpleCPU::resume() 14410497Ssteve.reinhardt@amd.com{ 14510497Ssteve.reinhardt@amd.com if (_status != SwitchedOut && _status != Idle) { 14610497Ssteve.reinhardt@amd.com // Delete the old event if it existed. 14710497Ssteve.reinhardt@amd.com if (fetchEvent) { 14810497Ssteve.reinhardt@amd.com if (fetchEvent->scheduled()) 14910497Ssteve.reinhardt@amd.com fetchEvent->deschedule(); 15010497Ssteve.reinhardt@amd.com 15110497Ssteve.reinhardt@amd.com delete fetchEvent; 15210497Ssteve.reinhardt@amd.com } 15310497Ssteve.reinhardt@amd.com 15410497Ssteve.reinhardt@amd.com fetchEvent = 15510497Ssteve.reinhardt@amd.com new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 15610497Ssteve.reinhardt@amd.com fetchEvent->schedule(curTick); 15710497Ssteve.reinhardt@amd.com } 15810497Ssteve.reinhardt@amd.com 15910497Ssteve.reinhardt@amd.com assert(system->getMemoryMode() == System::Timing); 16010497Ssteve.reinhardt@amd.com changeState(SimObject::Running); 16110497Ssteve.reinhardt@amd.com} 16210497Ssteve.reinhardt@amd.com 16310497Ssteve.reinhardt@amd.comvoid 16410497Ssteve.reinhardt@amd.comTimingSimpleCPU::switchOut() 16510497Ssteve.reinhardt@amd.com{ 16610497Ssteve.reinhardt@amd.com assert(status() == Running || status() == Idle); 16710497Ssteve.reinhardt@amd.com _status = SwitchedOut; 16810497Ssteve.reinhardt@amd.com 169 // If we've been scheduled to resume but are then told to switch out, 170 // we'll need to cancel it. 171 if (fetchEvent && fetchEvent->scheduled()) 172 fetchEvent->deschedule(); 173} 174 175 176void 177TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 178{ 179 BaseCPU::takeOverFrom(oldCPU); 180 181 // if any of this CPU's ThreadContexts are active, mark the CPU as 182 // running and schedule its tick event. 183 for (int i = 0; i < threadContexts.size(); ++i) { 184 ThreadContext *tc = threadContexts[i]; 185 if (tc->status() == ThreadContext::Active && _status != Running) { 186 _status = Running; 187 break; 188 } 189 } 190} 191 192 193void 194TimingSimpleCPU::activateContext(int thread_num, int delay) 195{ 196 assert(thread_num == 0); 197 assert(thread); 198 199 assert(_status == Idle); 200 201 notIdleFraction++; 202 _status = Running; 203 // kick things off by initiating the fetch of the next instruction 204 fetchEvent = 205 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 206 fetchEvent->schedule(curTick + cycles(delay)); 207} 208 209 210void 211TimingSimpleCPU::suspendContext(int thread_num) 212{ 213 assert(thread_num == 0); 214 assert(thread); 215 216 assert(_status == Running); 217 218 // just change status to Idle... if status != Running, 219 // completeInst() will not initiate fetch of next instruction. 220 221 notIdleFraction--; 222 _status = Idle; 223} 224 225 226template <class T> 227Fault 228TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 229{ 230 // need to fill in CPU & thread IDs here 231 Request *data_read_req = new Request(); 232 data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 233 data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 234 235 if (traceData) { 236 traceData->setAddr(data_read_req->getVaddr()); 237 } 238 239 // translate to physical address 240 Fault fault = thread->translateDataReadReq(data_read_req); 241 242 // Now do the access. 243 if (fault == NoFault) { 244 Packet *data_read_pkt = 245 new Packet(data_read_req, Packet::ReadReq, Packet::Broadcast); 246 data_read_pkt->dataDynamic<T>(new T); 247 248 if (!dcachePort.sendTiming(data_read_pkt)) { 249 _status = DcacheRetry; 250 dcache_pkt = data_read_pkt; 251 } else { 252 _status = DcacheWaitResponse; 253 dcache_pkt = NULL; 254 } 255 } 256 257 // This will need a new way to tell if it has a dcache attached. 258 if (data_read_req->getFlags() & UNCACHEABLE) 259 recordEvent("Uncached Read"); 260 261 return fault; 262} 263 264#ifndef DOXYGEN_SHOULD_SKIP_THIS 265 266template 267Fault 268TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 269 270template 271Fault 272TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 273 274template 275Fault 276TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 277 278template 279Fault 280TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 281 282#endif //DOXYGEN_SHOULD_SKIP_THIS 283 284template<> 285Fault 286TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 287{ 288 return read(addr, *(uint64_t*)&data, flags); 289} 290 291template<> 292Fault 293TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 294{ 295 return read(addr, *(uint32_t*)&data, flags); 296} 297 298 299template<> 300Fault 301TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 302{ 303 return read(addr, (uint32_t&)data, flags); 304} 305 306 307template <class T> 308Fault 309TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 310{ 311 // need to fill in CPU & thread IDs here 312 Request *data_write_req = new Request(); 313 data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 314 data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 315 316 // translate to physical address 317 Fault fault = thread->translateDataWriteReq(data_write_req); 318 // Now do the access. 319 if (fault == NoFault) { 320 Packet *data_write_pkt = 321 new Packet(data_write_req, Packet::WriteReq, Packet::Broadcast); 322 data_write_pkt->allocate(); 323 data_write_pkt->set(data); 324 325 if (!dcachePort.sendTiming(data_write_pkt)) { 326 _status = DcacheRetry; 327 dcache_pkt = data_write_pkt; 328 } else { 329 _status = DcacheWaitResponse; 330 dcache_pkt = NULL; 331 } 332 } 333 334 // This will need a new way to tell if it's hooked up to a cache or not. 335 if (data_write_req->getFlags() & UNCACHEABLE) 336 recordEvent("Uncached Write"); 337 338 // If the write needs to have a fault on the access, consider calling 339 // changeStatus() and changing it to "bad addr write" or something. 340 return fault; 341} 342 343 344#ifndef DOXYGEN_SHOULD_SKIP_THIS 345template 346Fault 347TimingSimpleCPU::write(uint64_t data, Addr addr, 348 unsigned flags, uint64_t *res); 349 350template 351Fault 352TimingSimpleCPU::write(uint32_t data, Addr addr, 353 unsigned flags, uint64_t *res); 354 355template 356Fault 357TimingSimpleCPU::write(uint16_t data, Addr addr, 358 unsigned flags, uint64_t *res); 359 360template 361Fault 362TimingSimpleCPU::write(uint8_t data, Addr addr, 363 unsigned flags, uint64_t *res); 364 365#endif //DOXYGEN_SHOULD_SKIP_THIS 366 367template<> 368Fault 369TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 370{ 371 return write(*(uint64_t*)&data, addr, flags, res); 372} 373 374template<> 375Fault 376TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 377{ 378 return write(*(uint32_t*)&data, addr, flags, res); 379} 380 381 382template<> 383Fault 384TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 385{ 386 return write((uint32_t)data, addr, flags, res); 387} 388 389 390void 391TimingSimpleCPU::fetch() 392{ 393 checkForInterrupts(); 394 395 // need to fill in CPU & thread IDs here 396 Request *ifetch_req = new Request(); 397 ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE 398 Fault fault = setupFetchRequest(ifetch_req); 399 400 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 401 ifetch_pkt->dataStatic(&inst); 402 403 if (fault == NoFault) { 404 if (!icachePort.sendTiming(ifetch_pkt)) { 405 // Need to wait for retry 406 _status = IcacheRetry; 407 } else { 408 // Need to wait for cache to respond 409 _status = IcacheWaitResponse; 410 // ownership of packet transferred to memory system 411 ifetch_pkt = NULL; 412 } 413 } else { 414 // fetch fault: advance directly to next instruction (fault handler) 415 advanceInst(fault); 416 } 417} 418 419 420void 421TimingSimpleCPU::advanceInst(Fault fault) 422{ 423 advancePC(fault); 424 425 if (_status == Running) { 426 // kick off fetch of next instruction... callback from icache 427 // response will cause that instruction to be executed, 428 // keeping the CPU running. 429 fetch(); 430 } 431} 432 433 434void 435TimingSimpleCPU::completeIfetch(Packet *pkt) 436{ 437 // received a response from the icache: execute the received 438 // instruction 439 assert(pkt->result == Packet::Success); 440 assert(_status == IcacheWaitResponse); 441 442 _status = Running; 443 444 delete pkt->req; 445 delete pkt; 446 447 if (getState() == SimObject::Draining) { 448 completeDrain(); 449 return; 450 } 451 452 preExecute(); 453 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 454 // load or store: just send to dcache 455 Fault fault = curStaticInst->initiateAcc(this, traceData); 456 if (fault == NoFault) { 457 // successfully initiated access: instruction will 458 // complete in dcache response callback 459 assert(_status == DcacheWaitResponse); 460 } else { 461 // fault: complete now to invoke fault handler 462 postExecute(); 463 advanceInst(fault); 464 } 465 } else { 466 // non-memory instruction: execute completely now 467 Fault fault = curStaticInst->execute(this, traceData); 468 postExecute(); 469 advanceInst(fault); 470 } 471} 472 473void 474TimingSimpleCPU::IcachePort::ITickEvent::process() 475{ 476 cpu->completeIfetch(pkt); 477} 478 479bool 480TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) 481{ 482 // These next few lines could be replaced with something faster 483 // who knows what though 484 Tick time = pkt->req->getTime(); 485 while (time < curTick) 486 time += lat; 487 488 if (time == curTick) 489 cpu->completeIfetch(pkt); 490 else 491 tickEvent.schedule(pkt, time); 492 493 return true; 494} 495 496void 497TimingSimpleCPU::IcachePort::recvRetry() 498{ 499 // we shouldn't get a retry unless we have a packet that we're 500 // waiting to transmit 501 assert(cpu->ifetch_pkt != NULL); 502 assert(cpu->_status == IcacheRetry); 503 Packet *tmp = cpu->ifetch_pkt; 504 if (sendTiming(tmp)) { 505 cpu->_status = IcacheWaitResponse; 506 cpu->ifetch_pkt = NULL; 507 } 508} 509 510void 511TimingSimpleCPU::completeDataAccess(Packet *pkt) 512{ 513 // received a response from the dcache: complete the load or store 514 // instruction 515 assert(pkt->result == Packet::Success); 516 assert(_status == DcacheWaitResponse); 517 _status = Running; 518 519 if (getState() == SimObject::Draining) { 520 completeDrain(); 521 522 delete pkt->req; 523 delete pkt; 524 525 return; 526 } 527 528 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 529 530 delete pkt->req; 531 delete pkt; 532 533 postExecute(); 534 advanceInst(fault); 535} 536 537 538void 539TimingSimpleCPU::completeDrain() 540{ 541 DPRINTF(Config, "Done draining\n"); 542 changeState(SimObject::Drained); 543 drainEvent->process(); 544} 545 546bool 547TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) 548{ 549 Tick time = pkt->req->getTime(); 550 while (time < curTick) 551 time += lat; 552 553 if (time == curTick) 554 cpu->completeDataAccess(pkt); 555 else 556 tickEvent.schedule(pkt, time); 557 558 return true; 559} 560 561void 562TimingSimpleCPU::DcachePort::DTickEvent::process() 563{ 564 cpu->completeDataAccess(pkt); 565} 566 567void 568TimingSimpleCPU::DcachePort::recvRetry() 569{ 570 // we shouldn't get a retry unless we have a packet that we're 571 // waiting to transmit 572 assert(cpu->dcache_pkt != NULL); 573 assert(cpu->_status == DcacheRetry); 574 Packet *tmp = cpu->dcache_pkt; 575 if (sendTiming(tmp)) { 576 cpu->_status = DcacheWaitResponse; 577 cpu->dcache_pkt = NULL; 578 } 579} 580 581 582//////////////////////////////////////////////////////////////////////// 583// 584// TimingSimpleCPU Simulation Object 585// 586BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 587 588 Param<Counter> max_insts_any_thread; 589 Param<Counter> max_insts_all_threads; 590 Param<Counter> max_loads_any_thread; 591 Param<Counter> max_loads_all_threads; 592 SimObjectParam<MemObject *> mem; 593 SimObjectParam<System *> system; 594 595#if FULL_SYSTEM 596 SimObjectParam<AlphaITB *> itb; 597 SimObjectParam<AlphaDTB *> dtb; 598 Param<int> cpu_id; 599 Param<Tick> profile; 600#else 601 SimObjectParam<Process *> workload; 602#endif // FULL_SYSTEM 603 604 Param<int> clock; 605 606 Param<bool> defer_registration; 607 Param<int> width; 608 Param<bool> function_trace; 609 Param<Tick> function_trace_start; 610 Param<bool> simulate_stalls; 611 612END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 613 614BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 615 616 INIT_PARAM(max_insts_any_thread, 617 "terminate when any thread reaches this inst count"), 618 INIT_PARAM(max_insts_all_threads, 619 "terminate when all threads have reached this inst count"), 620 INIT_PARAM(max_loads_any_thread, 621 "terminate when any thread reaches this load count"), 622 INIT_PARAM(max_loads_all_threads, 623 "terminate when all threads have reached this load count"), 624 INIT_PARAM(mem, "memory"), 625 INIT_PARAM(system, "system object"), 626 627#if FULL_SYSTEM 628 INIT_PARAM(itb, "Instruction TLB"), 629 INIT_PARAM(dtb, "Data TLB"), 630 INIT_PARAM(cpu_id, "processor ID"), 631 INIT_PARAM(profile, ""), 632#else 633 INIT_PARAM(workload, "processes to run"), 634#endif // FULL_SYSTEM 635 636 INIT_PARAM(clock, "clock speed"), 637 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 638 INIT_PARAM(width, "cpu width"), 639 INIT_PARAM(function_trace, "Enable function trace"), 640 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 641 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 642 643END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 644 645 646CREATE_SIM_OBJECT(TimingSimpleCPU) 647{ 648 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 649 params->name = getInstanceName(); 650 params->numberOfThreads = 1; 651 params->max_insts_any_thread = max_insts_any_thread; 652 params->max_insts_all_threads = max_insts_all_threads; 653 params->max_loads_any_thread = max_loads_any_thread; 654 params->max_loads_all_threads = max_loads_all_threads; 655 params->deferRegistration = defer_registration; 656 params->clock = clock; 657 params->functionTrace = function_trace; 658 params->functionTraceStart = function_trace_start; 659 params->mem = mem; 660 params->system = system; 661 662#if FULL_SYSTEM 663 params->itb = itb; 664 params->dtb = dtb; 665 params->cpu_id = cpu_id; 666 params->profile = profile; 667#else 668 params->process = workload; 669#endif 670 671 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 672 return cpu; 673} 674 675REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 676 677