mirror of https://github.com/bsnes-emu/bsnes.git
183 lines
3.7 KiB
C++
183 lines
3.7 KiB
C++
auto EpsonRTC::irq(uint2 period) -> void {
|
|
if(stop || pause) return;
|
|
|
|
if(period == irqperiod) irqflag = 1;
|
|
}
|
|
|
|
auto EpsonRTC::duty() -> void {
|
|
if(irqduty) irqflag = 0;
|
|
}
|
|
|
|
auto EpsonRTC::round_seconds() -> void {
|
|
if(roundseconds == 0) return;
|
|
roundseconds = 0;
|
|
|
|
if(secondhi >= 3) tick_minute();
|
|
secondlo = 0;
|
|
secondhi = 0;
|
|
}
|
|
|
|
auto EpsonRTC::tick() -> void {
|
|
if(stop || pause) return;
|
|
|
|
if(hold) {
|
|
holdtick = 1;
|
|
return;
|
|
}
|
|
|
|
resync = 1;
|
|
tick_second();
|
|
}
|
|
|
|
//below code provides bit-perfect emulation of invalid BCD values on the RTC-4513
|
|
//code makes extensive use of variable-length integers (see epsonrtc.hpp for sizes)
|
|
|
|
auto EpsonRTC::tick_second() -> void {
|
|
if(secondlo <= 8 || secondlo == 12) {
|
|
secondlo++;
|
|
} else {
|
|
secondlo = 0;
|
|
if(secondhi < 5) {
|
|
secondhi++;
|
|
} else {
|
|
secondhi = 0;
|
|
tick_minute();
|
|
}
|
|
}
|
|
}
|
|
|
|
auto EpsonRTC::tick_minute() -> void {
|
|
if(minutelo <= 8 || minutelo == 12) {
|
|
minutelo++;
|
|
} else {
|
|
minutelo = 0;
|
|
if(minutehi < 5) {
|
|
minutehi++;
|
|
} else {
|
|
minutehi = 0;
|
|
tick_hour();
|
|
}
|
|
}
|
|
}
|
|
|
|
auto EpsonRTC::tick_hour() -> void {
|
|
if(atime) {
|
|
if(hourhi < 2) {
|
|
if(hourlo <= 8 || hourlo == 12) {
|
|
hourlo++;
|
|
} else {
|
|
hourlo = !(hourlo & 1);
|
|
hourhi++;
|
|
}
|
|
} else {
|
|
if(hourlo != 3 && !(hourlo & 4)) {
|
|
if(hourlo <= 8 || hourlo >= 12) {
|
|
hourlo++;
|
|
} else {
|
|
hourlo = !(hourlo & 1);
|
|
hourhi++;
|
|
}
|
|
} else {
|
|
hourlo = !(hourlo & 1);
|
|
hourhi = 0;
|
|
tick_day();
|
|
}
|
|
}
|
|
} else {
|
|
if(hourhi == 0) {
|
|
if(hourlo <= 8 || hourlo == 12) {
|
|
hourlo++;
|
|
} else {
|
|
hourlo = !(hourlo & 1);
|
|
hourhi ^= 1;
|
|
}
|
|
} else {
|
|
if(hourlo & 1) meridian ^= 1;
|
|
if(hourlo < 2 || hourlo == 4 || hourlo == 5 || hourlo == 8 || hourlo == 12) {
|
|
hourlo++;
|
|
} else {
|
|
hourlo = !(hourlo & 1);
|
|
hourhi ^= 1;
|
|
}
|
|
if(meridian == 0 && !(hourlo & 1)) tick_day();
|
|
}
|
|
}
|
|
}
|
|
|
|
auto EpsonRTC::tick_day() -> void {
|
|
if(calendar == 0) return;
|
|
weekday = (weekday + 1) + (weekday == 6);
|
|
|
|
//January - December = 0x01 - 0x09; 0x10 - 0x12
|
|
static const uint daysinmonth[32] = {
|
|
30, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30, 31, 30,
|
|
31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30,
|
|
};
|
|
|
|
uint days = daysinmonth[monthhi << 4 | monthlo];
|
|
if(days == 28) {
|
|
//add one day for leap years
|
|
if((yearhi & 1) == 0 && ((yearlo - 0) & 3) == 0) days++;
|
|
if((yearhi & 1) == 1 && ((yearlo - 2) & 3) == 0) days++;
|
|
}
|
|
|
|
if(days == 28 && (dayhi == 3 || (dayhi == 2 && daylo >= 8))) {
|
|
daylo = 1;
|
|
dayhi = 0;
|
|
return tick_month();
|
|
}
|
|
|
|
if(days == 29 && (dayhi == 3 || (dayhi == 2 && (daylo > 8 && daylo != 12)))) {
|
|
daylo = 1;
|
|
dayhi = 0;
|
|
return tick_month();
|
|
}
|
|
|
|
if(days == 30 && (dayhi == 3 || (dayhi == 2 && (daylo == 10 || daylo == 14)))) {
|
|
daylo = 1;
|
|
dayhi = 0;
|
|
return tick_month();
|
|
}
|
|
|
|
if(days == 31 && (dayhi == 3 && (daylo & 3))) {
|
|
daylo = 1;
|
|
dayhi = 0;
|
|
return tick_month();
|
|
}
|
|
|
|
if(daylo <= 8 || daylo == 12) {
|
|
daylo++;
|
|
} else {
|
|
daylo = !(daylo & 1);
|
|
dayhi++;
|
|
}
|
|
}
|
|
|
|
auto EpsonRTC::tick_month() -> void {
|
|
if(monthhi == 0 || !(monthlo & 2)) {
|
|
if(monthlo <= 8 || monthlo == 12) {
|
|
monthlo++;
|
|
} else {
|
|
monthlo = !(monthlo & 1);
|
|
monthhi ^= 1;
|
|
}
|
|
} else {
|
|
monthlo = !(monthlo & 1);
|
|
monthhi = 0;
|
|
tick_year();
|
|
}
|
|
}
|
|
|
|
auto EpsonRTC::tick_year() -> void {
|
|
if(yearlo <= 8 || yearlo == 12) {
|
|
yearlo++;
|
|
} else {
|
|
yearlo = !(yearlo & 1);
|
|
if(yearhi <= 8 || yearhi == 12) {
|
|
yearhi++;
|
|
} else {
|
|
yearhi = !(yearhi & 1);
|
|
}
|
|
}
|
|
}
|