generic_timer.cc revision 12102:909ed81fd533
1/*
2 * Copyright (c) 2013, 2015, 2017 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 *          Andreas Sandberg
39 */
40
41#include "dev/arm/generic_timer.hh"
42
43#include "arch/arm/system.hh"
44#include "debug/Timer.hh"
45#include "dev/arm/base_gic.hh"
46#include "mem/packet_access.hh"
47#include "params/GenericTimer.hh"
48#include "params/GenericTimerMem.hh"
49
50SystemCounter::SystemCounter()
51    : _freq(0), _period(0), _resetTick(0), _regCntkctl(0)
52{
53    setFreq(0x01800000);
54}
55
56void
57SystemCounter::setFreq(uint32_t freq)
58{
59    if (_freq != 0) {
60        // Altering the frequency after boot shouldn't be done in practice.
61        warn_once("The frequency of the system counter has already been set");
62    }
63    _freq = freq;
64    _period = (1.0 / freq) * SimClock::Frequency;
65    _resetTick = curTick();
66}
67
68void
69SystemCounter::serialize(CheckpointOut &cp) const
70{
71    SERIALIZE_SCALAR(_regCntkctl);
72    SERIALIZE_SCALAR(_freq);
73    SERIALIZE_SCALAR(_period);
74    SERIALIZE_SCALAR(_resetTick);
75}
76
77void
78SystemCounter::unserialize(CheckpointIn &cp)
79{
80    // We didn't handle CNTKCTL in this class before, assume it's zero
81    // if it isn't present.
82    if (!UNSERIALIZE_OPT_SCALAR(_regCntkctl))
83        _regCntkctl = 0;
84    UNSERIALIZE_SCALAR(_freq);
85    UNSERIALIZE_SCALAR(_period);
86    UNSERIALIZE_SCALAR(_resetTick);
87}
88
89
90
91ArchTimer::ArchTimer(const std::string &name,
92                     SimObject &parent,
93                     SystemCounter &sysctr,
94                     const Interrupt &interrupt)
95    : _name(name), _parent(parent), _systemCounter(sysctr),
96      _interrupt(interrupt),
97      _control(0), _counterLimit(0), _offset(0),
98      _counterLimitReachedEvent([this]{ counterLimitReached(); }, name)
99{
100}
101
102void
103ArchTimer::counterLimitReached()
104{
105    _control.istatus = 1;
106
107    if (!_control.enable)
108        return;
109
110    DPRINTF(Timer, "Counter limit reached\n");
111    if (!_control.imask) {
112        if (scheduleEvents()) {
113            DPRINTF(Timer, "Causing interrupt\n");
114            _interrupt.send();
115        } else {
116            DPRINTF(Timer, "Kvm mode; skipping simulated interrupt\n");
117        }
118    }
119}
120
121void
122ArchTimer::updateCounter()
123{
124    if (_counterLimitReachedEvent.scheduled())
125        _parent.deschedule(_counterLimitReachedEvent);
126    if (value() >= _counterLimit) {
127        counterLimitReached();
128    } else {
129        _control.istatus = 0;
130        if (scheduleEvents()) {
131            const auto period(_systemCounter.period());
132            _parent.schedule(_counterLimitReachedEvent,
133                 curTick() + (_counterLimit - value()) * period);
134        }
135    }
136}
137
138void
139ArchTimer::setCompareValue(uint64_t val)
140{
141    _counterLimit = val;
142    updateCounter();
143}
144
145void
146ArchTimer::setTimerValue(uint32_t val)
147{
148    setCompareValue(value() + sext<32>(val));
149}
150
151void
152ArchTimer::setControl(uint32_t val)
153{
154    ArchTimerCtrl new_ctl = val;
155    if ((new_ctl.enable && !new_ctl.imask) &&
156        !(_control.enable && !_control.imask)) {
157        // Re-evalute the timer condition
158        if (_counterLimit >= value()) {
159            _control.istatus = 1;
160
161            DPRINTF(Timer, "Causing interrupt in control\n");
162            //_interrupt.send();
163        }
164    }
165    _control.enable = new_ctl.enable;
166    _control.imask = new_ctl.imask;
167}
168
169void
170ArchTimer::setOffset(uint64_t val)
171{
172    _offset = val;
173    updateCounter();
174}
175
176uint64_t
177ArchTimer::value() const
178{
179    return _systemCounter.value() - _offset;
180}
181
182void
183ArchTimer::serialize(CheckpointOut &cp) const
184{
185    paramOut(cp, "control_serial", _control);
186    SERIALIZE_SCALAR(_counterLimit);
187    SERIALIZE_SCALAR(_offset);
188}
189
190void
191ArchTimer::unserialize(CheckpointIn &cp)
192{
193    paramIn(cp, "control_serial", _control);
194    // We didn't serialize an offset before we added support for the
195    // virtual timer. Consider it optional to maintain backwards
196    // compatibility.
197    if (!UNSERIALIZE_OPT_SCALAR(_offset))
198        _offset = 0;
199
200    // We no longer schedule an event here because we may enter KVM
201    // emulation.  The event creation is delayed until drainResume().
202}
203
204DrainState
205ArchTimer::drain()
206{
207    if (_counterLimitReachedEvent.scheduled())
208        _parent.deschedule(_counterLimitReachedEvent);
209
210    return DrainState::Drained;
211}
212
213void
214ArchTimer::drainResume()
215{
216    updateCounter();
217}
218
219void
220ArchTimer::Interrupt::send()
221{
222    if (_ppi) {
223        _gic.sendPPInt(_irq, _cpu);
224    } else {
225        _gic.sendInt(_irq);
226    }
227}
228
229
230void
231ArchTimer::Interrupt::clear()
232{
233    if (_ppi) {
234        _gic.clearPPInt(_irq, _cpu);
235    } else {
236        _gic.clearInt(_irq);
237    }
238}
239
240
241GenericTimer::GenericTimer(GenericTimerParams *p)
242    : SimObject(p),
243      system(*p->system),
244      gic(p->gic),
245      irqPhys(p->int_phys),
246      irqVirt(p->int_virt)
247{
248    fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
249    system.setGenericTimer(this);
250}
251
252void
253GenericTimer::serialize(CheckpointOut &cp) const
254{
255    paramOut(cp, "cpu_count", timers.size());
256
257    systemCounter.serializeSection(cp, "sys_counter");
258
259    for (int i = 0; i < timers.size(); ++i) {
260        const CoreTimers &core(*timers[i]);
261
262        // This should really be phys_timerN, but we are stuck with
263        // arch_timer for backwards compatibility.
264        core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
265        core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
266    }
267}
268
269void
270GenericTimer::unserialize(CheckpointIn &cp)
271{
272    systemCounter.unserializeSection(cp, "sys_counter");
273
274    // Try to unserialize the CPU count. Old versions of the timer
275    // model assumed a 8 CPUs, so we fall back to that if the field
276    // isn't present.
277    static const unsigned OLD_CPU_MAX = 8;
278    unsigned cpu_count;
279    if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
280        warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
281             OLD_CPU_MAX);
282        cpu_count = OLD_CPU_MAX;
283    }
284
285    for (int i = 0; i < cpu_count; ++i) {
286        CoreTimers &core(getTimers(i));
287        // This should really be phys_timerN, but we are stuck with
288        // arch_timer for backwards compatibility.
289        core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
290        core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
291    }
292}
293
294
295GenericTimer::CoreTimers &
296GenericTimer::getTimers(int cpu_id)
297{
298    if (cpu_id >= timers.size())
299        createTimers(cpu_id + 1);
300
301    return *timers[cpu_id];
302}
303
304void
305GenericTimer::createTimers(unsigned cpus)
306{
307    assert(timers.size() < cpus);
308
309    const unsigned old_cpu_count(timers.size());
310    timers.resize(cpus);
311    for (unsigned i = old_cpu_count; i < cpus; ++i) {
312        timers[i].reset(
313            new CoreTimers(*this, system, i, irqPhys, irqVirt));
314    }
315}
316
317
318void
319GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
320{
321    // This method might have been called from another context if we
322    // are running in multi-core KVM. Migrate to the SimObject's event
323    // queue to prevent surprising race conditions.
324    EventQueue::ScopedMigration migrate(eventQueue());
325
326    CoreTimers &core(getTimers(cpu));
327
328    switch (reg) {
329      case MISCREG_CNTFRQ:
330      case MISCREG_CNTFRQ_EL0:
331        systemCounter.setFreq(val);
332        return;
333
334      case MISCREG_CNTKCTL:
335      case MISCREG_CNTKCTL_EL1:
336        systemCounter.setKernelControl(val);
337        return;
338
339      // Physical timer
340      case MISCREG_CNTP_CVAL:
341      case MISCREG_CNTP_CVAL_NS:
342      case MISCREG_CNTP_CVAL_EL0:
343        core.phys.setCompareValue(val);
344        return;
345
346      case MISCREG_CNTP_TVAL:
347      case MISCREG_CNTP_TVAL_NS:
348      case MISCREG_CNTP_TVAL_EL0:
349        core.phys.setTimerValue(val);
350        return;
351
352      case MISCREG_CNTP_CTL:
353      case MISCREG_CNTP_CTL_NS:
354      case MISCREG_CNTP_CTL_EL0:
355        core.phys.setControl(val);
356        return;
357
358      // Count registers
359      case MISCREG_CNTPCT:
360      case MISCREG_CNTPCT_EL0:
361      case MISCREG_CNTVCT:
362      case MISCREG_CNTVCT_EL0:
363        warn("Ignoring write to read only count register: %s\n",
364             miscRegName[reg]);
365        return;
366
367      // Virtual timer
368      case MISCREG_CNTVOFF:
369      case MISCREG_CNTVOFF_EL2:
370        core.virt.setOffset(val);
371        return;
372
373      case MISCREG_CNTV_CVAL:
374      case MISCREG_CNTV_CVAL_EL0:
375        core.virt.setCompareValue(val);
376        return;
377
378      case MISCREG_CNTV_TVAL:
379      case MISCREG_CNTV_TVAL_EL0:
380        core.virt.setTimerValue(val);
381        return;
382
383      case MISCREG_CNTV_CTL:
384      case MISCREG_CNTV_CTL_EL0:
385        core.virt.setControl(val);
386        return;
387
388      // PL1 phys. timer, secure
389      case MISCREG_CNTP_CTL_S:
390      case MISCREG_CNTPS_CVAL_EL1:
391      case MISCREG_CNTPS_TVAL_EL1:
392      case MISCREG_CNTPS_CTL_EL1:
393        /* FALLTHROUGH */
394
395      // PL2 phys. timer, non-secure
396      case MISCREG_CNTHCTL:
397      case MISCREG_CNTHCTL_EL2:
398      case MISCREG_CNTHP_CVAL:
399      case MISCREG_CNTHP_CVAL_EL2:
400      case MISCREG_CNTHP_TVAL:
401      case MISCREG_CNTHP_TVAL_EL2:
402      case MISCREG_CNTHP_CTL:
403      case MISCREG_CNTHP_CTL_EL2:
404        warn("Writing to unimplemented register: %s\n",
405             miscRegName[reg]);
406        return;
407
408      default:
409        warn("Writing to unknown register: %s\n", miscRegName[reg]);
410        return;
411    }
412}
413
414
415MiscReg
416GenericTimer::readMiscReg(int reg, unsigned cpu)
417{
418    // This method might have been called from another context if we
419    // are running in multi-core KVM. Migrate to the SimObject's event
420    // queue to prevent surprising race conditions.
421    EventQueue::ScopedMigration migrate(eventQueue());
422
423    CoreTimers &core(getTimers(cpu));
424
425    switch (reg) {
426      case MISCREG_CNTFRQ:
427      case MISCREG_CNTFRQ_EL0:
428        return systemCounter.freq();
429
430      case MISCREG_CNTKCTL:
431      case MISCREG_CNTKCTL_EL1:
432        return systemCounter.getKernelControl();
433
434      // Physical timer
435      case MISCREG_CNTP_CVAL:
436      case MISCREG_CNTP_CVAL_EL0:
437        return core.phys.compareValue();
438
439      case MISCREG_CNTP_TVAL:
440      case MISCREG_CNTP_TVAL_EL0:
441        return core.phys.timerValue();
442
443      case MISCREG_CNTP_CTL:
444      case MISCREG_CNTP_CTL_EL0:
445      case MISCREG_CNTP_CTL_NS:
446        return core.phys.control();
447
448      case MISCREG_CNTPCT:
449      case MISCREG_CNTPCT_EL0:
450        return core.phys.value();
451
452
453      // Virtual timer
454      case MISCREG_CNTVCT:
455      case MISCREG_CNTVCT_EL0:
456        return core.virt.value();
457
458      case MISCREG_CNTVOFF:
459      case MISCREG_CNTVOFF_EL2:
460        return core.virt.offset();
461
462      case MISCREG_CNTV_CVAL:
463      case MISCREG_CNTV_CVAL_EL0:
464        return core.virt.compareValue();
465
466      case MISCREG_CNTV_TVAL:
467      case MISCREG_CNTV_TVAL_EL0:
468        return core.virt.timerValue();
469
470      case MISCREG_CNTV_CTL:
471      case MISCREG_CNTV_CTL_EL0:
472        return core.virt.control();
473
474      // PL1 phys. timer, secure
475      case MISCREG_CNTP_CTL_S:
476      case MISCREG_CNTPS_CVAL_EL1:
477      case MISCREG_CNTPS_TVAL_EL1:
478      case MISCREG_CNTPS_CTL_EL1:
479        /* FALLTHROUGH */
480
481      // PL2 phys. timer, non-secure
482      case MISCREG_CNTHCTL:
483      case MISCREG_CNTHCTL_EL2:
484      case MISCREG_CNTHP_CVAL:
485      case MISCREG_CNTHP_CVAL_EL2:
486      case MISCREG_CNTHP_TVAL:
487      case MISCREG_CNTHP_TVAL_EL2:
488      case MISCREG_CNTHP_CTL:
489      case MISCREG_CNTHP_CTL_EL2:
490        warn("Reading from unimplemented register: %s\n",
491             miscRegName[reg]);
492        return 0;
493
494
495      default:
496        warn("Reading from unknown register: %s\n", miscRegName[reg]);
497        return 0;
498    }
499}
500
501
502
503GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
504    : PioDevice(p),
505      ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
506      timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
507      addrRanges{ctrlRange, timerRange},
508      systemCounter(),
509      physTimer(csprintf("%s.phys_timer0", name()),
510                *this, systemCounter,
511                ArchTimer::Interrupt(*p->gic, p->int_phys)),
512      virtTimer(csprintf("%s.virt_timer0", name()),
513                *this, systemCounter,
514                ArchTimer::Interrupt(*p->gic, p->int_virt))
515{
516}
517
518void
519GenericTimerMem::serialize(CheckpointOut &cp) const
520{
521    paramOut(cp, "timer_count", 1);
522
523    systemCounter.serializeSection(cp, "sys_counter");
524
525    physTimer.serializeSection(cp, "phys_timer0");
526    virtTimer.serializeSection(cp, "virt_timer0");
527}
528
529void
530GenericTimerMem::unserialize(CheckpointIn &cp)
531{
532    systemCounter.unserializeSection(cp, "sys_counter");
533
534    unsigned timer_count;
535    UNSERIALIZE_SCALAR(timer_count);
536    // The timer count variable is just here for future versions where
537    // we support more than one set of timers.
538    if (timer_count != 1)
539        panic("Incompatible checkpoint: Only one set of timers supported");
540
541    physTimer.unserializeSection(cp, "phys_timer0");
542    virtTimer.unserializeSection(cp, "virt_timer0");
543}
544
545Tick
546GenericTimerMem::read(PacketPtr pkt)
547{
548    const unsigned size(pkt->getSize());
549    const Addr addr(pkt->getAddr());
550    uint64_t value;
551
552    pkt->makeResponse();
553    if (ctrlRange.contains(addr)) {
554        value = ctrlRead(addr - ctrlRange.start(), size);
555    } else if (timerRange.contains(addr)) {
556        value = timerRead(addr - timerRange.start(), size);
557    } else {
558        panic("Invalid address: 0x%x\n", addr);
559    }
560
561    DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
562
563    if (size == 8) {
564        pkt->set<uint64_t>(value);
565    } else if (size == 4) {
566        pkt->set<uint32_t>(value);
567    } else {
568        panic("Unexpected access size: %i\n", size);
569    }
570
571    return 0;
572}
573
574Tick
575GenericTimerMem::write(PacketPtr pkt)
576{
577    const unsigned size(pkt->getSize());
578    if (size != 8 && size != 4)
579        panic("Unexpected access size\n");
580
581    const Addr addr(pkt->getAddr());
582    const uint64_t value(size == 8 ?
583                         pkt->get<uint64_t>() : pkt->get<uint32_t>());
584
585    DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
586    if (ctrlRange.contains(addr)) {
587        ctrlWrite(addr - ctrlRange.start(), size, value);
588    } else if (timerRange.contains(addr)) {
589        timerWrite(addr - timerRange.start(), size, value);
590    } else {
591        panic("Invalid address: 0x%x\n", addr);
592    }
593
594    pkt->makeResponse();
595    return 0;
596}
597
598uint64_t
599GenericTimerMem::ctrlRead(Addr addr, size_t size) const
600{
601    if (size == 4) {
602        switch (addr) {
603          case CTRL_CNTFRQ:
604            return systemCounter.freq();
605
606          case CTRL_CNTTIDR:
607            return 0x3; // Frame 0 implemented with virtual timers
608
609          case CTRL_CNTNSAR:
610          case CTRL_CNTACR_BASE:
611            warn("Reading from unimplemented control register (0x%x)\n", addr);
612            return 0;
613
614          case CTRL_CNTVOFF_LO_BASE:
615            return virtTimer.offset();
616
617          case CTRL_CNTVOFF_HI_BASE:
618            return virtTimer.offset() >> 32;
619
620          default:
621            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
622            return 0;
623        }
624    } else if (size == 8) {
625        switch (addr) {
626          case CTRL_CNTVOFF_LO_BASE:
627            return virtTimer.offset();
628
629          default:
630            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
631            return 0;
632        }
633    } else {
634        panic("Invalid access size: %i\n", size);
635    }
636}
637
638void
639GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
640{
641    if (size == 4) {
642        switch (addr) {
643          case CTRL_CNTFRQ:
644          case CTRL_CNTNSAR:
645          case CTRL_CNTTIDR:
646          case CTRL_CNTACR_BASE:
647            warn("Write to unimplemented control register (0x%x)\n", addr);
648            return;
649
650          case CTRL_CNTVOFF_LO_BASE:
651            virtTimer.setOffset(
652                insertBits(virtTimer.offset(), 31, 0, value));
653            return;
654
655          case CTRL_CNTVOFF_HI_BASE:
656            virtTimer.setOffset(
657                insertBits(virtTimer.offset(), 63, 32, value));
658            return;
659
660          default:
661            warn("Ignoring write to unexpected address (0x%x:%i)\n",
662                 addr, size);
663            return;
664        }
665    } else if (size == 8) {
666        switch (addr) {
667          case CTRL_CNTVOFF_LO_BASE:
668            virtTimer.setOffset(value);
669            return;
670
671          default:
672            warn("Ignoring write to unexpected address (0x%x:%i)\n",
673                 addr, size);
674            return;
675        }
676    } else {
677        panic("Invalid access size: %i\n", size);
678    }
679}
680
681uint64_t
682GenericTimerMem::timerRead(Addr addr, size_t size) const
683{
684    if (size == 4) {
685        switch (addr) {
686          case TIMER_CNTPCT_LO:
687            return physTimer.value();
688
689          case TIMER_CNTPCT_HI:
690            return physTimer.value() >> 32;
691
692          case TIMER_CNTVCT_LO:
693            return virtTimer.value();
694
695          case TIMER_CNTVCT_HI:
696            return virtTimer.value() >> 32;
697
698          case TIMER_CNTFRQ:
699            return systemCounter.freq();
700
701          case TIMER_CNTEL0ACR:
702            warn("Read from unimplemented timer register (0x%x)\n", addr);
703            return 0;
704
705          case CTRL_CNTVOFF_LO_BASE:
706            return virtTimer.offset();
707
708          case CTRL_CNTVOFF_HI_BASE:
709            return virtTimer.offset() >> 32;
710
711          case TIMER_CNTP_CVAL_LO:
712            return physTimer.compareValue();
713
714          case TIMER_CNTP_CVAL_HI:
715            return physTimer.compareValue() >> 32;
716
717          case TIMER_CNTP_TVAL:
718            return physTimer.timerValue();
719
720          case TIMER_CNTP_CTL:
721            return physTimer.control();
722
723          case TIMER_CNTV_CVAL_LO:
724            return virtTimer.compareValue();
725
726          case TIMER_CNTV_CVAL_HI:
727            return virtTimer.compareValue() >> 32;
728
729          case TIMER_CNTV_TVAL:
730            return virtTimer.timerValue();
731
732          case TIMER_CNTV_CTL:
733            return virtTimer.control();
734
735          default:
736            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
737            return 0;
738        }
739    } else if (size == 8) {
740        switch (addr) {
741          case TIMER_CNTPCT_LO:
742            return physTimer.value();
743
744          case TIMER_CNTVCT_LO:
745            return virtTimer.value();
746
747          case CTRL_CNTVOFF_LO_BASE:
748            return virtTimer.offset();
749
750          case TIMER_CNTP_CVAL_LO:
751            return physTimer.compareValue();
752
753          case TIMER_CNTV_CVAL_LO:
754            return virtTimer.compareValue();
755
756          default:
757            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
758            return 0;
759        }
760    } else {
761        panic("Invalid access size: %i\n", size);
762    }
763}
764
765void
766GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
767{
768    if (size == 4) {
769        switch (addr) {
770          case TIMER_CNTEL0ACR:
771            warn("Unimplemented timer register (0x%x)\n", addr);
772            return;
773
774          case TIMER_CNTP_CVAL_LO:
775            physTimer.setCompareValue(
776                insertBits(physTimer.compareValue(), 31, 0, value));
777            return;
778
779          case TIMER_CNTP_CVAL_HI:
780            physTimer.setCompareValue(
781                insertBits(physTimer.compareValue(), 63, 32, value));
782            return;
783
784          case TIMER_CNTP_TVAL:
785            physTimer.setTimerValue(value);
786            return;
787
788          case TIMER_CNTP_CTL:
789            physTimer.setControl(value);
790            return;
791
792          case TIMER_CNTV_CVAL_LO:
793            virtTimer.setCompareValue(
794                insertBits(virtTimer.compareValue(), 31, 0, value));
795            return;
796
797          case TIMER_CNTV_CVAL_HI:
798            virtTimer.setCompareValue(
799                insertBits(virtTimer.compareValue(), 63, 32, value));
800            return;
801
802          case TIMER_CNTV_TVAL:
803            virtTimer.setTimerValue(value);
804            return;
805
806          case TIMER_CNTV_CTL:
807            virtTimer.setControl(value);
808            return;
809
810          default:
811            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
812            return;
813        }
814    } else if (size == 8) {
815        switch (addr) {
816          case TIMER_CNTP_CVAL_LO:
817            return physTimer.setCompareValue(value);
818
819          case TIMER_CNTV_CVAL_LO:
820            return virtTimer.setCompareValue(value);
821
822          default:
823            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
824            return;
825        }
826    } else {
827        panic("Invalid access size: %i\n", size);
828    }
829}
830
831GenericTimer *
832GenericTimerParams::create()
833{
834    return new GenericTimer(this);
835}
836
837GenericTimerMem *
838GenericTimerMemParams::create()
839{
840    return new GenericTimerMem(this);
841}
842