gem5 [DEVELOP-FOR-25.1]
Loading...
Searching...
No Matches
timer_cpulocal.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010-2013,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
39
40#include <cassert>
41
42#include "arch/arm/system.hh"
43#include "base/intmath.hh"
44#include "base/logging.hh"
45#include "base/trace.hh"
46#include "debug/Checkpoint.hh"
47#include "debug/Timer.hh"
48#include "dev/arm/base_gic.hh"
49#include "mem/packet.hh"
50#include "mem/packet_access.hh"
51#include "params/CpuLocalTimer.hh"
52
53namespace gem5
54{
55
60
61void
63{
64 const auto &p = params();
65 // Initialize the timer registers for each per cpu timer
66 for (int i = 0; i < sys->threads.size(); i++) {
67 ThreadContext* tc = sys->threads[i];
68 std::stringstream oss;
69 oss << name() << ".timer" << i;
70
71 localTimer.emplace_back(
72 new Timer(oss.str(), this,
73 p.int_timer->get(tc),
74 p.int_watchdog->get(tc)));
75 }
76
78}
79
80CpuLocalTimer::Timer::Timer(const std::string &timer_name,
81 CpuLocalTimer* _parent,
82 ArmInterruptPin* int_timer,
83 ArmInterruptPin* int_watchdog)
84 : _name(timer_name), parent(_parent), intTimer(int_timer),
85 intWatchdog(int_watchdog), timerControl(0x0), watchdogControl(0x0),
86 rawIntTimer(false), rawIntWatchdog(false),
90 timerZeroEvent([this]{ timerAtZero(); }, name()),
91 watchdogZeroEvent([this]{ watchdogAtZero(); }, name())
92{
93}
94
95Tick
97{
98 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
99 assert(pkt->getSize() == 4);
100 Addr daddr = pkt->getAddr() - pioAddr;
101 ContextID cpu_id = pkt->req->contextId();
102 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
103 assert(cpu_id >= 0);
104 assert(cpu_id < localTimer.size());
105
106 if (daddr < Timer::Size)
107 localTimer[cpu_id]->read(pkt, daddr);
108 else
109 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
110 pkt->makeAtomicResponse();
111 return pioDelay;
112}
113
114
115void
117{
118 DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
119 Tick time;
120
121 switch(daddr) {
122 case TimerLoadReg:
123 pkt->setLE<uint32_t>(timerLoadValue);
124 break;
125 case TimerCounterReg:
126 DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n",
127 timerZeroEvent.when(), parent->clockPeriod(),
128 timerControl.prescalar);
129 time = timerZeroEvent.when() - curTick();
130 time = (time / parent->clockPeriod()) >> (4 * timerControl.prescalar);
131 DPRINTF(Timer, "-- returning counter at %d\n", time);
132 pkt->setLE<uint32_t>(time);
133 break;
134 case TimerControlReg:
135 pkt->setLE<uint32_t>(timerControl);
136 break;
138 pkt->setLE<uint32_t>(rawIntTimer);
139 break;
140 case WatchdogLoadReg:
141 pkt->setLE<uint32_t>(watchdogLoadValue);
142 break;
145 "Event schedule for watchdog %d, clock=%d, prescale=%d\n",
146 watchdogZeroEvent.when(), parent->clockPeriod(),
147 watchdogControl.prescalar);
148 time = watchdogZeroEvent.when() - curTick();
149 time = (time / parent->clockPeriod()) >>
150 (4 * watchdogControl.prescalar);
151 DPRINTF(Timer, "-- returning counter at %d\n", time);
152 pkt->setLE<uint32_t>(time);
153 break;
155 pkt->setLE<uint32_t>(watchdogControl);
156 break;
158 pkt->setLE<uint32_t>(rawIntWatchdog);
159 break;
161 pkt->setLE<uint32_t>(rawResetWatchdog);
162 break;
164 panic("Tried to read from WatchdogDisableRegister\n");
165 break;
166 default:
167 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr);
168 break;
169 }
170}
171
172Tick
174{
175 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
176 assert(pkt->getSize() == 4);
177 Addr daddr = pkt->getAddr() - pioAddr;
178 ContextID cpu_id = pkt->req->contextId();
179 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
180 assert(cpu_id >= 0);
181 assert(cpu_id < localTimer.size());
182
183 if (daddr < Timer::Size)
184 localTimer[cpu_id]->write(pkt, daddr);
185 else
186 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
187 pkt->makeAtomicResponse();
188 return pioDelay;
189}
190
191void
193{
194 DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
195 bool old_enable;
196 bool old_wd_mode;
197 uint32_t old_val;
198
199 switch (daddr) {
200 case TimerLoadReg:
201 // Writing to this register also resets the counter register and
202 // starts decrementing if the counter is enabled.
203 timerLoadValue = pkt->getLE<uint32_t>();
205 break;
206 case TimerCounterReg:
207 // Can be written, doesn't start counting unless the timer is enabled
208 restartTimerCounter(pkt->getLE<uint32_t>());
209 break;
210 case TimerControlReg:
211 old_enable = timerControl.enable;
212 timerControl = pkt->getLE<uint32_t>();
213 if ((old_enable == 0) && timerControl.enable)
215 break;
217 rawIntTimer = false;
218 if (pendingIntTimer) {
219 pendingIntTimer = false;
220 DPRINTF(Timer, "Clearing interrupt\n");
221 }
222 break;
223 case WatchdogLoadReg:
224 watchdogLoadValue = pkt->getLE<uint32_t>();
226 break;
228 // Can't be written when in watchdog mode, but can in timer mode
229 if (!watchdogControl.watchdogMode) {
230 restartWatchdogCounter(pkt->getLE<uint32_t>());
231 }
232 break;
234 old_enable = watchdogControl.enable;
235 old_wd_mode = watchdogControl.watchdogMode;
236 watchdogControl = pkt->getLE<uint32_t>();
237 if ((old_enable == 0) && watchdogControl.enable)
239 // cannot disable watchdog using control register
240 if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0)
241 watchdogControl.watchdogMode = 1;
242 break;
244 rawIntWatchdog = false;
245 if (pendingIntWatchdog) {
246 pendingIntWatchdog = false;
247 DPRINTF(Timer, "Clearing watchdog interrupt\n");
248 }
249 break;
251 rawResetWatchdog = false;
252 DPRINTF(Timer, "Clearing watchdog reset flag\n");
253 break;
255 old_val = watchdogDisableReg;
256 watchdogDisableReg = pkt->getLE<uint32_t>();
257 // if this sequence is observed, turn off watchdog mode
258 if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321)
259 watchdogControl.watchdogMode = 0;
260 break;
261 default:
262 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr);
263 break;
264 }
265}
266
267//XXX: Two functions are needed because the control registers are different types
268void
270{
271 DPRINTF(Timer, "Resetting timer counter with value %#x\n", val);
272 if (!timerControl.enable)
273 return;
274
275 Tick time = parent->clockPeriod() << (4 * timerControl.prescalar);
276 time *= val;
277
278 if (timerZeroEvent.scheduled()) {
279 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
280 parent->deschedule(timerZeroEvent);
281 }
282 parent->schedule(timerZeroEvent, curTick() + time);
283 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
284}
285
286void
288{
289 DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val);
290 if (!watchdogControl.enable)
291 return;
292
293 Tick time = parent->clockPeriod() << (4 * watchdogControl.prescalar);
294 time *= val;
295
296 if (watchdogZeroEvent.scheduled()) {
297 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
298 parent->deschedule(watchdogZeroEvent);
299 }
300 parent->schedule(watchdogZeroEvent, curTick() + time);
301 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
302}
303
304
305void
307{
308 if (!timerControl.enable)
309 return;
310
311 DPRINTF(Timer, "Timer Counter reached zero\n");
312
313 rawIntTimer = true;
314 bool old_pending = pendingIntTimer;
315 if (timerControl.intEnable)
316 pendingIntTimer = true;
317 if (pendingIntTimer && !old_pending) {
318 DPRINTF(Timer, "-- Causing interrupt\n");
319 intTimer->raise();
320 }
321
322 if (!timerControl.autoReload)
323 return;
324 else
326}
327
328void
330{
331 if (!watchdogControl.enable)
332 return;
333
334 DPRINTF(Timer, "Watchdog Counter reached zero\n");
335
336 rawIntWatchdog = true;
337 bool old_pending = pendingIntWatchdog;
338 // generates an interrupt only if the watchdog is in timer
339 // mode.
340 if (watchdogControl.intEnable && !watchdogControl.watchdogMode)
341 pendingIntWatchdog = true;
342 else if (watchdogControl.watchdogMode) {
343 rawResetWatchdog = true;
344 fatal("gem5 ARM Model does not support true watchdog operation!\n");
345 //XXX: Should we ever support a true watchdog reset?
346 }
347
348 if (pendingIntWatchdog && !old_pending) {
349 DPRINTF(Timer, "-- Causing interrupt\n");
350 intWatchdog->raise();
351 }
352
353 if (watchdogControl.watchdogMode)
354 return;
355 else if (watchdogControl.autoReload)
357}
358
359void
361{
362 DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n");
363
364 uint32_t timer_control_serial = timerControl;
365 uint32_t watchdog_control_serial = watchdogControl;
366 SERIALIZE_SCALAR(timer_control_serial);
367 SERIALIZE_SCALAR(watchdog_control_serial);
368
377
378 bool timer_is_in_event = timerZeroEvent.scheduled();
379 SERIALIZE_SCALAR(timer_is_in_event);
380 bool watchdog_is_in_event = watchdogZeroEvent.scheduled();
381 SERIALIZE_SCALAR(watchdog_is_in_event);
382
383 Tick timer_event_time;
384 if (timer_is_in_event){
385 timer_event_time = timerZeroEvent.when();
386 SERIALIZE_SCALAR(timer_event_time);
387 }
388 Tick watchdog_event_time;
389 if (watchdog_is_in_event){
390 watchdog_event_time = watchdogZeroEvent.when();
391 SERIALIZE_SCALAR(watchdog_event_time);
392 }
393}
394
395void
397{
398 DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n");
399
400 uint32_t timer_control_serial;
401 UNSERIALIZE_SCALAR(timer_control_serial);
402 timerControl = timer_control_serial;
403 uint32_t watchdog_control_serial;
404 UNSERIALIZE_SCALAR(watchdog_control_serial);
405 watchdogControl = watchdog_control_serial;
406
415
416 bool timer_is_in_event;
417 UNSERIALIZE_SCALAR(timer_is_in_event);
418 bool watchdog_is_in_event;
419 UNSERIALIZE_SCALAR(watchdog_is_in_event);
420
421 Tick timer_event_time;
422 if (timer_is_in_event){
423 UNSERIALIZE_SCALAR(timer_event_time);
424 parent->schedule(timerZeroEvent, timer_event_time);
425 }
426 Tick watchdog_event_time;
427 if (watchdog_is_in_event) {
428 UNSERIALIZE_SCALAR(watchdog_event_time);
429 parent->schedule(watchdogZeroEvent, watchdog_event_time);
430 }
431}
432
433
434
435void
437{
438 for (int i = 0; i < sys->threads.size(); i++)
439 localTimer[i]->serializeSection(cp, csprintf("timer%d", i));
440}
441
442void
444{
445 for (int i = 0; i < sys->threads.size(); i++)
446 localTimer[i]->unserializeSection(cp, csprintf("timer%d", i));
447}
448
449} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
Base class for ARM GIC implementations.
Generic representation of an Arm interrupt pin.
Definition base_gic.hh:200
Addr pioAddr
Address that the device listens to.
Definition io_device.hh:151
BasicPioDevice(const Params &p, Addr size)
Definition io_device.cc:75
Tick pioDelay
Delay that the device experinces on an access.
Definition io_device.hh:157
Addr pioSize
Size that the device's address range.
Definition io_device.hh:154
void serialize(CheckpointOut &cp) const override
Serialize an object.
bool rawIntTimer
If timer has caused an interrupt.
void restartTimerCounter(uint32_t val)
Restart the counter ticking at val.
EndBitUnion(WatchdogCtrl) protected CpuLocalTimer * parent
Pointer to parent class.
Timer(const std::string &name, CpuLocalTimer *_parent, ArmInterruptPin *int_timer, ArmInterruptPin *int_watchdog)
void write(PacketPtr pkt, Addr daddr)
Handle write for a single timer.
EventFunctionWrapper watchdogZeroEvent
uint32_t timerLoadValue
Value to load into counters when periodic mode reaches 0.
void timerAtZero()
Called when the counter reaches 0.
ArmInterruptPin * intWatchdog
EventFunctionWrapper timerZeroEvent
TimerCtrl timerControl
Control register as specified above.
void read(PacketPtr pkt, Addr daddr)
Handle read for a single timer.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool pendingIntTimer
If an interrupt is currently pending.
void restartWatchdogCounter(uint32_t val)
ArmInterruptPin * intTimer
Interrupt to cause/clear.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
std::vector< std::unique_ptr< Timer > > localTimer
Timers that do the actual work.
Tick read(PacketPtr pkt) override
Handle a read to the device.
Tick write(PacketPtr pkt) override
Handle a write to the device.
CpuLocalTimer(const Params &p)
The constructor for RealView just registers itself with the MMU.
void init() override
Inits the local timers.
const std::string _name
Definition named.hh:54
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
PioDeviceParams Params
Definition io_device.hh:134
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition io_device.cc:59
ThreadContext is the external interface to all thread state for anything outside of the CPU.
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:232
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition serialize.cc:74
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition serialize.cc:81
const Params & params() const
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 0 > p
Bitfield< 63 > val
Definition misc.hh:804
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
uint64_t Tick
Tick count type.
Definition types.hh:58
Packet * PacketPtr
int ContextID
Globally unique thread context ID.
Definition types.hh:239
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
Declaration of the Packet class.
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
This implements the cpu local timer from the Cortex-A9 MPCore Technical Reference Manual rev r2p2 (AR...
const std::string & name()
Definition trace.cc:48

Generated on Mon Oct 27 2025 04:13:01 for gem5 by doxygen 1.14.0