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