timing.cc revision 5669
12221SN/A/*
22221SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32221SN/A * All rights reserved.
42221SN/A *
52221SN/A * Redistribution and use in source and binary forms, with or without
62221SN/A * modification, are permitted provided that the following conditions are
72221SN/A * met: redistributions of source code must retain the above copyright
82221SN/A * notice, this list of conditions and the following disclaimer;
92221SN/A * redistributions in binary form must reproduce the above copyright
102221SN/A * notice, this list of conditions and the following disclaimer in the
112221SN/A * documentation and/or other materials provided with the distribution;
122221SN/A * neither the name of the copyright holders nor the names of its
132221SN/A * contributors may be used to endorse or promote products derived from
142221SN/A * this software without specific prior written permission.
152221SN/A *
162221SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172221SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182221SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192221SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202221SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212221SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222221SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232221SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242221SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252221SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262221SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292665Ssaidi@eecs.umich.edu */
302221SN/A
312221SN/A#include "arch/locked_mem.hh"
323890Ssaidi@eecs.umich.edu#include "arch/mmaped_ipr.hh"
333890Ssaidi@eecs.umich.edu#include "arch/utility.hh"
342221SN/A#include "base/bigint.hh"
354997Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
367678Sgblack@eecs.umich.edu#include "cpu/simple/timing.hh"
372221SN/A#include "mem/packet.hh"
382221SN/A#include "mem/packet_access.hh"
392221SN/A#include "params/TimingSimpleCPU.hh"
402221SN/A#include "sim/system.hh"
412223SN/A
422221SN/Ausing namespace std;
432221SN/Ausing namespace TheISA;
443415Sgblack@eecs.umich.edu
453415Sgblack@eecs.umich.eduPort *
462221SN/ATimingSimpleCPU::getPort(const std::string &if_name, int idx)
474997Sgblack@eecs.umich.edu{
484997Sgblack@eecs.umich.edu    if (if_name == "dcache_port")
493573Sgblack@eecs.umich.edu        return &dcachePort;
502221SN/A    else if (if_name == "icache_port")
512221SN/A        return &icachePort;
523576Sgblack@eecs.umich.edu    else
533576Sgblack@eecs.umich.edu        panic("No Such Port\n");
543576Sgblack@eecs.umich.edu}
553576Sgblack@eecs.umich.edu
563576Sgblack@eecs.umich.eduvoid
573576Sgblack@eecs.umich.eduTimingSimpleCPU::init()
583576Sgblack@eecs.umich.edu{
593576Sgblack@eecs.umich.edu    BaseCPU::init();
603576Sgblack@eecs.umich.edu    cpuId = tc->readCpuId();
613573Sgblack@eecs.umich.edu#if FULL_SYSTEM
623573Sgblack@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); ++i) {
633573Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
643573Sgblack@eecs.umich.edu
653573Sgblack@eecs.umich.edu        // initialize CPU, including PC
663576Sgblack@eecs.umich.edu        TheISA::initCPU(tc, cpuId);
673573Sgblack@eecs.umich.edu    }
683573Sgblack@eecs.umich.edu#endif
692221SN/A}
707678Sgblack@eecs.umich.edu
717678Sgblack@eecs.umich.eduTick
722221SN/ATimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
732223SN/A{
742223SN/A    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
752223SN/A    return curTick;
763576Sgblack@eecs.umich.edu}
772221SN/A
782221SN/Avoid
793573Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
803573Sgblack@eecs.umich.edu{
812221SN/A    //No internal storage to update, jusst return
823573Sgblack@eecs.umich.edu    return;
833573Sgblack@eecs.umich.edu}
842221SN/A
854695Sgblack@eecs.umich.eduvoid
863573Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::recvStatusChange(Status status)
873573Sgblack@eecs.umich.edu{
883573Sgblack@eecs.umich.edu    if (status == RangeChange) {
893576Sgblack@eecs.umich.edu        if (!snoopRangeSent) {
903576Sgblack@eecs.umich.edu            snoopRangeSent = true;
913576Sgblack@eecs.umich.edu            sendStatusChange(Port::RangeChange);
923576Sgblack@eecs.umich.edu        }
933573Sgblack@eecs.umich.edu        return;
943573Sgblack@eecs.umich.edu    }
953576Sgblack@eecs.umich.edu
963576Sgblack@eecs.umich.edu    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
977678Sgblack@eecs.umich.edu}
987678Sgblack@eecs.umich.edu
997678Sgblack@eecs.umich.edu
1007678Sgblack@eecs.umich.eduvoid
1013576Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
1023576Sgblack@eecs.umich.edu{
1033576Sgblack@eecs.umich.edu    pkt = _pkt;
1043576Sgblack@eecs.umich.edu    cpu->schedule(this, t);
1053576Sgblack@eecs.umich.edu}
1063576Sgblack@eecs.umich.edu
1073576Sgblack@eecs.umich.eduTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
1083576Sgblack@eecs.umich.edu    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
1093576Sgblack@eecs.umich.edu{
1103576Sgblack@eecs.umich.edu    _status = Idle;
1113576Sgblack@eecs.umich.edu
1123576Sgblack@eecs.umich.edu    icachePort.snoopRangeSent = false;
1133576Sgblack@eecs.umich.edu    dcachePort.snoopRangeSent = false;
1143576Sgblack@eecs.umich.edu
1153576Sgblack@eecs.umich.edu    ifetch_pkt = dcache_pkt = NULL;
1163576Sgblack@eecs.umich.edu    drainEvent = NULL;
1173576Sgblack@eecs.umich.edu    fetchEvent = NULL;
1183576Sgblack@eecs.umich.edu    previousTick = 0;
1193576Sgblack@eecs.umich.edu    changeState(SimObject::Running);
1203576Sgblack@eecs.umich.edu}
1213576Sgblack@eecs.umich.edu
1223576Sgblack@eecs.umich.edu
1233576Sgblack@eecs.umich.eduTimingSimpleCPU::~TimingSimpleCPU()
1243576Sgblack@eecs.umich.edu{
1253576Sgblack@eecs.umich.edu}
1263576Sgblack@eecs.umich.edu
1273576Sgblack@eecs.umich.eduvoid
1283576Sgblack@eecs.umich.eduTimingSimpleCPU::serialize(ostream &os)
1293576Sgblack@eecs.umich.edu{
1303576Sgblack@eecs.umich.edu    SimObject::State so_state = SimObject::getState();
1313576Sgblack@eecs.umich.edu    SERIALIZE_ENUM(so_state);
1323576Sgblack@eecs.umich.edu    BaseSimpleCPU::serialize(os);
1333576Sgblack@eecs.umich.edu}
1343576Sgblack@eecs.umich.edu
1353576Sgblack@eecs.umich.eduvoid
1363576Sgblack@eecs.umich.eduTimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1373576Sgblack@eecs.umich.edu{
1383576Sgblack@eecs.umich.edu    SimObject::State so_state;
1393573Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(so_state);
1403573Sgblack@eecs.umich.edu    BaseSimpleCPU::unserialize(cp, section);
1413573Sgblack@eecs.umich.edu}
1423573Sgblack@eecs.umich.edu
1434695Sgblack@eecs.umich.eduunsigned int
1442221SN/ATimingSimpleCPU::drain(Event *drain_event)
1452221SN/A{
1463576Sgblack@eecs.umich.edu    // TimingSimpleCPU is ready to drain if it's not waiting for
1473576Sgblack@eecs.umich.edu    // an access to complete.
1483576Sgblack@eecs.umich.edu    if (_status == Idle || _status == Running || _status == SwitchedOut) {
1493576Sgblack@eecs.umich.edu        changeState(SimObject::Drained);
1503576Sgblack@eecs.umich.edu        return 0;
1513576Sgblack@eecs.umich.edu    } else {
1523576Sgblack@eecs.umich.edu        changeState(SimObject::Draining);
1533576Sgblack@eecs.umich.edu        drainEvent = drain_event;
1543576Sgblack@eecs.umich.edu        return 1;
1553576Sgblack@eecs.umich.edu    }
1563576Sgblack@eecs.umich.edu}
1573576Sgblack@eecs.umich.edu
1583573Sgblack@eecs.umich.eduvoid
1593573Sgblack@eecs.umich.eduTimingSimpleCPU::resume()
1602221SN/A{
1612221SN/A    DPRINTF(SimpleCPU, "Resume\n");
1624695Sgblack@eecs.umich.edu    if (_status != SwitchedOut && _status != Idle) {
1632221SN/A        assert(system->getMemoryMode() == Enums::timing);
1642221SN/A
1653576Sgblack@eecs.umich.edu        // Delete the old event if it existed.
1663576Sgblack@eecs.umich.edu        if (fetchEvent) {
1673576Sgblack@eecs.umich.edu            if (fetchEvent->scheduled())
1683576Sgblack@eecs.umich.edu                deschedule(fetchEvent);
1693576Sgblack@eecs.umich.edu
1703576Sgblack@eecs.umich.edu            delete fetchEvent;
1713576Sgblack@eecs.umich.edu        }
1723576Sgblack@eecs.umich.edu
1733576Sgblack@eecs.umich.edu        fetchEvent = new FetchEvent(this, nextCycle());
1743576Sgblack@eecs.umich.edu    }
1753576Sgblack@eecs.umich.edu
1763576Sgblack@eecs.umich.edu    changeState(SimObject::Running);
1773576Sgblack@eecs.umich.edu}
1783576Sgblack@eecs.umich.edu
1793576Sgblack@eecs.umich.eduvoid
1803576Sgblack@eecs.umich.eduTimingSimpleCPU::switchOut()
1813576Sgblack@eecs.umich.edu{
1823576Sgblack@eecs.umich.edu    assert(_status == Running || _status == Idle);
1833576Sgblack@eecs.umich.edu    _status = SwitchedOut;
1843576Sgblack@eecs.umich.edu    numCycles += tickToCycles(curTick - previousTick);
1853576Sgblack@eecs.umich.edu
1863576Sgblack@eecs.umich.edu    // If we've been scheduled to resume but are then told to switch out,
1873576Sgblack@eecs.umich.edu    // we'll need to cancel it.
1883576Sgblack@eecs.umich.edu    if (fetchEvent && fetchEvent->scheduled())
1893576Sgblack@eecs.umich.edu        deschedule(fetchEvent);
1903576Sgblack@eecs.umich.edu}
1913576Sgblack@eecs.umich.edu
1923576Sgblack@eecs.umich.edu
1933576Sgblack@eecs.umich.eduvoid
1943576Sgblack@eecs.umich.eduTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
1953576Sgblack@eecs.umich.edu{
1963576Sgblack@eecs.umich.edu    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
1973576Sgblack@eecs.umich.edu
1983576Sgblack@eecs.umich.edu    // if any of this CPU's ThreadContexts are active, mark the CPU as
1993576Sgblack@eecs.umich.edu    // running and schedule its tick event.
2003576Sgblack@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); ++i) {
2013576Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
2023576Sgblack@eecs.umich.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2034103Ssaidi@eecs.umich.edu            _status = Running;
2044103Ssaidi@eecs.umich.edu            break;
2053576Sgblack@eecs.umich.edu        }
2063576Sgblack@eecs.umich.edu    }
2073576Sgblack@eecs.umich.edu
2083576Sgblack@eecs.umich.edu    if (_status != Running) {
2093576Sgblack@eecs.umich.edu        _status = Idle;
2104997Sgblack@eecs.umich.edu    }
2114997Sgblack@eecs.umich.edu    assert(threadContexts.size() == 1);
2124997Sgblack@eecs.umich.edu    cpuId = tc->readCpuId();
2134997Sgblack@eecs.umich.edu    previousTick = curTick;
2144997Sgblack@eecs.umich.edu}
2154997Sgblack@eecs.umich.edu
2164997Sgblack@eecs.umich.edu
2174997Sgblack@eecs.umich.eduvoid
2187678Sgblack@eecs.umich.eduTimingSimpleCPU::activateContext(int thread_num, int delay)
2197678Sgblack@eecs.umich.edu{
2204997Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2214997Sgblack@eecs.umich.edu
2223576Sgblack@eecs.umich.edu    assert(thread_num == 0);
2234997Sgblack@eecs.umich.edu    assert(thread);
2244997Sgblack@eecs.umich.edu
2254997Sgblack@eecs.umich.edu    assert(_status == Idle);
2264997Sgblack@eecs.umich.edu
2274997Sgblack@eecs.umich.edu    notIdleFraction++;
2284997Sgblack@eecs.umich.edu    _status = Running;
2294997Sgblack@eecs.umich.edu
2304997Sgblack@eecs.umich.edu    // kick things off by initiating the fetch of the next instruction
2317678Sgblack@eecs.umich.edu    fetchEvent = new FetchEvent(this);
2327678Sgblack@eecs.umich.edu    schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
2334997Sgblack@eecs.umich.edu}
2344997Sgblack@eecs.umich.edu
2353576Sgblack@eecs.umich.edu
2363576Sgblack@eecs.umich.eduvoid
2373576Sgblack@eecs.umich.eduTimingSimpleCPU::suspendContext(int thread_num)
2383576Sgblack@eecs.umich.edu{
2393576Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2403576Sgblack@eecs.umich.edu
2413576Sgblack@eecs.umich.edu    assert(thread_num == 0);
2423576Sgblack@eecs.umich.edu    assert(thread);
2433576Sgblack@eecs.umich.edu
2443893Shsul@eecs.umich.edu    assert(_status == Running);
2453576Sgblack@eecs.umich.edu
2463576Sgblack@eecs.umich.edu    // just change status to Idle... if status != Running,
2473576Sgblack@eecs.umich.edu    // completeInst() will not initiate fetch of next instruction.
2483576Sgblack@eecs.umich.edu
2493576Sgblack@eecs.umich.edu    notIdleFraction--;
2503576Sgblack@eecs.umich.edu    _status = Idle;
2513576Sgblack@eecs.umich.edu}
2527678Sgblack@eecs.umich.edu
2537678Sgblack@eecs.umich.edu
2543576Sgblack@eecs.umich.edutemplate <class T>
2553576Sgblack@eecs.umich.eduFault
2563576Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
2573576Sgblack@eecs.umich.edu{
2583576Sgblack@eecs.umich.edu    Request *req =
2593576Sgblack@eecs.umich.edu        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
2603576Sgblack@eecs.umich.edu                    cpuId, /* thread ID */ 0);
2613576Sgblack@eecs.umich.edu
2623576Sgblack@eecs.umich.edu    if (traceData) {
2633576Sgblack@eecs.umich.edu        traceData->setAddr(req->getVaddr());
2643576Sgblack@eecs.umich.edu    }
2653576Sgblack@eecs.umich.edu
2663576Sgblack@eecs.umich.edu   // translate to physical address
2673576Sgblack@eecs.umich.edu    Fault fault = thread->translateDataReadReq(req);
2683576Sgblack@eecs.umich.edu
2697678Sgblack@eecs.umich.edu    // Now do the access.
2707678Sgblack@eecs.umich.edu    if (fault == NoFault) {
2713576Sgblack@eecs.umich.edu        PacketPtr pkt =
2723576Sgblack@eecs.umich.edu            new Packet(req,
2733576Sgblack@eecs.umich.edu                       (req->isLocked() ?
2743576Sgblack@eecs.umich.edu                        MemCmd::LoadLockedReq : MemCmd::ReadReq),
2753576Sgblack@eecs.umich.edu                       Packet::Broadcast);
2763576Sgblack@eecs.umich.edu        pkt->dataDynamic<T>(new T);
2773576Sgblack@eecs.umich.edu
2783576Sgblack@eecs.umich.edu        if (req->isMmapedIpr()) {
2793576Sgblack@eecs.umich.edu            Tick delay;
2803576Sgblack@eecs.umich.edu            delay = TheISA::handleIprRead(thread->getTC(), pkt);
2813576Sgblack@eecs.umich.edu            new IprEvent(pkt, this, nextCycle(curTick + delay));
2823576Sgblack@eecs.umich.edu            _status = DcacheWaitResponse;
2833576Sgblack@eecs.umich.edu            dcache_pkt = NULL;
2844111Sgblack@eecs.umich.edu        } else if (!dcachePort.sendTiming(pkt)) {
2854111Sgblack@eecs.umich.edu            _status = DcacheRetry;
2867678Sgblack@eecs.umich.edu            dcache_pkt = pkt;
2877678Sgblack@eecs.umich.edu        } else {
2884111Sgblack@eecs.umich.edu            _status = DcacheWaitResponse;
2893576Sgblack@eecs.umich.edu            // memory system takes ownership of packet
2903576Sgblack@eecs.umich.edu            dcache_pkt = NULL;
2912221SN/A        }
2922221SN/A
2932223SN/A        // This will need a new way to tell if it has a dcache attached.
2942221SN/A        if (req->isUncacheable())
2952221SN/A            recordEvent("Uncached Read");
2962800Ssaidi@eecs.umich.edu    } else {
2972223SN/A        delete req;
2982221SN/A    }
2993890Ssaidi@eecs.umich.edu
300    if (traceData) {
301        traceData->setData(data);
302    }
303    return fault;
304}
305
306Fault
307TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
308        int size, unsigned flags)
309{
310    Request *req =
311        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
312
313    if (traceData) {
314        traceData->setAddr(vaddr);
315    }
316
317    Fault fault = thread->translateDataWriteReq(req);
318
319    if (fault == NoFault)
320        paddr = req->getPaddr();
321
322    delete req;
323    return fault;
324}
325
326#ifndef DOXYGEN_SHOULD_SKIP_THIS
327
328template
329Fault
330TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
331
332template
333Fault
334TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
335
336template
337Fault
338TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
339
340template
341Fault
342TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
343
344template
345Fault
346TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
347
348template
349Fault
350TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
351
352#endif //DOXYGEN_SHOULD_SKIP_THIS
353
354template<>
355Fault
356TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
357{
358    return read(addr, *(uint64_t*)&data, flags);
359}
360
361template<>
362Fault
363TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
364{
365    return read(addr, *(uint32_t*)&data, flags);
366}
367
368
369template<>
370Fault
371TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
372{
373    return read(addr, (uint32_t&)data, flags);
374}
375
376
377template <class T>
378Fault
379TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
380{
381    Request *req =
382        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
383                    cpuId, /* thread ID */ 0);
384
385    if (traceData) {
386        traceData->setAddr(req->getVaddr());
387    }
388
389    // translate to physical address
390    Fault fault = thread->translateDataWriteReq(req);
391
392    // Now do the access.
393    if (fault == NoFault) {
394        MemCmd cmd = MemCmd::WriteReq; // default
395        bool do_access = true;  // flag to suppress cache access
396
397        if (req->isLocked()) {
398            cmd = MemCmd::StoreCondReq;
399            do_access = TheISA::handleLockedWrite(thread, req);
400        } else if (req->isSwap()) {
401            cmd = MemCmd::SwapReq;
402            if (req->isCondSwap()) {
403                assert(res);
404                req->setExtraData(*res);
405            }
406        }
407
408        // Note: need to allocate dcache_pkt even if do_access is
409        // false, as it's used unconditionally to call completeAcc().
410        assert(dcache_pkt == NULL);
411        dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
412        dcache_pkt->allocate();
413        dcache_pkt->set(data);
414
415        if (do_access) {
416            if (req->isMmapedIpr()) {
417                Tick delay;
418                dcache_pkt->set(htog(data));
419                delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
420                new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
421                _status = DcacheWaitResponse;
422                dcache_pkt = NULL;
423            } else if (!dcachePort.sendTiming(dcache_pkt)) {
424                _status = DcacheRetry;
425            } else {
426                _status = DcacheWaitResponse;
427                // memory system takes ownership of packet
428                dcache_pkt = NULL;
429            }
430        }
431        // This will need a new way to tell if it's hooked up to a cache or not.
432        if (req->isUncacheable())
433            recordEvent("Uncached Write");
434    } else {
435        delete req;
436    }
437
438    if (traceData) {
439        traceData->setData(data);
440    }
441
442    // If the write needs to have a fault on the access, consider calling
443    // changeStatus() and changing it to "bad addr write" or something.
444    return fault;
445}
446
447Fault
448TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
449        int size, unsigned flags)
450{
451    Request *req =
452        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
453
454    if (traceData) {
455        traceData->setAddr(vaddr);
456    }
457
458    Fault fault = thread->translateDataWriteReq(req);
459
460    if (fault == NoFault)
461        paddr = req->getPaddr();
462
463    delete req;
464    return fault;
465}
466
467
468#ifndef DOXYGEN_SHOULD_SKIP_THIS
469template
470Fault
471TimingSimpleCPU::write(Twin32_t data, Addr addr,
472                       unsigned flags, uint64_t *res);
473
474template
475Fault
476TimingSimpleCPU::write(Twin64_t data, Addr addr,
477                       unsigned flags, uint64_t *res);
478
479template
480Fault
481TimingSimpleCPU::write(uint64_t data, Addr addr,
482                       unsigned flags, uint64_t *res);
483
484template
485Fault
486TimingSimpleCPU::write(uint32_t data, Addr addr,
487                       unsigned flags, uint64_t *res);
488
489template
490Fault
491TimingSimpleCPU::write(uint16_t data, Addr addr,
492                       unsigned flags, uint64_t *res);
493
494template
495Fault
496TimingSimpleCPU::write(uint8_t data, Addr addr,
497                       unsigned flags, uint64_t *res);
498
499#endif //DOXYGEN_SHOULD_SKIP_THIS
500
501template<>
502Fault
503TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
504{
505    return write(*(uint64_t*)&data, addr, flags, res);
506}
507
508template<>
509Fault
510TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
511{
512    return write(*(uint32_t*)&data, addr, flags, res);
513}
514
515
516template<>
517Fault
518TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
519{
520    return write((uint32_t)data, addr, flags, res);
521}
522
523
524void
525TimingSimpleCPU::fetch()
526{
527    DPRINTF(SimpleCPU, "Fetch\n");
528
529    if (!curStaticInst || !curStaticInst->isDelayedCommit())
530        checkForInterrupts();
531
532    checkPcEventQueue();
533
534    bool fromRom = isRomMicroPC(thread->readMicroPC());
535
536    if (!fromRom) {
537        Request *ifetch_req = new Request();
538        ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
539        Fault fault = setupFetchRequest(ifetch_req);
540
541        ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
542        ifetch_pkt->dataStatic(&inst);
543
544        if (fault == NoFault) {
545            if (!icachePort.sendTiming(ifetch_pkt)) {
546                // Need to wait for retry
547                _status = IcacheRetry;
548            } else {
549                // Need to wait for cache to respond
550                _status = IcacheWaitResponse;
551                // ownership of packet transferred to memory system
552                ifetch_pkt = NULL;
553            }
554        } else {
555            delete ifetch_req;
556            delete ifetch_pkt;
557            // fetch fault: advance directly to next instruction (fault handler)
558            advanceInst(fault);
559        }
560    } else {
561        _status = IcacheWaitResponse;
562        completeIfetch(NULL);
563    }
564
565    numCycles += tickToCycles(curTick - previousTick);
566    previousTick = curTick;
567}
568
569
570void
571TimingSimpleCPU::advanceInst(Fault fault)
572{
573    advancePC(fault);
574
575    if (_status == Running) {
576        // kick off fetch of next instruction... callback from icache
577        // response will cause that instruction to be executed,
578        // keeping the CPU running.
579        fetch();
580    }
581}
582
583
584void
585TimingSimpleCPU::completeIfetch(PacketPtr pkt)
586{
587    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
588
589    // received a response from the icache: execute the received
590    // instruction
591
592    assert(!pkt || !pkt->isError());
593    assert(_status == IcacheWaitResponse);
594
595    _status = Running;
596
597    numCycles += tickToCycles(curTick - previousTick);
598    previousTick = curTick;
599
600    if (getState() == SimObject::Draining) {
601        if (pkt) {
602            delete pkt->req;
603            delete pkt;
604        }
605
606        completeDrain();
607        return;
608    }
609
610    preExecute();
611    if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
612        // load or store: just send to dcache
613        Fault fault = curStaticInst->initiateAcc(this, traceData);
614        if (_status != Running) {
615            // instruction will complete in dcache response callback
616            assert(_status == DcacheWaitResponse || _status == DcacheRetry);
617            assert(fault == NoFault);
618        } else {
619            if (fault == NoFault) {
620                // Note that ARM can have NULL packets if the instruction gets
621                // squashed due to predication
622                // early fail on store conditional: complete now
623                assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
624
625                fault = curStaticInst->completeAcc(dcache_pkt, this,
626                                                   traceData);
627                if (dcache_pkt != NULL)
628                {
629                    delete dcache_pkt->req;
630                    delete dcache_pkt;
631                    dcache_pkt = NULL;
632                }
633
634                // keep an instruction count
635                if (fault == NoFault)
636                    countInst();
637            } else if (traceData) {
638                // If there was a fault, we shouldn't trace this instruction.
639                delete traceData;
640                traceData = NULL;
641            }
642
643            postExecute();
644            // @todo remove me after debugging with legion done
645            if (curStaticInst && (!curStaticInst->isMicroop() ||
646                        curStaticInst->isFirstMicroop()))
647                instCnt++;
648            advanceInst(fault);
649        }
650    } else {
651        // non-memory instruction: execute completely now
652        Fault fault = curStaticInst->execute(this, traceData);
653
654        // keep an instruction count
655        if (fault == NoFault)
656            countInst();
657        else if (traceData) {
658            // If there was a fault, we shouldn't trace this instruction.
659            delete traceData;
660            traceData = NULL;
661        }
662
663        postExecute();
664        // @todo remove me after debugging with legion done
665        if (curStaticInst && (!curStaticInst->isMicroop() ||
666                    curStaticInst->isFirstMicroop()))
667            instCnt++;
668        advanceInst(fault);
669    }
670
671    if (pkt) {
672        delete pkt->req;
673        delete pkt;
674    }
675}
676
677void
678TimingSimpleCPU::IcachePort::ITickEvent::process()
679{
680    cpu->completeIfetch(pkt);
681}
682
683bool
684TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
685{
686    if (pkt->isResponse() && !pkt->wasNacked()) {
687        // delay processing of returned data until next CPU clock edge
688        Tick next_tick = cpu->nextCycle(curTick);
689
690        if (next_tick == curTick)
691            cpu->completeIfetch(pkt);
692        else
693            tickEvent.schedule(pkt, next_tick);
694
695        return true;
696    }
697    else if (pkt->wasNacked()) {
698        assert(cpu->_status == IcacheWaitResponse);
699        pkt->reinitNacked();
700        if (!sendTiming(pkt)) {
701            cpu->_status = IcacheRetry;
702            cpu->ifetch_pkt = pkt;
703        }
704    }
705    //Snooping a Coherence Request, do nothing
706    return true;
707}
708
709void
710TimingSimpleCPU::IcachePort::recvRetry()
711{
712    // we shouldn't get a retry unless we have a packet that we're
713    // waiting to transmit
714    assert(cpu->ifetch_pkt != NULL);
715    assert(cpu->_status == IcacheRetry);
716    PacketPtr tmp = cpu->ifetch_pkt;
717    if (sendTiming(tmp)) {
718        cpu->_status = IcacheWaitResponse;
719        cpu->ifetch_pkt = NULL;
720    }
721}
722
723void
724TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
725{
726    // received a response from the dcache: complete the load or store
727    // instruction
728    assert(!pkt->isError());
729    assert(_status == DcacheWaitResponse);
730    _status = Running;
731
732    numCycles += tickToCycles(curTick - previousTick);
733    previousTick = curTick;
734
735    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
736
737    // keep an instruction count
738    if (fault == NoFault)
739        countInst();
740    else if (traceData) {
741        // If there was a fault, we shouldn't trace this instruction.
742        delete traceData;
743        traceData = NULL;
744    }
745
746    // the locked flag may be cleared on the response packet, so check
747    // pkt->req and not pkt to see if it was a load-locked
748    if (pkt->isRead() && pkt->req->isLocked()) {
749        TheISA::handleLockedRead(thread, pkt->req);
750    }
751
752    delete pkt->req;
753    delete pkt;
754
755    postExecute();
756
757    if (getState() == SimObject::Draining) {
758        advancePC(fault);
759        completeDrain();
760
761        return;
762    }
763
764    advanceInst(fault);
765}
766
767
768void
769TimingSimpleCPU::completeDrain()
770{
771    DPRINTF(Config, "Done draining\n");
772    changeState(SimObject::Drained);
773    drainEvent->process();
774}
775
776void
777TimingSimpleCPU::DcachePort::setPeer(Port *port)
778{
779    Port::setPeer(port);
780
781#if FULL_SYSTEM
782    // Update the ThreadContext's memory ports (Functional/Virtual
783    // Ports)
784    cpu->tcBase()->connectMemPorts(cpu->tcBase());
785#endif
786}
787
788bool
789TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
790{
791    if (pkt->isResponse() && !pkt->wasNacked()) {
792        // delay processing of returned data until next CPU clock edge
793        Tick next_tick = cpu->nextCycle(curTick);
794
795        if (next_tick == curTick)
796            cpu->completeDataAccess(pkt);
797        else
798            tickEvent.schedule(pkt, next_tick);
799
800        return true;
801    }
802    else if (pkt->wasNacked()) {
803        assert(cpu->_status == DcacheWaitResponse);
804        pkt->reinitNacked();
805        if (!sendTiming(pkt)) {
806            cpu->_status = DcacheRetry;
807            cpu->dcache_pkt = pkt;
808        }
809    }
810    //Snooping a Coherence Request, do nothing
811    return true;
812}
813
814void
815TimingSimpleCPU::DcachePort::DTickEvent::process()
816{
817    cpu->completeDataAccess(pkt);
818}
819
820void
821TimingSimpleCPU::DcachePort::recvRetry()
822{
823    // we shouldn't get a retry unless we have a packet that we're
824    // waiting to transmit
825    assert(cpu->dcache_pkt != NULL);
826    assert(cpu->_status == DcacheRetry);
827    PacketPtr tmp = cpu->dcache_pkt;
828    if (sendTiming(tmp)) {
829        cpu->_status = DcacheWaitResponse;
830        // memory system takes ownership of packet
831        cpu->dcache_pkt = NULL;
832    }
833}
834
835TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
836    Tick t)
837    : pkt(_pkt), cpu(_cpu)
838{
839    cpu->schedule(this, t);
840}
841
842void
843TimingSimpleCPU::IprEvent::process()
844{
845    cpu->completeDataAccess(pkt);
846}
847
848const char *
849TimingSimpleCPU::IprEvent::description() const
850{
851    return "Timing Simple CPU Delay IPR event";
852}
853
854
855void
856TimingSimpleCPU::printAddr(Addr a)
857{
858    dcachePort.printAddr(a);
859}
860
861
862////////////////////////////////////////////////////////////////////////
863//
864//  TimingSimpleCPU Simulation Object
865//
866TimingSimpleCPU *
867TimingSimpleCPUParams::create()
868{
869    numThreads = 1;
870#if !FULL_SYSTEM
871    if (workload.size() != 1)
872        panic("only one workload allowed");
873#endif
874    return new TimingSimpleCPU(this);
875}
876