2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
38 #include "base/bitfield.hh"
39 #include "base/time.hh"
40 #include "base/trace.hh"
41 #include "debug/MC146818.hh"
42 #include "dev/mc146818.hh"
43 #include "dev/rtcreg.h"
52 result
+= (val
/ 10) << 4;
61 result
+= (val
>> 4) * 10;
66 MC146818::setTime(const struct tm time
)
70 // Unix is 0-11 for month, data seet says start at 1
71 mon
= time
.tm_mon
+ 1;
77 // Datasheet says 1 is sunday
78 wday
= time
.tm_wday
+ 1;
80 if (!(stat_regB
& RTCB_BIN
)) {
81 // The datasheet says that the year field can be either BCD or
82 // years since 1900. Linux seems to be happy with years since
84 year
= bcdize(year
% 100);
93 MC146818::MC146818(EventManager
*em
, const string
&n
, const struct tm time
,
94 bool bcd
, Tick frequency
)
95 : EventManager(em
), _name(n
), event(this, frequency
), tickEvent(this)
97 memset(clock_data
, 0, sizeof(clock_data
));
98 stat_regA
= RTCA_32768HZ
| RTCA_1024HZ
;
99 stat_regB
= RTCB_PRDC_IE
| RTCB_24HR
;
101 stat_regB
|= RTCB_BIN
;
104 DPRINTFN("Real-time clock set to %s", asctime(&time
));
107 MC146818::~MC146818()
109 deschedule(tickEvent
);
114 MC146818::writeData(const uint8_t addr
, const uint8_t data
)
116 if (addr
< RTC_STAT_REGA
) {
117 clock_data
[addr
] = data
;
118 curTime
.tm_sec
= unbcdize(sec
);
119 curTime
.tm_min
= unbcdize(min
);
120 curTime
.tm_hour
= unbcdize(hour
);
121 curTime
.tm_mday
= unbcdize(mday
);
122 curTime
.tm_mon
= unbcdize(mon
) - 1;
123 curTime
.tm_year
= ((unbcdize(year
) + 50) % 100) + 1950;
124 curTime
.tm_wday
= unbcdize(wday
) - 1;
128 // The "update in progress" bit is read only.
129 if ((data
& ~RTCA_UIP
) != (RTCA_32768HZ
| RTCA_1024HZ
))
130 panic("Unimplemented RTC register A value write!\n");
131 replaceBits(stat_regA
, data
, 6, 0);
134 if ((data
& ~(RTCB_PRDC_IE
| RTCB_SQWE
)) != RTCB_24HR
)
135 panic("Write to RTC reg B bits that are not implemented!\n");
137 if (data
& RTCB_PRDC_IE
) {
138 if (!event
.scheduled())
139 event
.scheduleIntr();
141 if (event
.scheduled())
148 panic("RTC status registers C and D are not implemented.\n");
155 MC146818::readData(uint8_t addr
)
157 if (addr
< RTC_STAT_REGA
)
158 return clock_data
[addr
];
162 // toggle UIP bit for linux
163 stat_regA
^= RTCA_UIP
;
174 panic("Shouldn't be here");
180 MC146818::tickClock()
182 if (stat_regB
& RTCB_NO_UPDT
)
184 time_t calTime
= mkutctime(&curTime
);
186 setTime(*gmtime(&calTime
));
190 MC146818::serialize(const string
&base
, ostream
&os
)
192 arrayParamOut(os
, base
+ ".clock_data", clock_data
, sizeof(clock_data
));
193 paramOut(os
, base
+ ".stat_regA", stat_regA
);
194 paramOut(os
, base
+ ".stat_regB", stat_regB
);
197 // save the timer tick and rtc clock tick values to correctly reschedule
198 // them during unserialize
200 Tick rtcTimerInterruptTickOffset
= event
.when() - curTick();
201 SERIALIZE_SCALAR(rtcTimerInterruptTickOffset
);
202 Tick rtcClockTickOffset
= tickEvent
.when() - curTick();
203 SERIALIZE_SCALAR(rtcClockTickOffset
);
207 MC146818::unserialize(const string
&base
, Checkpoint
*cp
,
208 const string
§ion
)
210 arrayParamIn(cp
, section
, base
+ ".clock_data", clock_data
,
212 paramIn(cp
, section
, base
+ ".stat_regA", stat_regA
);
213 paramIn(cp
, section
, base
+ ".stat_regB", stat_regB
);
216 // properly schedule the timer and rtc clock events
218 Tick rtcTimerInterruptTickOffset
;
219 UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset
);
220 reschedule(event
, curTick() + rtcTimerInterruptTickOffset
);
221 Tick rtcClockTickOffset
;
222 UNSERIALIZE_SCALAR(rtcClockTickOffset
);
223 reschedule(tickEvent
, curTick() + rtcClockTickOffset
);
226 MC146818::RTCEvent::RTCEvent(MC146818
* _parent
, Tick i
)
227 : parent(_parent
), interval(i
)
229 DPRINTF(MC146818
, "RTC Event Initilizing\n");
230 parent
->schedule(this, curTick() + interval
);
234 MC146818::RTCEvent::scheduleIntr()
236 parent
->schedule(this, curTick() + interval
);
240 MC146818::RTCEvent::process()
242 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
243 parent
->schedule(this, curTick() + interval
);
244 parent
->handleEvent();
248 MC146818::RTCEvent::description() const
250 return "RTC interrupt";
254 MC146818::RTCTickEvent::process()
256 DPRINTF(MC146818
, "RTC clock tick\n");
257 parent
->schedule(this, curTick() + SimClock::Int::s
);
262 MC146818::RTCTickEvent::description() const
264 return "RTC clock tick";