1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/mmaped_ipr.hh" 33#include "arch/utility.hh" 34#include "base/bigint.hh" 35#include "cpu/exetrace.hh" 36#include "cpu/simple/timing.hh" 37#include "mem/packet.hh" 38#include "mem/packet_access.hh" 39#include "params/TimingSimpleCPU.hh" 40#include "sim/system.hh" 41 42using namespace std; 43using namespace TheISA; 44 45Port * 46TimingSimpleCPU::getPort(const std::string &if_name, int idx) 47{ 48 if (if_name == "dcache_port") 49 return &dcachePort; 50 else if (if_name == "icache_port") 51 return &icachePort; 52 else 53 panic("No Such Port\n"); 54} 55 56void 57TimingSimpleCPU::init() 58{ 59 BaseCPU::init(); 60#if FULL_SYSTEM 61 for (int i = 0; i < threadContexts.size(); ++i) { 62 ThreadContext *tc = threadContexts[i]; 63 64 // initialize CPU, including PC 65 TheISA::initCPU(tc, _cpuId); 66 } 67#endif 68} 69 70Tick 71TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 72{ 73 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 74 return curTick; 75} 76 77void 78TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 79{ 80 //No internal storage to update, jusst return 81 return; 82} 83 84void 85TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 86{ 87 if (status == RangeChange) { 88 if (!snoopRangeSent) { 89 snoopRangeSent = true; 90 sendStatusChange(Port::RangeChange); 91 } 92 return; 93 } 94 95 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 96} 97 98 99void 100TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 101{ 102 pkt = _pkt; 103 cpu->schedule(this, t); 104} 105 106TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 107 : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 108 dcachePort(this, p->clock), fetchEvent(this) 109{ 110 _status = Idle; 111 112 icachePort.snoopRangeSent = false; 113 dcachePort.snoopRangeSent = false; 114 115 ifetch_pkt = dcache_pkt = NULL; 116 drainEvent = NULL; 117 previousTick = 0; 118 changeState(SimObject::Running); 119} 120 121 122TimingSimpleCPU::~TimingSimpleCPU() 123{ 124} 125 126void 127TimingSimpleCPU::serialize(ostream &os) 128{ 129 SimObject::State so_state = SimObject::getState(); 130 SERIALIZE_ENUM(so_state); 131 BaseSimpleCPU::serialize(os); 132} 133 134void 135TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136{ 137 SimObject::State so_state; 138 UNSERIALIZE_ENUM(so_state); 139 BaseSimpleCPU::unserialize(cp, section); 140} 141 142unsigned int 143TimingSimpleCPU::drain(Event *drain_event) 144{ 145 // TimingSimpleCPU is ready to drain if it's not waiting for 146 // an access to complete. 147 if (_status == Idle || _status == Running || _status == SwitchedOut) { 148 changeState(SimObject::Drained); 149 return 0; 150 } else { 151 changeState(SimObject::Draining); 152 drainEvent = drain_event; 153 return 1; 154 } 155} 156 157void 158TimingSimpleCPU::resume() 159{ 160 DPRINTF(SimpleCPU, "Resume\n"); 161 if (_status != SwitchedOut && _status != Idle) { 162 assert(system->getMemoryMode() == Enums::timing); 163 164 if (fetchEvent.scheduled()) 165 deschedule(fetchEvent); 166 167 schedule(fetchEvent, nextCycle()); 168 } 169 170 changeState(SimObject::Running); 171} 172 173void 174TimingSimpleCPU::switchOut() 175{ 176 assert(_status == Running || _status == Idle); 177 _status = SwitchedOut; 178 numCycles += tickToCycles(curTick - previousTick); 179 180 // If we've been scheduled to resume but are then told to switch out, 181 // we'll need to cancel it. 182 if (fetchEvent.scheduled()) 183 deschedule(fetchEvent); 184} 185 186 187void 188TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 189{ 190 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 191 192 // if any of this CPU's ThreadContexts are active, mark the CPU as 193 // running and schedule its tick event. 194 for (int i = 0; i < threadContexts.size(); ++i) { 195 ThreadContext *tc = threadContexts[i]; 196 if (tc->status() == ThreadContext::Active && _status != Running) { 197 _status = Running; 198 break; 199 } 200 } 201 202 if (_status != Running) { 203 _status = Idle; 204 } 205 assert(threadContexts.size() == 1); 206 previousTick = curTick; 207} 208 209 210void 211TimingSimpleCPU::activateContext(int thread_num, int delay) 212{ 213 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 214 215 assert(thread_num == 0); 216 assert(thread); 217 218 assert(_status == Idle); 219 220 notIdleFraction++; 221 _status = Running; 222 223 // kick things off by initiating the fetch of the next instruction 224 schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 225} 226 227 228void 229TimingSimpleCPU::suspendContext(int thread_num) 230{ 231 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 232 233 assert(thread_num == 0); 234 assert(thread); 235 236 assert(_status == Running); 237 238 // just change status to Idle... if status != Running, 239 // completeInst() will not initiate fetch of next instruction. 240 241 notIdleFraction--; 242 _status = Idle; 243} 244 245bool 246TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 247{ 248 RequestPtr req = pkt->req; 249 if (req->isMmapedIpr()) { 250 Tick delay; 251 delay = TheISA::handleIprRead(thread->getTC(), pkt); 252 new IprEvent(pkt, this, nextCycle(curTick + delay)); 253 _status = DcacheWaitResponse; 254 dcache_pkt = NULL; 255 } else if (!dcachePort.sendTiming(pkt)) { 256 _status = DcacheRetry; 257 dcache_pkt = pkt; 258 } else { 259 _status = DcacheWaitResponse; 260 // memory system takes ownership of packet 261 dcache_pkt = NULL; 262 } 263 return dcache_pkt == NULL; 264} 265 266void 267TimingSimpleCPU::sendData(Fault fault, RequestPtr req, 268 uint8_t *data, uint64_t *res, bool read) 269{ 270 _status = Running; 271 if (fault != NoFault) { 272 delete data; 273 delete req; 274 275 translationFault(fault); 276 return; 277 } 278 PacketPtr pkt; 279 buildPacket(pkt, req, read); 280 pkt->dataDynamic<uint8_t>(data); 281 if (req->getFlags().isSet(Request::NO_ACCESS)) { 282 assert(!dcache_pkt); 283 pkt->makeResponse(); 284 completeDataAccess(pkt); 285 } else if (read) { 286 handleReadPacket(pkt); 287 } else { 288 bool do_access = true; // flag to suppress cache access 289 290 if (req->isLocked()) { 291 do_access = TheISA::handleLockedWrite(thread, req); 292 } else if (req->isCondSwap()) { 293 assert(res); 294 req->setExtraData(*res); 295 } 296 297 if (do_access) { 298 dcache_pkt = pkt; 299 handleWritePacket(); 300 } else { 301 _status = DcacheWaitResponse; 302 completeDataAccess(pkt); 303 } 304 } 305} 306 307void 308TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, 309 RequestPtr req1, RequestPtr req2, RequestPtr req, 310 uint8_t *data, bool read) 311{ 312 _status = Running; 313 if (fault1 != NoFault || fault2 != NoFault) { 314 delete data; 315 delete req1; 316 delete req2; 317 if (fault1 != NoFault) 318 translationFault(fault1); 319 else if (fault2 != NoFault) 320 translationFault(fault2); 321 return; 322 } 323 PacketPtr pkt1, pkt2; 324 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 325 if (req->getFlags().isSet(Request::NO_ACCESS)) { 326 assert(!dcache_pkt); 327 pkt1->makeResponse(); 328 completeDataAccess(pkt1); 329 } else if (read) { 330 if (handleReadPacket(pkt1)) { 331 SplitFragmentSenderState * send_state = 332 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 333 send_state->clearFromParent(); 334 if (handleReadPacket(pkt2)) { 335 send_state = dynamic_cast<SplitFragmentSenderState *>( 336 pkt1->senderState); 337 send_state->clearFromParent(); 338 } 339 } 340 } else { 341 dcache_pkt = pkt1; 342 if (handleWritePacket()) { 343 SplitFragmentSenderState * send_state = 344 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 345 send_state->clearFromParent(); 346 dcache_pkt = pkt2; 347 if (handleWritePacket()) { 348 send_state = dynamic_cast<SplitFragmentSenderState *>( 349 pkt1->senderState); 350 send_state->clearFromParent(); 351 } 352 } 353 } 354} 355 356void 357TimingSimpleCPU::translationFault(Fault fault) 358{ 359 numCycles += tickToCycles(curTick - previousTick); 360 previousTick = curTick; 361 362 if (traceData) { 363 // Since there was a fault, we shouldn't trace this instruction. 364 delete traceData; 365 traceData = NULL; 366 } 367 368 postExecute(); 369 370 if (getState() == SimObject::Draining) { 371 advancePC(fault); 372 completeDrain(); 373 } else { 374 advanceInst(fault); 375 } 376} 377 378void 379TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 380{ 381 MemCmd cmd; 382 if (read) { 383 cmd = MemCmd::ReadReq; 384 if (req->isLocked()) 385 cmd = MemCmd::LoadLockedReq; 386 } else { 387 cmd = MemCmd::WriteReq; 388 if (req->isLocked()) { 389 cmd = MemCmd::StoreCondReq; 390 } else if (req->isSwap()) { 391 cmd = MemCmd::SwapReq; 392 } 393 } 394 pkt = new Packet(req, cmd, Packet::Broadcast); 395} 396 397void 398TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 399 RequestPtr req1, RequestPtr req2, RequestPtr req, 400 uint8_t *data, bool read) 401{ 402 pkt1 = pkt2 = NULL; 403 404 assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 405 406 if (req->getFlags().isSet(Request::NO_ACCESS)) { 407 buildPacket(pkt1, req, read); 408 return; 409 } 410 411 buildPacket(pkt1, req1, read); 412 buildPacket(pkt2, req2, read); 413 414 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 415 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 416 Packet::Broadcast); 417 418 pkt->dataDynamic<uint8_t>(data); 419 pkt1->dataStatic<uint8_t>(data); 420 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 421 422 SplitMainSenderState * main_send_state = new SplitMainSenderState; 423 pkt->senderState = main_send_state; 424 main_send_state->fragments[0] = pkt1; 425 main_send_state->fragments[1] = pkt2; 426 main_send_state->outstanding = 2; 427 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 428 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 429} 430 431template <class T> 432Fault 433TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 434{ 435 Fault fault; 436 const int asid = 0; 437 const int thread_id = 0; 438 const Addr pc = thread->readPC(); 439 int block_size = dcachePort.peerBlockSize(); 440 int data_size = sizeof(T); 441 442 RequestPtr req = new Request(asid, addr, data_size, 443 flags, pc, _cpuId, thread_id); 444 445 Addr split_addr = roundDown(addr + data_size - 1, block_size); 446 assert(split_addr <= addr || split_addr - addr < block_size); 447 448 449 _status = DTBWaitResponse; 450 if (split_addr > addr) { 451 RequestPtr req1, req2; 452 assert(!req->isLocked() && !req->isSwap()); 453 req->splitOnVaddr(split_addr, req1, req2); 454 455 typedef SplitDataTranslation::WholeTranslationState WholeState; 456 WholeState *state = new WholeState(req1, req2, req, 457 (uint8_t *)(new T), true); 458 thread->dtb->translateTiming(req1, tc, 459 new SplitDataTranslation(this, 0, state), false); 460 thread->dtb->translateTiming(req2, tc, 461 new SplitDataTranslation(this, 1, state), false); 462 } else { 463 thread->dtb->translateTiming(req, tc, 464 new DataTranslation(this, (uint8_t *)(new T), NULL, true), 465 false); 466 } 467 468 if (traceData) { 469 traceData->setData(data); 470 traceData->setAddr(addr); 471 } 472 473 // This will need a new way to tell if it has a dcache attached. 474 if (req->isUncacheable()) 475 recordEvent("Uncached Read"); 476 477 return NoFault; 478} 479 480#ifndef DOXYGEN_SHOULD_SKIP_THIS 481 482template 483Fault 484TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 485 486template 487Fault 488TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 489 490template 491Fault 492TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 493 494template 495Fault 496TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 497 498template 499Fault 500TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 501 502template 503Fault 504TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 505 506#endif //DOXYGEN_SHOULD_SKIP_THIS 507 508template<> 509Fault 510TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 511{ 512 return read(addr, *(uint64_t*)&data, flags); 513} 514 515template<> 516Fault 517TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 518{ 519 return read(addr, *(uint32_t*)&data, flags); 520} 521 522 523template<> 524Fault 525TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 526{ 527 return read(addr, (uint32_t&)data, flags); 528} 529 530bool 531TimingSimpleCPU::handleWritePacket() 532{ 533 RequestPtr req = dcache_pkt->req; 534 if (req->isMmapedIpr()) { 535 Tick delay; 536 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 537 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 538 _status = DcacheWaitResponse; 539 dcache_pkt = NULL; 540 } else if (!dcachePort.sendTiming(dcache_pkt)) { 541 _status = DcacheRetry; 542 } else { 543 _status = DcacheWaitResponse; 544 // memory system takes ownership of packet 545 dcache_pkt = NULL; 546 } 547 return dcache_pkt == NULL; 548} 549 550template <class T> 551Fault 552TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 553{ 554 const int asid = 0; 555 const int thread_id = 0; 556 const Addr pc = thread->readPC(); 557 int block_size = dcachePort.peerBlockSize(); 558 int data_size = sizeof(T); 559 560 RequestPtr req = new Request(asid, addr, data_size, 561 flags, pc, _cpuId, thread_id); 562 563 Addr split_addr = roundDown(addr + data_size - 1, block_size); 564 assert(split_addr <= addr || split_addr - addr < block_size); 565 566 T *dataP = new T; 567 *dataP = TheISA::gtoh(data); 568 _status = DTBWaitResponse; 569 if (split_addr > addr) { 570 RequestPtr req1, req2; 571 assert(!req->isLocked() && !req->isSwap()); 572 req->splitOnVaddr(split_addr, req1, req2); 573 574 typedef SplitDataTranslation::WholeTranslationState WholeState; 575 WholeState *state = new WholeState(req1, req2, req, 576 (uint8_t *)dataP, false); 577 thread->dtb->translateTiming(req1, tc, 578 new SplitDataTranslation(this, 0, state), true); 579 thread->dtb->translateTiming(req2, tc, 580 new SplitDataTranslation(this, 1, state), true); 581 } else { 582 thread->dtb->translateTiming(req, tc, 583 new DataTranslation(this, (uint8_t *)dataP, res, false), 584 true); 585 } 586 587 if (traceData) { 588 traceData->setAddr(req->getVaddr()); 589 traceData->setData(data); 590 } 591 592 // This will need a new way to tell if it's hooked up to a cache or not. 593 if (req->isUncacheable()) 594 recordEvent("Uncached Write"); 595 596 // If the write needs to have a fault on the access, consider calling 597 // changeStatus() and changing it to "bad addr write" or something. 598 return NoFault; 599} 600 601 602#ifndef DOXYGEN_SHOULD_SKIP_THIS 603template 604Fault 605TimingSimpleCPU::write(Twin32_t data, Addr addr, 606 unsigned flags, uint64_t *res); 607 608template 609Fault 610TimingSimpleCPU::write(Twin64_t data, Addr addr, 611 unsigned flags, uint64_t *res); 612 613template 614Fault 615TimingSimpleCPU::write(uint64_t data, Addr addr, 616 unsigned flags, uint64_t *res); 617 618template 619Fault 620TimingSimpleCPU::write(uint32_t data, Addr addr, 621 unsigned flags, uint64_t *res); 622 623template 624Fault 625TimingSimpleCPU::write(uint16_t data, Addr addr, 626 unsigned flags, uint64_t *res); 627 628template 629Fault 630TimingSimpleCPU::write(uint8_t data, Addr addr, 631 unsigned flags, uint64_t *res); 632 633#endif //DOXYGEN_SHOULD_SKIP_THIS 634 635template<> 636Fault 637TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 638{ 639 return write(*(uint64_t*)&data, addr, flags, res); 640} 641 642template<> 643Fault 644TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 645{ 646 return write(*(uint32_t*)&data, addr, flags, res); 647} 648 649 650template<> 651Fault 652TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 653{ 654 return write((uint32_t)data, addr, flags, res); 655} 656 657 658void 659TimingSimpleCPU::fetch() 660{ 661 DPRINTF(SimpleCPU, "Fetch\n"); 662 663 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 664 checkForInterrupts(); 665 666 checkPcEventQueue(); 667 668 bool fromRom = isRomMicroPC(thread->readMicroPC()); 669
| 1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/mmaped_ipr.hh" 33#include "arch/utility.hh" 34#include "base/bigint.hh" 35#include "cpu/exetrace.hh" 36#include "cpu/simple/timing.hh" 37#include "mem/packet.hh" 38#include "mem/packet_access.hh" 39#include "params/TimingSimpleCPU.hh" 40#include "sim/system.hh" 41 42using namespace std; 43using namespace TheISA; 44 45Port * 46TimingSimpleCPU::getPort(const std::string &if_name, int idx) 47{ 48 if (if_name == "dcache_port") 49 return &dcachePort; 50 else if (if_name == "icache_port") 51 return &icachePort; 52 else 53 panic("No Such Port\n"); 54} 55 56void 57TimingSimpleCPU::init() 58{ 59 BaseCPU::init(); 60#if FULL_SYSTEM 61 for (int i = 0; i < threadContexts.size(); ++i) { 62 ThreadContext *tc = threadContexts[i]; 63 64 // initialize CPU, including PC 65 TheISA::initCPU(tc, _cpuId); 66 } 67#endif 68} 69 70Tick 71TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 72{ 73 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 74 return curTick; 75} 76 77void 78TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 79{ 80 //No internal storage to update, jusst return 81 return; 82} 83 84void 85TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 86{ 87 if (status == RangeChange) { 88 if (!snoopRangeSent) { 89 snoopRangeSent = true; 90 sendStatusChange(Port::RangeChange); 91 } 92 return; 93 } 94 95 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 96} 97 98 99void 100TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 101{ 102 pkt = _pkt; 103 cpu->schedule(this, t); 104} 105 106TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 107 : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 108 dcachePort(this, p->clock), fetchEvent(this) 109{ 110 _status = Idle; 111 112 icachePort.snoopRangeSent = false; 113 dcachePort.snoopRangeSent = false; 114 115 ifetch_pkt = dcache_pkt = NULL; 116 drainEvent = NULL; 117 previousTick = 0; 118 changeState(SimObject::Running); 119} 120 121 122TimingSimpleCPU::~TimingSimpleCPU() 123{ 124} 125 126void 127TimingSimpleCPU::serialize(ostream &os) 128{ 129 SimObject::State so_state = SimObject::getState(); 130 SERIALIZE_ENUM(so_state); 131 BaseSimpleCPU::serialize(os); 132} 133 134void 135TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136{ 137 SimObject::State so_state; 138 UNSERIALIZE_ENUM(so_state); 139 BaseSimpleCPU::unserialize(cp, section); 140} 141 142unsigned int 143TimingSimpleCPU::drain(Event *drain_event) 144{ 145 // TimingSimpleCPU is ready to drain if it's not waiting for 146 // an access to complete. 147 if (_status == Idle || _status == Running || _status == SwitchedOut) { 148 changeState(SimObject::Drained); 149 return 0; 150 } else { 151 changeState(SimObject::Draining); 152 drainEvent = drain_event; 153 return 1; 154 } 155} 156 157void 158TimingSimpleCPU::resume() 159{ 160 DPRINTF(SimpleCPU, "Resume\n"); 161 if (_status != SwitchedOut && _status != Idle) { 162 assert(system->getMemoryMode() == Enums::timing); 163 164 if (fetchEvent.scheduled()) 165 deschedule(fetchEvent); 166 167 schedule(fetchEvent, nextCycle()); 168 } 169 170 changeState(SimObject::Running); 171} 172 173void 174TimingSimpleCPU::switchOut() 175{ 176 assert(_status == Running || _status == Idle); 177 _status = SwitchedOut; 178 numCycles += tickToCycles(curTick - previousTick); 179 180 // If we've been scheduled to resume but are then told to switch out, 181 // we'll need to cancel it. 182 if (fetchEvent.scheduled()) 183 deschedule(fetchEvent); 184} 185 186 187void 188TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 189{ 190 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 191 192 // if any of this CPU's ThreadContexts are active, mark the CPU as 193 // running and schedule its tick event. 194 for (int i = 0; i < threadContexts.size(); ++i) { 195 ThreadContext *tc = threadContexts[i]; 196 if (tc->status() == ThreadContext::Active && _status != Running) { 197 _status = Running; 198 break; 199 } 200 } 201 202 if (_status != Running) { 203 _status = Idle; 204 } 205 assert(threadContexts.size() == 1); 206 previousTick = curTick; 207} 208 209 210void 211TimingSimpleCPU::activateContext(int thread_num, int delay) 212{ 213 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 214 215 assert(thread_num == 0); 216 assert(thread); 217 218 assert(_status == Idle); 219 220 notIdleFraction++; 221 _status = Running; 222 223 // kick things off by initiating the fetch of the next instruction 224 schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 225} 226 227 228void 229TimingSimpleCPU::suspendContext(int thread_num) 230{ 231 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 232 233 assert(thread_num == 0); 234 assert(thread); 235 236 assert(_status == Running); 237 238 // just change status to Idle... if status != Running, 239 // completeInst() will not initiate fetch of next instruction. 240 241 notIdleFraction--; 242 _status = Idle; 243} 244 245bool 246TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 247{ 248 RequestPtr req = pkt->req; 249 if (req->isMmapedIpr()) { 250 Tick delay; 251 delay = TheISA::handleIprRead(thread->getTC(), pkt); 252 new IprEvent(pkt, this, nextCycle(curTick + delay)); 253 _status = DcacheWaitResponse; 254 dcache_pkt = NULL; 255 } else if (!dcachePort.sendTiming(pkt)) { 256 _status = DcacheRetry; 257 dcache_pkt = pkt; 258 } else { 259 _status = DcacheWaitResponse; 260 // memory system takes ownership of packet 261 dcache_pkt = NULL; 262 } 263 return dcache_pkt == NULL; 264} 265 266void 267TimingSimpleCPU::sendData(Fault fault, RequestPtr req, 268 uint8_t *data, uint64_t *res, bool read) 269{ 270 _status = Running; 271 if (fault != NoFault) { 272 delete data; 273 delete req; 274 275 translationFault(fault); 276 return; 277 } 278 PacketPtr pkt; 279 buildPacket(pkt, req, read); 280 pkt->dataDynamic<uint8_t>(data); 281 if (req->getFlags().isSet(Request::NO_ACCESS)) { 282 assert(!dcache_pkt); 283 pkt->makeResponse(); 284 completeDataAccess(pkt); 285 } else if (read) { 286 handleReadPacket(pkt); 287 } else { 288 bool do_access = true; // flag to suppress cache access 289 290 if (req->isLocked()) { 291 do_access = TheISA::handleLockedWrite(thread, req); 292 } else if (req->isCondSwap()) { 293 assert(res); 294 req->setExtraData(*res); 295 } 296 297 if (do_access) { 298 dcache_pkt = pkt; 299 handleWritePacket(); 300 } else { 301 _status = DcacheWaitResponse; 302 completeDataAccess(pkt); 303 } 304 } 305} 306 307void 308TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, 309 RequestPtr req1, RequestPtr req2, RequestPtr req, 310 uint8_t *data, bool read) 311{ 312 _status = Running; 313 if (fault1 != NoFault || fault2 != NoFault) { 314 delete data; 315 delete req1; 316 delete req2; 317 if (fault1 != NoFault) 318 translationFault(fault1); 319 else if (fault2 != NoFault) 320 translationFault(fault2); 321 return; 322 } 323 PacketPtr pkt1, pkt2; 324 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 325 if (req->getFlags().isSet(Request::NO_ACCESS)) { 326 assert(!dcache_pkt); 327 pkt1->makeResponse(); 328 completeDataAccess(pkt1); 329 } else if (read) { 330 if (handleReadPacket(pkt1)) { 331 SplitFragmentSenderState * send_state = 332 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 333 send_state->clearFromParent(); 334 if (handleReadPacket(pkt2)) { 335 send_state = dynamic_cast<SplitFragmentSenderState *>( 336 pkt1->senderState); 337 send_state->clearFromParent(); 338 } 339 } 340 } else { 341 dcache_pkt = pkt1; 342 if (handleWritePacket()) { 343 SplitFragmentSenderState * send_state = 344 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 345 send_state->clearFromParent(); 346 dcache_pkt = pkt2; 347 if (handleWritePacket()) { 348 send_state = dynamic_cast<SplitFragmentSenderState *>( 349 pkt1->senderState); 350 send_state->clearFromParent(); 351 } 352 } 353 } 354} 355 356void 357TimingSimpleCPU::translationFault(Fault fault) 358{ 359 numCycles += tickToCycles(curTick - previousTick); 360 previousTick = curTick; 361 362 if (traceData) { 363 // Since there was a fault, we shouldn't trace this instruction. 364 delete traceData; 365 traceData = NULL; 366 } 367 368 postExecute(); 369 370 if (getState() == SimObject::Draining) { 371 advancePC(fault); 372 completeDrain(); 373 } else { 374 advanceInst(fault); 375 } 376} 377 378void 379TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 380{ 381 MemCmd cmd; 382 if (read) { 383 cmd = MemCmd::ReadReq; 384 if (req->isLocked()) 385 cmd = MemCmd::LoadLockedReq; 386 } else { 387 cmd = MemCmd::WriteReq; 388 if (req->isLocked()) { 389 cmd = MemCmd::StoreCondReq; 390 } else if (req->isSwap()) { 391 cmd = MemCmd::SwapReq; 392 } 393 } 394 pkt = new Packet(req, cmd, Packet::Broadcast); 395} 396 397void 398TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 399 RequestPtr req1, RequestPtr req2, RequestPtr req, 400 uint8_t *data, bool read) 401{ 402 pkt1 = pkt2 = NULL; 403 404 assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 405 406 if (req->getFlags().isSet(Request::NO_ACCESS)) { 407 buildPacket(pkt1, req, read); 408 return; 409 } 410 411 buildPacket(pkt1, req1, read); 412 buildPacket(pkt2, req2, read); 413 414 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 415 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 416 Packet::Broadcast); 417 418 pkt->dataDynamic<uint8_t>(data); 419 pkt1->dataStatic<uint8_t>(data); 420 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 421 422 SplitMainSenderState * main_send_state = new SplitMainSenderState; 423 pkt->senderState = main_send_state; 424 main_send_state->fragments[0] = pkt1; 425 main_send_state->fragments[1] = pkt2; 426 main_send_state->outstanding = 2; 427 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 428 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 429} 430 431template <class T> 432Fault 433TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 434{ 435 Fault fault; 436 const int asid = 0; 437 const int thread_id = 0; 438 const Addr pc = thread->readPC(); 439 int block_size = dcachePort.peerBlockSize(); 440 int data_size = sizeof(T); 441 442 RequestPtr req = new Request(asid, addr, data_size, 443 flags, pc, _cpuId, thread_id); 444 445 Addr split_addr = roundDown(addr + data_size - 1, block_size); 446 assert(split_addr <= addr || split_addr - addr < block_size); 447 448 449 _status = DTBWaitResponse; 450 if (split_addr > addr) { 451 RequestPtr req1, req2; 452 assert(!req->isLocked() && !req->isSwap()); 453 req->splitOnVaddr(split_addr, req1, req2); 454 455 typedef SplitDataTranslation::WholeTranslationState WholeState; 456 WholeState *state = new WholeState(req1, req2, req, 457 (uint8_t *)(new T), true); 458 thread->dtb->translateTiming(req1, tc, 459 new SplitDataTranslation(this, 0, state), false); 460 thread->dtb->translateTiming(req2, tc, 461 new SplitDataTranslation(this, 1, state), false); 462 } else { 463 thread->dtb->translateTiming(req, tc, 464 new DataTranslation(this, (uint8_t *)(new T), NULL, true), 465 false); 466 } 467 468 if (traceData) { 469 traceData->setData(data); 470 traceData->setAddr(addr); 471 } 472 473 // This will need a new way to tell if it has a dcache attached. 474 if (req->isUncacheable()) 475 recordEvent("Uncached Read"); 476 477 return NoFault; 478} 479 480#ifndef DOXYGEN_SHOULD_SKIP_THIS 481 482template 483Fault 484TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 485 486template 487Fault 488TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 489 490template 491Fault 492TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 493 494template 495Fault 496TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 497 498template 499Fault 500TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 501 502template 503Fault 504TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 505 506#endif //DOXYGEN_SHOULD_SKIP_THIS 507 508template<> 509Fault 510TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 511{ 512 return read(addr, *(uint64_t*)&data, flags); 513} 514 515template<> 516Fault 517TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 518{ 519 return read(addr, *(uint32_t*)&data, flags); 520} 521 522 523template<> 524Fault 525TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 526{ 527 return read(addr, (uint32_t&)data, flags); 528} 529 530bool 531TimingSimpleCPU::handleWritePacket() 532{ 533 RequestPtr req = dcache_pkt->req; 534 if (req->isMmapedIpr()) { 535 Tick delay; 536 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 537 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 538 _status = DcacheWaitResponse; 539 dcache_pkt = NULL; 540 } else if (!dcachePort.sendTiming(dcache_pkt)) { 541 _status = DcacheRetry; 542 } else { 543 _status = DcacheWaitResponse; 544 // memory system takes ownership of packet 545 dcache_pkt = NULL; 546 } 547 return dcache_pkt == NULL; 548} 549 550template <class T> 551Fault 552TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 553{ 554 const int asid = 0; 555 const int thread_id = 0; 556 const Addr pc = thread->readPC(); 557 int block_size = dcachePort.peerBlockSize(); 558 int data_size = sizeof(T); 559 560 RequestPtr req = new Request(asid, addr, data_size, 561 flags, pc, _cpuId, thread_id); 562 563 Addr split_addr = roundDown(addr + data_size - 1, block_size); 564 assert(split_addr <= addr || split_addr - addr < block_size); 565 566 T *dataP = new T; 567 *dataP = TheISA::gtoh(data); 568 _status = DTBWaitResponse; 569 if (split_addr > addr) { 570 RequestPtr req1, req2; 571 assert(!req->isLocked() && !req->isSwap()); 572 req->splitOnVaddr(split_addr, req1, req2); 573 574 typedef SplitDataTranslation::WholeTranslationState WholeState; 575 WholeState *state = new WholeState(req1, req2, req, 576 (uint8_t *)dataP, false); 577 thread->dtb->translateTiming(req1, tc, 578 new SplitDataTranslation(this, 0, state), true); 579 thread->dtb->translateTiming(req2, tc, 580 new SplitDataTranslation(this, 1, state), true); 581 } else { 582 thread->dtb->translateTiming(req, tc, 583 new DataTranslation(this, (uint8_t *)dataP, res, false), 584 true); 585 } 586 587 if (traceData) { 588 traceData->setAddr(req->getVaddr()); 589 traceData->setData(data); 590 } 591 592 // This will need a new way to tell if it's hooked up to a cache or not. 593 if (req->isUncacheable()) 594 recordEvent("Uncached Write"); 595 596 // If the write needs to have a fault on the access, consider calling 597 // changeStatus() and changing it to "bad addr write" or something. 598 return NoFault; 599} 600 601 602#ifndef DOXYGEN_SHOULD_SKIP_THIS 603template 604Fault 605TimingSimpleCPU::write(Twin32_t data, Addr addr, 606 unsigned flags, uint64_t *res); 607 608template 609Fault 610TimingSimpleCPU::write(Twin64_t data, Addr addr, 611 unsigned flags, uint64_t *res); 612 613template 614Fault 615TimingSimpleCPU::write(uint64_t data, Addr addr, 616 unsigned flags, uint64_t *res); 617 618template 619Fault 620TimingSimpleCPU::write(uint32_t data, Addr addr, 621 unsigned flags, uint64_t *res); 622 623template 624Fault 625TimingSimpleCPU::write(uint16_t data, Addr addr, 626 unsigned flags, uint64_t *res); 627 628template 629Fault 630TimingSimpleCPU::write(uint8_t data, Addr addr, 631 unsigned flags, uint64_t *res); 632 633#endif //DOXYGEN_SHOULD_SKIP_THIS 634 635template<> 636Fault 637TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 638{ 639 return write(*(uint64_t*)&data, addr, flags, res); 640} 641 642template<> 643Fault 644TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 645{ 646 return write(*(uint32_t*)&data, addr, flags, res); 647} 648 649 650template<> 651Fault 652TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 653{ 654 return write((uint32_t)data, addr, flags, res); 655} 656 657 658void 659TimingSimpleCPU::fetch() 660{ 661 DPRINTF(SimpleCPU, "Fetch\n"); 662 663 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 664 checkForInterrupts(); 665 666 checkPcEventQueue(); 667 668 bool fromRom = isRomMicroPC(thread->readMicroPC()); 669
|