generic_timer.cc revision 12733
12689Sktlim@umich.edu/*
22689Sktlim@umich.edu * Copyright (c) 2013, 2015, 2017 ARM Limited
32689Sktlim@umich.edu * All rights reserved.
42689Sktlim@umich.edu *
52689Sktlim@umich.edu * The license below extends only to copyright in the software and shall
62689Sktlim@umich.edu * not be construed as granting a license to any other intellectual
72689Sktlim@umich.edu * property including but not limited to intellectual property relating
82689Sktlim@umich.edu * to a hardware implementation of the functionality of the software
92689Sktlim@umich.edu * licensed hereunder.  You may use the software subject to the license
102689Sktlim@umich.edu * terms below provided that you ensure that this notice is replicated
112689Sktlim@umich.edu * unmodified and in its entirety in all distributions of the software,
122689Sktlim@umich.edu * modified or unmodified, in source code or in binary form.
132689Sktlim@umich.edu *
142689Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without
152689Sktlim@umich.edu * modification, are permitted provided that the following conditions are
162689Sktlim@umich.edu * met: redistributions of source code must retain the above copyright
172689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer;
182689Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright
192689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the
202689Sktlim@umich.edu * documentation and/or other materials provided with the distribution;
212689Sktlim@umich.edu * neither the name of the copyright holders nor the names of its
222689Sktlim@umich.edu * contributors may be used to endorse or promote products derived from
232689Sktlim@umich.edu * this software without specific prior written permission.
242689Sktlim@umich.edu *
252689Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262689Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302689Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312689Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322689Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332689Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342521SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
353960Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
364194Ssaidi@eecs.umich.edu *
371070SN/A * Authors: Giacomo Gabrielli
381070SN/A *          Andreas Sandberg
392521SN/A */
402680Sktlim@umich.edu
412521SN/A#include "dev/arm/generic_timer.hh"
422522SN/A
432037SN/A#include "arch/arm/system.hh"
4456SN/A#include "debug/Timer.hh"
455512SMichael.Adler@intel.com#include "dev/arm/base_gic.hh"
462378SN/A#include "mem/packet_access.hh"
472521SN/A#include "params/GenericTimer.hh"
482378SN/A#include "params/GenericTimerMem.hh"
494762Snate@binkert.org
504762Snate@binkert.orgSystemCounter::SystemCounter()
512378SN/A    : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
522SN/A{
532SN/A    setFreq(0x01800000);
542107SN/A}
552SN/A
562SN/Avoid
572SN/ASystemCounter::setFreq(uint32_t freq)
582SN/A{
592SN/A    if (_freq != 0) {
601070SN/A        // Altering the frequency after boot shouldn't be done in practice.
615034Smilesck@eecs.umich.edu        warn_once("The frequency of the system counter has already been set");
622378SN/A    }
632521SN/A    _freq = freq;
642640Sstever@eecs.umich.edu    _period = (1.0 / freq) * SimClock::Frequency;
652640Sstever@eecs.umich.edu    _resetTick = curTick();
662378SN/A}
672378SN/A
684997Sgblack@eecs.umich.eduvoid
692378SN/ASystemCounter::serialize(CheckpointOut &cp) const
702902Ssaidi@eecs.umich.edu{
712SN/A    SERIALIZE_SCALAR(_regCntkctl);
721070SN/A    SERIALIZE_SCALAR(_regCnthctl);
731070SN/A    SERIALIZE_SCALAR(_freq);
741070SN/A    SERIALIZE_SCALAR(_period);
752378SN/A    SERIALIZE_SCALAR(_resetTick);
761070SN/A}
774838Ssaidi@eecs.umich.edu
784838Ssaidi@eecs.umich.eduvoid
791070SN/ASystemCounter::unserialize(CheckpointIn &cp)
802520SN/A{
812520SN/A    // We didn't handle CNTKCTL in this class before, assume it's zero
822520SN/A    // if it isn't present.
832520SN/A    if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
842520SN/A        _regCntkctl = 0;
852520SN/A    if (!UNSERIALIZE_OPT_SCALAR(_regCnthctl))
862520SN/A        _regCnthctl = 0;
872520SN/A    UNSERIALIZE_SCALAR(_freq);
882520SN/A    UNSERIALIZE_SCALAR(_period);
892521SN/A    UNSERIALIZE_SCALAR(_resetTick);
902521SN/A}
912521SN/A
922521SN/A
932520SN/A
941070SN/AArchTimer::ArchTimer(const std::string &name,
952158SN/A                     SimObject &parent,
961070SN/A                     SystemCounter &sysctr,
974762Snate@binkert.org                     const Interrupt &interrupt)
983812Ssaidi@eecs.umich.edu    : _name(name), _parent(parent), _systemCounter(sysctr),
993812Ssaidi@eecs.umich.edu      _interrupt(interrupt),
1003812Ssaidi@eecs.umich.edu      _control(0), _counterLimit(0), _offset(0),
1013812Ssaidi@eecs.umich.edu      _counterLimitReachedEvent([this]{ counterLimitReached(); }, name)
1024762Snate@binkert.org{
1035222Sksewell@umich.edu}
1045222Sksewell@umich.edu
1053812Ssaidi@eecs.umich.eduvoid
1064762Snate@binkert.orgArchTimer::counterLimitReached()
1071070SN/A{
1083812Ssaidi@eecs.umich.edu    _control.istatus = 1;
1093812Ssaidi@eecs.umich.edu
1101070SN/A    if (!_control.enable)
1113812Ssaidi@eecs.umich.edu        return;
1123812Ssaidi@eecs.umich.edu
1133812Ssaidi@eecs.umich.edu    DPRINTF(Timer, "Counter limit reached\n");
1143812Ssaidi@eecs.umich.edu    if (!_control.imask) {
1151070SN/A        if (scheduleEvents()) {
1163812Ssaidi@eecs.umich.edu            DPRINTF(Timer, "Causing interrupt\n");
1173812Ssaidi@eecs.umich.edu            _interrupt.send();
1183812Ssaidi@eecs.umich.edu        } else {
1191070SN/A            DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n");
1203812Ssaidi@eecs.umich.edu        }
1213812Ssaidi@eecs.umich.edu    }
1221070SN/A}
1233812Ssaidi@eecs.umich.edu
1243812Ssaidi@eecs.umich.eduvoid
1251074SN/AArchTimer::updateCounter()
1263812Ssaidi@eecs.umich.edu{
1273812Ssaidi@eecs.umich.edu    if (_counterLimitReachedEvent.scheduled())
1281074SN/A        _parent.deschedule(_counterLimitReachedEvent);
1293812Ssaidi@eecs.umich.edu    if (value() >= _counterLimit) {
1303812Ssaidi@eecs.umich.edu        counterLimitReached();
1313812Ssaidi@eecs.umich.edu    } else {
1323812Ssaidi@eecs.umich.edu        _control.istatus = 0;
1333812Ssaidi@eecs.umich.edu        if (scheduleEvents()) {
1342378SN/A            const auto period(_systemCounter.period());
1352378SN/A            _parent.schedule(_counterLimitReachedEvent,
1361070SN/A                 curTick() + (_counterLimit - value()) * period);
137878SN/A        }
1382SN/A    }
1392SN/A}
1402SN/A
1412SN/Avoid
1422378SN/AArchTimer::setCompareValue(uint64_t val)
1431070SN/A{
1441070SN/A    _counterLimit = val;
1452378SN/A    updateCounter();
1462378SN/A}
1472378SN/A
1482378SN/Avoid
1492SN/AArchTimer::setTimerValue(uint32_t val)
1502SN/A{
1511808SN/A    setCompareValue(value() + sext<32>(val));
1524095Sbinkertn@umich.edu}
1531808SN/A
1542901Ssaidi@eecs.umich.eduvoid
1554762Snate@binkert.orgArchTimer::setControl(uint32_t val)
1562901Ssaidi@eecs.umich.edu{
1572901Ssaidi@eecs.umich.edu    ArchTimerCtrl new_ctl = val;
1582901Ssaidi@eecs.umich.edu    if ((new_ctl.enable && !new_ctl.imask) &&
1592901Ssaidi@eecs.umich.edu        !(_control.enable && !_control.imask)) {
1602901Ssaidi@eecs.umich.edu        // Re-evalute the timer condition
1613960Sgblack@eecs.umich.edu        if (_counterLimit >= value()) {
1623960Sgblack@eecs.umich.edu            _control.istatus = 1;
1634095Sbinkertn@umich.edu
1644095Sbinkertn@umich.edu            DPRINTF(Timer, "Causing interrupt in control\n");
1654095Sbinkertn@umich.edu            //_interrupt.send();
1663960Sgblack@eecs.umich.edu        }
1673960Sgblack@eecs.umich.edu    }
168180SN/A    _control.enable = new_ctl.enable;
1695712Shsul@eecs.umich.edu    _control.imask = new_ctl.imask;
1702SN/A}
1715712Shsul@eecs.umich.edu
1725712Shsul@eecs.umich.eduvoid
1735712Shsul@eecs.umich.eduArchTimer::setOffset(uint64_t val)
1745712Shsul@eecs.umich.edu{
1751806SN/A    _offset = val;
1761806SN/A    updateCounter();
1772680Sktlim@umich.edu}
1782680Sktlim@umich.edu
1791806SN/Auint64_t
1802680Sktlim@umich.eduArchTimer::value() const
1811806SN/A{
1821806SN/A    return _systemCounter.value() - _offset;
1832680Sktlim@umich.edu}
1841806SN/A
1851070SN/Avoid
1865512SMichael.Adler@intel.comArchTimer::serialize(CheckpointOut &cp) const
1875512SMichael.Adler@intel.com{
1884095Sbinkertn@umich.edu    paramOut(cp, "control_serial", _control);
1895512SMichael.Adler@intel.com    SERIALIZE_SCALAR(_counterLimit);
1904095Sbinkertn@umich.edu    SERIALIZE_SCALAR(_offset);
1914095Sbinkertn@umich.edu}
1924095Sbinkertn@umich.edu
1934095Sbinkertn@umich.eduvoid
1944095Sbinkertn@umich.eduArchTimer::unserialize(CheckpointIn &cp)
1954095Sbinkertn@umich.edu{
1964095Sbinkertn@umich.edu    paramIn(cp, "control_serial", _control);
1971070SN/A    // We didn't serialize an offset before we added support for the
1984095Sbinkertn@umich.edu    // virtual timer. Consider it optional to maintain backwards
1994095Sbinkertn@umich.edu    // compatibility.
2004095Sbinkertn@umich.edu    if (!UNSERIALIZE_OPT_SCALAR(_offset))
2014095Sbinkertn@umich.edu        _offset = 0;
2024095Sbinkertn@umich.edu
2031070SN/A    // We no longer schedule an event here because we may enter KVM
2041070SN/A    // emulation.  The event creation is delayed until drainResume().
2051806SN/A}
206180SN/A
20775SN/ADrainState
208180SN/AArchTimer::drain()
2091129SN/A{
2101129SN/A    if (_counterLimitReachedEvent.scheduled())
2115713Shsul@eecs.umich.edu        _parent.deschedule(_counterLimitReachedEvent);
2122114SN/A
2132680Sktlim@umich.edu    return DrainState::Drained;
2144194Ssaidi@eecs.umich.edu}
2155713Shsul@eecs.umich.edu
2161129SN/Avoid
2171129SN/AArchTimer::drainResume()
2181129SN/A{
2195713Shsul@eecs.umich.edu    updateCounter();
220180SN/A}
2215713Shsul@eecs.umich.edu
2222680Sktlim@umich.eduvoid
2235713Shsul@eecs.umich.eduArchTimer::Interrupt::send()
224180SN/A{
225180SN/A    if (_ppi) {
2265713Shsul@eecs.umich.edu        _gic.sendPPInt(_irq, _cpu);
2275713Shsul@eecs.umich.edu    } else {
2285713Shsul@eecs.umich.edu        _gic.sendInt(_irq);
2292SN/A    }
2302SN/A}
2312378SN/A
2322378SN/A
2332378SN/Avoid
2342378SN/AArchTimer::Interrupt::clear()
2352378SN/A{
2362378SN/A    if (_ppi) {
2373162Ssaidi@eecs.umich.edu        _gic.clearPPInt(_irq, _cpu);
2383162Ssaidi@eecs.umich.edu    } else {
2392378SN/A        _gic.clearInt(_irq);
2402378SN/A    }
2412378SN/A}
2422378SN/A
2431070SN/A
2441070SN/AGenericTimer::GenericTimer(GenericTimerParams *p)
2451070SN/A    : ClockedObject(p),
2462378SN/A      system(*p->system),
2471984SN/A      gic(p->gic),
2485183Ssaidi@eecs.umich.edu      irqPhysS(p->int_phys_s),
2495183Ssaidi@eecs.umich.edu      irqPhysNS(p->int_phys_ns),
2505183Ssaidi@eecs.umich.edu      irqVirt(p->int_virt),
2511070SN/A      irqHyp(p->int_hyp)
2521070SN/A{
2531070SN/A    fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
2541070SN/A    system.setGenericTimer(this);
2551070SN/A}
2561070SN/A
2572378SN/Avoid
2581984SN/AGenericTimer::serialize(CheckpointOut &cp) const
2595183Ssaidi@eecs.umich.edu{
2605183Ssaidi@eecs.umich.edu    paramOut(cp, "cpu_count", timers.size());
2615183Ssaidi@eecs.umich.edu
2621070SN/A    systemCounter.serializeSection(cp, "sys_counter");
2632SN/A
2642SN/A    for (int i = 0; i < timers.size(); ++i) {
2652SN/A        const CoreTimers &core(*timers[i]);
2662SN/A
2672SN/A        // This should really be phys_timerN, but we are stuck with
2682SN/A        // arch_timer for backwards compatibility.
2692SN/A        core.physNS.serializeSection(cp, csprintf("arch_timer%d", i));
2702SN/A        core.physS.serializeSection(cp, csprintf("phys_s_timer%d", i));
2712SN/A        core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
2722SN/A        core.hyp.serializeSection(cp, csprintf("hyp_timer%d", i));
2732SN/A    }
2742SN/A}
2752SN/A
2762SN/Avoid
2772SN/AGenericTimer::unserialize(CheckpointIn &cp)
2782SN/A{
2792SN/A    systemCounter.unserializeSection(cp, "sys_counter");
2802SN/A
2812902Ssaidi@eecs.umich.edu    // Try to unserialize the CPU count. Old versions of the timer
2822902Ssaidi@eecs.umich.edu    // model assumed a 8 CPUs, so we fall back to that if the field
2832902Ssaidi@eecs.umich.edu    // isn't present.
2844762Snate@binkert.org    static const unsigned OLD_CPU_MAX = 8;
2852424SN/A    unsigned cpu_count;
2864762Snate@binkert.org    if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
2874762Snate@binkert.org        warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
2882424SN/A             OLD_CPU_MAX);
2895530Snate@binkert.org        cpu_count = OLD_CPU_MAX;
2902424SN/A    }
2912424SN/A
2922424SN/A    for (int i = 0; i < cpu_count; ++i) {
293        CoreTimers &core(getTimers(i));
294        // This should really be phys_timerN, but we are stuck with
295        // arch_timer for backwards compatibility.
296        core.physNS.unserializeSection(cp, csprintf("arch_timer%d", i));
297        core.physS.unserializeSection(cp, csprintf("phys_s_timer%d", i));
298        core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
299        core.hyp.unserializeSection(cp, csprintf("hyp_timer%d", i));
300    }
301}
302
303
304GenericTimer::CoreTimers &
305GenericTimer::getTimers(int cpu_id)
306{
307    if (cpu_id >= timers.size())
308        createTimers(cpu_id + 1);
309
310    return *timers[cpu_id];
311}
312
313void
314GenericTimer::createTimers(unsigned cpus)
315{
316    assert(timers.size() < cpus);
317
318    const unsigned old_cpu_count(timers.size());
319    timers.resize(cpus);
320    for (unsigned i = old_cpu_count; i < cpus; ++i) {
321        timers[i].reset(
322            new CoreTimers(*this, system, i,
323                           irqPhysS, irqPhysNS, irqVirt, irqHyp));
324    }
325}
326
327
328void
329GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
330{
331    CoreTimers &core(getTimers(cpu));
332
333    switch (reg) {
334      case MISCREG_CNTFRQ:
335      case MISCREG_CNTFRQ_EL0:
336        systemCounter.setFreq(val);
337        return;
338
339      case MISCREG_CNTKCTL:
340      case MISCREG_CNTKCTL_EL1:
341        systemCounter.setKernelControl(val);
342        return;
343
344      case MISCREG_CNTHCTL:
345      case MISCREG_CNTHCTL_EL2:
346        systemCounter.setHypControl(val);
347        return;
348
349      // Physical timer (NS)
350      case MISCREG_CNTP_CVAL_NS:
351      case MISCREG_CNTP_CVAL_EL0:
352        core.physNS.setCompareValue(val);
353        return;
354
355      case MISCREG_CNTP_TVAL_NS:
356      case MISCREG_CNTP_TVAL_EL0:
357        core.physNS.setTimerValue(val);
358        return;
359
360      case MISCREG_CNTP_CTL_NS:
361      case MISCREG_CNTP_CTL_EL0:
362        core.physNS.setControl(val);
363        return;
364
365      // Count registers
366      case MISCREG_CNTPCT:
367      case MISCREG_CNTPCT_EL0:
368      case MISCREG_CNTVCT:
369      case MISCREG_CNTVCT_EL0:
370        warn("Ignoring write to read only count register: %s\n",
371             miscRegName[reg]);
372        return;
373
374      // Virtual timer
375      case MISCREG_CNTVOFF:
376      case MISCREG_CNTVOFF_EL2:
377        core.virt.setOffset(val);
378        return;
379
380      case MISCREG_CNTV_CVAL:
381      case MISCREG_CNTV_CVAL_EL0:
382        core.virt.setCompareValue(val);
383        return;
384
385      case MISCREG_CNTV_TVAL:
386      case MISCREG_CNTV_TVAL_EL0:
387        core.virt.setTimerValue(val);
388        return;
389
390      case MISCREG_CNTV_CTL:
391      case MISCREG_CNTV_CTL_EL0:
392        core.virt.setControl(val);
393        return;
394
395      // Physical timer (S)
396      case MISCREG_CNTP_CTL_S:
397      case MISCREG_CNTPS_CTL_EL1:
398        core.physS.setControl(val);
399        return;
400
401      case MISCREG_CNTP_CVAL_S:
402      case MISCREG_CNTPS_CVAL_EL1:
403        core.physS.setCompareValue(val);
404        return;
405
406      case MISCREG_CNTP_TVAL_S:
407      case MISCREG_CNTPS_TVAL_EL1:
408        core.physS.setTimerValue(val);
409        return;
410
411      // Hyp phys. timer, non-secure
412      case MISCREG_CNTHP_CTL:
413      case MISCREG_CNTHP_CTL_EL2:
414        core.hyp.setControl(val);
415        return;
416
417      case MISCREG_CNTHP_CVAL:
418      case MISCREG_CNTHP_CVAL_EL2:
419        core.hyp.setCompareValue(val);
420        return;
421
422      case MISCREG_CNTHP_TVAL:
423      case MISCREG_CNTHP_TVAL_EL2:
424        core.hyp.setTimerValue(val);
425        return;
426
427      default:
428        warn("Writing to unknown register: %s\n", miscRegName[reg]);
429        return;
430    }
431}
432
433
434MiscReg
435GenericTimer::readMiscReg(int reg, unsigned cpu)
436{
437    CoreTimers &core(getTimers(cpu));
438
439    switch (reg) {
440      case MISCREG_CNTFRQ:
441      case MISCREG_CNTFRQ_EL0:
442        return systemCounter.freq();
443
444      case MISCREG_CNTKCTL:
445      case MISCREG_CNTKCTL_EL1:
446        return systemCounter.getKernelControl();
447
448      case MISCREG_CNTHCTL:
449      case MISCREG_CNTHCTL_EL2:
450        return systemCounter.getHypControl();
451
452      // Physical timer
453      case MISCREG_CNTP_CVAL_NS:
454      case MISCREG_CNTP_CVAL_EL0:
455        return core.physNS.compareValue();
456
457      case MISCREG_CNTP_TVAL_NS:
458      case MISCREG_CNTP_TVAL_EL0:
459        return core.physNS.timerValue();
460
461      case MISCREG_CNTP_CTL_EL0:
462      case MISCREG_CNTP_CTL_NS:
463        return core.physNS.control();
464
465      case MISCREG_CNTPCT:
466      case MISCREG_CNTPCT_EL0:
467        return core.physNS.value();
468
469
470      // Virtual timer
471      case MISCREG_CNTVCT:
472      case MISCREG_CNTVCT_EL0:
473        return core.virt.value();
474
475      case MISCREG_CNTVOFF:
476      case MISCREG_CNTVOFF_EL2:
477        return core.virt.offset();
478
479      case MISCREG_CNTV_CVAL:
480      case MISCREG_CNTV_CVAL_EL0:
481        return core.virt.compareValue();
482
483      case MISCREG_CNTV_TVAL:
484      case MISCREG_CNTV_TVAL_EL0:
485        return core.virt.timerValue();
486
487      case MISCREG_CNTV_CTL:
488      case MISCREG_CNTV_CTL_EL0:
489        return core.virt.control();
490
491      // PL1 phys. timer, secure
492      case MISCREG_CNTP_CTL_S:
493      case MISCREG_CNTPS_CTL_EL1:
494        return core.physS.control();
495
496      case MISCREG_CNTP_CVAL_S:
497      case MISCREG_CNTPS_CVAL_EL1:
498        return core.physS.compareValue();
499
500      case MISCREG_CNTP_TVAL_S:
501      case MISCREG_CNTPS_TVAL_EL1:
502        return core.physS.timerValue();
503
504      // HYP phys. timer (NS)
505      case MISCREG_CNTHP_CTL:
506      case MISCREG_CNTHP_CTL_EL2:
507        return core.hyp.control();
508
509      case MISCREG_CNTHP_CVAL:
510      case MISCREG_CNTHP_CVAL_EL2:
511        return core.hyp.compareValue();
512
513      case MISCREG_CNTHP_TVAL:
514      case MISCREG_CNTHP_TVAL_EL2:
515        return core.hyp.timerValue();
516
517      default:
518        warn("Reading from unknown register: %s\n", miscRegName[reg]);
519        return 0;
520    }
521}
522
523
524
525GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
526    : PioDevice(p),
527      ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
528      timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
529      addrRanges{ctrlRange, timerRange},
530      systemCounter(),
531      physTimer(csprintf("%s.phys_timer0", name()),
532                *this, systemCounter,
533                ArchTimer::Interrupt(*p->gic, p->int_phys)),
534      virtTimer(csprintf("%s.virt_timer0", name()),
535                *this, systemCounter,
536                ArchTimer::Interrupt(*p->gic, p->int_virt))
537{
538}
539
540void
541GenericTimerMem::serialize(CheckpointOut &cp) const
542{
543    paramOut(cp, "timer_count", 1);
544
545    systemCounter.serializeSection(cp, "sys_counter");
546
547    physTimer.serializeSection(cp, "phys_timer0");
548    virtTimer.serializeSection(cp, "virt_timer0");
549}
550
551void
552GenericTimerMem::unserialize(CheckpointIn &cp)
553{
554    systemCounter.unserializeSection(cp, "sys_counter");
555
556    unsigned timer_count;
557    UNSERIALIZE_SCALAR(timer_count);
558    // The timer count variable is just here for future versions where
559    // we support more than one set of timers.
560    if (timer_count != 1)
561        panic("Incompatible checkpoint: Only one set of timers supported");
562
563    physTimer.unserializeSection(cp, "phys_timer0");
564    virtTimer.unserializeSection(cp, "virt_timer0");
565}
566
567Tick
568GenericTimerMem::read(PacketPtr pkt)
569{
570    const unsigned size(pkt->getSize());
571    const Addr addr(pkt->getAddr());
572    uint64_t value;
573
574    pkt->makeResponse();
575    if (ctrlRange.contains(addr)) {
576        value = ctrlRead(addr - ctrlRange.start(), size);
577    } else if (timerRange.contains(addr)) {
578        value = timerRead(addr - timerRange.start(), size);
579    } else {
580        panic("Invalid address: 0x%x\n", addr);
581    }
582
583    DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
584
585    if (size == 8) {
586        pkt->set<uint64_t>(value);
587    } else if (size == 4) {
588        pkt->set<uint32_t>(value);
589    } else {
590        panic("Unexpected access size: %i\n", size);
591    }
592
593    return 0;
594}
595
596Tick
597GenericTimerMem::write(PacketPtr pkt)
598{
599    const unsigned size(pkt->getSize());
600    if (size != 8 && size != 4)
601        panic("Unexpected access size\n");
602
603    const Addr addr(pkt->getAddr());
604    const uint64_t value(size == 8 ?
605                         pkt->get<uint64_t>() : pkt->get<uint32_t>());
606
607    DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
608    if (ctrlRange.contains(addr)) {
609        ctrlWrite(addr - ctrlRange.start(), size, value);
610    } else if (timerRange.contains(addr)) {
611        timerWrite(addr - timerRange.start(), size, value);
612    } else {
613        panic("Invalid address: 0x%x\n", addr);
614    }
615
616    pkt->makeResponse();
617    return 0;
618}
619
620uint64_t
621GenericTimerMem::ctrlRead(Addr addr, size_t size) const
622{
623    if (size == 4) {
624        switch (addr) {
625          case CTRL_CNTFRQ:
626            return systemCounter.freq();
627
628          case CTRL_CNTTIDR:
629            return 0x3; // Frame 0 implemented with virtual timers
630
631          case CTRL_CNTNSAR:
632          case CTRL_CNTACR_BASE:
633            warn("Reading from unimplemented control register (0x%x)\n", addr);
634            return 0;
635
636          case CTRL_CNTVOFF_LO_BASE:
637            return virtTimer.offset();
638
639          case CTRL_CNTVOFF_HI_BASE:
640            return virtTimer.offset() >> 32;
641
642          default:
643            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
644            return 0;
645        }
646    } else if (size == 8) {
647        switch (addr) {
648          case CTRL_CNTVOFF_LO_BASE:
649            return virtTimer.offset();
650
651          default:
652            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
653            return 0;
654        }
655    } else {
656        panic("Invalid access size: %i\n", size);
657    }
658}
659
660void
661GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
662{
663    if (size == 4) {
664        switch (addr) {
665          case CTRL_CNTFRQ:
666          case CTRL_CNTNSAR:
667          case CTRL_CNTTIDR:
668          case CTRL_CNTACR_BASE:
669            warn("Write to unimplemented control register (0x%x)\n", addr);
670            return;
671
672          case CTRL_CNTVOFF_LO_BASE:
673            virtTimer.setOffset(
674                insertBits(virtTimer.offset(), 31, 0, value));
675            return;
676
677          case CTRL_CNTVOFF_HI_BASE:
678            virtTimer.setOffset(
679                insertBits(virtTimer.offset(), 63, 32, value));
680            return;
681
682          default:
683            warn("Ignoring write to unexpected address (0x%x:%i)\n",
684                 addr, size);
685            return;
686        }
687    } else if (size == 8) {
688        switch (addr) {
689          case CTRL_CNTVOFF_LO_BASE:
690            virtTimer.setOffset(value);
691            return;
692
693          default:
694            warn("Ignoring write to unexpected address (0x%x:%i)\n",
695                 addr, size);
696            return;
697        }
698    } else {
699        panic("Invalid access size: %i\n", size);
700    }
701}
702
703uint64_t
704GenericTimerMem::timerRead(Addr addr, size_t size) const
705{
706    if (size == 4) {
707        switch (addr) {
708          case TIMER_CNTPCT_LO:
709            return physTimer.value();
710
711          case TIMER_CNTPCT_HI:
712            return physTimer.value() >> 32;
713
714          case TIMER_CNTVCT_LO:
715            return virtTimer.value();
716
717          case TIMER_CNTVCT_HI:
718            return virtTimer.value() >> 32;
719
720          case TIMER_CNTFRQ:
721            return systemCounter.freq();
722
723          case TIMER_CNTEL0ACR:
724            warn("Read from unimplemented timer register (0x%x)\n", addr);
725            return 0;
726
727          case CTRL_CNTVOFF_LO_BASE:
728            return virtTimer.offset();
729
730          case CTRL_CNTVOFF_HI_BASE:
731            return virtTimer.offset() >> 32;
732
733          case TIMER_CNTP_CVAL_LO:
734            return physTimer.compareValue();
735
736          case TIMER_CNTP_CVAL_HI:
737            return physTimer.compareValue() >> 32;
738
739          case TIMER_CNTP_TVAL:
740            return physTimer.timerValue();
741
742          case TIMER_CNTP_CTL:
743            return physTimer.control();
744
745          case TIMER_CNTV_CVAL_LO:
746            return virtTimer.compareValue();
747
748          case TIMER_CNTV_CVAL_HI:
749            return virtTimer.compareValue() >> 32;
750
751          case TIMER_CNTV_TVAL:
752            return virtTimer.timerValue();
753
754          case TIMER_CNTV_CTL:
755            return virtTimer.control();
756
757          default:
758            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
759            return 0;
760        }
761    } else if (size == 8) {
762        switch (addr) {
763          case TIMER_CNTPCT_LO:
764            return physTimer.value();
765
766          case TIMER_CNTVCT_LO:
767            return virtTimer.value();
768
769          case CTRL_CNTVOFF_LO_BASE:
770            return virtTimer.offset();
771
772          case TIMER_CNTP_CVAL_LO:
773            return physTimer.compareValue();
774
775          case TIMER_CNTV_CVAL_LO:
776            return virtTimer.compareValue();
777
778          default:
779            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
780            return 0;
781        }
782    } else {
783        panic("Invalid access size: %i\n", size);
784    }
785}
786
787void
788GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
789{
790    if (size == 4) {
791        switch (addr) {
792          case TIMER_CNTEL0ACR:
793            warn("Unimplemented timer register (0x%x)\n", addr);
794            return;
795
796          case TIMER_CNTP_CVAL_LO:
797            physTimer.setCompareValue(
798                insertBits(physTimer.compareValue(), 31, 0, value));
799            return;
800
801          case TIMER_CNTP_CVAL_HI:
802            physTimer.setCompareValue(
803                insertBits(physTimer.compareValue(), 63, 32, value));
804            return;
805
806          case TIMER_CNTP_TVAL:
807            physTimer.setTimerValue(value);
808            return;
809
810          case TIMER_CNTP_CTL:
811            physTimer.setControl(value);
812            return;
813
814          case TIMER_CNTV_CVAL_LO:
815            virtTimer.setCompareValue(
816                insertBits(virtTimer.compareValue(), 31, 0, value));
817            return;
818
819          case TIMER_CNTV_CVAL_HI:
820            virtTimer.setCompareValue(
821                insertBits(virtTimer.compareValue(), 63, 32, value));
822            return;
823
824          case TIMER_CNTV_TVAL:
825            virtTimer.setTimerValue(value);
826            return;
827
828          case TIMER_CNTV_CTL:
829            virtTimer.setControl(value);
830            return;
831
832          default:
833            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
834            return;
835        }
836    } else if (size == 8) {
837        switch (addr) {
838          case TIMER_CNTP_CVAL_LO:
839            return physTimer.setCompareValue(value);
840
841          case TIMER_CNTV_CVAL_LO:
842            return virtTimer.setCompareValue(value);
843
844          default:
845            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
846            return;
847        }
848    } else {
849        panic("Invalid access size: %i\n", size);
850    }
851}
852
853GenericTimer *
854GenericTimerParams::create()
855{
856    return new GenericTimer(this);
857}
858
859GenericTimerMem *
860GenericTimerMemParams::create()
861{
862    return new GenericTimerMem(this);
863}
864