Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/chip/srtc/srtc.cpp
2 views
1
#include <snes/snes.hpp>
2
3
#define SRTC_CPP
4
namespace SNES {
5
6
SRTC srtc;
7
8
#include "serialization.cpp"
9
10
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
11
12
SRTC::SRTC()
13
: rtc(nullptr)
14
{
15
}
16
17
SRTC::~SRTC()
18
{
19
interface()->freeSharedMemory(rtc);
20
}
21
22
void SRTC::initialize()
23
{
24
rtc = (uint8*)interface()->allocSharedMemory("RTC",20);
25
}
26
27
void SRTC::init() {
28
}
29
30
void SRTC::load() {
31
for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff;
32
cartridge.nvram.append({ "program.rtc", rtc, 20 });
33
}
34
35
void SRTC::unload() {
36
}
37
38
void SRTC::power() {
39
}
40
41
void SRTC::reset() {
42
rtc_mode = RtcRead;
43
rtc_index = -1;
44
update_time();
45
}
46
47
void SRTC::update_time() {
48
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
49
time_t current_time = SNES::interface()->currentTime();
50
51
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
52
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
53
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
54
//rtc[] timestamp to remain valid for up to ~34 years from the last update, even if
55
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
56
//or whether time_t is signed or unsigned.
57
time_t diff
58
= (current_time >= rtc_time)
59
? (current_time - rtc_time)
60
: (std::numeric_limits<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
61
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
62
63
if(diff > 0) {
64
unsigned second = rtc[ 0] + rtc[ 1] * 10;
65
unsigned minute = rtc[ 2] + rtc[ 3] * 10;
66
unsigned hour = rtc[ 4] + rtc[ 5] * 10;
67
unsigned day = rtc[ 6] + rtc[ 7] * 10;
68
unsigned month = rtc[ 8];
69
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
70
unsigned weekday = rtc[12];
71
72
day--;
73
month--;
74
year += 1000;
75
76
second += diff;
77
while(second >= 60) {
78
second -= 60;
79
80
minute++;
81
if(minute < 60) continue;
82
minute = 0;
83
84
hour++;
85
if(hour < 24) continue;
86
hour = 0;
87
88
day++;
89
weekday = (weekday + 1) % 7;
90
unsigned days = months[month % 12];
91
if(days == 28) {
92
bool leapyear = false;
93
if((year % 4) == 0) {
94
leapyear = true;
95
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
96
}
97
if(leapyear) days++;
98
}
99
if(day < days) continue;
100
day = 0;
101
102
month++;
103
if(month < 12) continue;
104
month = 0;
105
106
year++;
107
}
108
109
day++;
110
month++;
111
year -= 1000;
112
113
rtc[ 0] = second % 10;
114
rtc[ 1] = second / 10;
115
rtc[ 2] = minute % 10;
116
rtc[ 3] = minute / 10;
117
rtc[ 4] = hour % 10;
118
rtc[ 5] = hour / 10;
119
rtc[ 6] = day % 10;
120
rtc[ 7] = day / 10;
121
rtc[ 8] = month;
122
rtc[ 9] = year % 10;
123
rtc[10] = (year / 10) % 10;
124
rtc[11] = year / 100;
125
rtc[12] = weekday % 7;
126
}
127
128
rtc[16] = current_time >> 0;
129
rtc[17] = current_time >> 8;
130
rtc[18] = current_time >> 16;
131
rtc[19] = current_time >> 24;
132
}
133
134
//returns day of week for specified date
135
//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday
136
//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008
137
unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
138
unsigned y = 1900, m = 1; //epoch is 1900-01-01
139
unsigned sum = 0; //number of days passed since epoch
140
141
year = max(1900, year);
142
month = max(1, min(12, month));
143
day = max(1, min(31, day));
144
145
while(y < year) {
146
bool leapyear = false;
147
if((y % 4) == 0) {
148
leapyear = true;
149
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
150
}
151
sum += leapyear ? 366 : 365;
152
y++;
153
}
154
155
while(m < month) {
156
unsigned days = months[m - 1];
157
if(days == 28) {
158
bool leapyear = false;
159
if((y % 4) == 0) {
160
leapyear = true;
161
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
162
}
163
if(leapyear) days++;
164
}
165
sum += days;
166
m++;
167
}
168
169
sum += day - 1;
170
return (sum + 1) % 7; //1900-01-01 was a Monday
171
}
172
173
uint8 SRTC::read(unsigned addr) {
174
addr &= 0xffff;
175
176
if(addr == 0x2800) {
177
if(rtc_mode != RtcRead) return 0x00;
178
179
if(rtc_index < 0) {
180
update_time();
181
rtc_index++;
182
return 0x0f;
183
} else if(rtc_index > 12) {
184
rtc_index = -1;
185
return 0x0f;
186
} else {
187
return rtc[rtc_index++];
188
}
189
}
190
191
return cpu.regs.mdr;
192
}
193
194
void SRTC::write(unsigned addr, uint8 data) {
195
addr &= 0xffff;
196
197
if(addr == 0x2801) {
198
data &= 0x0f; //only the low four bits are used
199
200
if(data == 0x0d) {
201
rtc_mode = RtcRead;
202
rtc_index = -1;
203
return;
204
}
205
206
if(data == 0x0e) {
207
rtc_mode = RtcCommand;
208
return;
209
}
210
211
if(data == 0x0f) return; //unknown behavior
212
213
if(rtc_mode == RtcWrite) {
214
if(rtc_index >= 0 && rtc_index < 12) {
215
rtc[rtc_index++] = data;
216
217
if(rtc_index == 12) {
218
//day of week is automatically calculated and written
219
unsigned day = rtc[ 6] + rtc[ 7] * 10;
220
unsigned month = rtc[ 8];
221
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
222
year += 1000;
223
224
rtc[rtc_index++] = weekday(year, month, day);
225
}
226
}
227
} else if(rtc_mode == RtcCommand) {
228
if(data == 0) {
229
rtc_mode = RtcWrite;
230
rtc_index = 0;
231
} else if(data == 4) {
232
rtc_mode = RtcReady;
233
rtc_index = -1;
234
for(unsigned i = 0; i < 13; i++) rtc[i] = 0;
235
} else {
236
//unknown behavior
237
rtc_mode = RtcReady;
238
}
239
}
240
}
241
}
242
243
}
244
245