mirror of https://github.com/bsnes-emu/bsnes.git
204 lines
3.5 KiB
C++
204 lines
3.5 KiB
C++
#include <sfc/sfc.hpp>
|
|
|
|
namespace SuperFamicom {
|
|
|
|
#include "memory.cpp"
|
|
#include "time.cpp"
|
|
#include "serialization.cpp"
|
|
EpsonRTC epsonrtc;
|
|
|
|
auto EpsonRTC::Enter() -> void {
|
|
while(true) scheduler.synchronize(), epsonrtc.main();
|
|
}
|
|
|
|
auto EpsonRTC::main() -> void {
|
|
if(wait) { if(--wait == 0) ready = 1; }
|
|
|
|
clocks++;
|
|
if((clocks & ~0x00ff) == 0) round_seconds(); //125 microseconds
|
|
if((clocks & ~0x3fff) == 0) duty(); //1/128th second
|
|
if((clocks & ~0x7fff) == 0) irq(0); //1/64th second
|
|
if(clocks == 0) { //1 second
|
|
seconds++;
|
|
irq(1);
|
|
if(seconds % 60 == 0) irq(2); //1 minute
|
|
if(seconds % 1440 == 0) irq(3), seconds = 0; //1 hour
|
|
tick();
|
|
}
|
|
|
|
step(1);
|
|
synchronizeCPU();
|
|
}
|
|
|
|
auto EpsonRTC::init() -> void {
|
|
}
|
|
|
|
auto EpsonRTC::load() -> void {
|
|
secondlo = 0;
|
|
secondhi = 0;
|
|
batteryfailure = 1;
|
|
|
|
minutelo = 0;
|
|
minutehi = 0;
|
|
resync = 0;
|
|
|
|
hourlo = 0;
|
|
hourhi = 0;
|
|
meridian = 0;
|
|
|
|
daylo = 0;
|
|
dayhi = 0;
|
|
dayram = 0;
|
|
|
|
monthlo = 0;
|
|
monthhi = 0;
|
|
monthram = 0;
|
|
|
|
yearlo = 0;
|
|
yearhi = 0;
|
|
|
|
weekday = 0;
|
|
|
|
hold = 0;
|
|
calendar = 0;
|
|
irqflag = 0;
|
|
roundseconds = 0;
|
|
|
|
irqmask = 0;
|
|
irqduty = 0;
|
|
irqperiod = 0;
|
|
|
|
pause = 0;
|
|
stop = 0;
|
|
atime = 0;
|
|
test = 0;
|
|
}
|
|
|
|
auto EpsonRTC::unload() -> void {
|
|
}
|
|
|
|
auto EpsonRTC::power() -> void {
|
|
}
|
|
|
|
auto EpsonRTC::reset() -> void {
|
|
create(EpsonRTC::Enter, 32768 * 64);
|
|
|
|
clocks = 0;
|
|
seconds = 0;
|
|
|
|
chipselect = 0;
|
|
state = State::Mode;
|
|
offset = 0;
|
|
wait = 0;
|
|
ready = 0;
|
|
holdtick = 0;
|
|
}
|
|
|
|
auto EpsonRTC::sync() -> void {
|
|
time_t systime = time(0);
|
|
tm* timeinfo = localtime(&systime);
|
|
|
|
uint second = min(59, timeinfo->tm_sec);
|
|
secondlo = second % 10;
|
|
secondhi = second / 10;
|
|
|
|
uint minute = timeinfo->tm_min;
|
|
minutelo = minute % 10;
|
|
minutehi = minute / 10;
|
|
|
|
uint hour = timeinfo->tm_hour;
|
|
if(atime) {
|
|
hourlo = hour % 10;
|
|
hourhi = hour / 10;
|
|
} else {
|
|
meridian = hour >= 12;
|
|
hour %= 12;
|
|
if(hour == 0) hour = 12;
|
|
hourlo = hour % 10;
|
|
hourhi = hour / 10;
|
|
}
|
|
|
|
uint day = timeinfo->tm_mday;
|
|
daylo = day % 10;
|
|
dayhi = day / 10;
|
|
|
|
uint month = 1 + timeinfo->tm_mon;
|
|
monthlo = month % 10;
|
|
monthhi = month / 10;
|
|
|
|
uint year = timeinfo->tm_year % 100;
|
|
yearlo = year % 10;
|
|
yearhi = year / 10;
|
|
|
|
weekday = timeinfo->tm_wday;
|
|
|
|
resync = true; //alert program that time has changed
|
|
}
|
|
|
|
auto EpsonRTC::read(uint24 addr, uint8 data) -> uint8 {
|
|
cpu.synchronizeCoprocessors();
|
|
addr &= 3;
|
|
|
|
if(addr == 0) {
|
|
return chipselect;
|
|
}
|
|
|
|
if(addr == 1) {
|
|
if(chipselect != 1) return 0;
|
|
if(ready == 0) return 0;
|
|
if(state == State::Write) return mdr;
|
|
if(state != State::Read) return 0;
|
|
ready = 0;
|
|
wait = 8;
|
|
return rtc_read(offset++);
|
|
}
|
|
|
|
if(addr == 2) {
|
|
return ready << 7;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
auto EpsonRTC::write(uint24 addr, uint8 data) -> void {
|
|
cpu.synchronizeCoprocessors();
|
|
addr &= 3, data &= 15;
|
|
|
|
if(addr == 0) {
|
|
chipselect = data;
|
|
if(chipselect != 1) rtc_reset();
|
|
ready = 1;
|
|
}
|
|
|
|
if(addr == 1) {
|
|
if(chipselect != 1) return;
|
|
if(ready == 0) return;
|
|
|
|
if(state == State::Mode) {
|
|
if(data != 0x03 && data != 0x0c) return;
|
|
state = State::Seek;
|
|
ready = 0;
|
|
wait = 8;
|
|
mdr = data;
|
|
}
|
|
|
|
else if(state == State::Seek) {
|
|
if(mdr == 0x03) state = State::Write;
|
|
if(mdr == 0x0c) state = State::Read;
|
|
offset = data;
|
|
ready = 0;
|
|
wait = 8;
|
|
mdr = data;
|
|
}
|
|
|
|
else if(state == State::Write) {
|
|
rtc_write(offset++, data);
|
|
ready = 0;
|
|
wait = 8;
|
|
mdr = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|