#include 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) roundSeconds(); //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, 32'768 * 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 rtcRead(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) rtcReset(); 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) { rtcWrite(offset++, data); ready = 0; wait = 8; mdr = data; } } } }