2 * Copyright (c) 2010-2013 ARM Limited
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.
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.
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.
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"
50 CpuLocalTimer::CpuLocalTimer(Params
*p
)
51 : BasicPioDevice(p
, 0x38), gic(p
->gic
)
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
;
65 CpuLocalTimer::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)
73 CpuLocalTimer::read(PacketPtr pkt
)
75 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
76 assert(pkt
->getSize() == 4);
77 Addr daddr
= pkt
->getAddr() - pioAddr
;
78 int cpu_id
= pkt
->req
->contextId();
79 DPRINTF(Timer
, "Reading from CpuLocalTimer at offset: %#x\n", daddr
);
81 assert(cpu_id
< CPU_MAX
);
83 if (daddr
< Timer::Size
)
84 localTimer
[cpu_id
].read(pkt
, daddr
);
86 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr
);
87 pkt
->makeAtomicResponse();
93 CpuLocalTimer::Timer::read(PacketPtr pkt
, Addr daddr
)
95 DPRINTF(Timer
, "Reading from CpuLocalTimer at offset: %#x\n", daddr
);
100 pkt
->set
<uint32_t>(timerLoadValue
);
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
);
112 case TimerControlReg
:
113 pkt
->set
<uint32_t>(timerControl
);
115 case TimerIntStatusReg
:
116 pkt
->set
<uint32_t>(rawIntTimer
);
118 case WatchdogLoadReg
:
119 pkt
->set
<uint32_t>(watchdogLoadValue
);
121 case WatchdogCounterReg
:
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
);
132 case WatchdogControlReg
:
133 pkt
->set
<uint32_t>(watchdogControl
);
135 case WatchdogIntStatusReg
:
136 pkt
->set
<uint32_t>(rawIntWatchdog
);
138 case WatchdogResetStatusReg
:
139 pkt
->set
<uint32_t>(rawResetWatchdog
);
141 case WatchdogDisableReg
:
142 panic("Tried to read from WatchdogDisableRegister\n");
145 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr
);
151 CpuLocalTimer::write(PacketPtr pkt
)
153 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
154 assert(pkt
->getSize() == 4);
155 Addr daddr
= pkt
->getAddr() - pioAddr
;
156 int cpu_id
= pkt
->req
->contextId();
157 DPRINTF(Timer
, "Writing to CpuLocalTimer at offset: %#x\n", daddr
);
159 assert(cpu_id
< CPU_MAX
);
161 if (daddr
< Timer::Size
)
162 localTimer
[cpu_id
].write(pkt
, daddr
);
164 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr
);
165 pkt
->makeAtomicResponse();
170 CpuLocalTimer::Timer::write(PacketPtr pkt
, Addr daddr
)
172 DPRINTF(Timer
, "Writing to CpuLocalTimer at offset: %#x\n", daddr
);
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
);
184 case TimerCounterReg
:
185 // Can be written, doesn't start counting unless the timer is enabled
186 restartTimerCounter(pkt
->get
<uint32_t>());
188 case TimerControlReg
:
189 old_enable
= timerControl
.enable
;
190 timerControl
= pkt
->get
<uint32_t>();
191 if ((old_enable
== 0) && timerControl
.enable
)
192 restartTimerCounter(timerLoadValue
);
194 case TimerIntStatusReg
:
196 if (pendingIntTimer
) {
197 pendingIntTimer
= false;
198 DPRINTF(Timer
, "Clearing interrupt\n");
201 case WatchdogLoadReg
:
202 watchdogLoadValue
= pkt
->get
<uint32_t>();
203 restartWatchdogCounter(watchdogLoadValue
);
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>());
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;
221 case WatchdogIntStatusReg
:
222 rawIntWatchdog
= false;
223 if (pendingIntWatchdog
) {
224 pendingIntWatchdog
= false;
225 DPRINTF(Timer
, "Clearing watchdog interrupt\n");
228 case WatchdogResetStatusReg
:
229 rawResetWatchdog
= false;
230 DPRINTF(Timer
, "Clearing watchdog reset flag\n");
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;
240 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr
);
245 //XXX: Two functions are needed because the control registers are different types
247 CpuLocalTimer::Timer::restartTimerCounter(uint32_t val
)
249 DPRINTF(Timer
, "Resetting timer counter with value %#x\n", val
);
250 if (!timerControl
.enable
)
253 Tick time
= parent
->clockPeriod() * power(16, timerControl
.prescalar
);
256 if (timerZeroEvent
.scheduled()) {
257 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
258 parent
->deschedule(timerZeroEvent
);
260 parent
->schedule(timerZeroEvent
, curTick() + time
);
261 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", curTick() + time
);
265 CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val
)
267 DPRINTF(Timer
, "Resetting watchdog counter with value %#x\n", val
);
268 if (!watchdogControl
.enable
)
271 Tick time
= parent
->clockPeriod() * power(16, watchdogControl
.prescalar
);
274 if (watchdogZeroEvent
.scheduled()) {
275 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
276 parent
->deschedule(watchdogZeroEvent
);
278 parent
->schedule(watchdogZeroEvent
, curTick() + time
);
279 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", curTick() + time
);
284 CpuLocalTimer::Timer::timerAtZero()
286 if (!timerControl
.enable
)
289 DPRINTF(Timer
, "Timer Counter reached zero\n");
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
);
300 if (!timerControl
.autoReload
)
303 restartTimerCounter(timerLoadValue
);
307 CpuLocalTimer::Timer::watchdogAtZero()
309 if (!watchdogControl
.enable
)
312 DPRINTF(Timer
, "Watchdog Counter reached zero\n");
314 rawIntWatchdog
= true;
315 bool old_pending
= pendingIntWatchdog
;
316 // generates an interrupt only if the watchdog is in timer
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?
326 if (pendingIntWatchdog
&& !old_pending
) {
327 DPRINTF(Timer
, "-- Causing interrupt\n");
328 parent
->gic
->sendPPInt(intNumWatchdog
, cpuNum
);
331 if (watchdogControl
.watchdogMode
)
333 else if (watchdogControl
.autoReload
)
334 restartWatchdogCounter(watchdogLoadValue
);
338 CpuLocalTimer::Timer::serialize(std::ostream
&os
)
340 DPRINTF(Checkpoint
, "Serializing Arm CpuLocalTimer\n");
341 SERIALIZE_SCALAR(intNumTimer
);
342 SERIALIZE_SCALAR(intNumWatchdog
);
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
);
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
);
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
);
363 Tick timer_event_time
;
364 if (timer_is_in_event
){
365 timer_event_time
= timerZeroEvent
.when();
366 SERIALIZE_SCALAR(timer_event_time
);
368 Tick watchdog_event_time
;
369 if (watchdog_is_in_event
){
370 watchdog_event_time
= watchdogZeroEvent
.when();
371 SERIALIZE_SCALAR(watchdog_event_time
);
376 CpuLocalTimer::Timer::unserialize(Checkpoint
*cp
, const std::string
§ion
)
378 DPRINTF(Checkpoint
, "Unserializing Arm CpuLocalTimer\n");
380 UNSERIALIZE_SCALAR(intNumTimer
);
381 UNSERIALIZE_SCALAR(intNumWatchdog
);
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
;
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
);
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
);
404 Tick timer_event_time
;
405 if (timer_is_in_event
){
406 UNSERIALIZE_SCALAR(timer_event_time
);
407 parent
->schedule(timerZeroEvent
, timer_event_time
);
409 Tick watchdog_event_time
;
410 if (watchdog_is_in_event
) {
411 UNSERIALIZE_SCALAR(watchdog_event_time
);
412 parent
->schedule(watchdogZeroEvent
, watchdog_event_time
);
419 CpuLocalTimer::serialize(std::ostream
&os
)
421 for (int i
= 0; i
< CPU_MAX
; i
++) {
422 nameOut(os
, csprintf("%s.timer%d", name(), i
));
423 localTimer
[i
].serialize(os
);
428 CpuLocalTimer::unserialize(Checkpoint
*cp
, const std::string
§ion
)
430 for (int i
= 0; i
< CPU_MAX
; i
++) {
431 localTimer
[i
].unserialize(cp
, csprintf("%s.timer%d", section
, i
));
436 CpuLocalTimerParams::create()
438 return new CpuLocalTimer(this);