generic_timer.cc revision 10905:a6ca6831e775
114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2013, 2015 ARM Limited
314039Sstacze01@arm.com * All rights reserved.
414039Sstacze01@arm.com *
514039Sstacze01@arm.com * The license below extends only to copyright in the software and shall
614039Sstacze01@arm.com * not be construed as granting a license to any other intellectual
714039Sstacze01@arm.com * property including but not limited to intellectual property relating
814039Sstacze01@arm.com * to a hardware implementation of the functionality of the software
914039Sstacze01@arm.com * licensed hereunder.  You may use the software subject to the license
1014039Sstacze01@arm.com * terms below provided that you ensure that this notice is replicated
1114039Sstacze01@arm.com * unmodified and in its entirety in all distributions of the software,
1214039Sstacze01@arm.com * modified or unmodified, in source code or in binary form.
1314039Sstacze01@arm.com *
1414039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
1514039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
1614039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
1714039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
1814039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
1914039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
2014039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
2114039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
2214039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
2314039Sstacze01@arm.com * this software without specific prior written permission.
2414039Sstacze01@arm.com *
2514039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2614039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2714039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2814039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2914039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3014039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3114039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3214039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3314039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3414039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3514039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3614039Sstacze01@arm.com *
3714039Sstacze01@arm.com * Authors: Giacomo Gabrielli
3814039Sstacze01@arm.com *          Andreas Sandberg
3914039Sstacze01@arm.com */
4014039Sstacze01@arm.com
4114039Sstacze01@arm.com#include "dev/arm/generic_timer.hh"
4214039Sstacze01@arm.com
4314252Sgabeblack@google.com#include "arch/arm/system.hh"
4414039Sstacze01@arm.com#include "debug/Timer.hh"
4514252Sgabeblack@google.com#include "dev/arm/base_gic.hh"
4614039Sstacze01@arm.com#include "mem/packet_access.hh"
4714039Sstacze01@arm.com#include "params/GenericTimer.hh"
4814039Sstacze01@arm.com#include "params/GenericTimerMem.hh"
4914039Sstacze01@arm.com
5014039Sstacze01@arm.comSystemCounter::SystemCounter()
5114039Sstacze01@arm.com    : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
5214039Sstacze01@arm.com{
5314039Sstacze01@arm.com    setFreq(0x01800000);
5414039Sstacze01@arm.com}
5514039Sstacze01@arm.com
5614039Sstacze01@arm.comvoid
5714039Sstacze01@arm.comSystemCounter::setFreq(uint32_t freq)
5814039Sstacze01@arm.com{
5914039Sstacze01@arm.com    if (_freq != 0) {
6014039Sstacze01@arm.com        // Altering the frequency after boot shouldn't be done in practice.
6114039Sstacze01@arm.com        warn_once("The frequency of the system counter has already been set");
6214039Sstacze01@arm.com    }
6314039Sstacze01@arm.com    _freq = freq;
6414039Sstacze01@arm.com    _period = (1.0 / freq) * SimClock::Frequency;
6514039Sstacze01@arm.com    _resetTick = curTick();
6614039Sstacze01@arm.com}
6714039Sstacze01@arm.com
6814039Sstacze01@arm.comvoid
6914039Sstacze01@arm.comSystemCounter::serialize(CheckpointOut &cp) const
7014039Sstacze01@arm.com{
7114039Sstacze01@arm.com    SERIALIZE_SCALAR(_regCntkctl);
7214039Sstacze01@arm.com    SERIALIZE_SCALAR(_freq);
7314039Sstacze01@arm.com    SERIALIZE_SCALAR(_period);
7414039Sstacze01@arm.com    SERIALIZE_SCALAR(_resetTick);
7514039Sstacze01@arm.com}
7614252Sgabeblack@google.com
7714039Sstacze01@arm.comvoid
7814039Sstacze01@arm.comSystemCounter::unserialize(CheckpointIn &cp)
7914039Sstacze01@arm.com{
8014039Sstacze01@arm.com    // We didn't handle CNTKCTL in this class before, assume it's zero
8114039Sstacze01@arm.com    // if it isn't present.
8214039Sstacze01@arm.com    if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
8314039Sstacze01@arm.com        _regCntkctl = 0;
8414039Sstacze01@arm.com    UNSERIALIZE_SCALAR(_freq);
8514039Sstacze01@arm.com    UNSERIALIZE_SCALAR(_period);
8614039Sstacze01@arm.com    UNSERIALIZE_SCALAR(_resetTick);
8714039Sstacze01@arm.com}
8814039Sstacze01@arm.com
8914039Sstacze01@arm.com
9014039Sstacze01@arm.com
9114039Sstacze01@arm.comArchTimer::ArchTimer(const std::string &name,
9214039Sstacze01@arm.com                     SimObject &parent,
9314039Sstacze01@arm.com                     SystemCounter &sysctr,
9414039Sstacze01@arm.com                     const Interrupt &interrupt)
9514039Sstacze01@arm.com    : _name(name), _parent(parent), _systemCounter(sysctr),
9614039Sstacze01@arm.com      _interrupt(interrupt),
9714039Sstacze01@arm.com      _control(0), _counterLimit(0), _offset(0),
9814039Sstacze01@arm.com      _counterLimitReachedEvent(this)
9914039Sstacze01@arm.com{
10014039Sstacze01@arm.com}
10114039Sstacze01@arm.com
10214039Sstacze01@arm.comvoid
10314039Sstacze01@arm.comArchTimer::counterLimitReached()
10414039Sstacze01@arm.com{
10514039Sstacze01@arm.com    _control.istatus = 1;
10614039Sstacze01@arm.com
10714039Sstacze01@arm.com    if (!_control.enable)
10814039Sstacze01@arm.com        return;
10914039Sstacze01@arm.com
11014039Sstacze01@arm.com    DPRINTF(Timer, "Counter limit reached\n");
11114039Sstacze01@arm.com    if (!_control.imask) {
11214039Sstacze01@arm.com        DPRINTF(Timer, "Causing interrupt\n");
11314039Sstacze01@arm.com        _interrupt.send();
11414039Sstacze01@arm.com    }
11514039Sstacze01@arm.com}
11614039Sstacze01@arm.com
11714039Sstacze01@arm.comvoid
11814039Sstacze01@arm.comArchTimer::updateCounter()
11914039Sstacze01@arm.com{
12014039Sstacze01@arm.com    if (_counterLimitReachedEvent.scheduled())
12114039Sstacze01@arm.com        _parent.deschedule(_counterLimitReachedEvent);
12214039Sstacze01@arm.com    if (value() >= _counterLimit) {
12314039Sstacze01@arm.com        counterLimitReached();
12414039Sstacze01@arm.com    } else {
12514039Sstacze01@arm.com        const auto period(_systemCounter.period());
12614039Sstacze01@arm.com        _control.istatus = 0;
12714039Sstacze01@arm.com        _parent.schedule(_counterLimitReachedEvent,
12814039Sstacze01@arm.com             curTick() + (_counterLimit - value()) * period);
12914039Sstacze01@arm.com    }
13014039Sstacze01@arm.com}
13114039Sstacze01@arm.com
13214039Sstacze01@arm.comvoid
13314039Sstacze01@arm.comArchTimer::setCompareValue(uint64_t val)
13414039Sstacze01@arm.com{
13514039Sstacze01@arm.com    _counterLimit = val;
13614039Sstacze01@arm.com    updateCounter();
13714039Sstacze01@arm.com}
13814039Sstacze01@arm.com
13914039Sstacze01@arm.comvoid
14014039Sstacze01@arm.comArchTimer::setTimerValue(uint32_t val)
14114039Sstacze01@arm.com{
14214039Sstacze01@arm.com    setCompareValue(value() + sext<32>(val));
14314039Sstacze01@arm.com}
14414039Sstacze01@arm.com
14514039Sstacze01@arm.comvoid
14614039Sstacze01@arm.comArchTimer::setControl(uint32_t val)
14714039Sstacze01@arm.com{
14814039Sstacze01@arm.com    ArchTimerCtrl new_ctl = val;
14914039Sstacze01@arm.com    if ((new_ctl.enable && !new_ctl.imask) &&
15014039Sstacze01@arm.com        !(_control.enable && !_control.imask)) {
15114039Sstacze01@arm.com        // Re-evalute the timer condition
15214039Sstacze01@arm.com        if (_counterLimit >= value()) {
15314039Sstacze01@arm.com            _control.istatus = 1;
15414039Sstacze01@arm.com
15514039Sstacze01@arm.com            DPRINTF(Timer, "Causing interrupt in control\n");
15614039Sstacze01@arm.com            //_interrupt.send();
15714039Sstacze01@arm.com        }
15814039Sstacze01@arm.com    }
15914039Sstacze01@arm.com    _control.enable = new_ctl.enable;
16014039Sstacze01@arm.com    _control.imask = new_ctl.imask;
16114039Sstacze01@arm.com}
16214039Sstacze01@arm.com
16314039Sstacze01@arm.comvoid
16414039Sstacze01@arm.comArchTimer::setOffset(uint64_t val)
16514039Sstacze01@arm.com{
16614039Sstacze01@arm.com    _offset = val;
16714039Sstacze01@arm.com    updateCounter();
16814039Sstacze01@arm.com}
16914039Sstacze01@arm.com
17014039Sstacze01@arm.comuint64_t
17114039Sstacze01@arm.comArchTimer::value() const
17214039Sstacze01@arm.com{
17314039Sstacze01@arm.com    return _systemCounter.value() - _offset;
17414039Sstacze01@arm.com}
17514039Sstacze01@arm.com
17614039Sstacze01@arm.comvoid
17714039Sstacze01@arm.comArchTimer::serialize(CheckpointOut &cp) const
17814039Sstacze01@arm.com{
17914039Sstacze01@arm.com    paramOut(cp, "control_serial", _control);
18014039Sstacze01@arm.com    SERIALIZE_SCALAR(_counterLimit);
18114039Sstacze01@arm.com    SERIALIZE_SCALAR(_offset);
18214039Sstacze01@arm.com
18314039Sstacze01@arm.com    const bool event_scheduled(_counterLimitReachedEvent.scheduled());
18414039Sstacze01@arm.com    SERIALIZE_SCALAR(event_scheduled);
18514039Sstacze01@arm.com    if (event_scheduled) {
18614039Sstacze01@arm.com        const Tick event_time(_counterLimitReachedEvent.when());
18714039Sstacze01@arm.com        SERIALIZE_SCALAR(event_time);
18814039Sstacze01@arm.com    }
18914039Sstacze01@arm.com}
19014039Sstacze01@arm.com
19114039Sstacze01@arm.comvoid
19214039Sstacze01@arm.comArchTimer::unserialize(CheckpointIn &cp)
19314039Sstacze01@arm.com{
19414039Sstacze01@arm.com    paramIn(cp, "control_serial", _control);
19514039Sstacze01@arm.com    // We didn't serialize an offset before we added support for the
19614039Sstacze01@arm.com    // virtual timer. Consider it optional to maintain backwards
19714039Sstacze01@arm.com    // compatibility.
19814039Sstacze01@arm.com    if (!UNSERIALIZE_OPT_SCALAR(_offset))
19914039Sstacze01@arm.com        _offset = 0;
20014039Sstacze01@arm.com    bool event_scheduled;
20114039Sstacze01@arm.com    UNSERIALIZE_SCALAR(event_scheduled);
20214039Sstacze01@arm.com    if (event_scheduled) {
20314039Sstacze01@arm.com        Tick event_time;
20414039Sstacze01@arm.com        UNSERIALIZE_SCALAR(event_time);
20514039Sstacze01@arm.com        _parent.schedule(_counterLimitReachedEvent, event_time);
20614039Sstacze01@arm.com    }
20714039Sstacze01@arm.com}
20814039Sstacze01@arm.com
20914039Sstacze01@arm.comvoid
21014273Sgiacomo.travaglini@arm.comArchTimer::Interrupt::send()
21114273Sgiacomo.travaglini@arm.com{
21214273Sgiacomo.travaglini@arm.com    if (_ppi) {
21314273Sgiacomo.travaglini@arm.com        _gic.sendPPInt(_irq, _cpu);
214    } else {
215        _gic.sendInt(_irq);
216    }
217}
218
219
220void
221ArchTimer::Interrupt::clear()
222{
223    if (_ppi) {
224        _gic.clearPPInt(_irq, _cpu);
225    } else {
226        _gic.clearInt(_irq);
227    }
228}
229
230
231GenericTimer::GenericTimer(GenericTimerParams *p)
232    : SimObject(p),
233      gic(p->gic),
234      irqPhys(p->int_phys),
235      irqVirt(p->int_virt)
236{
237    dynamic_cast<ArmSystem &>(*p->system).setGenericTimer(this);
238}
239
240void
241GenericTimer::serialize(CheckpointOut &cp) const
242{
243    paramOut(cp, "cpu_count", timers.size());
244
245    systemCounter.serializeSection(cp, "sys_counter");
246
247    for (int i = 0; i < timers.size(); ++i) {
248        const CoreTimers &core(*timers[i]);
249
250        // This should really be phys_timerN, but we are stuck with
251        // arch_timer for backwards compatibility.
252        core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
253        core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
254    }
255}
256
257void
258GenericTimer::unserialize(CheckpointIn &cp)
259{
260    systemCounter.unserializeSection(cp, "sys_counter");
261
262    // Try to unserialize the CPU count. Old versions of the timer
263    // model assumed a 8 CPUs, so we fall back to that if the field
264    // isn't present.
265    static const unsigned OLD_CPU_MAX = 8;
266    unsigned cpu_count;
267    if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
268        warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
269             OLD_CPU_MAX);
270        cpu_count = OLD_CPU_MAX;
271    }
272
273    for (int i = 0; i < cpu_count; ++i) {
274        CoreTimers &core(getTimers(i));
275        // This should really be phys_timerN, but we are stuck with
276        // arch_timer for backwards compatibility.
277        core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
278        core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
279    }
280}
281
282
283GenericTimer::CoreTimers &
284GenericTimer::getTimers(int cpu_id)
285{
286    if (cpu_id >= timers.size())
287        createTimers(cpu_id + 1);
288
289    return *timers[cpu_id];
290}
291
292void
293GenericTimer::createTimers(unsigned cpus)
294{
295    assert(timers.size() < cpus);
296
297    const unsigned old_cpu_count(timers.size());
298    timers.resize(cpus);
299    for (unsigned i = old_cpu_count; i < cpus; ++i) {
300        timers[i].reset(
301            new CoreTimers(*this, i, irqPhys, irqVirt));
302    }
303}
304
305
306void
307GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
308{
309    CoreTimers &core(getTimers(cpu));
310
311    switch (reg) {
312      case MISCREG_CNTFRQ:
313      case MISCREG_CNTFRQ_EL0:
314        systemCounter.setFreq(val);
315        return;
316
317      case MISCREG_CNTKCTL:
318      case MISCREG_CNTKCTL_EL1:
319        systemCounter.setKernelControl(val);
320        return;
321
322      // Physical timer
323      case MISCREG_CNTP_CVAL:
324      case MISCREG_CNTP_CVAL_NS:
325      case MISCREG_CNTP_CVAL_EL0:
326        core.phys.setCompareValue(val);
327        return;
328
329      case MISCREG_CNTP_TVAL:
330      case MISCREG_CNTP_TVAL_NS:
331      case MISCREG_CNTP_TVAL_EL0:
332        core.phys.setTimerValue(val);
333        return;
334
335      case MISCREG_CNTP_CTL:
336      case MISCREG_CNTP_CTL_NS:
337      case MISCREG_CNTP_CTL_EL0:
338        core.phys.setControl(val);
339        return;
340
341      // Count registers
342      case MISCREG_CNTPCT:
343      case MISCREG_CNTPCT_EL0:
344      case MISCREG_CNTVCT:
345      case MISCREG_CNTVCT_EL0:
346        warn("Ignoring write to read only count register: %s\n",
347             miscRegName[reg]);
348        return;
349
350      // Virtual timer
351      case MISCREG_CNTVOFF:
352      case MISCREG_CNTVOFF_EL2:
353        core.virt.setOffset(val);
354        return;
355
356      case MISCREG_CNTV_CVAL:
357      case MISCREG_CNTV_CVAL_EL0:
358        core.virt.setCompareValue(val);
359        return;
360
361      case MISCREG_CNTV_TVAL:
362      case MISCREG_CNTV_TVAL_EL0:
363        core.virt.setTimerValue(val);
364        return;
365
366      case MISCREG_CNTV_CTL:
367      case MISCREG_CNTV_CTL_EL0:
368        core.virt.setControl(val);
369        return;
370
371      // PL1 phys. timer, secure
372      case MISCREG_CNTP_CTL_S:
373      case MISCREG_CNTPS_CVAL_EL1:
374      case MISCREG_CNTPS_TVAL_EL1:
375      case MISCREG_CNTPS_CTL_EL1:
376        /* FALLTHROUGH */
377
378      // PL2 phys. timer, non-secure
379      case MISCREG_CNTHCTL:
380      case MISCREG_CNTHCTL_EL2:
381      case MISCREG_CNTHP_CVAL:
382      case MISCREG_CNTHP_CVAL_EL2:
383      case MISCREG_CNTHP_TVAL:
384      case MISCREG_CNTHP_TVAL_EL2:
385      case MISCREG_CNTHP_CTL:
386      case MISCREG_CNTHP_CTL_EL2:
387        warn("Writing to unimplemented register: %s\n",
388             miscRegName[reg]);
389        return;
390
391      default:
392        warn("Writing to unknown register: %s\n", miscRegName[reg]);
393        return;
394    }
395}
396
397
398MiscReg
399GenericTimer::readMiscReg(int reg, unsigned cpu)
400{
401    CoreTimers &core(getTimers(cpu));
402
403    switch (reg) {
404      case MISCREG_CNTFRQ:
405      case MISCREG_CNTFRQ_EL0:
406        return systemCounter.freq();
407
408      case MISCREG_CNTKCTL:
409      case MISCREG_CNTKCTL_EL1:
410        return systemCounter.getKernelControl();
411
412      // Physical timer
413      case MISCREG_CNTP_CVAL:
414      case MISCREG_CNTP_CVAL_EL0:
415        return core.phys.compareValue();
416
417      case MISCREG_CNTP_TVAL:
418      case MISCREG_CNTP_TVAL_EL0:
419        return core.phys.timerValue();
420
421      case MISCREG_CNTP_CTL:
422      case MISCREG_CNTP_CTL_EL0:
423      case MISCREG_CNTP_CTL_NS:
424        return core.phys.control();
425
426      case MISCREG_CNTPCT:
427      case MISCREG_CNTPCT_EL0:
428        return core.phys.value();
429
430
431      // Virtual timer
432      case MISCREG_CNTVCT:
433      case MISCREG_CNTVCT_EL0:
434        return core.virt.value();
435
436      case MISCREG_CNTVOFF:
437      case MISCREG_CNTVOFF_EL2:
438        return core.virt.offset();
439
440      case MISCREG_CNTV_CVAL:
441      case MISCREG_CNTV_CVAL_EL0:
442        return core.virt.compareValue();
443
444      case MISCREG_CNTV_TVAL:
445      case MISCREG_CNTV_TVAL_EL0:
446        return core.virt.timerValue();
447
448      case MISCREG_CNTV_CTL:
449      case MISCREG_CNTV_CTL_EL0:
450        return core.virt.control();
451
452      // PL1 phys. timer, secure
453      case MISCREG_CNTP_CTL_S:
454      case MISCREG_CNTPS_CVAL_EL1:
455      case MISCREG_CNTPS_TVAL_EL1:
456      case MISCREG_CNTPS_CTL_EL1:
457        /* FALLTHROUGH */
458
459      // PL2 phys. timer, non-secure
460      case MISCREG_CNTHCTL:
461      case MISCREG_CNTHCTL_EL2:
462      case MISCREG_CNTHP_CVAL:
463      case MISCREG_CNTHP_CVAL_EL2:
464      case MISCREG_CNTHP_TVAL:
465      case MISCREG_CNTHP_TVAL_EL2:
466      case MISCREG_CNTHP_CTL:
467      case MISCREG_CNTHP_CTL_EL2:
468        warn("Reading from unimplemented register: %s\n",
469             miscRegName[reg]);
470        return 0;
471
472
473      default:
474        warn("Reading from unknown register: %s\n", miscRegName[reg]);
475        return 0;
476    }
477}
478
479
480
481GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
482    : PioDevice(p),
483      ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
484      timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
485      addrRanges{ctrlRange, timerRange},
486      systemCounter(),
487      physTimer(csprintf("%s.phys_timer0", name()),
488                *this, systemCounter,
489                ArchTimer::Interrupt(*p->gic, p->int_phys)),
490      virtTimer(csprintf("%s.virt_timer0", name()),
491                *this, systemCounter,
492                ArchTimer::Interrupt(*p->gic, p->int_virt))
493{
494}
495
496void
497GenericTimerMem::serialize(CheckpointOut &cp) const
498{
499    paramOut(cp, "timer_count", 1);
500
501    systemCounter.serializeSection(cp, "sys_counter");
502
503    physTimer.serializeSection(cp, "phys_timer0");
504    virtTimer.serializeSection(cp, "virt_timer0");
505}
506
507void
508GenericTimerMem::unserialize(CheckpointIn &cp)
509{
510    systemCounter.unserializeSection(cp, "sys_counter");
511
512    unsigned timer_count;
513    UNSERIALIZE_SCALAR(timer_count);
514    // The timer count variable is just here for future versions where
515    // we support more than one set of timers.
516    if (timer_count != 1)
517        panic("Incompatible checkpoint: Only one set of timers supported");
518
519    physTimer.unserializeSection(cp, "phys_timer0");
520    virtTimer.unserializeSection(cp, "virt_timer0");
521}
522
523Tick
524GenericTimerMem::read(PacketPtr pkt)
525{
526    const unsigned size(pkt->getSize());
527    const Addr addr(pkt->getAddr());
528    uint64_t value;
529
530    pkt->makeResponse();
531    if (ctrlRange.contains(addr)) {
532        value = ctrlRead(addr - ctrlRange.start(), size);
533    } else if (timerRange.contains(addr)) {
534        value = timerRead(addr - timerRange.start(), size);
535    } else {
536        panic("Invalid address: 0x%x\n", addr);
537    }
538
539    DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
540
541    if (size == 8) {
542        pkt->set<uint64_t>(value);
543    } else if (size == 4) {
544        pkt->set<uint32_t>(value);
545    } else {
546        panic("Unexpected access size: %i\n", size);
547    }
548
549    return 0;
550}
551
552Tick
553GenericTimerMem::write(PacketPtr pkt)
554{
555    const unsigned size(pkt->getSize());
556    if (size != 8 && size != 4)
557        panic("Unexpected access size\n");
558
559    const Addr addr(pkt->getAddr());
560    const uint64_t value(size == 8 ?
561                         pkt->get<uint64_t>() : pkt->get<uint32_t>());
562
563    DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
564    if (ctrlRange.contains(addr)) {
565        ctrlWrite(addr - ctrlRange.start(), size, value);
566    } else if (timerRange.contains(addr)) {
567        timerWrite(addr - timerRange.start(), size, value);
568    } else {
569        panic("Invalid address: 0x%x\n", addr);
570    }
571
572    pkt->makeResponse();
573    return 0;
574}
575
576uint64_t
577GenericTimerMem::ctrlRead(Addr addr, size_t size) const
578{
579    if (size == 4) {
580        switch (addr) {
581          case CTRL_CNTFRQ:
582            return systemCounter.freq();
583
584          case CTRL_CNTTIDR:
585            return 0x3; // Frame 0 implemented with virtual timers
586
587          case CTRL_CNTNSAR:
588          case CTRL_CNTACR_BASE:
589            warn("Reading from unimplemented control register (0x%x)\n", addr);
590            return 0;
591
592          case CTRL_CNTVOFF_LO_BASE:
593            return virtTimer.offset();
594
595          case CTRL_CNTVOFF_HI_BASE:
596            return virtTimer.offset() >> 32;
597
598          default:
599            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
600            return 0;
601        }
602    } else if (size == 8) {
603        switch (addr) {
604          case CTRL_CNTVOFF_LO_BASE:
605            return virtTimer.offset();
606
607          default:
608            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
609            return 0;
610        }
611    } else {
612        panic("Invalid access size: %i\n", size);
613    }
614}
615
616void
617GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
618{
619    if (size == 4) {
620        switch (addr) {
621          case CTRL_CNTFRQ:
622          case CTRL_CNTNSAR:
623          case CTRL_CNTTIDR:
624          case CTRL_CNTACR_BASE:
625            warn("Write to unimplemented control register (0x%x)\n", addr);
626            return;
627
628          case CTRL_CNTVOFF_LO_BASE:
629            virtTimer.setOffset(
630                insertBits(virtTimer.offset(), 31, 0, value));
631            return;
632
633          case CTRL_CNTVOFF_HI_BASE:
634            virtTimer.setOffset(
635                insertBits(virtTimer.offset(), 63, 32, value));
636            return;
637
638          default:
639            warn("Ignoring write to unexpected address (0x%x:%i)\n",
640                 addr, size);
641            return;
642        }
643    } else if (size == 8) {
644        switch (addr) {
645          case CTRL_CNTVOFF_LO_BASE:
646            virtTimer.setOffset(value);
647            return;
648
649          default:
650            warn("Ignoring write to unexpected address (0x%x:%i)\n",
651                 addr, size);
652            return;
653        }
654    } else {
655        panic("Invalid access size: %i\n", size);
656    }
657}
658
659uint64_t
660GenericTimerMem::timerRead(Addr addr, size_t size) const
661{
662    if (size == 4) {
663        switch (addr) {
664          case TIMER_CNTPCT_LO:
665            return physTimer.value();
666
667          case TIMER_CNTPCT_HI:
668            return physTimer.value() >> 32;
669
670          case TIMER_CNTVCT_LO:
671            return virtTimer.value();
672
673          case TIMER_CNTVCT_HI:
674            return virtTimer.value() >> 32;
675
676          case TIMER_CNTFRQ:
677            return systemCounter.freq();
678
679          case TIMER_CNTEL0ACR:
680            warn("Read from unimplemented timer register (0x%x)\n", addr);
681            return 0;
682
683          case CTRL_CNTVOFF_LO_BASE:
684            return virtTimer.offset();
685
686          case CTRL_CNTVOFF_HI_BASE:
687            return virtTimer.offset() >> 32;
688
689          case TIMER_CNTP_CVAL_LO:
690            return physTimer.compareValue();
691
692          case TIMER_CNTP_CVAL_HI:
693            return physTimer.compareValue() >> 32;
694
695          case TIMER_CNTP_TVAL:
696            return physTimer.timerValue();
697
698          case TIMER_CNTP_CTL:
699            return physTimer.control();
700
701          case TIMER_CNTV_CVAL_LO:
702            return virtTimer.compareValue();
703
704          case TIMER_CNTV_CVAL_HI:
705            return virtTimer.compareValue() >> 32;
706
707          case TIMER_CNTV_TVAL:
708            return virtTimer.timerValue();
709
710          case TIMER_CNTV_CTL:
711            return virtTimer.control();
712
713          default:
714            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
715            return 0;
716        }
717    } else if (size == 8) {
718        switch (addr) {
719          case TIMER_CNTPCT_LO:
720            return physTimer.value();
721
722          case TIMER_CNTVCT_LO:
723            return virtTimer.value();
724
725          case CTRL_CNTVOFF_LO_BASE:
726            return virtTimer.offset();
727
728          case TIMER_CNTP_CVAL_LO:
729            return physTimer.compareValue();
730
731          case TIMER_CNTV_CVAL_LO:
732            return virtTimer.compareValue();
733
734          default:
735            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
736            return 0;
737        }
738    } else {
739        panic("Invalid access size: %i\n", size);
740    }
741}
742
743void
744GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
745{
746    if (size == 4) {
747        switch (addr) {
748          case TIMER_CNTEL0ACR:
749            warn("Unimplemented timer register (0x%x)\n", addr);
750            return;
751
752          case TIMER_CNTP_CVAL_LO:
753            physTimer.setCompareValue(
754                insertBits(physTimer.compareValue(), 31, 0, value));
755            return;
756
757          case TIMER_CNTP_CVAL_HI:
758            physTimer.setCompareValue(
759                insertBits(physTimer.compareValue(), 63, 32, value));
760            return;
761
762          case TIMER_CNTP_TVAL:
763            physTimer.setTimerValue(value);
764            return;
765
766          case TIMER_CNTP_CTL:
767            physTimer.setControl(value);
768            return;
769
770          case TIMER_CNTV_CVAL_LO:
771            virtTimer.setCompareValue(
772                insertBits(virtTimer.compareValue(), 31, 0, value));
773            return;
774
775          case TIMER_CNTV_CVAL_HI:
776            virtTimer.setCompareValue(
777                insertBits(virtTimer.compareValue(), 63, 32, value));
778            return;
779
780          case TIMER_CNTV_TVAL:
781            virtTimer.setTimerValue(value);
782            return;
783
784          case TIMER_CNTV_CTL:
785            virtTimer.setControl(value);
786            return;
787
788          default:
789            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
790            return;
791        }
792    } else if (size == 8) {
793        switch (addr) {
794          case TIMER_CNTP_CVAL_LO:
795            return physTimer.setCompareValue(value);
796
797          case TIMER_CNTV_CVAL_LO:
798            return virtTimer.setCompareValue(value);
799
800          default:
801            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
802            return;
803        }
804    } else {
805        panic("Invalid access size: %i\n", size);
806    }
807}
808
809GenericTimer *
810GenericTimerParams::create()
811{
812    return new GenericTimer(this);
813}
814
815GenericTimerMem *
816GenericTimerMemParams::create()
817{
818    return new GenericTimerMem(this);
819}
820