timer_sp804.cc revision 7584:28ddf6d9e982
12SN/A/*
21762SN/A * Copyright (c) 2010 ARM Limited
32SN/A * All rights reserved
42SN/A *
52SN/A * The license below extends only to copyright in the software and shall
62SN/A * not be construed as granting a license to any other intellectual
72SN/A * property including but not limited to intellectual property relating
82SN/A * to a hardware implementation of the functionality of the software
92SN/A * licensed hereunder.  You may use the software subject to the license
102SN/A * terms below provided that you ensure that this notice is replicated
112SN/A * unmodified and in its entirety in all distributions of the software,
122SN/A * modified or unmodified, in source code or in binary form.
132SN/A *
142SN/A * Redistribution and use in source and binary forms, with or without
152SN/A * modification, are permitted provided that the following conditions are
162SN/A * met: redistributions of source code must retain the above copyright
172SN/A * notice, this list of conditions and the following disclaimer;
182SN/A * redistributions in binary form must reproduce the above copyright
192SN/A * notice, this list of conditions and the following disclaimer in the
202SN/A * documentation and/or other materials provided with the distribution;
212SN/A * neither the name of the copyright holders nor the names of its
222SN/A * contributors may be used to endorse or promote products derived from
232SN/A * this software without specific prior written permission.
242SN/A *
252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
328229Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
338229Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
348229Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
358229Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368229Snate@binkert.org *
378229Snate@binkert.org * Authors: Ali Saidi
382SN/A */
392SN/A
402SN/A#include "base/intmath.hh"
418229Snate@binkert.org#include "base/trace.hh"
429538Satgutier@umich.edu#include "dev/arm/gic.hh"
438229Snate@binkert.org#include "dev/arm/timer_sp804.hh"
448229Snate@binkert.org#include "mem/packet.hh"
458229Snate@binkert.org#include "mem/packet_access.hh"
468229Snate@binkert.org
478229Snate@binkert.orgSp804::Sp804(Params *p)
4856SN/A    : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0),
498706Sandreas.hansson@arm.com      timer1(name() + ".timer1", this, p->int_num1, p->clock1)
502420SN/A{
512SN/A    pioSize = 0xfff;
522SN/A}
5310880SCurtis.Dunham@arm.com
54360SN/ASp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock)
55360SN/A    : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20),
5610880SCurtis.Dunham@arm.com      rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this)
5710422Sandreas.hansson@arm.com{
5810422Sandreas.hansson@arm.com}
5912SN/A
6012SN/A
612SN/ATick
622SN/ASp804::read(PacketPtr pkt)
632SN/A{
642SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
652SN/A    assert(pkt->getSize() == 4);
6612SN/A    Addr daddr = pkt->getAddr() - pioAddr;
672SN/A    pkt->allocate();
682SN/A    DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr);
692420SN/A
7010037SARM gem5 Developers    if (daddr < Timer::Size)
712420SN/A        timer0.read(pkt, daddr);
722420SN/A    else if ((daddr - Timer::Size) < Timer::Size)
7310037SARM gem5 Developers        timer1.read(pkt, daddr - Timer::Size);
742420SN/A    else if (!readId(pkt))
758852Sandreas.hansson@arm.com        panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr);
762420SN/A    pkt->makeAtomicResponse();
772420SN/A    return pioDelay;
782420SN/A}
798852Sandreas.hansson@arm.com
802420SN/A
812420SN/Avoid
822420SN/ASp804::Timer::read(PacketPtr pkt, Addr daddr)
832420SN/A{
842420SN/A    DPRINTF(Timer, "Reading from Timer at offset: %#x\n", daddr);
852420SN/A
862420SN/A    switch(daddr) {
8710037SARM gem5 Developers      case LoadReg:
882420SN/A        pkt->set<uint32_t>(loadValue);
8910037SARM gem5 Developers        break;
9010037SARM gem5 Developers      case CurrentReg:
9110037SARM gem5 Developers        DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n",
922420SN/A                zeroEvent.when(), clock, control.timerPrescale);
932420SN/A        Tick time;
942420SN/A        time = zeroEvent.when() - curTick;
952SN/A        time = time / clock / power(16, control.timerPrescale);
962SN/A        DPRINTF(Timer, "-- returning counter at %d\n", time);
972SN/A        pkt->set<uint32_t>(time);
9812SN/A        break;
993918Ssaidi@eecs.umich.edu      case ControlReg:
10012SN/A        pkt->set<uint32_t>(control);
10112SN/A        break;
1022SN/A      case RawISR:
1032SN/A        pkt->set<uint32_t>(rawInt);
10412SN/A        break;
10512SN/A      case MaskedISR:
1063584Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(pendingInt);
1072SN/A        break;
10812SN/A      case BGLoad:
10912SN/A        pkt->set<uint32_t>(loadValue);
11012SN/A        break;
11112SN/A      default:
1122SN/A        panic("Tried to read SP804 timer at offset %#x\n", daddr);
1132SN/A        break;
11412SN/A    }
11510422Sandreas.hansson@arm.com}
11610422Sandreas.hansson@arm.com
11710422Sandreas.hansson@arm.comTick
11812SN/ASp804::write(PacketPtr pkt)
11912SN/A{
12012SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
12112SN/A    assert(pkt->getSize() == 4);
12210880SCurtis.Dunham@arm.com    Addr daddr = pkt->getAddr() - pioAddr;
12312SN/A    pkt->allocate();
12412SN/A    DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr);
1252SN/A
1262SN/A    if (daddr < Timer::Size)
12712SN/A        timer0.write(pkt, daddr);
1282SN/A    else if ((daddr - Timer::Size) < Timer::Size)
12912SN/A        timer1.write(pkt, daddr - Timer::Size);
13010880SCurtis.Dunham@arm.com    else if (!readId(pkt))
13112SN/A        panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr);
1322SN/A    pkt->makeAtomicResponse();
1332SN/A    return pioDelay;
13410880SCurtis.Dunham@arm.com}
13512SN/A
1362SN/Avoid
1372SN/ASp804::Timer::write(PacketPtr pkt, Addr daddr)
13810880SCurtis.Dunham@arm.com{
13912SN/A    DPRINTF(Timer, "Writing to Timer at offset: %#x\n", daddr);
1402SN/A    switch (daddr) {
1412SN/A      case LoadReg:
14210880SCurtis.Dunham@arm.com        loadValue = pkt->get<uint32_t>();
1439538Satgutier@umich.edu        restartCounter(loadValue);
1449538Satgutier@umich.edu        break;
1459538Satgutier@umich.edu      case CurrentReg:
1463584Ssaidi@eecs.umich.edu        // Spec says this value can't be written, but linux writes it anyway
14710880SCurtis.Dunham@arm.com        break;
1483584Ssaidi@eecs.umich.edu      case ControlReg:
14912SN/A        bool old_enable;
1503918Ssaidi@eecs.umich.edu        old_enable = control.timerEnable;
15112SN/A        control = pkt->get<uint32_t>();
1522SN/A        if ((old_enable == 0) && control.timerEnable)
153            restartCounter(loadValue);
154        break;
155      case IntClear:
156        rawInt = false;
157        if (pendingInt) {
158            pendingInt = false;
159            DPRINTF(Timer, "Clearing interrupt\n");
160            parent->gic->clearInt(intNum);
161        }
162        break;
163      case BGLoad:
164        loadValue = pkt->get<uint32_t>();
165        break;
166      default:
167        panic("Tried to write SP804 timer at offset %#x\n", daddr);
168        break;
169    }
170}
171
172void
173Sp804::Timer::restartCounter(uint32_t val)
174{
175    DPRINTF(Timer, "Resetting counter with value %#x\n", val);
176    if (!control.timerEnable)
177        return;
178
179    Tick time = clock << power(16, control.timerPrescale);
180    if (control.timerSize)
181        time *= bits(val,15,0);
182    else
183        time *= val;
184
185    if (zeroEvent.scheduled()) {
186        DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
187        parent->deschedule(zeroEvent);
188    }
189    parent->schedule(zeroEvent, curTick + time);
190    DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick + time);
191}
192
193void
194Sp804::Timer::counterAtZero()
195{
196    if (!control.timerEnable)
197        return;
198
199    DPRINTF(Timer, "Counter reached zero\n");
200
201    rawInt = true;
202    bool old_pending = pendingInt;
203    if (control.intEnable)
204        pendingInt = true;
205    if (pendingInt && ~old_pending) {
206        DPRINTF(Timer, "-- Causing interrupt\n");
207        parent->gic->sendInt(intNum);
208    }
209
210    if (control.oneShot)
211        return;
212
213    // Free-running
214    if (control.timerMode == 0)
215        restartCounter(0xffffffff);
216    else
217        restartCounter(loadValue);
218}
219
220
221void
222Sp804::serialize(std::ostream &os)
223{
224    panic("Need to implement serialization\n");
225}
226
227void
228Sp804::unserialize(Checkpoint *cp, const std::string &section)
229{
230    panic("Need to implement serialization\n");
231}
232
233Sp804 *
234Sp804Params::create()
235{
236    return new Sp804(this);
237}
238