generic_timer.cc revision 12101:f3e183c78529
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        DPRINTF(Timer, "Causing interrupt\n");
113        _interrupt.send();
114    }
115}
116
117void
118ArchTimer::updateCounter()
119{
120    if (_counterLimitReachedEvent.scheduled())
121        _parent.deschedule(_counterLimitReachedEvent);
122    if (value() >= _counterLimit) {
123        counterLimitReached();
124    } else {
125        const auto period(_systemCounter.period());
126        _control.istatus = 0;
127        _parent.schedule(_counterLimitReachedEvent,
128             curTick() + (_counterLimit - value()) * period);
129    }
130}
131
132void
133ArchTimer::setCompareValue(uint64_t val)
134{
135    _counterLimit = val;
136    updateCounter();
137}
138
139void
140ArchTimer::setTimerValue(uint32_t val)
141{
142    setCompareValue(value() + sext<32>(val));
143}
144
145void
146ArchTimer::setControl(uint32_t val)
147{
148    ArchTimerCtrl new_ctl = val;
149    if ((new_ctl.enable && !new_ctl.imask) &&
150        !(_control.enable && !_control.imask)) {
151        // Re-evalute the timer condition
152        if (_counterLimit >= value()) {
153            _control.istatus = 1;
154
155            DPRINTF(Timer, "Causing interrupt in control\n");
156            //_interrupt.send();
157        }
158    }
159    _control.enable = new_ctl.enable;
160    _control.imask = new_ctl.imask;
161}
162
163void
164ArchTimer::setOffset(uint64_t val)
165{
166    _offset = val;
167    updateCounter();
168}
169
170uint64_t
171ArchTimer::value() const
172{
173    return _systemCounter.value() - _offset;
174}
175
176void
177ArchTimer::serialize(CheckpointOut &cp) const
178{
179    paramOut(cp, "control_serial", _control);
180    SERIALIZE_SCALAR(_counterLimit);
181    SERIALIZE_SCALAR(_offset);
182}
183
184void
185ArchTimer::unserialize(CheckpointIn &cp)
186{
187    paramIn(cp, "control_serial", _control);
188    // We didn't serialize an offset before we added support for the
189    // virtual timer. Consider it optional to maintain backwards
190    // compatibility.
191    if (!UNSERIALIZE_OPT_SCALAR(_offset))
192        _offset = 0;
193
194    // We no longer schedule an event here because we may enter KVM
195    // emulation.  The event creation is delayed until drainResume().
196}
197
198DrainState
199ArchTimer::drain()
200{
201    if (_counterLimitReachedEvent.scheduled())
202        _parent.deschedule(_counterLimitReachedEvent);
203
204    return DrainState::Drained;
205}
206
207void
208ArchTimer::drainResume()
209{
210    updateCounter();
211}
212
213void
214ArchTimer::Interrupt::send()
215{
216    if (_ppi) {
217        _gic.sendPPInt(_irq, _cpu);
218    } else {
219        _gic.sendInt(_irq);
220    }
221}
222
223
224void
225ArchTimer::Interrupt::clear()
226{
227    if (_ppi) {
228        _gic.clearPPInt(_irq, _cpu);
229    } else {
230        _gic.clearInt(_irq);
231    }
232}
233
234
235GenericTimer::GenericTimer(GenericTimerParams *p)
236    : SimObject(p),
237      gic(p->gic),
238      irqPhys(p->int_phys),
239      irqVirt(p->int_virt)
240{
241    fatal_if(!p->system, "No system specified, can't instantiate timer.\n");
242    p->system->setGenericTimer(this);
243}
244
245void
246GenericTimer::serialize(CheckpointOut &cp) const
247{
248    paramOut(cp, "cpu_count", timers.size());
249
250    systemCounter.serializeSection(cp, "sys_counter");
251
252    for (int i = 0; i < timers.size(); ++i) {
253        const CoreTimers &core(*timers[i]);
254
255        // This should really be phys_timerN, but we are stuck with
256        // arch_timer for backwards compatibility.
257        core.phys.serializeSection(cp, csprintf("arch_timer%d", i));
258        core.virt.serializeSection(cp, csprintf("virt_timer%d", i));
259    }
260}
261
262void
263GenericTimer::unserialize(CheckpointIn &cp)
264{
265    systemCounter.unserializeSection(cp, "sys_counter");
266
267    // Try to unserialize the CPU count. Old versions of the timer
268    // model assumed a 8 CPUs, so we fall back to that if the field
269    // isn't present.
270    static const unsigned OLD_CPU_MAX = 8;
271    unsigned cpu_count;
272    if (!UNSERIALIZE_OPT_SCALAR(cpu_count)) {
273        warn("Checkpoint does not contain CPU count, assuming %i CPUs\n",
274             OLD_CPU_MAX);
275        cpu_count = OLD_CPU_MAX;
276    }
277
278    for (int i = 0; i < cpu_count; ++i) {
279        CoreTimers &core(getTimers(i));
280        // This should really be phys_timerN, but we are stuck with
281        // arch_timer for backwards compatibility.
282        core.phys.unserializeSection(cp, csprintf("arch_timer%d", i));
283        core.virt.unserializeSection(cp, csprintf("virt_timer%d", i));
284    }
285}
286
287
288GenericTimer::CoreTimers &
289GenericTimer::getTimers(int cpu_id)
290{
291    if (cpu_id >= timers.size())
292        createTimers(cpu_id + 1);
293
294    return *timers[cpu_id];
295}
296
297void
298GenericTimer::createTimers(unsigned cpus)
299{
300    assert(timers.size() < cpus);
301
302    const unsigned old_cpu_count(timers.size());
303    timers.resize(cpus);
304    for (unsigned i = old_cpu_count; i < cpus; ++i) {
305        timers[i].reset(
306            new CoreTimers(*this, i, irqPhys, irqVirt));
307    }
308}
309
310
311void
312GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
313{
314    // This method might have been called from another context if we
315    // are running in multi-core KVM. Migrate to the SimObject's event
316    // queue to prevent surprising race conditions.
317    EventQueue::ScopedMigration migrate(eventQueue());
318
319    CoreTimers &core(getTimers(cpu));
320
321    switch (reg) {
322      case MISCREG_CNTFRQ:
323      case MISCREG_CNTFRQ_EL0:
324        systemCounter.setFreq(val);
325        return;
326
327      case MISCREG_CNTKCTL:
328      case MISCREG_CNTKCTL_EL1:
329        systemCounter.setKernelControl(val);
330        return;
331
332      // Physical timer
333      case MISCREG_CNTP_CVAL:
334      case MISCREG_CNTP_CVAL_NS:
335      case MISCREG_CNTP_CVAL_EL0:
336        core.phys.setCompareValue(val);
337        return;
338
339      case MISCREG_CNTP_TVAL:
340      case MISCREG_CNTP_TVAL_NS:
341      case MISCREG_CNTP_TVAL_EL0:
342        core.phys.setTimerValue(val);
343        return;
344
345      case MISCREG_CNTP_CTL:
346      case MISCREG_CNTP_CTL_NS:
347      case MISCREG_CNTP_CTL_EL0:
348        core.phys.setControl(val);
349        return;
350
351      // Count registers
352      case MISCREG_CNTPCT:
353      case MISCREG_CNTPCT_EL0:
354      case MISCREG_CNTVCT:
355      case MISCREG_CNTVCT_EL0:
356        warn("Ignoring write to read only count register: %s\n",
357             miscRegName[reg]);
358        return;
359
360      // Virtual timer
361      case MISCREG_CNTVOFF:
362      case MISCREG_CNTVOFF_EL2:
363        core.virt.setOffset(val);
364        return;
365
366      case MISCREG_CNTV_CVAL:
367      case MISCREG_CNTV_CVAL_EL0:
368        core.virt.setCompareValue(val);
369        return;
370
371      case MISCREG_CNTV_TVAL:
372      case MISCREG_CNTV_TVAL_EL0:
373        core.virt.setTimerValue(val);
374        return;
375
376      case MISCREG_CNTV_CTL:
377      case MISCREG_CNTV_CTL_EL0:
378        core.virt.setControl(val);
379        return;
380
381      // PL1 phys. timer, secure
382      case MISCREG_CNTP_CTL_S:
383      case MISCREG_CNTPS_CVAL_EL1:
384      case MISCREG_CNTPS_TVAL_EL1:
385      case MISCREG_CNTPS_CTL_EL1:
386        /* FALLTHROUGH */
387
388      // PL2 phys. timer, non-secure
389      case MISCREG_CNTHCTL:
390      case MISCREG_CNTHCTL_EL2:
391      case MISCREG_CNTHP_CVAL:
392      case MISCREG_CNTHP_CVAL_EL2:
393      case MISCREG_CNTHP_TVAL:
394      case MISCREG_CNTHP_TVAL_EL2:
395      case MISCREG_CNTHP_CTL:
396      case MISCREG_CNTHP_CTL_EL2:
397        warn("Writing to unimplemented register: %s\n",
398             miscRegName[reg]);
399        return;
400
401      default:
402        warn("Writing to unknown register: %s\n", miscRegName[reg]);
403        return;
404    }
405}
406
407
408MiscReg
409GenericTimer::readMiscReg(int reg, unsigned cpu)
410{
411    // This method might have been called from another context if we
412    // are running in multi-core KVM. Migrate to the SimObject's event
413    // queue to prevent surprising race conditions.
414    EventQueue::ScopedMigration migrate(eventQueue());
415
416    CoreTimers &core(getTimers(cpu));
417
418    switch (reg) {
419      case MISCREG_CNTFRQ:
420      case MISCREG_CNTFRQ_EL0:
421        return systemCounter.freq();
422
423      case MISCREG_CNTKCTL:
424      case MISCREG_CNTKCTL_EL1:
425        return systemCounter.getKernelControl();
426
427      // Physical timer
428      case MISCREG_CNTP_CVAL:
429      case MISCREG_CNTP_CVAL_EL0:
430        return core.phys.compareValue();
431
432      case MISCREG_CNTP_TVAL:
433      case MISCREG_CNTP_TVAL_EL0:
434        return core.phys.timerValue();
435
436      case MISCREG_CNTP_CTL:
437      case MISCREG_CNTP_CTL_EL0:
438      case MISCREG_CNTP_CTL_NS:
439        return core.phys.control();
440
441      case MISCREG_CNTPCT:
442      case MISCREG_CNTPCT_EL0:
443        return core.phys.value();
444
445
446      // Virtual timer
447      case MISCREG_CNTVCT:
448      case MISCREG_CNTVCT_EL0:
449        return core.virt.value();
450
451      case MISCREG_CNTVOFF:
452      case MISCREG_CNTVOFF_EL2:
453        return core.virt.offset();
454
455      case MISCREG_CNTV_CVAL:
456      case MISCREG_CNTV_CVAL_EL0:
457        return core.virt.compareValue();
458
459      case MISCREG_CNTV_TVAL:
460      case MISCREG_CNTV_TVAL_EL0:
461        return core.virt.timerValue();
462
463      case MISCREG_CNTV_CTL:
464      case MISCREG_CNTV_CTL_EL0:
465        return core.virt.control();
466
467      // PL1 phys. timer, secure
468      case MISCREG_CNTP_CTL_S:
469      case MISCREG_CNTPS_CVAL_EL1:
470      case MISCREG_CNTPS_TVAL_EL1:
471      case MISCREG_CNTPS_CTL_EL1:
472        /* FALLTHROUGH */
473
474      // PL2 phys. timer, non-secure
475      case MISCREG_CNTHCTL:
476      case MISCREG_CNTHCTL_EL2:
477      case MISCREG_CNTHP_CVAL:
478      case MISCREG_CNTHP_CVAL_EL2:
479      case MISCREG_CNTHP_TVAL:
480      case MISCREG_CNTHP_TVAL_EL2:
481      case MISCREG_CNTHP_CTL:
482      case MISCREG_CNTHP_CTL_EL2:
483        warn("Reading from unimplemented register: %s\n",
484             miscRegName[reg]);
485        return 0;
486
487
488      default:
489        warn("Reading from unknown register: %s\n", miscRegName[reg]);
490        return 0;
491    }
492}
493
494
495
496GenericTimerMem::GenericTimerMem(GenericTimerMemParams *p)
497    : PioDevice(p),
498      ctrlRange(RangeSize(p->base, TheISA::PageBytes)),
499      timerRange(RangeSize(p->base + TheISA::PageBytes, TheISA::PageBytes)),
500      addrRanges{ctrlRange, timerRange},
501      systemCounter(),
502      physTimer(csprintf("%s.phys_timer0", name()),
503                *this, systemCounter,
504                ArchTimer::Interrupt(*p->gic, p->int_phys)),
505      virtTimer(csprintf("%s.virt_timer0", name()),
506                *this, systemCounter,
507                ArchTimer::Interrupt(*p->gic, p->int_virt))
508{
509}
510
511void
512GenericTimerMem::serialize(CheckpointOut &cp) const
513{
514    paramOut(cp, "timer_count", 1);
515
516    systemCounter.serializeSection(cp, "sys_counter");
517
518    physTimer.serializeSection(cp, "phys_timer0");
519    virtTimer.serializeSection(cp, "virt_timer0");
520}
521
522void
523GenericTimerMem::unserialize(CheckpointIn &cp)
524{
525    systemCounter.unserializeSection(cp, "sys_counter");
526
527    unsigned timer_count;
528    UNSERIALIZE_SCALAR(timer_count);
529    // The timer count variable is just here for future versions where
530    // we support more than one set of timers.
531    if (timer_count != 1)
532        panic("Incompatible checkpoint: Only one set of timers supported");
533
534    physTimer.unserializeSection(cp, "phys_timer0");
535    virtTimer.unserializeSection(cp, "virt_timer0");
536}
537
538Tick
539GenericTimerMem::read(PacketPtr pkt)
540{
541    const unsigned size(pkt->getSize());
542    const Addr addr(pkt->getAddr());
543    uint64_t value;
544
545    pkt->makeResponse();
546    if (ctrlRange.contains(addr)) {
547        value = ctrlRead(addr - ctrlRange.start(), size);
548    } else if (timerRange.contains(addr)) {
549        value = timerRead(addr - timerRange.start(), size);
550    } else {
551        panic("Invalid address: 0x%x\n", addr);
552    }
553
554    DPRINTF(Timer, "Read 0x%x <- 0x%x(%i)\n", value, addr, size);
555
556    if (size == 8) {
557        pkt->set<uint64_t>(value);
558    } else if (size == 4) {
559        pkt->set<uint32_t>(value);
560    } else {
561        panic("Unexpected access size: %i\n", size);
562    }
563
564    return 0;
565}
566
567Tick
568GenericTimerMem::write(PacketPtr pkt)
569{
570    const unsigned size(pkt->getSize());
571    if (size != 8 && size != 4)
572        panic("Unexpected access size\n");
573
574    const Addr addr(pkt->getAddr());
575    const uint64_t value(size == 8 ?
576                         pkt->get<uint64_t>() : pkt->get<uint32_t>());
577
578    DPRINTF(Timer, "Write 0x%x -> 0x%x(%i)\n", value, addr, size);
579    if (ctrlRange.contains(addr)) {
580        ctrlWrite(addr - ctrlRange.start(), size, value);
581    } else if (timerRange.contains(addr)) {
582        timerWrite(addr - timerRange.start(), size, value);
583    } else {
584        panic("Invalid address: 0x%x\n", addr);
585    }
586
587    pkt->makeResponse();
588    return 0;
589}
590
591uint64_t
592GenericTimerMem::ctrlRead(Addr addr, size_t size) const
593{
594    if (size == 4) {
595        switch (addr) {
596          case CTRL_CNTFRQ:
597            return systemCounter.freq();
598
599          case CTRL_CNTTIDR:
600            return 0x3; // Frame 0 implemented with virtual timers
601
602          case CTRL_CNTNSAR:
603          case CTRL_CNTACR_BASE:
604            warn("Reading from unimplemented control register (0x%x)\n", addr);
605            return 0;
606
607          case CTRL_CNTVOFF_LO_BASE:
608            return virtTimer.offset();
609
610          case CTRL_CNTVOFF_HI_BASE:
611            return virtTimer.offset() >> 32;
612
613          default:
614            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
615            return 0;
616        }
617    } else if (size == 8) {
618        switch (addr) {
619          case CTRL_CNTVOFF_LO_BASE:
620            return virtTimer.offset();
621
622          default:
623            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
624            return 0;
625        }
626    } else {
627        panic("Invalid access size: %i\n", size);
628    }
629}
630
631void
632GenericTimerMem::ctrlWrite(Addr addr, size_t size, uint64_t value)
633{
634    if (size == 4) {
635        switch (addr) {
636          case CTRL_CNTFRQ:
637          case CTRL_CNTNSAR:
638          case CTRL_CNTTIDR:
639          case CTRL_CNTACR_BASE:
640            warn("Write to unimplemented control register (0x%x)\n", addr);
641            return;
642
643          case CTRL_CNTVOFF_LO_BASE:
644            virtTimer.setOffset(
645                insertBits(virtTimer.offset(), 31, 0, value));
646            return;
647
648          case CTRL_CNTVOFF_HI_BASE:
649            virtTimer.setOffset(
650                insertBits(virtTimer.offset(), 63, 32, value));
651            return;
652
653          default:
654            warn("Ignoring write to unexpected address (0x%x:%i)\n",
655                 addr, size);
656            return;
657        }
658    } else if (size == 8) {
659        switch (addr) {
660          case CTRL_CNTVOFF_LO_BASE:
661            virtTimer.setOffset(value);
662            return;
663
664          default:
665            warn("Ignoring write to unexpected address (0x%x:%i)\n",
666                 addr, size);
667            return;
668        }
669    } else {
670        panic("Invalid access size: %i\n", size);
671    }
672}
673
674uint64_t
675GenericTimerMem::timerRead(Addr addr, size_t size) const
676{
677    if (size == 4) {
678        switch (addr) {
679          case TIMER_CNTPCT_LO:
680            return physTimer.value();
681
682          case TIMER_CNTPCT_HI:
683            return physTimer.value() >> 32;
684
685          case TIMER_CNTVCT_LO:
686            return virtTimer.value();
687
688          case TIMER_CNTVCT_HI:
689            return virtTimer.value() >> 32;
690
691          case TIMER_CNTFRQ:
692            return systemCounter.freq();
693
694          case TIMER_CNTEL0ACR:
695            warn("Read from unimplemented timer register (0x%x)\n", addr);
696            return 0;
697
698          case CTRL_CNTVOFF_LO_BASE:
699            return virtTimer.offset();
700
701          case CTRL_CNTVOFF_HI_BASE:
702            return virtTimer.offset() >> 32;
703
704          case TIMER_CNTP_CVAL_LO:
705            return physTimer.compareValue();
706
707          case TIMER_CNTP_CVAL_HI:
708            return physTimer.compareValue() >> 32;
709
710          case TIMER_CNTP_TVAL:
711            return physTimer.timerValue();
712
713          case TIMER_CNTP_CTL:
714            return physTimer.control();
715
716          case TIMER_CNTV_CVAL_LO:
717            return virtTimer.compareValue();
718
719          case TIMER_CNTV_CVAL_HI:
720            return virtTimer.compareValue() >> 32;
721
722          case TIMER_CNTV_TVAL:
723            return virtTimer.timerValue();
724
725          case TIMER_CNTV_CTL:
726            return virtTimer.control();
727
728          default:
729            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
730            return 0;
731        }
732    } else if (size == 8) {
733        switch (addr) {
734          case TIMER_CNTPCT_LO:
735            return physTimer.value();
736
737          case TIMER_CNTVCT_LO:
738            return virtTimer.value();
739
740          case CTRL_CNTVOFF_LO_BASE:
741            return virtTimer.offset();
742
743          case TIMER_CNTP_CVAL_LO:
744            return physTimer.compareValue();
745
746          case TIMER_CNTV_CVAL_LO:
747            return virtTimer.compareValue();
748
749          default:
750            warn("Unexpected address (0x%x:%i), assuming RAZ\n", addr, size);
751            return 0;
752        }
753    } else {
754        panic("Invalid access size: %i\n", size);
755    }
756}
757
758void
759GenericTimerMem::timerWrite(Addr addr, size_t size, uint64_t value)
760{
761    if (size == 4) {
762        switch (addr) {
763          case TIMER_CNTEL0ACR:
764            warn("Unimplemented timer register (0x%x)\n", addr);
765            return;
766
767          case TIMER_CNTP_CVAL_LO:
768            physTimer.setCompareValue(
769                insertBits(physTimer.compareValue(), 31, 0, value));
770            return;
771
772          case TIMER_CNTP_CVAL_HI:
773            physTimer.setCompareValue(
774                insertBits(physTimer.compareValue(), 63, 32, value));
775            return;
776
777          case TIMER_CNTP_TVAL:
778            physTimer.setTimerValue(value);
779            return;
780
781          case TIMER_CNTP_CTL:
782            physTimer.setControl(value);
783            return;
784
785          case TIMER_CNTV_CVAL_LO:
786            virtTimer.setCompareValue(
787                insertBits(virtTimer.compareValue(), 31, 0, value));
788            return;
789
790          case TIMER_CNTV_CVAL_HI:
791            virtTimer.setCompareValue(
792                insertBits(virtTimer.compareValue(), 63, 32, value));
793            return;
794
795          case TIMER_CNTV_TVAL:
796            virtTimer.setTimerValue(value);
797            return;
798
799          case TIMER_CNTV_CTL:
800            virtTimer.setControl(value);
801            return;
802
803          default:
804            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
805            return;
806        }
807    } else if (size == 8) {
808        switch (addr) {
809          case TIMER_CNTP_CVAL_LO:
810            return physTimer.setCompareValue(value);
811
812          case TIMER_CNTV_CVAL_LO:
813            return virtTimer.setCompareValue(value);
814
815          default:
816            warn("Unexpected address (0x%x:%i), ignoring write\n", addr, size);
817            return;
818        }
819    } else {
820        panic("Invalid access size: %i\n", size);
821    }
822}
823
824GenericTimer *
825GenericTimerParams::create()
826{
827    return new GenericTimer(this);
828}
829
830GenericTimerMem *
831GenericTimerMemParams::create()
832{
833    return new GenericTimerMem(this);
834}
835