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

Generated on Wed Sep 30 2020 14:02:10 for gem5 by doxygen 1.8.17