generic_timer.cc revision 10847
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 §ion) 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 §ion) 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 §ion) 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 §ion) 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