gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
42namespace gem5
43{
44
45static uint8_t
46bcdize(uint8_t val)
47{
48 uint8_t result;
49 result = val % 10;
50 result += (val / 10) << 4;
51 return result;
52}
53
54static uint8_t
55unbcdize(uint8_t val)
56{
57 uint8_t result;
58 result = val & 0xf;
59 result += (val >> 4) * 10;
60 return result;
61}
62
63void
64MC146818::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
91MC146818::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
115
116bool
117MC146818::rega_dv_disabled(const RtcRegA &reg)
118{
119 return reg.dv == RTCA_DV_DISABLED0 ||
121}
122
123void
125{
126 assert(!event.scheduled());
127 assert(!tickEvent.scheduled());
128
129 if (stat_regB.pie)
131 if (!rega_dv_disabled(stat_regA))
133}
134
135void
136MC146818::writeData(const uint8_t addr, const uint8_t data)
137{
138 bool panic_unsupported(false);
139
140 if (addr < RTC_STAT_REGA) {
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())
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
228uint8_t
230{
231 if (addr < RTC_STAT_REGA)
232 return clock_data[addr];
233 else {
234 switch (addr) {
235 case RTC_STAT_REGA:
236 // Linux after v5.10 checks this multiple times so toggling
237 // leads to a deadlock on bootup.
238 stat_regA.uip = 0;
239 return stat_regA;
240 break;
241 case RTC_STAT_REGB:
242 return stat_regB;
243 break;
244 case RTC_STAT_REGC:
245 case RTC_STAT_REGD:
246 return 0x00;
247 break;
248 default:
249 panic("Shouldn't be here");
250 }
251 }
252}
253
254void
256{
257 assert(!rega_dv_disabled(stat_regA));
258
259 if (stat_regB.set)
260 return;
261 time_t calTime = mkutctime(&curTime);
262 calTime++;
263 setTime(*gmtime(&calTime));
264}
265
266void
267MC146818::serialize(const std::string &base, CheckpointOut &cp) const
268{
269 uint8_t regA_serial(stat_regA);
270 uint8_t regB_serial(stat_regB);
271
272 arrayParamOut(cp, base + ".clock_data", clock_data, sizeof(clock_data));
273 paramOut(cp, base + ".stat_regA", (uint8_t)regA_serial);
274 paramOut(cp, base + ".stat_regB", (uint8_t)regB_serial);
275
276 //
277 // save the timer tick and rtc clock tick values to correctly reschedule
278 // them during unserialize
279 //
280 Tick rtcTimerInterruptTickOffset = event.when() - curTick();
281 SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
282 Tick rtcClockTickOffset = tickEvent.when() - curTick();
283 SERIALIZE_SCALAR(rtcClockTickOffset);
284}
285
286void
288{
289 uint8_t tmp8;
290
291 arrayParamIn(cp, base + ".clock_data", clock_data,
292 sizeof(clock_data));
293
294 paramIn(cp, base + ".stat_regA", tmp8);
295 stat_regA = tmp8;
296 paramIn(cp, base + ".stat_regB", tmp8);
297 stat_regB = tmp8;
298
299 //
300 // properly schedule the timer and rtc clock events
301 //
302 Tick rtcTimerInterruptTickOffset;
303 UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
304 event.offset = rtcTimerInterruptTickOffset;
305 Tick rtcClockTickOffset;
306 UNSERIALIZE_SCALAR(rtcClockTickOffset);
307 tickEvent.offset = rtcClockTickOffset;
308}
309
311 : parent(_parent), interval(i), offset(i)
312{
313 DPRINTF(MC146818, "RTC Event Initilizing\n");
314}
315
316void
318{
319 parent->schedule(this, curTick() + interval);
320}
321
322void
324{
325 DPRINTF(MC146818, "RTC Timer Interrupt\n");
326 parent->schedule(this, curTick() + interval);
327 parent->handleEvent();
328}
329
330const char *
332{
333 return "RTC interrupt";
334}
335
336void
338{
339 DPRINTF(MC146818, "RTC clock tick\n");
340 parent->schedule(this, curTick() + sim_clock::as_int::s);
341 parent->tickClock();
342}
343
344const char *
346{
347 return "RTC clock tick";
348}
349
350} // namespace gem5
#define DPRINTFN(...)
Definition trace.hh:238
#define DPRINTF(x,...)
Definition trace.hh:210
const char data[]
Real-Time Clock (MC146818)
Definition mc146818.hh:42
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 clock_data[10]
Definition mc146818.hh:99
void tickClock()
Definition mc146818.cc:255
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:267
void unserialize(const std::string &base, CheckpointIn &cp)
Reconstruct the state of this object from a checkpoint.
Definition mc146818.cc:287
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:1021
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
Tick when() const
Get the time that the event is scheduled.
Definition eventq.hh:501
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define inform(...)
Definition logging.hh:257
Bitfield< 31 > n
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:804
Bitfield< 3 > addr
Definition types.hh:84
Bitfield< 2 > em
Definition misc.hh:617
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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
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
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > &param)
Definition circlebuf.hh:247
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:331
RTCEvent(MC146818 *_parent, Tick i)
Definition mc146818.cc:310
virtual void process()
Event process to occur at interrupt.
Definition mc146818.cc:323
void scheduleIntr()
Schedule the RTC periodic interrupt.
Definition mc146818.cc:317
const char * description() const
Event description.
Definition mc146818.cc:345
void process()
Event process to occur at interrupt.
Definition mc146818.cc:337

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0