timer_sp804.cc revision 8524
12817Sksewell@umich.edu/*
22817Sksewell@umich.edu * Copyright (c) 2010 ARM Limited
32817Sksewell@umich.edu * All rights reserved
42817Sksewell@umich.edu *
52817Sksewell@umich.edu * The license below extends only to copyright in the software and shall
62817Sksewell@umich.edu * not be construed as granting a license to any other intellectual
72817Sksewell@umich.edu * property including but not limited to intellectual property relating
82817Sksewell@umich.edu * to a hardware implementation of the functionality of the software
92817Sksewell@umich.edu * licensed hereunder.  You may use the software subject to the license
102817Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated
112817Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software,
122817Sksewell@umich.edu * modified or unmodified, in source code or in binary form.
132817Sksewell@umich.edu *
142817Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without
152817Sksewell@umich.edu * modification, are permitted provided that the following conditions are
162817Sksewell@umich.edu * met: redistributions of source code must retain the above copyright
172817Sksewell@umich.edu * notice, this list of conditions and the following disclaimer;
182817Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright
192817Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the
202817Sksewell@umich.edu * documentation and/or other materials provided with the distribution;
212817Sksewell@umich.edu * neither the name of the copyright holders nor the names of its
222817Sksewell@umich.edu * contributors may be used to endorse or promote products derived from
232817Sksewell@umich.edu * this software without specific prior written permission.
242817Sksewell@umich.edu *
252817Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262817Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272817Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282817Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292817Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302817Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312817Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323776Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332817Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342834Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352817Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362817Sksewell@umich.edu *
372817Sksewell@umich.edu * Authors: Ali Saidi
382817Sksewell@umich.edu */
395499Ssaidi@eecs.umich.edu
402817Sksewell@umich.edu#include "base/intmath.hh"
415499Ssaidi@eecs.umich.edu#include "base/trace.hh"
422817Sksewell@umich.edu#include "debug/Checkpoint.hh"
432817Sksewell@umich.edu#include "debug/Timer.hh"
442817Sksewell@umich.edu#include "dev/arm/gic.hh"
452817Sksewell@umich.edu#include "dev/arm/timer_sp804.hh"
462817Sksewell@umich.edu#include "mem/packet.hh"
472817Sksewell@umich.edu#include "mem/packet_access.hh"
483126Sktlim@umich.edu
492817Sksewell@umich.eduusing namespace AmbaDev;
502817Sksewell@umich.edu
512817Sksewell@umich.eduSp804::Sp804(Params *p)
522817Sksewell@umich.edu    : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0),
532817Sksewell@umich.edu      timer1(name() + ".timer1", this, p->int_num1, p->clock1)
542817Sksewell@umich.edu{
552817Sksewell@umich.edu    pioSize = 0xfff;
562817Sksewell@umich.edu}
572817Sksewell@umich.edu
585803Snate@binkert.orgSp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock)
592817Sksewell@umich.edu    : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20),
602817Sksewell@umich.edu      rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this)
612817Sksewell@umich.edu{
622817Sksewell@umich.edu}
632817Sksewell@umich.edu
642817Sksewell@umich.edu
655714Shsul@eecs.umich.eduTick
665715Shsul@eecs.umich.eduSp804::read(PacketPtr pkt)
672817Sksewell@umich.edu{
682817Sksewell@umich.edu    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
692817Sksewell@umich.edu    assert(pkt->getSize() == 4);
702817Sksewell@umich.edu    Addr daddr = pkt->getAddr() - pioAddr;
712817Sksewell@umich.edu    pkt->allocate();
722817Sksewell@umich.edu    DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr);
732817Sksewell@umich.edu
742817Sksewell@umich.edu    if (daddr < Timer::Size)
752817Sksewell@umich.edu        timer0.read(pkt, daddr);
762817Sksewell@umich.edu    else if ((daddr - Timer::Size) < Timer::Size)
772817Sksewell@umich.edu        timer1.read(pkt, daddr - Timer::Size);
782817Sksewell@umich.edu    else if (!readId(pkt, ambaId, pioAddr))
792817Sksewell@umich.edu        panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr);
802817Sksewell@umich.edu    pkt->makeAtomicResponse();
812817Sksewell@umich.edu    return pioDelay;
822817Sksewell@umich.edu}
832817Sksewell@umich.edu
842817Sksewell@umich.edu
852817Sksewell@umich.eduvoid
862817Sksewell@umich.eduSp804::Timer::read(PacketPtr pkt, Addr daddr)
872817Sksewell@umich.edu{
882817Sksewell@umich.edu    switch(daddr) {
892817Sksewell@umich.edu      case LoadReg:
902817Sksewell@umich.edu        pkt->set<uint32_t>(loadValue);
912817Sksewell@umich.edu        break;
922817Sksewell@umich.edu      case CurrentReg:
932817Sksewell@umich.edu        DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n",
942817Sksewell@umich.edu                zeroEvent.when(), clock, control.timerPrescale);
952817Sksewell@umich.edu        Tick time;
962817Sksewell@umich.edu        time = zeroEvent.when() - curTick();
972875Sksewell@umich.edu        time = time / clock / power(16, control.timerPrescale);
985715Shsul@eecs.umich.edu        DPRINTF(Timer, "-- returning counter at %d\n", time);
992817Sksewell@umich.edu        pkt->set<uint32_t>(time);
1002817Sksewell@umich.edu        break;
1012817Sksewell@umich.edu      case ControlReg:
1022817Sksewell@umich.edu        pkt->set<uint32_t>(control);
1032817Sksewell@umich.edu        break;
1042817Sksewell@umich.edu      case RawISR:
1052817Sksewell@umich.edu        pkt->set<uint32_t>(rawInt);
1062817Sksewell@umich.edu        break;
1072817Sksewell@umich.edu      case MaskedISR:
1085715Shsul@eecs.umich.edu        pkt->set<uint32_t>(pendingInt);
1092817Sksewell@umich.edu        break;
1102817Sksewell@umich.edu      case BGLoad:
1112817Sksewell@umich.edu        pkt->set<uint32_t>(loadValue);
1122817Sksewell@umich.edu        break;
1132817Sksewell@umich.edu      default:
1142817Sksewell@umich.edu        panic("Tried to read SP804 timer at offset %#x\n", daddr);
1155715Shsul@eecs.umich.edu        break;
1162817Sksewell@umich.edu    }
1172817Sksewell@umich.edu    DPRINTF(Timer, "Reading %#x from Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
1182817Sksewell@umich.edu}
1192817Sksewell@umich.edu
1205250Sksewell@umich.eduTick
1212817Sksewell@umich.eduSp804::write(PacketPtr pkt)
1222875Sksewell@umich.edu{
1235715Shsul@eecs.umich.edu    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
1242817Sksewell@umich.edu    assert(pkt->getSize() == 4);
1252817Sksewell@umich.edu    Addr daddr = pkt->getAddr() - pioAddr;
1262817Sksewell@umich.edu    pkt->allocate();
1272817Sksewell@umich.edu    DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr);
1282817Sksewell@umich.edu
1292817Sksewell@umich.edu    if (daddr < Timer::Size)
1302817Sksewell@umich.edu        timer0.write(pkt, daddr);
1312817Sksewell@umich.edu    else if ((daddr - Timer::Size) < Timer::Size)
1322817Sksewell@umich.edu        timer1.write(pkt, daddr - Timer::Size);
1332817Sksewell@umich.edu    else if (!readId(pkt, ambaId, pioAddr))
1342817Sksewell@umich.edu        panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr);
1355704Snate@binkert.org    pkt->makeAtomicResponse();
1362817Sksewell@umich.edu    return pioDelay;
1372817Sksewell@umich.edu}
1382817Sksewell@umich.edu
1392817Sksewell@umich.eduvoid
1402817Sksewell@umich.eduSp804::Timer::write(PacketPtr pkt, Addr daddr)
1412817Sksewell@umich.edu{
1425715Shsul@eecs.umich.edu    DPRINTF(Timer, "Writing %#x to Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
1432817Sksewell@umich.edu    switch (daddr) {
1442817Sksewell@umich.edu      case LoadReg:
1452817Sksewell@umich.edu        loadValue = pkt->get<uint32_t>();
1462817Sksewell@umich.edu        restartCounter(loadValue);
1472875Sksewell@umich.edu        break;
1482817Sksewell@umich.edu      case CurrentReg:
1493221Sktlim@umich.edu        // Spec says this value can't be written, but linux writes it anyway
1505715Shsul@eecs.umich.edu        break;
1512817Sksewell@umich.edu      case ControlReg:
1522817Sksewell@umich.edu        bool old_enable;
1532817Sksewell@umich.edu        old_enable = control.timerEnable;
1542817Sksewell@umich.edu        control = pkt->get<uint32_t>();
1552817Sksewell@umich.edu        if ((old_enable == 0) && control.timerEnable)
1565715Shsul@eecs.umich.edu            restartCounter(loadValue);
1572817Sksewell@umich.edu        break;
1582817Sksewell@umich.edu      case IntClear:
1592817Sksewell@umich.edu        rawInt = false;
1602817Sksewell@umich.edu        if (pendingInt) {
1615250Sksewell@umich.edu            pendingInt = false;
1622817Sksewell@umich.edu            DPRINTF(Timer, "Clearing interrupt\n");
1632875Sksewell@umich.edu            parent->gic->clearInt(intNum);
1645715Shsul@eecs.umich.edu        }
1652817Sksewell@umich.edu        break;
1662817Sksewell@umich.edu      case BGLoad:
1672817Sksewell@umich.edu        loadValue = pkt->get<uint32_t>();
1682817Sksewell@umich.edu        break;
1692817Sksewell@umich.edu      default:
1705715Shsul@eecs.umich.edu        panic("Tried to write SP804 timer at offset %#x\n", daddr);
1712817Sksewell@umich.edu        break;
1722817Sksewell@umich.edu    }
1732817Sksewell@umich.edu}
1742817Sksewell@umich.edu
1752817Sksewell@umich.eduvoid
1762817Sksewell@umich.eduSp804::Timer::restartCounter(uint32_t val)
1772817Sksewell@umich.edu{
1783548Sgblack@eecs.umich.edu    DPRINTF(Timer, "Resetting counter with value %#x\n", val);
1792817Sksewell@umich.edu    if (!control.timerEnable)
1802817Sksewell@umich.edu        return;
1812817Sksewell@umich.edu
1822817Sksewell@umich.edu    Tick time = clock * power(16, control.timerPrescale);
1832817Sksewell@umich.edu    if (control.timerSize)
1842817Sksewell@umich.edu        time *= val;
1852817Sksewell@umich.edu    else
1862817Sksewell@umich.edu        time *= bits(val,15,0);
1872817Sksewell@umich.edu
1882817Sksewell@umich.edu    if (zeroEvent.scheduled()) {
1892817Sksewell@umich.edu        DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
1902817Sksewell@umich.edu        parent->deschedule(zeroEvent);
1912817Sksewell@umich.edu    }
1922817Sksewell@umich.edu    parent->schedule(zeroEvent, curTick() + time);
1932817Sksewell@umich.edu    DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
1942817Sksewell@umich.edu}
1952817Sksewell@umich.edu
1962817Sksewell@umich.eduvoid
1972817Sksewell@umich.eduSp804::Timer::counterAtZero()
1982817Sksewell@umich.edu{
1992817Sksewell@umich.edu    if (!control.timerEnable)
2002817Sksewell@umich.edu        return;
2012817Sksewell@umich.edu
2022817Sksewell@umich.edu    DPRINTF(Timer, "Counter reached zero\n");
2032817Sksewell@umich.edu
2042817Sksewell@umich.edu    rawInt = true;
2052817Sksewell@umich.edu    bool old_pending = pendingInt;
2062817Sksewell@umich.edu    if (control.intEnable)
2072817Sksewell@umich.edu        pendingInt = true;
2082817Sksewell@umich.edu    if (pendingInt && ~old_pending) {
2092817Sksewell@umich.edu        DPRINTF(Timer, "-- Causing interrupt\n");
2102817Sksewell@umich.edu        parent->gic->sendInt(intNum);
2112817Sksewell@umich.edu    }
2122817Sksewell@umich.edu
2132817Sksewell@umich.edu    if (control.oneShot)
2142817Sksewell@umich.edu        return;
2152817Sksewell@umich.edu
2162817Sksewell@umich.edu    // Free-running
2172817Sksewell@umich.edu    if (control.timerMode == 0)
2182817Sksewell@umich.edu        restartCounter(0xffffffff);
2192817Sksewell@umich.edu    else
2202817Sksewell@umich.edu        restartCounter(loadValue);
2212817Sksewell@umich.edu}
2222817Sksewell@umich.edu
2233126Sktlim@umich.eduvoid
2243126Sktlim@umich.eduSp804::Timer::serialize(std::ostream &os)
2253126Sktlim@umich.edu{
2262817Sksewell@umich.edu    DPRINTF(Checkpoint, "Serializing Arm Sp804\n");
2272817Sksewell@umich.edu    SERIALIZE_SCALAR(intNum);
2282817Sksewell@umich.edu    SERIALIZE_SCALAR(clock);
2292817Sksewell@umich.edu
2303126Sktlim@umich.edu    uint32_t control_serial = control;
2313126Sktlim@umich.edu    SERIALIZE_SCALAR(control_serial);
2323126Sktlim@umich.edu
2332817Sksewell@umich.edu    SERIALIZE_SCALAR(rawInt);
2342817Sksewell@umich.edu    SERIALIZE_SCALAR(pendingInt);
2352817Sksewell@umich.edu    SERIALIZE_SCALAR(loadValue);
2362817Sksewell@umich.edu
2372817Sksewell@umich.edu    bool is_in_event = zeroEvent.scheduled();
2382817Sksewell@umich.edu    SERIALIZE_SCALAR(is_in_event);
2392817Sksewell@umich.edu
2402817Sksewell@umich.edu    Tick event_time;
2412817Sksewell@umich.edu    if (is_in_event){
2422817Sksewell@umich.edu        event_time = zeroEvent.when();
2432817Sksewell@umich.edu        SERIALIZE_SCALAR(event_time);
2442817Sksewell@umich.edu    }
2452817Sksewell@umich.edu}
2462817Sksewell@umich.edu
2472817Sksewell@umich.eduvoid
2485715Shsul@eecs.umich.eduSp804::Timer::unserialize(Checkpoint *cp, const std::string &section)
2492817Sksewell@umich.edu{
2502817Sksewell@umich.edu    DPRINTF(Checkpoint, "Unserializing Arm Sp804\n");
2512817Sksewell@umich.edu
2522817Sksewell@umich.edu    UNSERIALIZE_SCALAR(intNum);
2532817Sksewell@umich.edu    UNSERIALIZE_SCALAR(clock);
2542817Sksewell@umich.edu
2552817Sksewell@umich.edu    uint32_t control_serial;
2562817Sksewell@umich.edu    UNSERIALIZE_SCALAR(control_serial);
2572817Sksewell@umich.edu    control = control_serial;
2582817Sksewell@umich.edu
2592817Sksewell@umich.edu    UNSERIALIZE_SCALAR(rawInt);
2602817Sksewell@umich.edu    UNSERIALIZE_SCALAR(pendingInt);
2612817Sksewell@umich.edu    UNSERIALIZE_SCALAR(loadValue);
2622817Sksewell@umich.edu
2632817Sksewell@umich.edu    bool is_in_event;
2642817Sksewell@umich.edu    UNSERIALIZE_SCALAR(is_in_event);
2652817Sksewell@umich.edu
2662817Sksewell@umich.edu    Tick event_time;
2672817Sksewell@umich.edu    if (is_in_event){
2682817Sksewell@umich.edu        UNSERIALIZE_SCALAR(event_time);
2692817Sksewell@umich.edu        parent->schedule(zeroEvent, event_time);
2702817Sksewell@umich.edu    }
2712986Sgblack@eecs.umich.edu}
2722817Sksewell@umich.edu
2735258Sksewell@umich.edu
2745258Sksewell@umich.edu
2752817Sksewell@umich.eduvoid
2762817Sksewell@umich.eduSp804::serialize(std::ostream &os)
2775258Sksewell@umich.edu{
2785258Sksewell@umich.edu    nameOut(os, csprintf("%s.timer0", name()));
2795258Sksewell@umich.edu    timer0.serialize(os);
2802817Sksewell@umich.edu    nameOut(os, csprintf("%s.timer1", name()));
2812817Sksewell@umich.edu    timer1.serialize(os);
2822817Sksewell@umich.edu}
2832817Sksewell@umich.edu
2842817Sksewell@umich.eduvoid
2852817Sksewell@umich.eduSp804::unserialize(Checkpoint *cp, const std::string &section)
2862817Sksewell@umich.edu{
2872817Sksewell@umich.edu    timer0.unserialize(cp, csprintf("%s.timer0", section));
2882817Sksewell@umich.edu    timer1.unserialize(cp, csprintf("%s.timer1", section));
2892817Sksewell@umich.edu}
2902817Sksewell@umich.edu
2912817Sksewell@umich.eduSp804 *
2922817Sksewell@umich.eduSp804Params::create()
2932817Sksewell@umich.edu{
2943776Sgblack@eecs.umich.edu    return new Sp804(this);
2955715Shsul@eecs.umich.edu}
2962817Sksewell@umich.edu