15static constexpr nibble MODE_REG = 13;
16static constexpr nibble TEST_REG = 14;
17static constexpr nibble RESET_REG = 15;
19static constexpr nibble TIME_BLOCK = 0;
20static constexpr nibble ALARM_BLOCK = 1;
22static constexpr nibble MODE_BLOK_SELECT = 0x3;
23static constexpr nibble MODE_ALARM_ENABLE = 0x4;
24static constexpr nibble MODE_TIMER_ENABLE = 0x8;
26static constexpr nibble TEST_SECONDS = 0x1;
27static constexpr nibble TEST_MINUTES = 0x2;
28static constexpr nibble TEST_DAYS = 0x4;
29static constexpr nibble TEST_YEARS = 0x8;
31static constexpr nibble RESET_ALARM = 0x1;
32static constexpr nibble RESET_FRACTION = 0x2;
36static constexpr std::array mask = {
37 std::array<nibble, 13>{0xf, 0x7, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0xf, 0x1, 0xf, 0xf},
38 std::array<nibble, 13>{0x0, 0x0, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0x0, 0x1, 0x3, 0x0},
39 std::array<nibble, 13>{0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf},
40 std::array<nibble, 13>{0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf},
44 EmuTime::param time,
const std::string& name)
48 ((name ==
"Real time clock") ?
std::string_view(
"rtcmode")
50 "Real Time Clock mode",
RP5C01::EMUTIME,
60void RP5C01::reset(EmuTime::param time)
62 modeReg = MODE_TIMER_ENABLE;
77 unsigned block = modeReg & MODE_BLOK_SELECT;
78 if (block ==
one_of(TIME_BLOCK, ALARM_BLOCK)) {
82 return peekPort(port);
96 unsigned block = modeReg & MODE_BLOK_SELECT;
97 nibble tmp = regs[block * 13 + port];
98 return tmp & mask[block][port];
104 assert (port <= 0x0f);
107 updateTimeRegs(time);
111 updateTimeRegs(time);
116 if (value & RESET_ALARM) {
119 if (value & RESET_FRACTION) {
124 unsigned block = modeReg & MODE_BLOK_SELECT;
125 if (block ==
one_of(TIME_BLOCK, ALARM_BLOCK)) {
126 updateTimeRegs(time);
128 regs.write(block * 13 + port, value & mask[block][port]);
129 if (block ==
one_of(TIME_BLOCK, ALARM_BLOCK)) {
135void RP5C01::initializeTime()
137 time_t
t = time(
nullptr);
138 const struct tm* tm = localtime(&
t);
140 seconds = tm->tm_sec;
141 minutes = tm->tm_min;
143 dayWeek = tm->tm_wday;
144 days = tm->tm_mday-1;
146 years = tm->tm_year - 80;
147 leapYear = tm->tm_year % 4;
151void RP5C01::regs2Time()
153 seconds = regs[TIME_BLOCK * 13 + 0] + 10 * regs[TIME_BLOCK * 13 + 1];
154 minutes = regs[TIME_BLOCK * 13 + 2] + 10 * regs[TIME_BLOCK * 13 + 3];
155 hours = regs[TIME_BLOCK * 13 + 4] + 10 * regs[TIME_BLOCK * 13 + 5];
156 dayWeek = regs[TIME_BLOCK * 13 + 6];
157 days = regs[TIME_BLOCK * 13 + 7] + 10 * regs[TIME_BLOCK * 13 + 8] - 1;
158 months = regs[TIME_BLOCK * 13 + 9] + 10 * regs[TIME_BLOCK * 13 +10] - 1;
159 years = regs[TIME_BLOCK * 13 +11] + 10 * regs[TIME_BLOCK * 13 +12];
160 leapYear = regs[ALARM_BLOCK * 13 +11];
162 if (!regs[ALARM_BLOCK * 13 + 10]) {
164 if (hours >= 20) hours = (hours - 20) + 12;
168void RP5C01::time2Regs()
170 unsigned hours_ = hours;
171 if (!regs[ALARM_BLOCK * 13 + 10]) {
173 if (hours >= 12) hours_ = (hours - 12) + 20;
176 regs.write(TIME_BLOCK * 13 + 0, narrow<byte>( seconds % 10));
177 regs.write(TIME_BLOCK * 13 + 1, narrow<byte>( seconds / 10));
178 regs.write(TIME_BLOCK * 13 + 2, narrow<byte>( minutes % 10));
179 regs.write(TIME_BLOCK * 13 + 3, narrow<byte>( minutes / 10));
180 regs.write(TIME_BLOCK * 13 + 4, narrow<byte>( hours_ % 10));
181 regs.write(TIME_BLOCK * 13 + 5, narrow<byte>( hours_ / 10));
182 regs.write(TIME_BLOCK * 13 + 6, narrow<byte>( dayWeek));
183 regs.write(TIME_BLOCK * 13 + 7, narrow<byte>((days+1) % 10));
184 regs.write(TIME_BLOCK * 13 + 8, narrow<byte>((days+1) / 10));
185 regs.write(TIME_BLOCK * 13 + 9, narrow<byte>((months+1) % 10));
186 regs.write(TIME_BLOCK * 13 + 10, narrow<byte>((months+1) / 10));
187 regs.write(TIME_BLOCK * 13 + 11, narrow<byte>( years % 10));
188 regs.write(TIME_BLOCK * 13 + 12, narrow<byte>( years / 10));
189 regs.write(ALARM_BLOCK * 13 + 11, narrow<byte>( leapYear));
192static constexpr int daysInMonth(
int month,
unsigned leapYear)
194 constexpr std::array<uint8_t, 12> daysInMonths = {
195 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
199 return ((month == 1) && (leapYear == 0)) ? 29 : daysInMonths[month];
202void RP5C01::updateTimeRegs(EmuTime::param time)
204 if (modeSetting.getEnum() == EMUTIME) {
206 auto elapsed = reference.getTicksTill(time);
207 reference.advance(time);
210 fraction += (modeReg & MODE_TIMER_ENABLE) ? elapsed : 0;
211 unsigned carrySeconds = (testReg & TEST_SECONDS)
212 ? elapsed : fraction / FREQ;
213 seconds += carrySeconds;
214 unsigned carryMinutes = (testReg & TEST_MINUTES)
215 ? elapsed : seconds / 60;
216 minutes += carryMinutes;
217 hours += minutes / 60;
218 unsigned carryDays = (testReg & TEST_DAYS)
219 ? elapsed : hours / 24;
231 days += narrow_cast<int>(carryDays);
232 dayWeek += carryDays;
233 while (days >= daysInMonth(months, leapYear)) {
237 days -= daysInMonth(months, leapYear);
241 unsigned carryYears = (testReg & TEST_YEARS)
242 ? elapsed : unsigned(months / 12);
244 leapYear += carryYears;
263void RP5C01::resetAlarm()
265 for (
auto i :
xrange(2, 9)) {
266 regs.write(ALARM_BLOCK * 13 + i, 0);
270template<
typename Archive>
271void RP5C01::serialize(Archive& ar,
unsigned )
273 ar.serialize(
"reference", reference,
274 "fraction", fraction,
280 "leapYear", leapYear,
285 "resetReg", resetReg);
RP5C01(CommandController &commandController, SRAM ®s, EmuTime::param time, const std::string &name)
This file implemented 3 utility functions:
uint8_t nibble
4 bit integer
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
TemporaryString tmpStrCat(Ts &&... ts)
constexpr auto xrange(T e)