timing.cc revision 6012:47748a3b6ecf
16973Stjones1@inf.ed.ac.uk/* 27944SGiacomo.Gabrielli@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 37944SGiacomo.Gabrielli@arm.com * All rights reserved. 47944SGiacomo.Gabrielli@arm.com * 57944SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 67944SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are 77944SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright 87944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 97944SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 107944SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 117944SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution; 127944SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its 137944SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from 146973Stjones1@inf.ed.ac.uk * this software without specific prior written permission. 156973Stjones1@inf.ed.ac.uk * 166973Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176973Stjones1@inf.ed.ac.uk * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186973Stjones1@inf.ed.ac.uk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196973Stjones1@inf.ed.ac.uk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206973Stjones1@inf.ed.ac.uk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216973Stjones1@inf.ed.ac.uk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226973Stjones1@inf.ed.ac.uk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236973Stjones1@inf.ed.ac.uk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246973Stjones1@inf.ed.ac.uk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256973Stjones1@inf.ed.ac.uk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266973Stjones1@inf.ed.ac.uk * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276973Stjones1@inf.ed.ac.uk * 286973Stjones1@inf.ed.ac.uk * Authors: Steve Reinhardt 296973Stjones1@inf.ed.ac.uk */ 306973Stjones1@inf.ed.ac.uk 316973Stjones1@inf.ed.ac.uk#include "arch/locked_mem.hh" 326973Stjones1@inf.ed.ac.uk#include "arch/mmaped_ipr.hh" 336973Stjones1@inf.ed.ac.uk#include "arch/utility.hh" 346973Stjones1@inf.ed.ac.uk#include "base/bigint.hh" 356973Stjones1@inf.ed.ac.uk#include "cpu/exetrace.hh" 366973Stjones1@inf.ed.ac.uk#include "cpu/simple/timing.hh" 376973Stjones1@inf.ed.ac.uk#include "mem/packet.hh" 386973Stjones1@inf.ed.ac.uk#include "mem/packet_access.hh" 396973Stjones1@inf.ed.ac.uk#include "params/TimingSimpleCPU.hh" 406973Stjones1@inf.ed.ac.uk#include "sim/system.hh" 416973Stjones1@inf.ed.ac.uk 426973Stjones1@inf.ed.ac.ukusing namespace std; 436973Stjones1@inf.ed.ac.ukusing namespace TheISA; 446973Stjones1@inf.ed.ac.uk 456973Stjones1@inf.ed.ac.ukPort * 466973Stjones1@inf.ed.ac.ukTimingSimpleCPU::getPort(const std::string &if_name, int idx) 476973Stjones1@inf.ed.ac.uk{ 4810687SAndreas.Sandberg@ARM.com if (if_name == "dcache_port") 497678Sgblack@eecs.umich.edu return &dcachePort; 506973Stjones1@inf.ed.ac.uk else if (if_name == "icache_port") 517049Stjones1@inf.ed.ac.uk return &icachePort; 527049Stjones1@inf.ed.ac.uk else 537049Stjones1@inf.ed.ac.uk panic("No Such Port\n"); 547049Stjones1@inf.ed.ac.uk} 557049Stjones1@inf.ed.ac.uk 567049Stjones1@inf.ed.ac.ukvoid 577049Stjones1@inf.ed.ac.ukTimingSimpleCPU::init() 587049Stjones1@inf.ed.ac.uk{ 597049Stjones1@inf.ed.ac.uk BaseCPU::init(); 607049Stjones1@inf.ed.ac.uk#if FULL_SYSTEM 616973Stjones1@inf.ed.ac.uk for (int i = 0; i < threadContexts.size(); ++i) { 626973Stjones1@inf.ed.ac.uk ThreadContext *tc = threadContexts[i]; 636973Stjones1@inf.ed.ac.uk 646973Stjones1@inf.ed.ac.uk // initialize CPU, including PC 656973Stjones1@inf.ed.ac.uk TheISA::initCPU(tc, _cpuId); 666973Stjones1@inf.ed.ac.uk } 676973Stjones1@inf.ed.ac.uk#endif 687944SGiacomo.Gabrielli@arm.com} 696973Stjones1@inf.ed.ac.uk 706973Stjones1@inf.ed.ac.ukTick 716973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 726973Stjones1@inf.ed.ac.uk{ 736973Stjones1@inf.ed.ac.uk panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 746973Stjones1@inf.ed.ac.uk return curTick; 756973Stjones1@inf.ed.ac.uk} 766973Stjones1@inf.ed.ac.uk 777049Stjones1@inf.ed.ac.ukvoid 787049Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 797049Stjones1@inf.ed.ac.uk{ 807049Stjones1@inf.ed.ac.uk //No internal storage to update, jusst return 8112749Sgiacomo.travaglini@arm.com return; 8212749Sgiacomo.travaglini@arm.com} 837944SGiacomo.Gabrielli@arm.com 847944SGiacomo.Gabrielli@arm.comvoid 856973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 866973Stjones1@inf.ed.ac.uk{ 876973Stjones1@inf.ed.ac.uk if (status == RangeChange) { 886973Stjones1@inf.ed.ac.uk if (!snoopRangeSent) { 896973Stjones1@inf.ed.ac.uk snoopRangeSent = true; 907049Stjones1@inf.ed.ac.uk sendStatusChange(Port::RangeChange); 917049Stjones1@inf.ed.ac.uk } 927049Stjones1@inf.ed.ac.uk return; 937049Stjones1@inf.ed.ac.uk } 947049Stjones1@inf.ed.ac.uk 9512749Sgiacomo.travaglini@arm.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 9612749Sgiacomo.travaglini@arm.com} 9712749Sgiacomo.travaglini@arm.com 987944SGiacomo.Gabrielli@arm.com 997944SGiacomo.Gabrielli@arm.comvoid 1007944SGiacomo.Gabrielli@arm.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1016973Stjones1@inf.ed.ac.uk{ 1026973Stjones1@inf.ed.ac.uk pkt = _pkt; 1036973Stjones1@inf.ed.ac.uk cpu->schedule(this, t); 1046973Stjones1@inf.ed.ac.uk} 1056973Stjones1@inf.ed.ac.uk 1067049Stjones1@inf.ed.ac.ukTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1077049Stjones1@inf.ed.ac.uk : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 1087049Stjones1@inf.ed.ac.uk dcachePort(this, p->clock), fetchEvent(this) 1097049Stjones1@inf.ed.ac.uk{ 1107049Stjones1@inf.ed.ac.uk _status = Idle; 1117049Stjones1@inf.ed.ac.uk 1127049Stjones1@inf.ed.ac.uk icachePort.snoopRangeSent = false; 1136973Stjones1@inf.ed.ac.uk dcachePort.snoopRangeSent = false; 11410379Sandreas.hansson@arm.com 1156973Stjones1@inf.ed.ac.uk ifetch_pkt = dcache_pkt = NULL; 1166973Stjones1@inf.ed.ac.uk drainEvent = NULL; 1176973Stjones1@inf.ed.ac.uk previousTick = 0; 1186973Stjones1@inf.ed.ac.uk changeState(SimObject::Running); 1196973Stjones1@inf.ed.ac.uk} 1206973Stjones1@inf.ed.ac.uk 1216973Stjones1@inf.ed.ac.uk 1226973Stjones1@inf.ed.ac.ukTimingSimpleCPU::~TimingSimpleCPU() 1236973Stjones1@inf.ed.ac.uk{ 1246973Stjones1@inf.ed.ac.uk} 1256973Stjones1@inf.ed.ac.uk 1266973Stjones1@inf.ed.ac.ukvoid 1276973Stjones1@inf.ed.ac.ukTimingSimpleCPU::serialize(ostream &os) 1286973Stjones1@inf.ed.ac.uk{ 1296973Stjones1@inf.ed.ac.uk SimObject::State so_state = SimObject::getState(); 1306973Stjones1@inf.ed.ac.uk SERIALIZE_ENUM(so_state); 1317049Stjones1@inf.ed.ac.uk BaseSimpleCPU::serialize(os); 1327049Stjones1@inf.ed.ac.uk} 1337049Stjones1@inf.ed.ac.uk 1347049Stjones1@inf.ed.ac.ukvoid 1356973Stjones1@inf.ed.ac.ukTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1366973Stjones1@inf.ed.ac.uk{ 1376973Stjones1@inf.ed.ac.uk SimObject::State so_state; 1386973Stjones1@inf.ed.ac.uk UNSERIALIZE_ENUM(so_state); 1396973Stjones1@inf.ed.ac.uk BaseSimpleCPU::unserialize(cp, section); 1406973Stjones1@inf.ed.ac.uk} 1416973Stjones1@inf.ed.ac.uk 1426973Stjones1@inf.ed.ac.ukunsigned int 1436973Stjones1@inf.ed.ac.ukTimingSimpleCPU::drain(Event *drain_event) 1446973Stjones1@inf.ed.ac.uk{ 1456973Stjones1@inf.ed.ac.uk // TimingSimpleCPU is ready to drain if it's not waiting for 1466973Stjones1@inf.ed.ac.uk // an access to complete. 1476973Stjones1@inf.ed.ac.uk if (_status == Idle || _status == Running || _status == SwitchedOut) { 1487049Stjones1@inf.ed.ac.uk changeState(SimObject::Drained); 1496973Stjones1@inf.ed.ac.uk return 0; 1506973Stjones1@inf.ed.ac.uk } else { 1516973Stjones1@inf.ed.ac.uk changeState(SimObject::Draining); 1526973Stjones1@inf.ed.ac.uk drainEvent = drain_event; 1536973Stjones1@inf.ed.ac.uk return 1; 1546973Stjones1@inf.ed.ac.uk } 1557049Stjones1@inf.ed.ac.uk} 15610824SAndreas.Sandberg@ARM.com 15710824SAndreas.Sandberg@ARM.comvoid 15810824SAndreas.Sandberg@ARM.comTimingSimpleCPU::resume() 1597049Stjones1@inf.ed.ac.uk{ 1606973Stjones1@inf.ed.ac.uk DPRINTF(SimpleCPU, "Resume\n"); 16110824SAndreas.Sandberg@ARM.com if (_status != SwitchedOut && _status != Idle) { 1626973Stjones1@inf.ed.ac.uk assert(system->getMemoryMode() == Enums::timing); 16310824SAndreas.Sandberg@ARM.com 1646973Stjones1@inf.ed.ac.uk if (fetchEvent.scheduled()) 1656973Stjones1@inf.ed.ac.uk deschedule(fetchEvent); 1667049Stjones1@inf.ed.ac.uk 1677049Stjones1@inf.ed.ac.uk schedule(fetchEvent, nextCycle()); 1687049Stjones1@inf.ed.ac.uk } 1697049Stjones1@inf.ed.ac.uk 1707049Stjones1@inf.ed.ac.uk changeState(SimObject::Running); 1716973Stjones1@inf.ed.ac.uk} 1726973Stjones1@inf.ed.ac.uk 1736973Stjones1@inf.ed.ac.ukvoid 1746973Stjones1@inf.ed.ac.ukTimingSimpleCPU::switchOut() 1756973Stjones1@inf.ed.ac.uk{ 1766973Stjones1@inf.ed.ac.uk assert(_status == Running || _status == Idle); 1777049Stjones1@inf.ed.ac.uk _status = SwitchedOut; 1786973Stjones1@inf.ed.ac.uk numCycles += tickToCycles(curTick - previousTick); 1796973Stjones1@inf.ed.ac.uk 1806973Stjones1@inf.ed.ac.uk // If we've been scheduled to resume but are then told to switch out, 1816973Stjones1@inf.ed.ac.uk // we'll need to cancel it. 1826973Stjones1@inf.ed.ac.uk if (fetchEvent.scheduled()) 1836973Stjones1@inf.ed.ac.uk deschedule(fetchEvent); 1847049Stjones1@inf.ed.ac.uk} 1857049Stjones1@inf.ed.ac.uk 1867049Stjones1@inf.ed.ac.uk 1877049Stjones1@inf.ed.ac.ukvoid 1887049Stjones1@inf.ed.ac.ukTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1896973Stjones1@inf.ed.ac.uk{ 1906973Stjones1@inf.ed.ac.uk BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 1916973Stjones1@inf.ed.ac.uk 1926973Stjones1@inf.ed.ac.uk // if any of this CPU's ThreadContexts are active, mark the CPU as 1936973Stjones1@inf.ed.ac.uk // running and schedule its tick event. 1946973Stjones1@inf.ed.ac.uk for (int i = 0; i < threadContexts.size(); ++i) { 1957049Stjones1@inf.ed.ac.uk ThreadContext *tc = threadContexts[i]; 1966973Stjones1@inf.ed.ac.uk if (tc->status() == ThreadContext::Active && _status != Running) { 1976973Stjones1@inf.ed.ac.uk _status = Running; 1986973Stjones1@inf.ed.ac.uk break; 19912749Sgiacomo.travaglini@arm.com } 2006973Stjones1@inf.ed.ac.uk } 20112749Sgiacomo.travaglini@arm.com 20212749Sgiacomo.travaglini@arm.com if (_status != Running) { 2036973Stjones1@inf.ed.ac.uk _status = Idle; 2046973Stjones1@inf.ed.ac.uk } 2056973Stjones1@inf.ed.ac.uk assert(threadContexts.size() == 1); 2066973Stjones1@inf.ed.ac.uk previousTick = curTick; 2077049Stjones1@inf.ed.ac.uk} 2087049Stjones1@inf.ed.ac.uk 2097049Stjones1@inf.ed.ac.uk 2107049Stjones1@inf.ed.ac.ukvoid 2117049Stjones1@inf.ed.ac.ukTimingSimpleCPU::activateContext(int thread_num, int delay) 2127049Stjones1@inf.ed.ac.uk{ 2137049Stjones1@inf.ed.ac.uk DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2147049Stjones1@inf.ed.ac.uk 2157049Stjones1@inf.ed.ac.uk assert(thread_num == 0); 2167049Stjones1@inf.ed.ac.uk assert(thread); 2178486Sgblack@eecs.umich.edu 2186973Stjones1@inf.ed.ac.uk assert(_status == Idle); 2196973Stjones1@inf.ed.ac.uk 2206973Stjones1@inf.ed.ac.uk notIdleFraction++; 2218486Sgblack@eecs.umich.edu _status = Running; 2226973Stjones1@inf.ed.ac.uk 2236973Stjones1@inf.ed.ac.uk // kick things off by initiating the fetch of the next instruction 2246973Stjones1@inf.ed.ac.uk schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 2256973Stjones1@inf.ed.ac.uk} 2268486Sgblack@eecs.umich.edu 2276973Stjones1@inf.ed.ac.uk 2286973Stjones1@inf.ed.ac.ukvoid 2296973Stjones1@inf.ed.ac.ukTimingSimpleCPU::suspendContext(int thread_num) 2306973Stjones1@inf.ed.ac.uk{ 2318486Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2326973Stjones1@inf.ed.ac.uk 2336973Stjones1@inf.ed.ac.uk assert(thread_num == 0); 2346973Stjones1@inf.ed.ac.uk assert(thread); 2356973Stjones1@inf.ed.ac.uk 2366973Stjones1@inf.ed.ac.uk assert(_status == Running); 2377049Stjones1@inf.ed.ac.uk 2387944SGiacomo.Gabrielli@arm.com // just change status to Idle... if status != Running, 2397944SGiacomo.Gabrielli@arm.com // completeInst() will not initiate fetch of next instruction. 2407944SGiacomo.Gabrielli@arm.com 2417944SGiacomo.Gabrielli@arm.com notIdleFraction--; 2427944SGiacomo.Gabrielli@arm.com _status = Idle; 2437944SGiacomo.Gabrielli@arm.com} 2447944SGiacomo.Gabrielli@arm.com 2457944SGiacomo.Gabrielli@arm.combool 2467944SGiacomo.Gabrielli@arm.comTimingSimpleCPU::handleReadPacket(PacketPtr pkt) 2477944SGiacomo.Gabrielli@arm.com{ 2487049Stjones1@inf.ed.ac.uk RequestPtr req = pkt->req; 2497049Stjones1@inf.ed.ac.uk if (req->isMmapedIpr()) { 2507049Stjones1@inf.ed.ac.uk Tick delay; 2516973Stjones1@inf.ed.ac.uk delay = TheISA::handleIprRead(thread->getTC(), pkt); 25212749Sgiacomo.travaglini@arm.com new IprEvent(pkt, this, nextCycle(curTick + delay)); 2536973Stjones1@inf.ed.ac.uk _status = DcacheWaitResponse; 2546973Stjones1@inf.ed.ac.uk dcache_pkt = NULL; 2556973Stjones1@inf.ed.ac.uk } else if (!dcachePort.sendTiming(pkt)) { 2566973Stjones1@inf.ed.ac.uk _status = DcacheRetry; 2576973Stjones1@inf.ed.ac.uk dcache_pkt = pkt; 25810177SMitchell.Hayenga@ARM.com } else { 25910177SMitchell.Hayenga@ARM.com _status = DcacheWaitResponse; 26010177SMitchell.Hayenga@ARM.com // memory system takes ownership of packet 26110177SMitchell.Hayenga@ARM.com dcache_pkt = NULL; 2626973Stjones1@inf.ed.ac.uk } 2636973Stjones1@inf.ed.ac.uk return dcache_pkt == NULL; 2646973Stjones1@inf.ed.ac.uk} 2656973Stjones1@inf.ed.ac.uk 2669258SAli.Saidi@ARM.comvoid 2679258SAli.Saidi@ARM.comTimingSimpleCPU::sendData(Fault fault, RequestPtr req, 2689258SAli.Saidi@ARM.com uint8_t *data, uint64_t *res, bool read) 2699258SAli.Saidi@ARM.com{ 2709258SAli.Saidi@ARM.com _status = Running; 2719258SAli.Saidi@ARM.com if (fault != NoFault) { 2726973Stjones1@inf.ed.ac.uk delete data; 2736973Stjones1@inf.ed.ac.uk delete req; 2746973Stjones1@inf.ed.ac.uk 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::htog(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 670 if (!fromRom && !curMacroStaticInst) { 671 Request *ifetch_req = new Request(); 672 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 673 setupFetchRequest(ifetch_req); 674 thread->itb->translateTiming(ifetch_req, tc, 675 &fetchTranslation); 676 } else { 677 _status = IcacheWaitResponse; 678 completeIfetch(NULL); 679 680 numCycles += tickToCycles(curTick - previousTick); 681 previousTick = curTick; 682 } 683} 684 685 686void 687TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 688{ 689 if (fault == NoFault) { 690 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 691 ifetch_pkt->dataStatic(&inst); 692 693 if (!icachePort.sendTiming(ifetch_pkt)) { 694 // Need to wait for retry 695 _status = IcacheRetry; 696 } else { 697 // Need to wait for cache to respond 698 _status = IcacheWaitResponse; 699 // ownership of packet transferred to memory system 700 ifetch_pkt = NULL; 701 } 702 } else { 703 delete req; 704 // fetch fault: advance directly to next instruction (fault handler) 705 advanceInst(fault); 706 } 707 708 numCycles += tickToCycles(curTick - previousTick); 709 previousTick = curTick; 710} 711 712 713void 714TimingSimpleCPU::advanceInst(Fault fault) 715{ 716 if (fault != NoFault || !stayAtPC) 717 advancePC(fault); 718 719 if (_status == Running) { 720 // kick off fetch of next instruction... callback from icache 721 // response will cause that instruction to be executed, 722 // keeping the CPU running. 723 fetch(); 724 } 725} 726 727 728void 729TimingSimpleCPU::completeIfetch(PacketPtr pkt) 730{ 731 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 732 733 // received a response from the icache: execute the received 734 // instruction 735 736 assert(!pkt || !pkt->isError()); 737 assert(_status == IcacheWaitResponse); 738 739 _status = Running; 740 741 numCycles += tickToCycles(curTick - previousTick); 742 previousTick = curTick; 743 744 if (getState() == SimObject::Draining) { 745 if (pkt) { 746 delete pkt->req; 747 delete pkt; 748 } 749 750 completeDrain(); 751 return; 752 } 753 754 preExecute(); 755 if (curStaticInst && 756 curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 757 // load or store: just send to dcache 758 Fault fault = curStaticInst->initiateAcc(this, traceData); 759 if (_status != Running) { 760 // instruction will complete in dcache response callback 761 assert(_status == DcacheWaitResponse || 762 _status == DcacheRetry || DTBWaitResponse); 763 assert(fault == NoFault); 764 } else { 765 if (fault != NoFault && traceData) { 766 // If there was a fault, we shouldn't trace this instruction. 767 delete traceData; 768 traceData = NULL; 769 } 770 771 postExecute(); 772 // @todo remove me after debugging with legion done 773 if (curStaticInst && (!curStaticInst->isMicroop() || 774 curStaticInst->isFirstMicroop())) 775 instCnt++; 776 advanceInst(fault); 777 } 778 } else if (curStaticInst) { 779 // non-memory instruction: execute completely now 780 Fault fault = curStaticInst->execute(this, traceData); 781 782 // keep an instruction count 783 if (fault == NoFault) 784 countInst(); 785 else if (traceData) { 786 // If there was a fault, we shouldn't trace this instruction. 787 delete traceData; 788 traceData = NULL; 789 } 790 791 postExecute(); 792 // @todo remove me after debugging with legion done 793 if (curStaticInst && (!curStaticInst->isMicroop() || 794 curStaticInst->isFirstMicroop())) 795 instCnt++; 796 advanceInst(fault); 797 } else { 798 advanceInst(NoFault); 799 } 800 801 if (pkt) { 802 delete pkt->req; 803 delete pkt; 804 } 805} 806 807void 808TimingSimpleCPU::IcachePort::ITickEvent::process() 809{ 810 cpu->completeIfetch(pkt); 811} 812 813bool 814TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 815{ 816 if (pkt->isResponse() && !pkt->wasNacked()) { 817 // delay processing of returned data until next CPU clock edge 818 Tick next_tick = cpu->nextCycle(curTick); 819 820 if (next_tick == curTick) 821 cpu->completeIfetch(pkt); 822 else 823 tickEvent.schedule(pkt, next_tick); 824 825 return true; 826 } 827 else if (pkt->wasNacked()) { 828 assert(cpu->_status == IcacheWaitResponse); 829 pkt->reinitNacked(); 830 if (!sendTiming(pkt)) { 831 cpu->_status = IcacheRetry; 832 cpu->ifetch_pkt = pkt; 833 } 834 } 835 //Snooping a Coherence Request, do nothing 836 return true; 837} 838 839void 840TimingSimpleCPU::IcachePort::recvRetry() 841{ 842 // we shouldn't get a retry unless we have a packet that we're 843 // waiting to transmit 844 assert(cpu->ifetch_pkt != NULL); 845 assert(cpu->_status == IcacheRetry); 846 PacketPtr tmp = cpu->ifetch_pkt; 847 if (sendTiming(tmp)) { 848 cpu->_status = IcacheWaitResponse; 849 cpu->ifetch_pkt = NULL; 850 } 851} 852 853void 854TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 855{ 856 // received a response from the dcache: complete the load or store 857 // instruction 858 assert(!pkt->isError()); 859 860 numCycles += tickToCycles(curTick - previousTick); 861 previousTick = curTick; 862 863 if (pkt->senderState) { 864 SplitFragmentSenderState * send_state = 865 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 866 assert(send_state); 867 delete pkt->req; 868 delete pkt; 869 PacketPtr big_pkt = send_state->bigPkt; 870 delete send_state; 871 872 SplitMainSenderState * main_send_state = 873 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 874 assert(main_send_state); 875 // Record the fact that this packet is no longer outstanding. 876 assert(main_send_state->outstanding != 0); 877 main_send_state->outstanding--; 878 879 if (main_send_state->outstanding) { 880 return; 881 } else { 882 delete main_send_state; 883 big_pkt->senderState = NULL; 884 pkt = big_pkt; 885 } 886 } 887 888 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); 889 _status = Running; 890 891 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 892 893 // keep an instruction count 894 if (fault == NoFault) 895 countInst(); 896 else if (traceData) { 897 // If there was a fault, we shouldn't trace this instruction. 898 delete traceData; 899 traceData = NULL; 900 } 901 902 // the locked flag may be cleared on the response packet, so check 903 // pkt->req and not pkt to see if it was a load-locked 904 if (pkt->isRead() && pkt->req->isLocked()) { 905 TheISA::handleLockedRead(thread, pkt->req); 906 } 907 908 delete pkt->req; 909 delete pkt; 910 911 postExecute(); 912 913 if (getState() == SimObject::Draining) { 914 advancePC(fault); 915 completeDrain(); 916 917 return; 918 } 919 920 advanceInst(fault); 921} 922 923 924void 925TimingSimpleCPU::completeDrain() 926{ 927 DPRINTF(Config, "Done draining\n"); 928 changeState(SimObject::Drained); 929 drainEvent->process(); 930} 931 932void 933TimingSimpleCPU::DcachePort::setPeer(Port *port) 934{ 935 Port::setPeer(port); 936 937#if FULL_SYSTEM 938 // Update the ThreadContext's memory ports (Functional/Virtual 939 // Ports) 940 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 941#endif 942} 943 944bool 945TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 946{ 947 if (pkt->isResponse() && !pkt->wasNacked()) { 948 // delay processing of returned data until next CPU clock edge 949 Tick next_tick = cpu->nextCycle(curTick); 950 951 if (next_tick == curTick) { 952 cpu->completeDataAccess(pkt); 953 } else { 954 tickEvent.schedule(pkt, next_tick); 955 } 956 957 return true; 958 } 959 else if (pkt->wasNacked()) { 960 assert(cpu->_status == DcacheWaitResponse); 961 pkt->reinitNacked(); 962 if (!sendTiming(pkt)) { 963 cpu->_status = DcacheRetry; 964 cpu->dcache_pkt = pkt; 965 } 966 } 967 //Snooping a Coherence Request, do nothing 968 return true; 969} 970 971void 972TimingSimpleCPU::DcachePort::DTickEvent::process() 973{ 974 cpu->completeDataAccess(pkt); 975} 976 977void 978TimingSimpleCPU::DcachePort::recvRetry() 979{ 980 // we shouldn't get a retry unless we have a packet that we're 981 // waiting to transmit 982 assert(cpu->dcache_pkt != NULL); 983 assert(cpu->_status == DcacheRetry); 984 PacketPtr tmp = cpu->dcache_pkt; 985 if (tmp->senderState) { 986 // This is a packet from a split access. 987 SplitFragmentSenderState * send_state = 988 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 989 assert(send_state); 990 PacketPtr big_pkt = send_state->bigPkt; 991 992 SplitMainSenderState * main_send_state = 993 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 994 assert(main_send_state); 995 996 if (sendTiming(tmp)) { 997 // If we were able to send without retrying, record that fact 998 // and try sending the other fragment. 999 send_state->clearFromParent(); 1000 int other_index = main_send_state->getPendingFragment(); 1001 if (other_index > 0) { 1002 tmp = main_send_state->fragments[other_index]; 1003 cpu->dcache_pkt = tmp; 1004 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1005 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1006 main_send_state->fragments[other_index] = NULL; 1007 } 1008 } else { 1009 cpu->_status = DcacheWaitResponse; 1010 // memory system takes ownership of packet 1011 cpu->dcache_pkt = NULL; 1012 } 1013 } 1014 } else if (sendTiming(tmp)) { 1015 cpu->_status = DcacheWaitResponse; 1016 // memory system takes ownership of packet 1017 cpu->dcache_pkt = NULL; 1018 } 1019} 1020 1021TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1022 Tick t) 1023 : pkt(_pkt), cpu(_cpu) 1024{ 1025 cpu->schedule(this, t); 1026} 1027 1028void 1029TimingSimpleCPU::IprEvent::process() 1030{ 1031 cpu->completeDataAccess(pkt); 1032} 1033 1034const char * 1035TimingSimpleCPU::IprEvent::description() const 1036{ 1037 return "Timing Simple CPU Delay IPR event"; 1038} 1039 1040 1041void 1042TimingSimpleCPU::printAddr(Addr a) 1043{ 1044 dcachePort.printAddr(a); 1045} 1046 1047 1048//////////////////////////////////////////////////////////////////////// 1049// 1050// TimingSimpleCPU Simulation Object 1051// 1052TimingSimpleCPU * 1053TimingSimpleCPUParams::create() 1054{ 1055 numThreads = 1; 1056#if !FULL_SYSTEM 1057 if (workload.size() != 1) 1058 panic("only one workload allowed"); 1059#endif 1060 return new TimingSimpleCPU(this); 1061} 1062