timer_cpulocal.cc (9808:13ffc0066b76) | timer_cpulocal.cc (10565:23593fdaadcd) |
---|---|
1/* 2 * Copyright (c) 2010-2013 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: Ali Saidi 38 * Geoffrey Blake 39 */ 40 41#include "base/intmath.hh" 42#include "base/trace.hh" 43#include "debug/Checkpoint.hh" 44#include "debug/Timer.hh" 45#include "dev/arm/base_gic.hh" 46#include "dev/arm/timer_cpulocal.hh" 47#include "mem/packet.hh" 48#include "mem/packet_access.hh" 49 50CpuLocalTimer::CpuLocalTimer(Params *p) 51 : BasicPioDevice(p, 0x38), gic(p->gic) 52{ 53 // Initialize the timer registers for each per cpu timer 54 for (int i = 0; i < CPU_MAX; i++) { 55 std::stringstream oss; 56 oss << name() << ".timer" << i; 57 localTimer[i]._name = oss.str(); 58 localTimer[i].parent = this; 59 localTimer[i].intNumTimer = p->int_num_timer; 60 localTimer[i].intNumWatchdog = p->int_num_watchdog; 61 localTimer[i].cpuNum = i; 62 } 63} 64 65CpuLocalTimer::Timer::Timer() 66 : timerControl(0x0), watchdogControl(0x0), rawIntTimer(false), rawIntWatchdog(false), 67 rawResetWatchdog(false), watchdogDisableReg(0x0), pendingIntTimer(false), pendingIntWatchdog(false), 68 timerLoadValue(0x0), watchdogLoadValue(0x0), timerZeroEvent(this), watchdogZeroEvent(this) 69{ 70} 71 72Tick 73CpuLocalTimer::read(PacketPtr pkt) 74{ 75 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 76 assert(pkt->getSize() == 4); 77 Addr daddr = pkt->getAddr() - pioAddr; | 1/* 2 * Copyright (c) 2010-2013 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: Ali Saidi 38 * Geoffrey Blake 39 */ 40 41#include "base/intmath.hh" 42#include "base/trace.hh" 43#include "debug/Checkpoint.hh" 44#include "debug/Timer.hh" 45#include "dev/arm/base_gic.hh" 46#include "dev/arm/timer_cpulocal.hh" 47#include "mem/packet.hh" 48#include "mem/packet_access.hh" 49 50CpuLocalTimer::CpuLocalTimer(Params *p) 51 : BasicPioDevice(p, 0x38), gic(p->gic) 52{ 53 // Initialize the timer registers for each per cpu timer 54 for (int i = 0; i < CPU_MAX; i++) { 55 std::stringstream oss; 56 oss << name() << ".timer" << i; 57 localTimer[i]._name = oss.str(); 58 localTimer[i].parent = this; 59 localTimer[i].intNumTimer = p->int_num_timer; 60 localTimer[i].intNumWatchdog = p->int_num_watchdog; 61 localTimer[i].cpuNum = i; 62 } 63} 64 65CpuLocalTimer::Timer::Timer() 66 : timerControl(0x0), watchdogControl(0x0), rawIntTimer(false), rawIntWatchdog(false), 67 rawResetWatchdog(false), watchdogDisableReg(0x0), pendingIntTimer(false), pendingIntWatchdog(false), 68 timerLoadValue(0x0), watchdogLoadValue(0x0), timerZeroEvent(this), watchdogZeroEvent(this) 69{ 70} 71 72Tick 73CpuLocalTimer::read(PacketPtr pkt) 74{ 75 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 76 assert(pkt->getSize() == 4); 77 Addr daddr = pkt->getAddr() - pioAddr; |
78 pkt->allocate(); | |
79 int cpu_id = pkt->req->contextId(); 80 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 81 assert(cpu_id >= 0); 82 assert(cpu_id < CPU_MAX); 83 84 if (daddr < Timer::Size) 85 localTimer[cpu_id].read(pkt, daddr); 86 else 87 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 88 pkt->makeAtomicResponse(); 89 return pioDelay; 90} 91 92 93void 94CpuLocalTimer::Timer::read(PacketPtr pkt, Addr daddr) 95{ 96 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 97 Tick time; 98 99 switch(daddr) { 100 case TimerLoadReg: 101 pkt->set<uint32_t>(timerLoadValue); 102 break; 103 case TimerCounterReg: 104 DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n", 105 timerZeroEvent.when(), parent->clockPeriod(), 106 timerControl.prescalar); 107 time = timerZeroEvent.when() - curTick(); 108 time = time / parent->clockPeriod() / 109 power(16, timerControl.prescalar); 110 DPRINTF(Timer, "-- returning counter at %d\n", time); 111 pkt->set<uint32_t>(time); 112 break; 113 case TimerControlReg: 114 pkt->set<uint32_t>(timerControl); 115 break; 116 case TimerIntStatusReg: 117 pkt->set<uint32_t>(rawIntTimer); 118 break; 119 case WatchdogLoadReg: 120 pkt->set<uint32_t>(watchdogLoadValue); 121 break; 122 case WatchdogCounterReg: 123 DPRINTF(Timer, 124 "Event schedule for watchdog %d, clock=%d, prescale=%d\n", 125 watchdogZeroEvent.when(), parent->clockPeriod(), 126 watchdogControl.prescalar); 127 time = watchdogZeroEvent.when() - curTick(); 128 time = time / parent->clockPeriod() / 129 power(16, watchdogControl.prescalar); 130 DPRINTF(Timer, "-- returning counter at %d\n", time); 131 pkt->set<uint32_t>(time); 132 break; 133 case WatchdogControlReg: 134 pkt->set<uint32_t>(watchdogControl); 135 break; 136 case WatchdogIntStatusReg: 137 pkt->set<uint32_t>(rawIntWatchdog); 138 break; 139 case WatchdogResetStatusReg: 140 pkt->set<uint32_t>(rawResetWatchdog); 141 break; 142 case WatchdogDisableReg: 143 panic("Tried to read from WatchdogDisableRegister\n"); 144 break; 145 default: 146 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr); 147 break; 148 } 149} 150 151Tick 152CpuLocalTimer::write(PacketPtr pkt) 153{ 154 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 155 assert(pkt->getSize() == 4); 156 Addr daddr = pkt->getAddr() - pioAddr; | 78 int cpu_id = pkt->req->contextId(); 79 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 80 assert(cpu_id >= 0); 81 assert(cpu_id < CPU_MAX); 82 83 if (daddr < Timer::Size) 84 localTimer[cpu_id].read(pkt, daddr); 85 else 86 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 87 pkt->makeAtomicResponse(); 88 return pioDelay; 89} 90 91 92void 93CpuLocalTimer::Timer::read(PacketPtr pkt, Addr daddr) 94{ 95 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr); 96 Tick time; 97 98 switch(daddr) { 99 case TimerLoadReg: 100 pkt->set<uint32_t>(timerLoadValue); 101 break; 102 case TimerCounterReg: 103 DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n", 104 timerZeroEvent.when(), parent->clockPeriod(), 105 timerControl.prescalar); 106 time = timerZeroEvent.when() - curTick(); 107 time = time / parent->clockPeriod() / 108 power(16, timerControl.prescalar); 109 DPRINTF(Timer, "-- returning counter at %d\n", time); 110 pkt->set<uint32_t>(time); 111 break; 112 case TimerControlReg: 113 pkt->set<uint32_t>(timerControl); 114 break; 115 case TimerIntStatusReg: 116 pkt->set<uint32_t>(rawIntTimer); 117 break; 118 case WatchdogLoadReg: 119 pkt->set<uint32_t>(watchdogLoadValue); 120 break; 121 case WatchdogCounterReg: 122 DPRINTF(Timer, 123 "Event schedule for watchdog %d, clock=%d, prescale=%d\n", 124 watchdogZeroEvent.when(), parent->clockPeriod(), 125 watchdogControl.prescalar); 126 time = watchdogZeroEvent.when() - curTick(); 127 time = time / parent->clockPeriod() / 128 power(16, watchdogControl.prescalar); 129 DPRINTF(Timer, "-- returning counter at %d\n", time); 130 pkt->set<uint32_t>(time); 131 break; 132 case WatchdogControlReg: 133 pkt->set<uint32_t>(watchdogControl); 134 break; 135 case WatchdogIntStatusReg: 136 pkt->set<uint32_t>(rawIntWatchdog); 137 break; 138 case WatchdogResetStatusReg: 139 pkt->set<uint32_t>(rawResetWatchdog); 140 break; 141 case WatchdogDisableReg: 142 panic("Tried to read from WatchdogDisableRegister\n"); 143 break; 144 default: 145 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr); 146 break; 147 } 148} 149 150Tick 151CpuLocalTimer::write(PacketPtr pkt) 152{ 153 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 154 assert(pkt->getSize() == 4); 155 Addr daddr = pkt->getAddr() - pioAddr; |
157 pkt->allocate(); | |
158 int cpu_id = pkt->req->contextId(); 159 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 160 assert(cpu_id >= 0); 161 assert(cpu_id < CPU_MAX); 162 163 if (daddr < Timer::Size) 164 localTimer[cpu_id].write(pkt, daddr); 165 else 166 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 167 pkt->makeAtomicResponse(); 168 return pioDelay; 169} 170 171void 172CpuLocalTimer::Timer::write(PacketPtr pkt, Addr daddr) 173{ 174 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 175 bool old_enable; 176 bool old_wd_mode; 177 uint32_t old_val; 178 179 switch (daddr) { 180 case TimerLoadReg: 181 // Writing to this register also resets the counter register and 182 // starts decrementing if the counter is enabled. 183 timerLoadValue = pkt->get<uint32_t>(); 184 restartTimerCounter(timerLoadValue); 185 break; 186 case TimerCounterReg: 187 // Can be written, doesn't start counting unless the timer is enabled 188 restartTimerCounter(pkt->get<uint32_t>()); 189 break; 190 case TimerControlReg: 191 old_enable = timerControl.enable; 192 timerControl = pkt->get<uint32_t>(); 193 if ((old_enable == 0) && timerControl.enable) 194 restartTimerCounter(timerLoadValue); 195 break; 196 case TimerIntStatusReg: 197 rawIntTimer = false; 198 if (pendingIntTimer) { 199 pendingIntTimer = false; 200 DPRINTF(Timer, "Clearing interrupt\n"); 201 } 202 break; 203 case WatchdogLoadReg: 204 watchdogLoadValue = pkt->get<uint32_t>(); 205 restartWatchdogCounter(watchdogLoadValue); 206 break; 207 case WatchdogCounterReg: 208 // Can't be written when in watchdog mode, but can in timer mode 209 if (!watchdogControl.watchdogMode) { 210 restartWatchdogCounter(pkt->get<uint32_t>()); 211 } 212 break; 213 case WatchdogControlReg: 214 old_enable = watchdogControl.enable; 215 old_wd_mode = watchdogControl.watchdogMode; 216 watchdogControl = pkt->get<uint32_t>(); 217 if ((old_enable == 0) && watchdogControl.enable) 218 restartWatchdogCounter(watchdogLoadValue); 219 // cannot disable watchdog using control register 220 if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0) 221 watchdogControl.watchdogMode = 1; 222 break; 223 case WatchdogIntStatusReg: 224 rawIntWatchdog = false; 225 if (pendingIntWatchdog) { 226 pendingIntWatchdog = false; 227 DPRINTF(Timer, "Clearing watchdog interrupt\n"); 228 } 229 break; 230 case WatchdogResetStatusReg: 231 rawResetWatchdog = false; 232 DPRINTF(Timer, "Clearing watchdog reset flag\n"); 233 break; 234 case WatchdogDisableReg: 235 old_val = watchdogDisableReg; 236 watchdogDisableReg = pkt->get<uint32_t>(); 237 // if this sequence is observed, turn off watchdog mode 238 if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321) 239 watchdogControl.watchdogMode = 0; 240 break; 241 default: 242 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr); 243 break; 244 } 245} 246 247//XXX: Two functions are needed because the control registers are different types 248void 249CpuLocalTimer::Timer::restartTimerCounter(uint32_t val) 250{ 251 DPRINTF(Timer, "Resetting timer counter with value %#x\n", val); 252 if (!timerControl.enable) 253 return; 254 255 Tick time = parent->clockPeriod() * power(16, timerControl.prescalar); 256 time *= val; 257 258 if (timerZeroEvent.scheduled()) { 259 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 260 parent->deschedule(timerZeroEvent); 261 } 262 parent->schedule(timerZeroEvent, curTick() + time); 263 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 264} 265 266void 267CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val) 268{ 269 DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val); 270 if (!watchdogControl.enable) 271 return; 272 273 Tick time = parent->clockPeriod() * power(16, watchdogControl.prescalar); 274 time *= val; 275 276 if (watchdogZeroEvent.scheduled()) { 277 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 278 parent->deschedule(watchdogZeroEvent); 279 } 280 parent->schedule(watchdogZeroEvent, curTick() + time); 281 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 282} 283////// 284 285void 286CpuLocalTimer::Timer::timerAtZero() 287{ 288 if (!timerControl.enable) 289 return; 290 291 DPRINTF(Timer, "Timer Counter reached zero\n"); 292 293 rawIntTimer = true; 294 bool old_pending = pendingIntTimer; 295 if (timerControl.intEnable) 296 pendingIntTimer = true; 297 if (pendingIntTimer && !old_pending) { 298 DPRINTF(Timer, "-- Causing interrupt\n"); 299 parent->gic->sendPPInt(intNumTimer, cpuNum); 300 } 301 302 if (!timerControl.autoReload) 303 return; 304 else 305 restartTimerCounter(timerLoadValue); 306} 307 308void 309CpuLocalTimer::Timer::watchdogAtZero() 310{ 311 if (!watchdogControl.enable) 312 return; 313 314 DPRINTF(Timer, "Watchdog Counter reached zero\n"); 315 316 rawIntWatchdog = true; 317 bool old_pending = pendingIntWatchdog; 318 // generates an interrupt only if the watchdog is in timer 319 // mode. 320 if (watchdogControl.intEnable && !watchdogControl.watchdogMode) 321 pendingIntWatchdog = true; 322 else if (watchdogControl.watchdogMode) { 323 rawResetWatchdog = true; 324 fatal("gem5 ARM Model does not support true watchdog operation!\n"); 325 //XXX: Should we ever support a true watchdog reset? 326 } 327 328 if (pendingIntWatchdog && !old_pending) { 329 DPRINTF(Timer, "-- Causing interrupt\n"); 330 parent->gic->sendPPInt(intNumWatchdog, cpuNum); 331 } 332 333 if (watchdogControl.watchdogMode) 334 return; 335 else if (watchdogControl.autoReload) 336 restartWatchdogCounter(watchdogLoadValue); 337} 338 339void 340CpuLocalTimer::Timer::serialize(std::ostream &os) 341{ 342 DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n"); 343 SERIALIZE_SCALAR(intNumTimer); 344 SERIALIZE_SCALAR(intNumWatchdog); 345 346 uint32_t timer_control_serial = timerControl; 347 uint32_t watchdog_control_serial = watchdogControl; 348 SERIALIZE_SCALAR(timer_control_serial); 349 SERIALIZE_SCALAR(watchdog_control_serial); 350 351 SERIALIZE_SCALAR(rawIntTimer); 352 SERIALIZE_SCALAR(rawIntWatchdog); 353 SERIALIZE_SCALAR(rawResetWatchdog); 354 SERIALIZE_SCALAR(watchdogDisableReg); 355 SERIALIZE_SCALAR(pendingIntTimer); 356 SERIALIZE_SCALAR(pendingIntWatchdog); 357 SERIALIZE_SCALAR(timerLoadValue); 358 SERIALIZE_SCALAR(watchdogLoadValue); 359 360 bool timer_is_in_event = timerZeroEvent.scheduled(); 361 SERIALIZE_SCALAR(timer_is_in_event); 362 bool watchdog_is_in_event = watchdogZeroEvent.scheduled(); 363 SERIALIZE_SCALAR(watchdog_is_in_event); 364 365 Tick timer_event_time; 366 if (timer_is_in_event){ 367 timer_event_time = timerZeroEvent.when(); 368 SERIALIZE_SCALAR(timer_event_time); 369 } 370 Tick watchdog_event_time; 371 if (watchdog_is_in_event){ 372 watchdog_event_time = watchdogZeroEvent.when(); 373 SERIALIZE_SCALAR(watchdog_event_time); 374 } 375} 376 377void 378CpuLocalTimer::Timer::unserialize(Checkpoint *cp, const std::string §ion) 379{ 380 DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n"); 381 382 UNSERIALIZE_SCALAR(intNumTimer); 383 UNSERIALIZE_SCALAR(intNumWatchdog); 384 385 uint32_t timer_control_serial; 386 UNSERIALIZE_SCALAR(timer_control_serial); 387 timerControl = timer_control_serial; 388 uint32_t watchdog_control_serial; 389 UNSERIALIZE_SCALAR(watchdog_control_serial); 390 watchdogControl = watchdog_control_serial; 391 392 UNSERIALIZE_SCALAR(rawIntTimer); 393 UNSERIALIZE_SCALAR(rawIntWatchdog); 394 UNSERIALIZE_SCALAR(rawResetWatchdog); 395 UNSERIALIZE_SCALAR(watchdogDisableReg); 396 UNSERIALIZE_SCALAR(pendingIntTimer); 397 UNSERIALIZE_SCALAR(pendingIntWatchdog); 398 UNSERIALIZE_SCALAR(timerLoadValue); 399 UNSERIALIZE_SCALAR(watchdogLoadValue); 400 401 bool timer_is_in_event; 402 UNSERIALIZE_SCALAR(timer_is_in_event); 403 bool watchdog_is_in_event; 404 UNSERIALIZE_SCALAR(watchdog_is_in_event); 405 406 Tick timer_event_time; 407 if (timer_is_in_event){ 408 UNSERIALIZE_SCALAR(timer_event_time); 409 parent->schedule(timerZeroEvent, timer_event_time); 410 } 411 Tick watchdog_event_time; 412 if (watchdog_is_in_event) { 413 UNSERIALIZE_SCALAR(watchdog_event_time); 414 parent->schedule(watchdogZeroEvent, watchdog_event_time); 415 } 416} 417 418 419 420void 421CpuLocalTimer::serialize(std::ostream &os) 422{ 423 for (int i = 0; i < CPU_MAX; i++) { 424 nameOut(os, csprintf("%s.timer%d", name(), i)); 425 localTimer[i].serialize(os); 426 } 427} 428 429void 430CpuLocalTimer::unserialize(Checkpoint *cp, const std::string §ion) 431{ 432 for (int i = 0; i < CPU_MAX; i++) { 433 localTimer[i].unserialize(cp, csprintf("%s.timer%d", section, i)); 434 } 435} 436 437CpuLocalTimer * 438CpuLocalTimerParams::create() 439{ 440 return new CpuLocalTimer(this); 441} | 156 int cpu_id = pkt->req->contextId(); 157 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 158 assert(cpu_id >= 0); 159 assert(cpu_id < CPU_MAX); 160 161 if (daddr < Timer::Size) 162 localTimer[cpu_id].write(pkt, daddr); 163 else 164 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr); 165 pkt->makeAtomicResponse(); 166 return pioDelay; 167} 168 169void 170CpuLocalTimer::Timer::write(PacketPtr pkt, Addr daddr) 171{ 172 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr); 173 bool old_enable; 174 bool old_wd_mode; 175 uint32_t old_val; 176 177 switch (daddr) { 178 case TimerLoadReg: 179 // Writing to this register also resets the counter register and 180 // starts decrementing if the counter is enabled. 181 timerLoadValue = pkt->get<uint32_t>(); 182 restartTimerCounter(timerLoadValue); 183 break; 184 case TimerCounterReg: 185 // Can be written, doesn't start counting unless the timer is enabled 186 restartTimerCounter(pkt->get<uint32_t>()); 187 break; 188 case TimerControlReg: 189 old_enable = timerControl.enable; 190 timerControl = pkt->get<uint32_t>(); 191 if ((old_enable == 0) && timerControl.enable) 192 restartTimerCounter(timerLoadValue); 193 break; 194 case TimerIntStatusReg: 195 rawIntTimer = false; 196 if (pendingIntTimer) { 197 pendingIntTimer = false; 198 DPRINTF(Timer, "Clearing interrupt\n"); 199 } 200 break; 201 case WatchdogLoadReg: 202 watchdogLoadValue = pkt->get<uint32_t>(); 203 restartWatchdogCounter(watchdogLoadValue); 204 break; 205 case WatchdogCounterReg: 206 // Can't be written when in watchdog mode, but can in timer mode 207 if (!watchdogControl.watchdogMode) { 208 restartWatchdogCounter(pkt->get<uint32_t>()); 209 } 210 break; 211 case WatchdogControlReg: 212 old_enable = watchdogControl.enable; 213 old_wd_mode = watchdogControl.watchdogMode; 214 watchdogControl = pkt->get<uint32_t>(); 215 if ((old_enable == 0) && watchdogControl.enable) 216 restartWatchdogCounter(watchdogLoadValue); 217 // cannot disable watchdog using control register 218 if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0) 219 watchdogControl.watchdogMode = 1; 220 break; 221 case WatchdogIntStatusReg: 222 rawIntWatchdog = false; 223 if (pendingIntWatchdog) { 224 pendingIntWatchdog = false; 225 DPRINTF(Timer, "Clearing watchdog interrupt\n"); 226 } 227 break; 228 case WatchdogResetStatusReg: 229 rawResetWatchdog = false; 230 DPRINTF(Timer, "Clearing watchdog reset flag\n"); 231 break; 232 case WatchdogDisableReg: 233 old_val = watchdogDisableReg; 234 watchdogDisableReg = pkt->get<uint32_t>(); 235 // if this sequence is observed, turn off watchdog mode 236 if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321) 237 watchdogControl.watchdogMode = 0; 238 break; 239 default: 240 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr); 241 break; 242 } 243} 244 245//XXX: Two functions are needed because the control registers are different types 246void 247CpuLocalTimer::Timer::restartTimerCounter(uint32_t val) 248{ 249 DPRINTF(Timer, "Resetting timer counter with value %#x\n", val); 250 if (!timerControl.enable) 251 return; 252 253 Tick time = parent->clockPeriod() * power(16, timerControl.prescalar); 254 time *= val; 255 256 if (timerZeroEvent.scheduled()) { 257 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 258 parent->deschedule(timerZeroEvent); 259 } 260 parent->schedule(timerZeroEvent, curTick() + time); 261 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 262} 263 264void 265CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val) 266{ 267 DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val); 268 if (!watchdogControl.enable) 269 return; 270 271 Tick time = parent->clockPeriod() * power(16, watchdogControl.prescalar); 272 time *= val; 273 274 if (watchdogZeroEvent.scheduled()) { 275 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 276 parent->deschedule(watchdogZeroEvent); 277 } 278 parent->schedule(watchdogZeroEvent, curTick() + time); 279 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 280} 281////// 282 283void 284CpuLocalTimer::Timer::timerAtZero() 285{ 286 if (!timerControl.enable) 287 return; 288 289 DPRINTF(Timer, "Timer Counter reached zero\n"); 290 291 rawIntTimer = true; 292 bool old_pending = pendingIntTimer; 293 if (timerControl.intEnable) 294 pendingIntTimer = true; 295 if (pendingIntTimer && !old_pending) { 296 DPRINTF(Timer, "-- Causing interrupt\n"); 297 parent->gic->sendPPInt(intNumTimer, cpuNum); 298 } 299 300 if (!timerControl.autoReload) 301 return; 302 else 303 restartTimerCounter(timerLoadValue); 304} 305 306void 307CpuLocalTimer::Timer::watchdogAtZero() 308{ 309 if (!watchdogControl.enable) 310 return; 311 312 DPRINTF(Timer, "Watchdog Counter reached zero\n"); 313 314 rawIntWatchdog = true; 315 bool old_pending = pendingIntWatchdog; 316 // generates an interrupt only if the watchdog is in timer 317 // mode. 318 if (watchdogControl.intEnable && !watchdogControl.watchdogMode) 319 pendingIntWatchdog = true; 320 else if (watchdogControl.watchdogMode) { 321 rawResetWatchdog = true; 322 fatal("gem5 ARM Model does not support true watchdog operation!\n"); 323 //XXX: Should we ever support a true watchdog reset? 324 } 325 326 if (pendingIntWatchdog && !old_pending) { 327 DPRINTF(Timer, "-- Causing interrupt\n"); 328 parent->gic->sendPPInt(intNumWatchdog, cpuNum); 329 } 330 331 if (watchdogControl.watchdogMode) 332 return; 333 else if (watchdogControl.autoReload) 334 restartWatchdogCounter(watchdogLoadValue); 335} 336 337void 338CpuLocalTimer::Timer::serialize(std::ostream &os) 339{ 340 DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n"); 341 SERIALIZE_SCALAR(intNumTimer); 342 SERIALIZE_SCALAR(intNumWatchdog); 343 344 uint32_t timer_control_serial = timerControl; 345 uint32_t watchdog_control_serial = watchdogControl; 346 SERIALIZE_SCALAR(timer_control_serial); 347 SERIALIZE_SCALAR(watchdog_control_serial); 348 349 SERIALIZE_SCALAR(rawIntTimer); 350 SERIALIZE_SCALAR(rawIntWatchdog); 351 SERIALIZE_SCALAR(rawResetWatchdog); 352 SERIALIZE_SCALAR(watchdogDisableReg); 353 SERIALIZE_SCALAR(pendingIntTimer); 354 SERIALIZE_SCALAR(pendingIntWatchdog); 355 SERIALIZE_SCALAR(timerLoadValue); 356 SERIALIZE_SCALAR(watchdogLoadValue); 357 358 bool timer_is_in_event = timerZeroEvent.scheduled(); 359 SERIALIZE_SCALAR(timer_is_in_event); 360 bool watchdog_is_in_event = watchdogZeroEvent.scheduled(); 361 SERIALIZE_SCALAR(watchdog_is_in_event); 362 363 Tick timer_event_time; 364 if (timer_is_in_event){ 365 timer_event_time = timerZeroEvent.when(); 366 SERIALIZE_SCALAR(timer_event_time); 367 } 368 Tick watchdog_event_time; 369 if (watchdog_is_in_event){ 370 watchdog_event_time = watchdogZeroEvent.when(); 371 SERIALIZE_SCALAR(watchdog_event_time); 372 } 373} 374 375void 376CpuLocalTimer::Timer::unserialize(Checkpoint *cp, const std::string §ion) 377{ 378 DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n"); 379 380 UNSERIALIZE_SCALAR(intNumTimer); 381 UNSERIALIZE_SCALAR(intNumWatchdog); 382 383 uint32_t timer_control_serial; 384 UNSERIALIZE_SCALAR(timer_control_serial); 385 timerControl = timer_control_serial; 386 uint32_t watchdog_control_serial; 387 UNSERIALIZE_SCALAR(watchdog_control_serial); 388 watchdogControl = watchdog_control_serial; 389 390 UNSERIALIZE_SCALAR(rawIntTimer); 391 UNSERIALIZE_SCALAR(rawIntWatchdog); 392 UNSERIALIZE_SCALAR(rawResetWatchdog); 393 UNSERIALIZE_SCALAR(watchdogDisableReg); 394 UNSERIALIZE_SCALAR(pendingIntTimer); 395 UNSERIALIZE_SCALAR(pendingIntWatchdog); 396 UNSERIALIZE_SCALAR(timerLoadValue); 397 UNSERIALIZE_SCALAR(watchdogLoadValue); 398 399 bool timer_is_in_event; 400 UNSERIALIZE_SCALAR(timer_is_in_event); 401 bool watchdog_is_in_event; 402 UNSERIALIZE_SCALAR(watchdog_is_in_event); 403 404 Tick timer_event_time; 405 if (timer_is_in_event){ 406 UNSERIALIZE_SCALAR(timer_event_time); 407 parent->schedule(timerZeroEvent, timer_event_time); 408 } 409 Tick watchdog_event_time; 410 if (watchdog_is_in_event) { 411 UNSERIALIZE_SCALAR(watchdog_event_time); 412 parent->schedule(watchdogZeroEvent, watchdog_event_time); 413 } 414} 415 416 417 418void 419CpuLocalTimer::serialize(std::ostream &os) 420{ 421 for (int i = 0; i < CPU_MAX; i++) { 422 nameOut(os, csprintf("%s.timer%d", name(), i)); 423 localTimer[i].serialize(os); 424 } 425} 426 427void 428CpuLocalTimer::unserialize(Checkpoint *cp, const std::string §ion) 429{ 430 for (int i = 0; i < CPU_MAX; i++) { 431 localTimer[i].unserialize(cp, csprintf("%s.timer%d", section, i)); 432 } 433} 434 435CpuLocalTimer * 436CpuLocalTimerParams::create() 437{ 438 return new CpuLocalTimer(this); 439} |