void RTC::event_callback(int event_id, int err) { if(event_id == EVENT_1HZ) { // update calendar if(cur_time.initialized) { cur_time.increment(); } else { get_host_time(&cur_time); // resync cur_time.initialized = true; } read_from_cur_time(); // 1sec interrupt rtdsr |= 4; update_intr(); } else if(event_id == EVENT_32HZ) { // update tcnt regs[TCNT]++; } else if(event_id == EVENT_DONE) { int ch = (rtadr >> 1) & 0x3f; if(rtadr & 1) { // invalid address } else if(rtadr & 0x80) { // write if(ch <= 6) { regs[ch] = (uint8_t)rtobr; write_to_cur_time(); } else if(ch == POWON) { regs[ch] = (regs[ch] & 0xe0) | (rtobr & 0x1f); if((rtobr & 0xe0) == 0xc0) { // reipl regs[ch] = (regs[ch] & 0x1f) | 0xc0; vm->reset(); } else if((rtobr & 0xe0) == 0xe0) { // power off emu->power_off(); } update_checksum(); } else if(7 <= ch && ch < 32) { regs[ch] = (uint8_t)rtobr; update_checksum(); } } else { // read if(ch < 40) { rtibr = regs[ch]; } } // update flags rtdsr &= ~1; rtdsr |= 2; update_intr(); }
void RP5C01::write_io8(uint32 addr, uint32 data) { addr &= 0x0f; if(addr <= 0x0c) { #ifndef HAS_RP5C15 switch(regs[0x0d] & 3) { #else switch(regs[0x0d] & 1) { #endif case 0: if(time[addr] != data) { time[addr] = data; write_to_cur_time(); } return; #ifndef HAS_RP5C15 case 2: ram[addr] = data; return; case 3: ram[addr + 13] = data; return; #endif } } uint8 tmp = regs[addr] ^ data; regs[addr] = data; if(addr == 0x0a) { if(tmp & 1) { // am/pm is changed read_from_cur_time(); } } else if(addr == 0x0f) { #ifndef HAS_RP5C15 switch(regs[0x0d] & 3) { #else switch(regs[0x0d] & 1) { #endif case 0: if(data & 3) { // timer reset } break; case 1: #ifndef HAS_RP5C15 case 2: case 3: #endif if(data & 2) { // timer reset } if(data & 1) { if(alarm) { alarm = false; update_pulse(); } } break; } } } uint32 RP5C01::read_io8(uint32 addr) { addr &= 0x0f; if(addr <= 0x0c) { #ifndef HAS_RP5C15 switch(regs[0x0d] & 3) { #else switch(regs[0x0d] & 1) { #endif case 0: return time[addr]; #ifndef HAS_RP5C15 case 2: return ram[addr]; case 3: return ram[addr + 13]; #endif } } if(addr == 0x0b) { for(int i = 0; i < 3; i++) { if(LEAP_YEAR(cur_time.year - i)) { return i; } } return 3; } return regs[addr]; } void RP5C01::event_callback(int event_id, int err) { if(event_id == EVENT_1SEC) { if(cur_time.initialized) { cur_time.increment(); } else { emu->get_host_time(&cur_time); // resync cur_time.initialized = true; } if(regs[0x0d] & 8) { read_from_cur_time(); if(regs[0x0d] & 4) { update_pulse(); } } } else if(event_id == EVENT_16HZ) { bool update = false; // 1Hz if(++count_16hz == 16) { pulse_1hz = !pulse_1hz; if(!(regs[0x0f] & 8)) { update = true; } count_16hz = 0; } // 16Hz pulse_16hz = !pulse_16hz; if(!(regs[0x0f] & 4)) { update = true; } if(update) { update_pulse(); } } // update signal } void RP5C01::update_pulse() { bool pulse = false; if(regs[0x0d] & 4) { pulse |= alarm; } if(!(regs[0x0f] & 8)) { pulse |= pulse_1hz; } if(!(regs[0x0f] & 4)) { pulse |= pulse_16hz; } write_signals(&outputs_pulse, pulse ? 0 : 0xffffffff); } #define MODE_12H !(regs[0x0a] & 1) void RP5C01::read_from_cur_time() { int hour = MODE_12H ? (cur_time.hour % 12) : cur_time.hour; int ampm = (MODE_12H && cur_time.hour >= 12) ? 2 : 0; time[ 0] = TO_BCD_LO(cur_time.second); time[ 1] = TO_BCD_HI(cur_time.second); time[ 2] = TO_BCD_LO(cur_time.minute); time[ 3] = TO_BCD_HI(cur_time.minute); time[ 4] = TO_BCD_LO(hour); time[ 5] = TO_BCD_HI(hour) | ampm; time[ 6] = cur_time.day_of_week; time[ 7] = TO_BCD_LO(cur_time.day); time[ 8] = TO_BCD_HI(cur_time.day); time[ 9] = TO_BCD_LO(cur_time.month); time[10] = TO_BCD_HI(cur_time.month); time[11] = TO_BCD_LO(cur_time.year); time[12] = TO_BCD_HI(cur_time.year); // check alarm static uint8 mask[9] = {0, 0, 0x0f, 0x07, 0x0f, 0x03, 0x07, 0x0f, 0x03}; bool tmp = true; for(int i = 3; i < 9; i++) { if((time[i] & mask[i]) != (regs[i] & mask[i])) { tmp = false; break; } } if(tmp) { alarm = true; } }