timing.cc revision 2867:cc92d58a3210
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/utility.hh"
326973Stjones1@inf.ed.ac.uk#include "cpu/exetrace.hh"
336973Stjones1@inf.ed.ac.uk#include "cpu/simple/timing.hh"
346973Stjones1@inf.ed.ac.uk#include "mem/packet_impl.hh"
356973Stjones1@inf.ed.ac.uk#include "sim/builder.hh"
366973Stjones1@inf.ed.ac.uk
376973Stjones1@inf.ed.ac.ukusing namespace std;
386973Stjones1@inf.ed.ac.ukusing namespace TheISA;
396973Stjones1@inf.ed.ac.uk
406973Stjones1@inf.ed.ac.uk
416973Stjones1@inf.ed.ac.ukvoid
426973Stjones1@inf.ed.ac.ukTimingSimpleCPU::init()
436973Stjones1@inf.ed.ac.uk{
446973Stjones1@inf.ed.ac.uk    //Create Memory Ports (conect them up)
456973Stjones1@inf.ed.ac.uk    Port *mem_dport = mem->getPort("");
466973Stjones1@inf.ed.ac.uk    dcachePort.setPeer(mem_dport);
476973Stjones1@inf.ed.ac.uk    mem_dport->setPeer(&dcachePort);
487678Sgblack@eecs.umich.edu
496973Stjones1@inf.ed.ac.uk    Port *mem_iport = mem->getPort("");
506973Stjones1@inf.ed.ac.uk    icachePort.setPeer(mem_iport);
517049Stjones1@inf.ed.ac.uk    mem_iport->setPeer(&icachePort);
527049Stjones1@inf.ed.ac.uk
537049Stjones1@inf.ed.ac.uk    BaseCPU::init();
547049Stjones1@inf.ed.ac.uk#if FULL_SYSTEM
557049Stjones1@inf.ed.ac.uk    for (int i = 0; i < threadContexts.size(); ++i) {
567049Stjones1@inf.ed.ac.uk        ThreadContext *tc = threadContexts[i];
577049Stjones1@inf.ed.ac.uk
587049Stjones1@inf.ed.ac.uk        // initialize CPU, including PC
597049Stjones1@inf.ed.ac.uk        TheISA::initCPU(tc, tc->readCpuId());
607049Stjones1@inf.ed.ac.uk    }
616973Stjones1@inf.ed.ac.uk#endif
626973Stjones1@inf.ed.ac.uk}
636973Stjones1@inf.ed.ac.uk
646973Stjones1@inf.ed.ac.ukTick
656973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt)
666973Stjones1@inf.ed.ac.uk{
676973Stjones1@inf.ed.ac.uk    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
687944SGiacomo.Gabrielli@arm.com    return curTick;
696973Stjones1@inf.ed.ac.uk}
706973Stjones1@inf.ed.ac.uk
716973Stjones1@inf.ed.ac.ukvoid
726973Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt)
736973Stjones1@inf.ed.ac.uk{
746973Stjones1@inf.ed.ac.uk    panic("TimingSimpleCPU doesn't expect recvFunctional callback!");
756973Stjones1@inf.ed.ac.uk}
766973Stjones1@inf.ed.ac.uk
777049Stjones1@inf.ed.ac.ukvoid
787049Stjones1@inf.ed.ac.ukTimingSimpleCPU::CpuPort::recvStatusChange(Status status)
797049Stjones1@inf.ed.ac.uk{
807049Stjones1@inf.ed.ac.uk    if (status == RangeChange)
816973Stjones1@inf.ed.ac.uk        return;
826973Stjones1@inf.ed.ac.uk
837944SGiacomo.Gabrielli@arm.com    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
847944SGiacomo.Gabrielli@arm.com}
856973Stjones1@inf.ed.ac.uk
866973Stjones1@inf.ed.ac.ukTimingSimpleCPU::TimingSimpleCPU(Params *p)
876973Stjones1@inf.ed.ac.uk    : BaseSimpleCPU(p), icachePort(this), dcachePort(this)
886973Stjones1@inf.ed.ac.uk{
896973Stjones1@inf.ed.ac.uk    _status = Idle;
907049Stjones1@inf.ed.ac.uk    ifetch_pkt = dcache_pkt = NULL;
917049Stjones1@inf.ed.ac.uk    drainEvent = NULL;
927049Stjones1@inf.ed.ac.uk    fetchEvent = NULL;
937049Stjones1@inf.ed.ac.uk    state = SimObject::Timing;
947049Stjones1@inf.ed.ac.uk}
956973Stjones1@inf.ed.ac.uk
966973Stjones1@inf.ed.ac.uk
976973Stjones1@inf.ed.ac.ukTimingSimpleCPU::~TimingSimpleCPU()
987944SGiacomo.Gabrielli@arm.com{
997944SGiacomo.Gabrielli@arm.com}
1007944SGiacomo.Gabrielli@arm.com
1016973Stjones1@inf.ed.ac.ukvoid
1026973Stjones1@inf.ed.ac.ukTimingSimpleCPU::serialize(ostream &os)
1036973Stjones1@inf.ed.ac.uk{
1046973Stjones1@inf.ed.ac.uk    SERIALIZE_ENUM(_status);
1056973Stjones1@inf.ed.ac.uk    BaseSimpleCPU::serialize(os);
1067049Stjones1@inf.ed.ac.uk}
1077049Stjones1@inf.ed.ac.uk
1087049Stjones1@inf.ed.ac.ukvoid
1097049Stjones1@inf.ed.ac.ukTimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1107049Stjones1@inf.ed.ac.uk{
1117049Stjones1@inf.ed.ac.uk    UNSERIALIZE_ENUM(_status);
1127049Stjones1@inf.ed.ac.uk    BaseSimpleCPU::unserialize(cp, section);
1136973Stjones1@inf.ed.ac.uk}
1146973Stjones1@inf.ed.ac.uk
1156973Stjones1@inf.ed.ac.ukbool
1166973Stjones1@inf.ed.ac.ukTimingSimpleCPU::drain(Event *drain_event)
1176973Stjones1@inf.ed.ac.uk{
1186973Stjones1@inf.ed.ac.uk    // TimingSimpleCPU is ready to drain if it's not waiting for
1196973Stjones1@inf.ed.ac.uk    // an access to complete.
1206973Stjones1@inf.ed.ac.uk    if (status() == Idle || status() == Running || status() == SwitchedOut) {
1216973Stjones1@inf.ed.ac.uk        changeState(SimObject::DrainedTiming);
1226973Stjones1@inf.ed.ac.uk        return true;
1236973Stjones1@inf.ed.ac.uk    } else {
1246973Stjones1@inf.ed.ac.uk        changeState(SimObject::Draining);
1256973Stjones1@inf.ed.ac.uk        drainEvent = drain_event;
1266973Stjones1@inf.ed.ac.uk        return false;
1276973Stjones1@inf.ed.ac.uk    }
1286973Stjones1@inf.ed.ac.uk}
1296973Stjones1@inf.ed.ac.uk
1306973Stjones1@inf.ed.ac.ukvoid
1317049Stjones1@inf.ed.ac.ukTimingSimpleCPU::resume()
1327049Stjones1@inf.ed.ac.uk{
1337049Stjones1@inf.ed.ac.uk    if (_status != SwitchedOut && _status != Idle) {
1347049Stjones1@inf.ed.ac.uk        // Delete the old event if it existed.
1356973Stjones1@inf.ed.ac.uk        if (fetchEvent) {
1366973Stjones1@inf.ed.ac.uk            assert(!fetchEvent->scheduled());
1376973Stjones1@inf.ed.ac.uk            delete fetchEvent;
1386973Stjones1@inf.ed.ac.uk        }
1396973Stjones1@inf.ed.ac.uk
1406973Stjones1@inf.ed.ac.uk        fetchEvent =
1416973Stjones1@inf.ed.ac.uk            new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
1426973Stjones1@inf.ed.ac.uk        fetchEvent->schedule(curTick);
1436973Stjones1@inf.ed.ac.uk    }
1446973Stjones1@inf.ed.ac.uk}
1456973Stjones1@inf.ed.ac.uk
1466973Stjones1@inf.ed.ac.ukvoid
1476973Stjones1@inf.ed.ac.ukTimingSimpleCPU::setMemoryMode(State new_mode)
1487049Stjones1@inf.ed.ac.uk{
1496973Stjones1@inf.ed.ac.uk    assert(new_mode == SimObject::Timing);
1506973Stjones1@inf.ed.ac.uk}
1516973Stjones1@inf.ed.ac.uk
1526973Stjones1@inf.ed.ac.ukvoid
1536973Stjones1@inf.ed.ac.ukTimingSimpleCPU::switchOut()
1546973Stjones1@inf.ed.ac.uk{
1557049Stjones1@inf.ed.ac.uk    assert(status() == Running || status() == Idle);
1567049Stjones1@inf.ed.ac.uk    _status = SwitchedOut;
1577049Stjones1@inf.ed.ac.uk
1587049Stjones1@inf.ed.ac.uk    // If we've been scheduled to resume but are then told to switch out,
1597049Stjones1@inf.ed.ac.uk    // we'll need to cancel it.
1606973Stjones1@inf.ed.ac.uk    if (fetchEvent && fetchEvent->scheduled())
1616973Stjones1@inf.ed.ac.uk        fetchEvent->deschedule();
1626973Stjones1@inf.ed.ac.uk}
1636973Stjones1@inf.ed.ac.uk
1646973Stjones1@inf.ed.ac.uk
1656973Stjones1@inf.ed.ac.ukvoid
1667049Stjones1@inf.ed.ac.ukTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
1677049Stjones1@inf.ed.ac.uk{
1687049Stjones1@inf.ed.ac.uk    BaseCPU::takeOverFrom(oldCPU);
1697049Stjones1@inf.ed.ac.uk
1707049Stjones1@inf.ed.ac.uk    // if any of this CPU's ThreadContexts are active, mark the CPU as
1716973Stjones1@inf.ed.ac.uk    // running and schedule its tick event.
1726973Stjones1@inf.ed.ac.uk    for (int i = 0; i < threadContexts.size(); ++i) {
1736973Stjones1@inf.ed.ac.uk        ThreadContext *tc = threadContexts[i];
1746973Stjones1@inf.ed.ac.uk        if (tc->status() == ThreadContext::Active && _status != Running) {
1756973Stjones1@inf.ed.ac.uk            _status = Running;
1766973Stjones1@inf.ed.ac.uk            break;
1777049Stjones1@inf.ed.ac.uk        }
1786973Stjones1@inf.ed.ac.uk    }
1796973Stjones1@inf.ed.ac.uk}
1806973Stjones1@inf.ed.ac.uk
1816973Stjones1@inf.ed.ac.uk
1826973Stjones1@inf.ed.ac.ukvoid
1836973Stjones1@inf.ed.ac.ukTimingSimpleCPU::activateContext(int thread_num, int delay)
1847049Stjones1@inf.ed.ac.uk{
1857049Stjones1@inf.ed.ac.uk    assert(thread_num == 0);
1867049Stjones1@inf.ed.ac.uk    assert(thread);
1877049Stjones1@inf.ed.ac.uk
1887049Stjones1@inf.ed.ac.uk    assert(_status == Idle);
1896973Stjones1@inf.ed.ac.uk
1906973Stjones1@inf.ed.ac.uk    notIdleFraction++;
1916973Stjones1@inf.ed.ac.uk    _status = Running;
1926973Stjones1@inf.ed.ac.uk    // kick things off by initiating the fetch of the next instruction
1936973Stjones1@inf.ed.ac.uk    fetchEvent =
1946973Stjones1@inf.ed.ac.uk        new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
1957049Stjones1@inf.ed.ac.uk    fetchEvent->schedule(curTick + cycles(delay));
1966973Stjones1@inf.ed.ac.uk}
1976973Stjones1@inf.ed.ac.uk
1986973Stjones1@inf.ed.ac.uk
1996973Stjones1@inf.ed.ac.ukvoid
2006973Stjones1@inf.ed.ac.ukTimingSimpleCPU::suspendContext(int thread_num)
2016973Stjones1@inf.ed.ac.uk{
2026973Stjones1@inf.ed.ac.uk    assert(thread_num == 0);
2036973Stjones1@inf.ed.ac.uk    assert(thread);
2046973Stjones1@inf.ed.ac.uk
2056973Stjones1@inf.ed.ac.uk    assert(_status == Running);
2066973Stjones1@inf.ed.ac.uk
2077049Stjones1@inf.ed.ac.uk    // just change status to Idle... if status != Running,
2087049Stjones1@inf.ed.ac.uk    // completeInst() will not initiate fetch of next instruction.
2097049Stjones1@inf.ed.ac.uk
2107049Stjones1@inf.ed.ac.uk    notIdleFraction--;
2117049Stjones1@inf.ed.ac.uk    _status = Idle;
2127049Stjones1@inf.ed.ac.uk}
2137049Stjones1@inf.ed.ac.uk
2147049Stjones1@inf.ed.ac.uk
2157049Stjones1@inf.ed.ac.uktemplate <class T>
2167049Stjones1@inf.ed.ac.ukFault
2178486Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
2186973Stjones1@inf.ed.ac.uk{
2196973Stjones1@inf.ed.ac.uk    // need to fill in CPU & thread IDs here
2206973Stjones1@inf.ed.ac.uk    Request *data_read_req = new Request();
2218486Sgblack@eecs.umich.edu    data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
2226973Stjones1@inf.ed.ac.uk    data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
2236973Stjones1@inf.ed.ac.uk
2246973Stjones1@inf.ed.ac.uk    if (traceData) {
2256973Stjones1@inf.ed.ac.uk        traceData->setAddr(data_read_req->getVaddr());
2268486Sgblack@eecs.umich.edu    }
2276973Stjones1@inf.ed.ac.uk
2286973Stjones1@inf.ed.ac.uk   // translate to physical address
2296973Stjones1@inf.ed.ac.uk    Fault fault = thread->translateDataReadReq(data_read_req);
2306973Stjones1@inf.ed.ac.uk
2318486Sgblack@eecs.umich.edu    // Now do the access.
2326973Stjones1@inf.ed.ac.uk    if (fault == NoFault) {
2336973Stjones1@inf.ed.ac.uk        Packet *data_read_pkt =
2346973Stjones1@inf.ed.ac.uk            new Packet(data_read_req, Packet::ReadReq, Packet::Broadcast);
2356973Stjones1@inf.ed.ac.uk        data_read_pkt->dataDynamic<T>(new T);
2366973Stjones1@inf.ed.ac.uk
2377049Stjones1@inf.ed.ac.uk        if (!dcachePort.sendTiming(data_read_pkt)) {
2387944SGiacomo.Gabrielli@arm.com            _status = DcacheRetry;
2397944SGiacomo.Gabrielli@arm.com            dcache_pkt = data_read_pkt;
2407944SGiacomo.Gabrielli@arm.com        } else {
2417944SGiacomo.Gabrielli@arm.com            _status = DcacheWaitResponse;
2427944SGiacomo.Gabrielli@arm.com            dcache_pkt = NULL;
2437944SGiacomo.Gabrielli@arm.com        }
2447944SGiacomo.Gabrielli@arm.com    }
2457944SGiacomo.Gabrielli@arm.com
2467944SGiacomo.Gabrielli@arm.com    // This will need a new way to tell if it has a dcache attached.
2477944SGiacomo.Gabrielli@arm.com    if (data_read_req->getFlags() & UNCACHEABLE)
2487049Stjones1@inf.ed.ac.uk        recordEvent("Uncached Read");
2497049Stjones1@inf.ed.ac.uk
2507049Stjones1@inf.ed.ac.uk    return fault;
2516973Stjones1@inf.ed.ac.uk}
2526973Stjones1@inf.ed.ac.uk
2536973Stjones1@inf.ed.ac.uk#ifndef DOXYGEN_SHOULD_SKIP_THIS
2546973Stjones1@inf.ed.ac.uk
2556973Stjones1@inf.ed.ac.uktemplate
2566973Stjones1@inf.ed.ac.ukFault
2576973Stjones1@inf.ed.ac.ukTimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
2586973Stjones1@inf.ed.ac.uk
2596973Stjones1@inf.ed.ac.uktemplate
2606973Stjones1@inf.ed.ac.ukFault
2616973Stjones1@inf.ed.ac.ukTimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
2626973Stjones1@inf.ed.ac.uk
2636973Stjones1@inf.ed.ac.uktemplate
2646973Stjones1@inf.ed.ac.ukFault
265TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
266
267template
268Fault
269TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
270
271#endif //DOXYGEN_SHOULD_SKIP_THIS
272
273template<>
274Fault
275TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
276{
277    return read(addr, *(uint64_t*)&data, flags);
278}
279
280template<>
281Fault
282TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
283{
284    return read(addr, *(uint32_t*)&data, flags);
285}
286
287
288template<>
289Fault
290TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
291{
292    return read(addr, (uint32_t&)data, flags);
293}
294
295
296template <class T>
297Fault
298TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
299{
300    // need to fill in CPU & thread IDs here
301    Request *data_write_req = new Request();
302    data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
303    data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
304
305    // translate to physical address
306    Fault fault = thread->translateDataWriteReq(data_write_req);
307    // Now do the access.
308    if (fault == NoFault) {
309        Packet *data_write_pkt =
310            new Packet(data_write_req, Packet::WriteReq, Packet::Broadcast);
311        data_write_pkt->allocate();
312        data_write_pkt->set(data);
313
314        if (!dcachePort.sendTiming(data_write_pkt)) {
315            _status = DcacheRetry;
316            dcache_pkt = data_write_pkt;
317        } else {
318            _status = DcacheWaitResponse;
319            dcache_pkt = NULL;
320        }
321    }
322
323    // This will need a new way to tell if it's hooked up to a cache or not.
324    if (data_write_req->getFlags() & UNCACHEABLE)
325        recordEvent("Uncached Write");
326
327    // If the write needs to have a fault on the access, consider calling
328    // changeStatus() and changing it to "bad addr write" or something.
329    return fault;
330}
331
332
333#ifndef DOXYGEN_SHOULD_SKIP_THIS
334template
335Fault
336TimingSimpleCPU::write(uint64_t data, Addr addr,
337                       unsigned flags, uint64_t *res);
338
339template
340Fault
341TimingSimpleCPU::write(uint32_t data, Addr addr,
342                       unsigned flags, uint64_t *res);
343
344template
345Fault
346TimingSimpleCPU::write(uint16_t data, Addr addr,
347                       unsigned flags, uint64_t *res);
348
349template
350Fault
351TimingSimpleCPU::write(uint8_t data, Addr addr,
352                       unsigned flags, uint64_t *res);
353
354#endif //DOXYGEN_SHOULD_SKIP_THIS
355
356template<>
357Fault
358TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
359{
360    return write(*(uint64_t*)&data, addr, flags, res);
361}
362
363template<>
364Fault
365TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
366{
367    return write(*(uint32_t*)&data, addr, flags, res);
368}
369
370
371template<>
372Fault
373TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
374{
375    return write((uint32_t)data, addr, flags, res);
376}
377
378
379void
380TimingSimpleCPU::fetch()
381{
382    checkForInterrupts();
383
384    // need to fill in CPU & thread IDs here
385    Request *ifetch_req = new Request();
386    ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
387    Fault fault = setupFetchRequest(ifetch_req);
388
389    ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
390    ifetch_pkt->dataStatic(&inst);
391
392    if (fault == NoFault) {
393        if (!icachePort.sendTiming(ifetch_pkt)) {
394            // Need to wait for retry
395            _status = IcacheRetry;
396        } else {
397            // Need to wait for cache to respond
398            _status = IcacheWaitResponse;
399            // ownership of packet transferred to memory system
400            ifetch_pkt = NULL;
401        }
402    } else {
403        // fetch fault: advance directly to next instruction (fault handler)
404        advanceInst(fault);
405    }
406}
407
408
409void
410TimingSimpleCPU::advanceInst(Fault fault)
411{
412    advancePC(fault);
413
414    if (_status == Running) {
415        // kick off fetch of next instruction... callback from icache
416        // response will cause that instruction to be executed,
417        // keeping the CPU running.
418        fetch();
419    }
420}
421
422
423void
424TimingSimpleCPU::completeIfetch(Packet *pkt)
425{
426    // received a response from the icache: execute the received
427    // instruction
428    assert(pkt->result == Packet::Success);
429    assert(_status == IcacheWaitResponse);
430
431    _status = Running;
432
433    delete pkt->req;
434    delete pkt;
435
436    if (getState() == SimObject::Draining) {
437        completeDrain();
438        return;
439    }
440
441    preExecute();
442    if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
443        // load or store: just send to dcache
444        Fault fault = curStaticInst->initiateAcc(this, traceData);
445        if (fault == NoFault) {
446            // successfully initiated access: instruction will
447            // complete in dcache response callback
448            assert(_status == DcacheWaitResponse);
449        } else {
450            // fault: complete now to invoke fault handler
451            postExecute();
452            advanceInst(fault);
453        }
454    } else {
455        // non-memory instruction: execute completely now
456        Fault fault = curStaticInst->execute(this, traceData);
457        postExecute();
458        advanceInst(fault);
459    }
460}
461
462
463bool
464TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
465{
466    if (cpu->_status == DcacheWaitResponse)
467        cpu->completeDataAccess(pkt);
468    else if (cpu->_status == IcacheWaitResponse)
469        cpu->completeIfetch(pkt);
470    else
471        assert("OOPS" && 0);
472    return true;
473}
474
475void
476TimingSimpleCPU::IcachePort::recvRetry()
477{
478    // we shouldn't get a retry unless we have a packet that we're
479    // waiting to transmit
480    assert(cpu->ifetch_pkt != NULL);
481    assert(cpu->_status == IcacheRetry);
482    Packet *tmp = cpu->ifetch_pkt;
483    if (sendTiming(tmp)) {
484        cpu->_status = IcacheWaitResponse;
485        cpu->ifetch_pkt = NULL;
486    }
487}
488
489void
490TimingSimpleCPU::completeDataAccess(Packet *pkt)
491{
492    // received a response from the dcache: complete the load or store
493    // instruction
494    assert(pkt->result == Packet::Success);
495    assert(_status == DcacheWaitResponse);
496    _status = Running;
497
498    if (getState() == SimObject::Draining) {
499        completeDrain();
500
501        delete pkt->req;
502        delete pkt;
503
504        return;
505    }
506
507    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
508
509    delete pkt->req;
510    delete pkt;
511
512    postExecute();
513    advanceInst(fault);
514}
515
516
517void
518TimingSimpleCPU::completeDrain()
519{
520    DPRINTF(Config, "Done draining\n");
521    changeState(SimObject::DrainedTiming);
522    drainEvent->process();
523}
524
525bool
526TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
527{
528    cpu->completeDataAccess(pkt);
529    return true;
530}
531
532void
533TimingSimpleCPU::DcachePort::recvRetry()
534{
535    // we shouldn't get a retry unless we have a packet that we're
536    // waiting to transmit
537    assert(cpu->dcache_pkt != NULL);
538    assert(cpu->_status == DcacheRetry);
539    Packet *tmp = cpu->dcache_pkt;
540    if (sendTiming(tmp)) {
541        cpu->_status = DcacheWaitResponse;
542        cpu->dcache_pkt = NULL;
543    }
544}
545
546
547////////////////////////////////////////////////////////////////////////
548//
549//  TimingSimpleCPU Simulation Object
550//
551BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
552
553    Param<Counter> max_insts_any_thread;
554    Param<Counter> max_insts_all_threads;
555    Param<Counter> max_loads_any_thread;
556    Param<Counter> max_loads_all_threads;
557    SimObjectParam<MemObject *> mem;
558
559#if FULL_SYSTEM
560    SimObjectParam<AlphaITB *> itb;
561    SimObjectParam<AlphaDTB *> dtb;
562    SimObjectParam<System *> system;
563    Param<int> cpu_id;
564    Param<Tick> profile;
565#else
566    SimObjectParam<Process *> workload;
567#endif // FULL_SYSTEM
568
569    Param<int> clock;
570
571    Param<bool> defer_registration;
572    Param<int> width;
573    Param<bool> function_trace;
574    Param<Tick> function_trace_start;
575    Param<bool> simulate_stalls;
576
577END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
578
579BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
580
581    INIT_PARAM(max_insts_any_thread,
582               "terminate when any thread reaches this inst count"),
583    INIT_PARAM(max_insts_all_threads,
584               "terminate when all threads have reached this inst count"),
585    INIT_PARAM(max_loads_any_thread,
586               "terminate when any thread reaches this load count"),
587    INIT_PARAM(max_loads_all_threads,
588               "terminate when all threads have reached this load count"),
589    INIT_PARAM(mem, "memory"),
590
591#if FULL_SYSTEM
592    INIT_PARAM(itb, "Instruction TLB"),
593    INIT_PARAM(dtb, "Data TLB"),
594    INIT_PARAM(system, "system object"),
595    INIT_PARAM(cpu_id, "processor ID"),
596    INIT_PARAM(profile, ""),
597#else
598    INIT_PARAM(workload, "processes to run"),
599#endif // FULL_SYSTEM
600
601    INIT_PARAM(clock, "clock speed"),
602    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
603    INIT_PARAM(width, "cpu width"),
604    INIT_PARAM(function_trace, "Enable function trace"),
605    INIT_PARAM(function_trace_start, "Cycle to start function trace"),
606    INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
607
608END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
609
610
611CREATE_SIM_OBJECT(TimingSimpleCPU)
612{
613    TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
614    params->name = getInstanceName();
615    params->numberOfThreads = 1;
616    params->max_insts_any_thread = max_insts_any_thread;
617    params->max_insts_all_threads = max_insts_all_threads;
618    params->max_loads_any_thread = max_loads_any_thread;
619    params->max_loads_all_threads = max_loads_all_threads;
620    params->deferRegistration = defer_registration;
621    params->clock = clock;
622    params->functionTrace = function_trace;
623    params->functionTraceStart = function_trace_start;
624    params->mem = mem;
625
626#if FULL_SYSTEM
627    params->itb = itb;
628    params->dtb = dtb;
629    params->system = system;
630    params->cpu_id = cpu_id;
631    params->profile = profile;
632#else
633    params->process = workload;
634#endif
635
636    TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
637    return cpu;
638}
639
640REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU)
641
642