gem5  v22.1.0.0
mc146818.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "dev/mc146818.hh"
30 
31 #include <sys/time.h>
32 
33 #include <ctime>
34 #include <string>
35 
36 #include "base/bitfield.hh"
37 #include "base/time.hh"
38 #include "base/trace.hh"
39 #include "debug/MC146818.hh"
40 #include "dev/rtcreg.h"
41 
42 namespace gem5
43 {
44 
45 static uint8_t
46 bcdize(uint8_t val)
47 {
48  uint8_t result;
49  result = val % 10;
50  result += (val / 10) << 4;
51  return result;
52 }
53 
54 static uint8_t
55 unbcdize(uint8_t val)
56 {
57  uint8_t result;
58  result = val & 0xf;
59  result += (val >> 4) * 10;
60  return result;
61 }
62 
63 void
64 MC146818::setTime(const struct tm time)
65 {
66  curTime = time;
67  year = time.tm_year;
68  // Unix is 0-11 for month, data seet says start at 1
69  mon = time.tm_mon + 1;
70  mday = time.tm_mday;
71  hour = time.tm_hour;
72  min = time.tm_min;
73  sec = time.tm_sec;
74 
75  // Datasheet says 1 is sunday
76  wday = time.tm_wday + 1;
77 
78  if (!stat_regB.dm) {
79  // The datasheet says that the year field can be either BCD or
80  // years since 1900. Linux seems to be happy with years since
81  // 1900.
82  year = bcdize(year % 100);
83  mon = bcdize(mon);
84  mday = bcdize(mday);
85  hour = bcdize(hour);
86  min = bcdize(min);
87  sec = bcdize(sec);
88  }
89 }
90 
91 MC146818::MC146818(EventManager *em, const std::string &n,
92  const struct tm time, bool bcd, Tick frequency)
93  : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
94 {
95  memset(clock_data, 0, sizeof(clock_data));
96 
97  stat_regA = 0;
98  stat_regA.dv = RTCA_DV_32768HZ;
99  stat_regA.rs = RTCA_RS_1024HZ;
100 
101  stat_regB = 0;
102  stat_regB.pie = 1;
103  stat_regB.format24h = 1;
104  stat_regB.dm = bcd ? 0 : 1;
105 
106  setTime(time);
107  DPRINTFN("Real-time clock set to %s", asctime(&time));
108 }
109 
111 {
113  deschedule(event);
114 }
115 
116 bool
117 MC146818::rega_dv_disabled(const RtcRegA &reg)
118 {
119  return reg.dv == RTCA_DV_DISABLED0 ||
120  reg.dv == RTCA_DV_DISABLED1;
121 }
122 
123 void
125 {
126  assert(!event.scheduled());
127  assert(!tickEvent.scheduled());
128 
129  if (stat_regB.pie)
131  if (!rega_dv_disabled(stat_regA))
133 }
134 
135 void
136 MC146818::writeData(const uint8_t addr, const uint8_t data)
137 {
138  bool panic_unsupported(false);
139 
140  if (addr < RTC_STAT_REGA) {
141  clock_data[addr] = data;
142  curTime.tm_sec = unbcdize(sec);
143  curTime.tm_min = unbcdize(min);
144  curTime.tm_hour = unbcdize(hour);
145  curTime.tm_mday = unbcdize(mday);
146  curTime.tm_mon = unbcdize(mon) - 1;
147  curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
148  curTime.tm_wday = unbcdize(wday) - 1;
149  } else {
150  switch (addr) {
151  case RTC_STAT_REGA: {
152  RtcRegA old_rega(stat_regA);
153  stat_regA = data;
154  // The "update in progress" bit is read only.
155  stat_regA.uip = old_rega;
156 
157  if (!rega_dv_disabled(stat_regA) &&
158  stat_regA.dv != RTCA_DV_32768HZ) {
159  inform("RTC: Unimplemented divider configuration: %i\n",
160  stat_regA.dv);
161  panic_unsupported = true;
162  }
163 
164  if (stat_regA.rs != RTCA_RS_1024HZ) {
165  inform("RTC: Unimplemented interrupt rate: %i\n",
166  stat_regA.rs);
167  panic_unsupported = true;
168  }
169 
170  if (rega_dv_disabled(stat_regA)) {
171  // The divider is disabled, make sure that we don't
172  // schedule any ticks.
173  if (tickEvent.scheduled())
175  } else if (rega_dv_disabled(old_rega)) {
176  // According to the specification, the next tick
177  // happens after 0.5s when the divider chain goes
178  // from reset to active. So, we simply schedule the
179  // tick after 0.5s.
180  assert(!tickEvent.scheduled());
182  }
183  } break;
184  case RTC_STAT_REGB:
185  stat_regB = data;
186  if (stat_regB.aie || stat_regB.uie) {
187  inform("RTC: Unimplemented interrupt configuration: %s %s\n",
188  stat_regB.aie ? "alarm" : "",
189  stat_regB.uie ? "update" : "");
190  panic_unsupported = true;
191  }
192 
193  if (stat_regB.dm) {
194  inform("RTC: The binary interface is not fully implemented.\n");
195  panic_unsupported = true;
196  }
197 
198  if (!stat_regB.format24h) {
199  inform("RTC: The 12h time format not supported.\n");
200  panic_unsupported = true;
201  }
202 
203  if (stat_regB.dse) {
204  inform("RTC: Automatic daylight saving time not supported.\n");
205  panic_unsupported = true;
206  }
207 
208  if (stat_regB.pie) {
209  if (!event.scheduled())
210  event.scheduleIntr();
211  } else {
212  if (event.scheduled())
213  deschedule(event);
214  }
215  break;
216  case RTC_STAT_REGC:
217  case RTC_STAT_REGD:
218  panic("RTC status registers C and D are not implemented.\n");
219  break;
220  }
221  }
222 
223  if (panic_unsupported)
224  panic("Unimplemented RTC configuration!\n");
225 
226 }
227 
228 uint8_t
230 {
231  if (addr < RTC_STAT_REGA)
232  return clock_data[addr];
233  else {
234  switch (addr) {
235  case RTC_STAT_REGA:
236  // toggle UIP bit for linux
237  stat_regA.uip = !stat_regA.uip;
238  return stat_regA;
239  break;
240  case RTC_STAT_REGB:
241  return stat_regB;
242  break;
243  case RTC_STAT_REGC:
244  case RTC_STAT_REGD:
245  return 0x00;
246  break;
247  default:
248  panic("Shouldn't be here");
249  }
250  }
251 }
252 
253 void
255 {
256  assert(!rega_dv_disabled(stat_regA));
257 
258  if (stat_regB.set)
259  return;
260  time_t calTime = mkutctime(&curTime);
261  calTime++;
262  setTime(*gmtime(&calTime));
263 }
264 
265 void
266 MC146818::serialize(const std::string &base, CheckpointOut &cp) const
267 {
268  uint8_t regA_serial(stat_regA);
269  uint8_t regB_serial(stat_regB);
270 
271  arrayParamOut(cp, base + ".clock_data", clock_data, sizeof(clock_data));
272  paramOut(cp, base + ".stat_regA", (uint8_t)regA_serial);
273  paramOut(cp, base + ".stat_regB", (uint8_t)regB_serial);
274 
275  //
276  // save the timer tick and rtc clock tick values to correctly reschedule
277  // them during unserialize
278  //
279  Tick rtcTimerInterruptTickOffset = event.when() - curTick();
280  SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
281  Tick rtcClockTickOffset = tickEvent.when() - curTick();
282  SERIALIZE_SCALAR(rtcClockTickOffset);
283 }
284 
285 void
286 MC146818::unserialize(const std::string &base, CheckpointIn &cp)
287 {
288  uint8_t tmp8;
289 
290  arrayParamIn(cp, base + ".clock_data", clock_data,
291  sizeof(clock_data));
292 
293  paramIn(cp, base + ".stat_regA", tmp8);
294  stat_regA = tmp8;
295  paramIn(cp, base + ".stat_regB", tmp8);
296  stat_regB = tmp8;
297 
298  //
299  // properly schedule the timer and rtc clock events
300  //
301  Tick rtcTimerInterruptTickOffset;
302  UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
303  event.offset = rtcTimerInterruptTickOffset;
304  Tick rtcClockTickOffset;
305  UNSERIALIZE_SCALAR(rtcClockTickOffset);
306  tickEvent.offset = rtcClockTickOffset;
307 }
308 
310  : parent(_parent), interval(i), offset(i)
311 {
312  DPRINTF(MC146818, "RTC Event Initilizing\n");
313 }
314 
315 void
317 {
318  parent->schedule(this, curTick() + interval);
319 }
320 
321 void
323 {
324  DPRINTF(MC146818, "RTC Timer Interrupt\n");
325  parent->schedule(this, curTick() + interval);
326  parent->handleEvent();
327 }
328 
329 const char *
331 {
332  return "RTC interrupt";
333 }
334 
335 void
337 {
338  DPRINTF(MC146818, "RTC clock tick\n");
339  parent->schedule(this, curTick() + sim_clock::as_int::s);
340  parent->tickClock();
341 }
342 
343 const char *
345 {
346  return "RTC clock tick";
347 }
348 
349 } // namespace gem5
#define DPRINTFN(...)
Definition: trace.hh:214
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
Real-Time Clock (MC146818)
Definition: mc146818.hh:42
uint8_t mday
Definition: mc146818.hh:110
uint8_t hour
Definition: mc146818.hh:107
void setTime(const struct tm time)
Definition: mc146818.cc:64
MC146818(EventManager *em, const std::string &name, const struct tm time, bool bcd, Tick frequency)
Definition: mc146818.cc:91
RTCTickEvent tickEvent
RTC tick event.
Definition: mc146818.hh:94
virtual void startup()
Start ticking.
Definition: mc146818.cc:124
RtcRegB stat_regB
RTC status register B.
Definition: mc146818.hh:153
uint8_t sec
Definition: mc146818.hh:103
uint8_t clock_data[10]
Definition: mc146818.hh:99
uint8_t wday
Definition: mc146818.hh:109
void tickClock()
Definition: mc146818.cc:254
uint8_t year
Definition: mc146818.hh:112
uint8_t mon
Definition: mc146818.hh:111
virtual ~MC146818()
Definition: mc146818.cc:110
void serialize(const std::string &base, CheckpointOut &cp) const
Serialize this object to the given output stream.
Definition: mc146818.cc:266
void unserialize(const std::string &base, CheckpointIn &cp)
Reconstruct the state of this object from a checkpoint.
Definition: mc146818.cc:286
uint8_t min
Definition: mc146818.hh:105
struct tm curTime
Definition: mc146818.hh:116
RTCEvent event
RTC periodic interrupt event.
Definition: mc146818.hh:91
uint8_t readData(const uint8_t addr)
RTC read data.
Definition: mc146818.cc:229
void writeData(const uint8_t addr, const uint8_t data)
RTC write data.
Definition: mc146818.cc:136
void deschedule(Event &event)
Definition: eventq.hh:1028
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
decltype(std::begin(std::declval< const T & >()), std::end(std::declval< const T & >()), void()) arrayParamOut(CheckpointOut &os, const std::string &name, const T &param)
Definition: serialize.hh:409
#define inform(...)
Definition: logging.hh:247
Bitfield< 31 > n
Definition: misc_types.hh:462
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 10, 5 > event
Bitfield< 32 > tm
Definition: misc.hh:112
Bitfield< 5, 3 > reg
Definition: types.hh:92
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
Bitfield< 63 > val
Definition: misc.hh:776
Bitfield< 3 > addr
Definition: types.hh:84
Bitfield< 2 > em
Definition: misc.hh:607
Tick s
second
Definition: core.cc:68
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
time_t mkutctime(struct tm *time)
Definition: time.cc:154
static uint8_t unbcdize(uint8_t val)
Definition: mc146818.cc:55
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
uint64_t Tick
Tick count type.
Definition: types.hh:58
static uint8_t bcdize(uint8_t val)
Definition: mc146818.cc:46
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > &param)
Definition: circlebuf.hh:257
static const int RTCA_RS_1024HZ
Definition: rtcreg.h:49
static const int RTCA_DV_DISABLED0
Definition: rtcreg.h:45
static const int RTC_STAT_REGA
Definition: rtcreg.h:40
static const int RTC_STAT_REGB
Definition: rtcreg.h:51
static const int RTC_STAT_REGD
Definition: rtcreg.h:54
static const int RTC_STAT_REGC
Definition: rtcreg.h:53
static const int RTCA_DV_DISABLED1
Definition: rtcreg.h:46
static const int RTCA_DV_32768HZ
Definition: rtcreg.h:44
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
virtual const char * description() const
Event description.
Definition: mc146818.cc:330
RTCEvent(MC146818 *_parent, Tick i)
Definition: mc146818.cc:309
virtual void process()
Event process to occur at interrupt.
Definition: mc146818.cc:322
void scheduleIntr()
Schedule the RTC periodic interrupt.
Definition: mc146818.cc:316
const char * description() const
Event description.
Definition: mc146818.cc:344
void process()
Event process to occur at interrupt.
Definition: mc146818.cc:336

Generated on Wed Dec 21 2022 10:22:34 for gem5 by doxygen 1.9.1