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