timing.cc revision 6043:19852407f5c9
110623Smitch.hayenga@arm.com/* 29288Sandreas.hansson@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 39288Sandreas.hansson@arm.com * All rights reserved. 49288Sandreas.hansson@arm.com * 59288Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 69288Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 79288Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 89288Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 99288Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 109288Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 119288Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 129288Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 139288Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 149288Sandreas.hansson@arm.com * this software without specific prior written permission. 159288Sandreas.hansson@arm.com * 169288Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179288Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189288Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 199288Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 209288Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 219288Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 229288Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239288Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249288Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259288Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 269288Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279288Sandreas.hansson@arm.com * 289288Sandreas.hansson@arm.com * Authors: Steve Reinhardt 299288Sandreas.hansson@arm.com */ 309288Sandreas.hansson@arm.com 319288Sandreas.hansson@arm.com#include "arch/locked_mem.hh" 329288Sandreas.hansson@arm.com#include "arch/mmaped_ipr.hh" 339288Sandreas.hansson@arm.com#include "arch/utility.hh" 349288Sandreas.hansson@arm.com#include "base/bigint.hh" 359288Sandreas.hansson@arm.com#include "cpu/exetrace.hh" 369288Sandreas.hansson@arm.com#include "cpu/simple/timing.hh" 379288Sandreas.hansson@arm.com#include "mem/packet.hh" 389288Sandreas.hansson@arm.com#include "mem/packet_access.hh" 399288Sandreas.hansson@arm.com#include "params/TimingSimpleCPU.hh" 4010623Smitch.hayenga@arm.com#include "sim/system.hh" 419288Sandreas.hansson@arm.com 429288Sandreas.hansson@arm.comusing namespace std; 4313553Sjavier.bueno@metempsy.comusing namespace TheISA; 4413416Sjavier.bueno@metempsy.com 458831Smrinmoy.ghosh@arm.comPort * 468832SAli.Saidi@ARM.comTimingSimpleCPU::getPort(const std::string &if_name, int idx) 4713427Sodanrc@yahoo.com.br{ 488832SAli.Saidi@ARM.com if (if_name == "dcache_port") 4913416Sjavier.bueno@metempsy.com return &dcachePort; 5013416Sjavier.bueno@metempsy.com else if (if_name == "icache_port") 5113416Sjavier.bueno@metempsy.com return &icachePort; 5213416Sjavier.bueno@metempsy.com else 5313416Sjavier.bueno@metempsy.com panic("No Such Port\n"); 5413416Sjavier.bueno@metempsy.com} 5513416Sjavier.bueno@metempsy.com 5613416Sjavier.bueno@metempsy.comvoid 5713416Sjavier.bueno@metempsy.comTimingSimpleCPU::init() 5813416Sjavier.bueno@metempsy.com{ 5913416Sjavier.bueno@metempsy.com BaseCPU::init(); 6013416Sjavier.bueno@metempsy.com#if FULL_SYSTEM 619288Sandreas.hansson@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 628831Smrinmoy.ghosh@arm.com ThreadContext *tc = threadContexts[i]; 638831Smrinmoy.ghosh@arm.com 649338SAndreas.Sandberg@arm.com // initialize CPU, including PC 6513416Sjavier.bueno@metempsy.com TheISA::initCPU(tc, _cpuId); 6613416Sjavier.bueno@metempsy.com } 6713416Sjavier.bueno@metempsy.com#endif 6810466Sandreas.hansson@arm.com} 698831Smrinmoy.ghosh@arm.com 7013422Sodanrc@yahoo.com.brTick 7113422Sodanrc@yahoo.com.brTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 7213422Sodanrc@yahoo.com.br{ 7310623Smitch.hayenga@arm.com panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 7410623Smitch.hayenga@arm.com return curTick; 7510623Smitch.hayenga@arm.com} 7610623Smitch.hayenga@arm.com 7710623Smitch.hayenga@arm.comvoid 7813416Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 7913416Sjavier.bueno@metempsy.com{ 8013551Sjavier.bueno@metempsy.com //No internal storage to update, jusst return 8113551Sjavier.bueno@metempsy.com return; 8213416Sjavier.bueno@metempsy.com} 8313416Sjavier.bueno@metempsy.com 8413416Sjavier.bueno@metempsy.comvoid 8513416Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 8613416Sjavier.bueno@metempsy.com{ 8713416Sjavier.bueno@metempsy.com if (status == RangeChange) { 8813416Sjavier.bueno@metempsy.com if (!snoopRangeSent) { 8913416Sjavier.bueno@metempsy.com snoopRangeSent = true; 9013416Sjavier.bueno@metempsy.com sendStatusChange(Port::RangeChange); 9113416Sjavier.bueno@metempsy.com } 9213416Sjavier.bueno@metempsy.com return; 9313416Sjavier.bueno@metempsy.com } 9413416Sjavier.bueno@metempsy.com 9513416Sjavier.bueno@metempsy.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 9613416Sjavier.bueno@metempsy.com} 9713416Sjavier.bueno@metempsy.com 9813416Sjavier.bueno@metempsy.com 9913416Sjavier.bueno@metempsy.comvoid 10010623Smitch.hayenga@arm.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 10110623Smitch.hayenga@arm.com{ 10210623Smitch.hayenga@arm.com pkt = _pkt; 10310623Smitch.hayenga@arm.com cpu->schedule(this, t); 10410623Smitch.hayenga@arm.com} 10510623Smitch.hayenga@arm.com 10610623Smitch.hayenga@arm.comTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 10710623Smitch.hayenga@arm.com : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 10810623Smitch.hayenga@arm.com dcachePort(this, p->clock), fetchEvent(this) 10910623Smitch.hayenga@arm.com{ 11010623Smitch.hayenga@arm.com _status = Idle; 11110623Smitch.hayenga@arm.com 11210623Smitch.hayenga@arm.com icachePort.snoopRangeSent = false; 11310623Smitch.hayenga@arm.com dcachePort.snoopRangeSent = false; 11410623Smitch.hayenga@arm.com 1158831Smrinmoy.ghosh@arm.com ifetch_pkt = dcache_pkt = NULL; 1168831Smrinmoy.ghosh@arm.com drainEvent = NULL; 1179338SAndreas.Sandberg@arm.com previousTick = 0; 1188831Smrinmoy.ghosh@arm.com changeState(SimObject::Running); 11913422Sodanrc@yahoo.com.br} 12013422Sodanrc@yahoo.com.br 12113422Sodanrc@yahoo.com.br 12210623Smitch.hayenga@arm.comTimingSimpleCPU::~TimingSimpleCPU() 12310623Smitch.hayenga@arm.com{ 12410623Smitch.hayenga@arm.com} 12510623Smitch.hayenga@arm.com 12610623Smitch.hayenga@arm.comvoid 12710623Smitch.hayenga@arm.comTimingSimpleCPU::serialize(ostream &os) 12810623Smitch.hayenga@arm.com{ 12910623Smitch.hayenga@arm.com SimObject::State so_state = SimObject::getState(); 13010623Smitch.hayenga@arm.com SERIALIZE_ENUM(so_state); 13110623Smitch.hayenga@arm.com BaseSimpleCPU::serialize(os); 13210623Smitch.hayenga@arm.com} 13313427Sodanrc@yahoo.com.br 13413427Sodanrc@yahoo.com.brvoid 13513427Sodanrc@yahoo.com.brTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 13613427Sodanrc@yahoo.com.br{ 13710623Smitch.hayenga@arm.com SimObject::State so_state; 1388831Smrinmoy.ghosh@arm.com UNSERIALIZE_ENUM(so_state); 1398831Smrinmoy.ghosh@arm.com BaseSimpleCPU::unserialize(cp, section); 1409338SAndreas.Sandberg@arm.com} 1418831Smrinmoy.ghosh@arm.com 14210623Smitch.hayenga@arm.comunsigned int 14313553Sjavier.bueno@metempsy.comTimingSimpleCPU::drain(Event *drain_event) 14413553Sjavier.bueno@metempsy.com{ 14513553Sjavier.bueno@metempsy.com // TimingSimpleCPU is ready to drain if it's not waiting for 14613553Sjavier.bueno@metempsy.com // an access to complete. 14713553Sjavier.bueno@metempsy.com if (_status == Idle || _status == Running || _status == SwitchedOut) { 14813553Sjavier.bueno@metempsy.com changeState(SimObject::Drained); 14913553Sjavier.bueno@metempsy.com return 0; 15013553Sjavier.bueno@metempsy.com } else { 15113553Sjavier.bueno@metempsy.com changeState(SimObject::Draining); 15213553Sjavier.bueno@metempsy.com drainEvent = drain_event; 15313553Sjavier.bueno@metempsy.com return 1; 15413553Sjavier.bueno@metempsy.com } 15513553Sjavier.bueno@metempsy.com} 15613553Sjavier.bueno@metempsy.com 15713553Sjavier.bueno@metempsy.comvoid 15813553Sjavier.bueno@metempsy.comTimingSimpleCPU::resume() 15913553Sjavier.bueno@metempsy.com{ 16013553Sjavier.bueno@metempsy.com DPRINTF(SimpleCPU, "Resume\n"); 16113553Sjavier.bueno@metempsy.com if (_status != SwitchedOut && _status != Idle) { 16213553Sjavier.bueno@metempsy.com assert(system->getMemoryMode() == Enums::timing); 16313553Sjavier.bueno@metempsy.com 16413553Sjavier.bueno@metempsy.com if (fetchEvent.scheduled()) 16513553Sjavier.bueno@metempsy.com deschedule(fetchEvent); 16613553Sjavier.bueno@metempsy.com 16713553Sjavier.bueno@metempsy.com schedule(fetchEvent, nextCycle()); 16813553Sjavier.bueno@metempsy.com } 16913553Sjavier.bueno@metempsy.com 17013553Sjavier.bueno@metempsy.com changeState(SimObject::Running); 17113553Sjavier.bueno@metempsy.com} 17213553Sjavier.bueno@metempsy.com 17313553Sjavier.bueno@metempsy.comvoid 17413553Sjavier.bueno@metempsy.comTimingSimpleCPU::switchOut() 17513553Sjavier.bueno@metempsy.com{ 17613553Sjavier.bueno@metempsy.com assert(_status == Running || _status == Idle); 17713553Sjavier.bueno@metempsy.com _status = SwitchedOut; 17813553Sjavier.bueno@metempsy.com numCycles += tickToCycles(curTick - previousTick); 17913553Sjavier.bueno@metempsy.com 18013553Sjavier.bueno@metempsy.com // If we've been scheduled to resume but are then told to switch out, 18113553Sjavier.bueno@metempsy.com // we'll need to cancel it. 18213554Sjavier.bueno@metempsy.com if (fetchEvent.scheduled()) 18313624Sjavier.bueno@metempsy.com deschedule(fetchEvent); 18413624Sjavier.bueno@metempsy.com} 18513624Sjavier.bueno@metempsy.com 18613624Sjavier.bueno@metempsy.com 18713624Sjavier.bueno@metempsy.comvoid 18813624Sjavier.bueno@metempsy.comTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 18913624Sjavier.bueno@metempsy.com{ 19013624Sjavier.bueno@metempsy.com BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 19113624Sjavier.bueno@metempsy.com 19213624Sjavier.bueno@metempsy.com // if any of this CPU's ThreadContexts are active, mark the CPU as 19313624Sjavier.bueno@metempsy.com // running and schedule its tick event. 19413624Sjavier.bueno@metempsy.com for (int i = 0; i < threadContexts.size(); ++i) { 19513624Sjavier.bueno@metempsy.com ThreadContext *tc = threadContexts[i]; 19613624Sjavier.bueno@metempsy.com if (tc->status() == ThreadContext::Active && _status != Running) { 19713624Sjavier.bueno@metempsy.com _status = Running; 19813624Sjavier.bueno@metempsy.com break; 19913624Sjavier.bueno@metempsy.com } 20013624Sjavier.bueno@metempsy.com } 20113624Sjavier.bueno@metempsy.com 20213624Sjavier.bueno@metempsy.com if (_status != Running) { 20313624Sjavier.bueno@metempsy.com _status = Idle; 20413624Sjavier.bueno@metempsy.com } 20513624Sjavier.bueno@metempsy.com assert(threadContexts.size() == 1); 20613554Sjavier.bueno@metempsy.com previousTick = curTick; 20713554Sjavier.bueno@metempsy.com} 20813554Sjavier.bueno@metempsy.com 20913554Sjavier.bueno@metempsy.com 21013554Sjavier.bueno@metempsy.comvoid 21113554Sjavier.bueno@metempsy.comTimingSimpleCPU::activateContext(int thread_num, int delay) 21213554Sjavier.bueno@metempsy.com{ 21313554Sjavier.bueno@metempsy.com DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 21413554Sjavier.bueno@metempsy.com 21513554Sjavier.bueno@metempsy.com assert(thread_num == 0); 21613554Sjavier.bueno@metempsy.com assert(thread); 21713554Sjavier.bueno@metempsy.com 21813554Sjavier.bueno@metempsy.com assert(_status == Idle); 21913554Sjavier.bueno@metempsy.com 22013554Sjavier.bueno@metempsy.com notIdleFraction++; 22113554Sjavier.bueno@metempsy.com _status = Running; 22213554Sjavier.bueno@metempsy.com 22313554Sjavier.bueno@metempsy.com // kick things off by initiating the fetch of the next instruction 22413554Sjavier.bueno@metempsy.com schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 22513554Sjavier.bueno@metempsy.com} 22613554Sjavier.bueno@metempsy.com 22713554Sjavier.bueno@metempsy.com 22813554Sjavier.bueno@metempsy.comvoid 22913554Sjavier.bueno@metempsy.comTimingSimpleCPU::suspendContext(int thread_num) 23013554Sjavier.bueno@metempsy.com{ 23113554Sjavier.bueno@metempsy.com DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 23213554Sjavier.bueno@metempsy.com 23313554Sjavier.bueno@metempsy.com assert(thread_num == 0); 23413554Sjavier.bueno@metempsy.com assert(thread); 23513554Sjavier.bueno@metempsy.com 23613554Sjavier.bueno@metempsy.com if (_status == Idle) 23713554Sjavier.bueno@metempsy.com return; 23813554Sjavier.bueno@metempsy.com 239 assert(_status == Running); 240 241 // just change status to Idle... if status != Running, 242 // completeInst() will not initiate fetch of next instruction. 243 244 notIdleFraction--; 245 _status = Idle; 246} 247 248bool 249TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 250{ 251 RequestPtr req = pkt->req; 252 if (req->isMmapedIpr()) { 253 Tick delay; 254 delay = TheISA::handleIprRead(thread->getTC(), pkt); 255 new IprEvent(pkt, this, nextCycle(curTick + delay)); 256 _status = DcacheWaitResponse; 257 dcache_pkt = NULL; 258 } else if (!dcachePort.sendTiming(pkt)) { 259 _status = DcacheRetry; 260 dcache_pkt = pkt; 261 } else { 262 _status = DcacheWaitResponse; 263 // memory system takes ownership of packet 264 dcache_pkt = NULL; 265 } 266 return dcache_pkt == NULL; 267} 268 269void 270TimingSimpleCPU::sendData(Fault fault, RequestPtr req, 271 uint8_t *data, uint64_t *res, bool read) 272{ 273 _status = Running; 274 if (fault != NoFault) { 275 delete data; 276 delete req; 277 278 translationFault(fault); 279 return; 280 } 281 PacketPtr pkt; 282 buildPacket(pkt, req, read); 283 pkt->dataDynamic<uint8_t>(data); 284 if (req->getFlags().isSet(Request::NO_ACCESS)) { 285 assert(!dcache_pkt); 286 pkt->makeResponse(); 287 completeDataAccess(pkt); 288 } else if (read) { 289 handleReadPacket(pkt); 290 } else { 291 bool do_access = true; // flag to suppress cache access 292 293 if (req->isLocked()) { 294 do_access = TheISA::handleLockedWrite(thread, req); 295 } else if (req->isCondSwap()) { 296 assert(res); 297 req->setExtraData(*res); 298 } 299 300 if (do_access) { 301 dcache_pkt = pkt; 302 handleWritePacket(); 303 } else { 304 _status = DcacheWaitResponse; 305 completeDataAccess(pkt); 306 } 307 } 308} 309 310void 311TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, 312 RequestPtr req1, RequestPtr req2, RequestPtr req, 313 uint8_t *data, bool read) 314{ 315 _status = Running; 316 if (fault1 != NoFault || fault2 != NoFault) { 317 delete data; 318 delete req1; 319 delete req2; 320 if (fault1 != NoFault) 321 translationFault(fault1); 322 else if (fault2 != NoFault) 323 translationFault(fault2); 324 return; 325 } 326 PacketPtr pkt1, pkt2; 327 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 328 if (req->getFlags().isSet(Request::NO_ACCESS)) { 329 assert(!dcache_pkt); 330 pkt1->makeResponse(); 331 completeDataAccess(pkt1); 332 } else if (read) { 333 if (handleReadPacket(pkt1)) { 334 SplitFragmentSenderState * send_state = 335 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 336 send_state->clearFromParent(); 337 if (handleReadPacket(pkt2)) { 338 send_state = dynamic_cast<SplitFragmentSenderState *>( 339 pkt1->senderState); 340 send_state->clearFromParent(); 341 } 342 } 343 } else { 344 dcache_pkt = pkt1; 345 if (handleWritePacket()) { 346 SplitFragmentSenderState * send_state = 347 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 348 send_state->clearFromParent(); 349 dcache_pkt = pkt2; 350 if (handleWritePacket()) { 351 send_state = dynamic_cast<SplitFragmentSenderState *>( 352 pkt1->senderState); 353 send_state->clearFromParent(); 354 } 355 } 356 } 357} 358 359void 360TimingSimpleCPU::translationFault(Fault fault) 361{ 362 numCycles += tickToCycles(curTick - previousTick); 363 previousTick = curTick; 364 365 if (traceData) { 366 // Since there was a fault, we shouldn't trace this instruction. 367 delete traceData; 368 traceData = NULL; 369 } 370 371 postExecute(); 372 373 if (getState() == SimObject::Draining) { 374 advancePC(fault); 375 completeDrain(); 376 } else { 377 advanceInst(fault); 378 } 379} 380 381void 382TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 383{ 384 MemCmd cmd; 385 if (read) { 386 cmd = MemCmd::ReadReq; 387 if (req->isLocked()) 388 cmd = MemCmd::LoadLockedReq; 389 } else { 390 cmd = MemCmd::WriteReq; 391 if (req->isLocked()) { 392 cmd = MemCmd::StoreCondReq; 393 } else if (req->isSwap()) { 394 cmd = MemCmd::SwapReq; 395 } 396 } 397 pkt = new Packet(req, cmd, Packet::Broadcast); 398} 399 400void 401TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 402 RequestPtr req1, RequestPtr req2, RequestPtr req, 403 uint8_t *data, bool read) 404{ 405 pkt1 = pkt2 = NULL; 406 407 assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 408 409 if (req->getFlags().isSet(Request::NO_ACCESS)) { 410 buildPacket(pkt1, req, read); 411 return; 412 } 413 414 buildPacket(pkt1, req1, read); 415 buildPacket(pkt2, req2, read); 416 417 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 418 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 419 Packet::Broadcast); 420 421 pkt->dataDynamic<uint8_t>(data); 422 pkt1->dataStatic<uint8_t>(data); 423 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 424 425 SplitMainSenderState * main_send_state = new SplitMainSenderState; 426 pkt->senderState = main_send_state; 427 main_send_state->fragments[0] = pkt1; 428 main_send_state->fragments[1] = pkt2; 429 main_send_state->outstanding = 2; 430 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 431 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 432} 433 434template <class T> 435Fault 436TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 437{ 438 Fault fault; 439 const int asid = 0; 440 const int thread_id = 0; 441 const Addr pc = thread->readPC(); 442 int block_size = dcachePort.peerBlockSize(); 443 int data_size = sizeof(T); 444 445 RequestPtr req = new Request(asid, addr, data_size, 446 flags, pc, _cpuId, thread_id); 447 448 Addr split_addr = roundDown(addr + data_size - 1, block_size); 449 assert(split_addr <= addr || split_addr - addr < block_size); 450 451 452 _status = DTBWaitResponse; 453 if (split_addr > addr) { 454 RequestPtr req1, req2; 455 assert(!req->isLocked() && !req->isSwap()); 456 req->splitOnVaddr(split_addr, req1, req2); 457 458 typedef SplitDataTranslation::WholeTranslationState WholeState; 459 WholeState *state = new WholeState(req1, req2, req, 460 (uint8_t *)(new T), BaseTLB::Read); 461 thread->dtb->translateTiming(req1, tc, 462 new SplitDataTranslation(this, 0, state), BaseTLB::Read); 463 thread->dtb->translateTiming(req2, tc, 464 new SplitDataTranslation(this, 1, state), BaseTLB::Read); 465 } else { 466 DataTranslation *translation = 467 new DataTranslation(this, (uint8_t *)(new T), NULL, BaseTLB::Read); 468 thread->dtb->translateTiming(req, tc, translation, BaseTLB::Read); 469 } 470 471 if (traceData) { 472 traceData->setData(data); 473 traceData->setAddr(addr); 474 } 475 476 // This will need a new way to tell if it has a dcache attached. 477 if (req->isUncacheable()) 478 recordEvent("Uncached Read"); 479 480 return NoFault; 481} 482 483#ifndef DOXYGEN_SHOULD_SKIP_THIS 484 485template 486Fault 487TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 488 489template 490Fault 491TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 492 493template 494Fault 495TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 496 497template 498Fault 499TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 500 501template 502Fault 503TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 504 505template 506Fault 507TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 508 509#endif //DOXYGEN_SHOULD_SKIP_THIS 510 511template<> 512Fault 513TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 514{ 515 return read(addr, *(uint64_t*)&data, flags); 516} 517 518template<> 519Fault 520TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 521{ 522 return read(addr, *(uint32_t*)&data, flags); 523} 524 525 526template<> 527Fault 528TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 529{ 530 return read(addr, (uint32_t&)data, flags); 531} 532 533bool 534TimingSimpleCPU::handleWritePacket() 535{ 536 RequestPtr req = dcache_pkt->req; 537 if (req->isMmapedIpr()) { 538 Tick delay; 539 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 540 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 541 _status = DcacheWaitResponse; 542 dcache_pkt = NULL; 543 } else if (!dcachePort.sendTiming(dcache_pkt)) { 544 _status = DcacheRetry; 545 } else { 546 _status = DcacheWaitResponse; 547 // memory system takes ownership of packet 548 dcache_pkt = NULL; 549 } 550 return dcache_pkt == NULL; 551} 552 553template <class T> 554Fault 555TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 556{ 557 const int asid = 0; 558 const int thread_id = 0; 559 const Addr pc = thread->readPC(); 560 int block_size = dcachePort.peerBlockSize(); 561 int data_size = sizeof(T); 562 563 RequestPtr req = new Request(asid, addr, data_size, 564 flags, pc, _cpuId, thread_id); 565 566 Addr split_addr = roundDown(addr + data_size - 1, block_size); 567 assert(split_addr <= addr || split_addr - addr < block_size); 568 569 T *dataP = new T; 570 *dataP = TheISA::htog(data); 571 _status = DTBWaitResponse; 572 if (split_addr > addr) { 573 RequestPtr req1, req2; 574 assert(!req->isLocked() && !req->isSwap()); 575 req->splitOnVaddr(split_addr, req1, req2); 576 577 typedef SplitDataTranslation::WholeTranslationState WholeState; 578 WholeState *state = new WholeState(req1, req2, req, 579 (uint8_t *)dataP, BaseTLB::Write); 580 thread->dtb->translateTiming(req1, tc, 581 new SplitDataTranslation(this, 0, state), BaseTLB::Write); 582 thread->dtb->translateTiming(req2, tc, 583 new SplitDataTranslation(this, 1, state), BaseTLB::Write); 584 } else { 585 DataTranslation *translation = 586 new DataTranslation(this, (uint8_t *)dataP, res, BaseTLB::Write); 587 thread->dtb->translateTiming(req, tc, translation, BaseTLB::Write); 588 } 589 590 if (traceData) { 591 traceData->setAddr(req->getVaddr()); 592 traceData->setData(data); 593 } 594 595 // This will need a new way to tell if it's hooked up to a cache or not. 596 if (req->isUncacheable()) 597 recordEvent("Uncached Write"); 598 599 // If the write needs to have a fault on the access, consider calling 600 // changeStatus() and changing it to "bad addr write" or something. 601 return NoFault; 602} 603 604 605#ifndef DOXYGEN_SHOULD_SKIP_THIS 606template 607Fault 608TimingSimpleCPU::write(Twin32_t data, Addr addr, 609 unsigned flags, uint64_t *res); 610 611template 612Fault 613TimingSimpleCPU::write(Twin64_t data, Addr addr, 614 unsigned flags, uint64_t *res); 615 616template 617Fault 618TimingSimpleCPU::write(uint64_t data, Addr addr, 619 unsigned flags, uint64_t *res); 620 621template 622Fault 623TimingSimpleCPU::write(uint32_t data, Addr addr, 624 unsigned flags, uint64_t *res); 625 626template 627Fault 628TimingSimpleCPU::write(uint16_t data, Addr addr, 629 unsigned flags, uint64_t *res); 630 631template 632Fault 633TimingSimpleCPU::write(uint8_t data, Addr addr, 634 unsigned flags, uint64_t *res); 635 636#endif //DOXYGEN_SHOULD_SKIP_THIS 637 638template<> 639Fault 640TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 641{ 642 return write(*(uint64_t*)&data, addr, flags, res); 643} 644 645template<> 646Fault 647TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 648{ 649 return write(*(uint32_t*)&data, addr, flags, res); 650} 651 652 653template<> 654Fault 655TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 656{ 657 return write((uint32_t)data, addr, flags, res); 658} 659 660 661void 662TimingSimpleCPU::fetch() 663{ 664 DPRINTF(SimpleCPU, "Fetch\n"); 665 666 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 667 checkForInterrupts(); 668 669 checkPcEventQueue(); 670 671 bool fromRom = isRomMicroPC(thread->readMicroPC()); 672 673 if (!fromRom && !curMacroStaticInst) { 674 Request *ifetch_req = new Request(); 675 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 676 setupFetchRequest(ifetch_req); 677 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 678 BaseTLB::Execute); 679 } else { 680 _status = IcacheWaitResponse; 681 completeIfetch(NULL); 682 683 numCycles += tickToCycles(curTick - previousTick); 684 previousTick = curTick; 685 } 686} 687 688 689void 690TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 691{ 692 if (fault == NoFault) { 693 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 694 ifetch_pkt->dataStatic(&inst); 695 696 if (!icachePort.sendTiming(ifetch_pkt)) { 697 // Need to wait for retry 698 _status = IcacheRetry; 699 } else { 700 // Need to wait for cache to respond 701 _status = IcacheWaitResponse; 702 // ownership of packet transferred to memory system 703 ifetch_pkt = NULL; 704 } 705 } else { 706 delete req; 707 // fetch fault: advance directly to next instruction (fault handler) 708 advanceInst(fault); 709 } 710 711 numCycles += tickToCycles(curTick - previousTick); 712 previousTick = curTick; 713} 714 715 716void 717TimingSimpleCPU::advanceInst(Fault fault) 718{ 719 if (fault != NoFault || !stayAtPC) 720 advancePC(fault); 721 722 if (_status == Running) { 723 // kick off fetch of next instruction... callback from icache 724 // response will cause that instruction to be executed, 725 // keeping the CPU running. 726 fetch(); 727 } 728} 729 730 731void 732TimingSimpleCPU::completeIfetch(PacketPtr pkt) 733{ 734 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 735 736 // received a response from the icache: execute the received 737 // instruction 738 739 assert(!pkt || !pkt->isError()); 740 assert(_status == IcacheWaitResponse); 741 742 _status = Running; 743 744 numCycles += tickToCycles(curTick - previousTick); 745 previousTick = curTick; 746 747 if (getState() == SimObject::Draining) { 748 if (pkt) { 749 delete pkt->req; 750 delete pkt; 751 } 752 753 completeDrain(); 754 return; 755 } 756 757 preExecute(); 758 if (curStaticInst && 759 curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 760 // load or store: just send to dcache 761 Fault fault = curStaticInst->initiateAcc(this, traceData); 762 if (_status != Running) { 763 // instruction will complete in dcache response callback 764 assert(_status == DcacheWaitResponse || 765 _status == DcacheRetry || DTBWaitResponse); 766 assert(fault == NoFault); 767 } else { 768 if (fault != NoFault && traceData) { 769 // If there was a fault, we shouldn't trace this instruction. 770 delete traceData; 771 traceData = NULL; 772 } 773 774 postExecute(); 775 // @todo remove me after debugging with legion done 776 if (curStaticInst && (!curStaticInst->isMicroop() || 777 curStaticInst->isFirstMicroop())) 778 instCnt++; 779 advanceInst(fault); 780 } 781 } else if (curStaticInst) { 782 // non-memory instruction: execute completely now 783 Fault fault = curStaticInst->execute(this, traceData); 784 785 // keep an instruction count 786 if (fault == NoFault) 787 countInst(); 788 else if (traceData) { 789 // If there was a fault, we shouldn't trace this instruction. 790 delete traceData; 791 traceData = NULL; 792 } 793 794 postExecute(); 795 // @todo remove me after debugging with legion done 796 if (curStaticInst && (!curStaticInst->isMicroop() || 797 curStaticInst->isFirstMicroop())) 798 instCnt++; 799 advanceInst(fault); 800 } else { 801 advanceInst(NoFault); 802 } 803 804 if (pkt) { 805 delete pkt->req; 806 delete pkt; 807 } 808} 809 810void 811TimingSimpleCPU::IcachePort::ITickEvent::process() 812{ 813 cpu->completeIfetch(pkt); 814} 815 816bool 817TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 818{ 819 if (pkt->isResponse() && !pkt->wasNacked()) { 820 // delay processing of returned data until next CPU clock edge 821 Tick next_tick = cpu->nextCycle(curTick); 822 823 if (next_tick == curTick) 824 cpu->completeIfetch(pkt); 825 else 826 tickEvent.schedule(pkt, next_tick); 827 828 return true; 829 } 830 else if (pkt->wasNacked()) { 831 assert(cpu->_status == IcacheWaitResponse); 832 pkt->reinitNacked(); 833 if (!sendTiming(pkt)) { 834 cpu->_status = IcacheRetry; 835 cpu->ifetch_pkt = pkt; 836 } 837 } 838 //Snooping a Coherence Request, do nothing 839 return true; 840} 841 842void 843TimingSimpleCPU::IcachePort::recvRetry() 844{ 845 // we shouldn't get a retry unless we have a packet that we're 846 // waiting to transmit 847 assert(cpu->ifetch_pkt != NULL); 848 assert(cpu->_status == IcacheRetry); 849 PacketPtr tmp = cpu->ifetch_pkt; 850 if (sendTiming(tmp)) { 851 cpu->_status = IcacheWaitResponse; 852 cpu->ifetch_pkt = NULL; 853 } 854} 855 856void 857TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 858{ 859 // received a response from the dcache: complete the load or store 860 // instruction 861 assert(!pkt->isError()); 862 863 numCycles += tickToCycles(curTick - previousTick); 864 previousTick = curTick; 865 866 if (pkt->senderState) { 867 SplitFragmentSenderState * send_state = 868 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 869 assert(send_state); 870 delete pkt->req; 871 delete pkt; 872 PacketPtr big_pkt = send_state->bigPkt; 873 delete send_state; 874 875 SplitMainSenderState * main_send_state = 876 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 877 assert(main_send_state); 878 // Record the fact that this packet is no longer outstanding. 879 assert(main_send_state->outstanding != 0); 880 main_send_state->outstanding--; 881 882 if (main_send_state->outstanding) { 883 return; 884 } else { 885 delete main_send_state; 886 big_pkt->senderState = NULL; 887 pkt = big_pkt; 888 } 889 } 890 891 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); 892 _status = Running; 893 894 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 895 896 // keep an instruction count 897 if (fault == NoFault) 898 countInst(); 899 else if (traceData) { 900 // If there was a fault, we shouldn't trace this instruction. 901 delete traceData; 902 traceData = NULL; 903 } 904 905 // the locked flag may be cleared on the response packet, so check 906 // pkt->req and not pkt to see if it was a load-locked 907 if (pkt->isRead() && pkt->req->isLocked()) { 908 TheISA::handleLockedRead(thread, pkt->req); 909 } 910 911 delete pkt->req; 912 delete pkt; 913 914 postExecute(); 915 916 if (getState() == SimObject::Draining) { 917 advancePC(fault); 918 completeDrain(); 919 920 return; 921 } 922 923 advanceInst(fault); 924} 925 926 927void 928TimingSimpleCPU::completeDrain() 929{ 930 DPRINTF(Config, "Done draining\n"); 931 changeState(SimObject::Drained); 932 drainEvent->process(); 933} 934 935void 936TimingSimpleCPU::DcachePort::setPeer(Port *port) 937{ 938 Port::setPeer(port); 939 940#if FULL_SYSTEM 941 // Update the ThreadContext's memory ports (Functional/Virtual 942 // Ports) 943 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 944#endif 945} 946 947bool 948TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 949{ 950 if (pkt->isResponse() && !pkt->wasNacked()) { 951 // delay processing of returned data until next CPU clock edge 952 Tick next_tick = cpu->nextCycle(curTick); 953 954 if (next_tick == curTick) { 955 cpu->completeDataAccess(pkt); 956 } else { 957 tickEvent.schedule(pkt, next_tick); 958 } 959 960 return true; 961 } 962 else if (pkt->wasNacked()) { 963 assert(cpu->_status == DcacheWaitResponse); 964 pkt->reinitNacked(); 965 if (!sendTiming(pkt)) { 966 cpu->_status = DcacheRetry; 967 cpu->dcache_pkt = pkt; 968 } 969 } 970 //Snooping a Coherence Request, do nothing 971 return true; 972} 973 974void 975TimingSimpleCPU::DcachePort::DTickEvent::process() 976{ 977 cpu->completeDataAccess(pkt); 978} 979 980void 981TimingSimpleCPU::DcachePort::recvRetry() 982{ 983 // we shouldn't get a retry unless we have a packet that we're 984 // waiting to transmit 985 assert(cpu->dcache_pkt != NULL); 986 assert(cpu->_status == DcacheRetry); 987 PacketPtr tmp = cpu->dcache_pkt; 988 if (tmp->senderState) { 989 // This is a packet from a split access. 990 SplitFragmentSenderState * send_state = 991 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 992 assert(send_state); 993 PacketPtr big_pkt = send_state->bigPkt; 994 995 SplitMainSenderState * main_send_state = 996 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 997 assert(main_send_state); 998 999 if (sendTiming(tmp)) { 1000 // If we were able to send without retrying, record that fact 1001 // and try sending the other fragment. 1002 send_state->clearFromParent(); 1003 int other_index = main_send_state->getPendingFragment(); 1004 if (other_index > 0) { 1005 tmp = main_send_state->fragments[other_index]; 1006 cpu->dcache_pkt = tmp; 1007 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1008 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1009 main_send_state->fragments[other_index] = NULL; 1010 } 1011 } else { 1012 cpu->_status = DcacheWaitResponse; 1013 // memory system takes ownership of packet 1014 cpu->dcache_pkt = NULL; 1015 } 1016 } 1017 } else if (sendTiming(tmp)) { 1018 cpu->_status = DcacheWaitResponse; 1019 // memory system takes ownership of packet 1020 cpu->dcache_pkt = NULL; 1021 } 1022} 1023 1024TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1025 Tick t) 1026 : pkt(_pkt), cpu(_cpu) 1027{ 1028 cpu->schedule(this, t); 1029} 1030 1031void 1032TimingSimpleCPU::IprEvent::process() 1033{ 1034 cpu->completeDataAccess(pkt); 1035} 1036 1037const char * 1038TimingSimpleCPU::IprEvent::description() const 1039{ 1040 return "Timing Simple CPU Delay IPR event"; 1041} 1042 1043 1044void 1045TimingSimpleCPU::printAddr(Addr a) 1046{ 1047 dcachePort.printAddr(a); 1048} 1049 1050 1051//////////////////////////////////////////////////////////////////////// 1052// 1053// TimingSimpleCPU Simulation Object 1054// 1055TimingSimpleCPU * 1056TimingSimpleCPUParams::create() 1057{ 1058 numThreads = 1; 1059#if !FULL_SYSTEM 1060 if (workload.size() != 1) 1061 panic("only one workload allowed"); 1062#endif 1063 return new TimingSimpleCPU(this); 1064} 1065