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