diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f3ce550a..11484f1ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -925,15 +925,15 @@ if(NOT SKIP_LIBRARY) install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}-dev NAMELINK_ONLY) endif() if(UNIX AND NOT APPLE AND NOT HAIKU) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-16.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/16x16/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-24.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/24x24/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-32.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/32x32/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-96.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/96x96/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-512.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/512x512/apps RENAME ${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-16.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/16x16/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-24.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/24x24/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-32.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/32x32/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-96.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/96x96/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/icon-512.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/512x512/apps RENAME io.mgba.${BINARY_NAME}.png COMPONENT ${BINARY_NAME}) endif() else() set(BUILD_SHARED OFF) diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index bc9199ffa..6e02ffa4d 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -138,6 +138,8 @@ enum GBTAMA6Command { GBTAMA6_HOUR_WRITE = 0x5, GBTAMA6_MINUTE_READ = 0x6, GBTAMA6_HOUR_READ = 0x7, + GBTAMA6_DISABLE_ALARM = 0x10, + GBTAMA6_ENABLE_ALARM = 0x11, }; enum GBHuC3Register { diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index 52f1fe8aa..3ff904086 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -465,6 +465,9 @@ struct GBSerializedState { struct { uint8_t registers[8]; uint8_t rtcTimerPage[8]; + uint8_t rtcAlarmPage[8]; + uint8_t rtcFreePage0[8]; + uint8_t rtcFreePage1[8]; } tama5Registers; }; diff --git a/res/qt.desktop b/res/qt.desktop index 15dcc63bb..fdf1b403b 100644 --- a/res/qt.desktop +++ b/res/qt.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Version=1.0 -Icon=medusa-emu +Icon=io.mgba.medusa Exec=medusa-emu-qt %f Terminal=false Type=Application diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 5c7fb0310..d6c39035c 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -17,6 +17,12 @@ const uint32_t GB_LOGO_HASH = 0x46195417; mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC", "gb.mbc"); +static const uint8_t _tama6RTCMask[32] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0xF, 0x7, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0xF, 0x1, 0xF, 0xF, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0x0, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, +}; + static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) { UNUSED(address); UNUSED(value); @@ -1537,7 +1543,7 @@ static int _tama6DMYToDayOfYear(int day, int month, int year) { return -1; } day += _daysToMonth[month]; - if (month > 2 && (year % 4) == 0) { + if (month > 2 && (year & 3) == 0) { ++day; } return day; @@ -1549,7 +1555,7 @@ static int _tama6DayOfYearToMonth(int day, int year) { if (day <= _daysToMonth[month + 1]) { return month; } - if (month == 2 && year % 4 == 0) { + if (month == 2 && (year & 3) == 0) { if (day == 60) { return 2; } @@ -1565,7 +1571,7 @@ static int _tama6DayOfYearToDayOfMonth(int day, int year) { if (day <= _daysToMonth[month + 1]) { return day - _daysToMonth[month]; } - if (month == 2 && year % 4 == 0) { + if (month == 2 && (year & 3) == 0) { if (day == 60) { return 29; } @@ -1593,6 +1599,7 @@ static void _latchTAMA6Rtc(struct mRTCSource* rtc, struct GBTAMA5State* tama5, t } uint8_t* timerRegs = tama5->rtcTimerPage; + bool is24hour = tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_24_HOUR]; int64_t diff; diff = timerRegs[GBTAMA6_RTC_PA0_SECOND_1] + timerRegs[GBTAMA6_RTC_PA0_SECOND_10] * 10 + t % 60; if (diff < 0) { @@ -1614,31 +1621,47 @@ static void _latchTAMA6Rtc(struct mRTCSource* rtc, struct GBTAMA5State* tama5, t t /= 60; t += diff / 60; - diff = timerRegs[GBTAMA6_RTC_PA0_HOUR_1] + timerRegs[GBTAMA6_RTC_PA0_HOUR_10] * 10 + t % 24; + diff = timerRegs[GBTAMA6_RTC_PA0_HOUR_1]; + if (is24hour) { + diff += timerRegs[GBTAMA6_RTC_PA0_HOUR_10] * 10; + } else { + int hour10 = timerRegs[GBTAMA6_RTC_PA0_HOUR_10]; + diff += (hour10 & 1) * 10; + diff += (hour10 & 2) * 12; + } + diff += t % 24; if (diff < 0) { diff += 24; t -= 24; } - timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 24) % 10; - timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 24) / 10; + if (is24hour) { + timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 24) % 10; + timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 24) / 10; + } else { + timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 12) % 10; + timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 12) / 10 + (diff / 12) * 2; + } t /= 24; t += diff / 24; int day = timerRegs[GBTAMA6_RTC_PA0_DAY_1] + timerRegs[GBTAMA6_RTC_PA0_DAY_10] * 10; int month = timerRegs[GBTAMA6_RTC_PA0_MONTH_1] + timerRegs[GBTAMA6_RTC_PA0_MONTH_10] * 10; int year = timerRegs[GBTAMA6_RTC_PA0_YEAR_1] + timerRegs[GBTAMA6_RTC_PA0_YEAR_10] * 10; - int dayInYear = _tama6DMYToDayOfYear(day, month, year); + int leapYear = tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_LEAP_YEAR]; + int dayOfWeek = timerRegs[GBTAMA6_RTC_PA0_WEEK]; + int dayInYear = _tama6DMYToDayOfYear(day, month, leapYear); diff = dayInYear + t; while (diff <= 0) { // Previous year - if (year % 4) { + if (leapYear & 3) { diff += 365; } else { diff += 366; } --year; + --leapYear; } - while (diff > (year % 4 ? 365 : 366)) { + while (diff > (leapYear & 3 ? 365 : 366)) { // Future year if (year % 4) { diff -= 365; @@ -1646,11 +1669,17 @@ static void _latchTAMA6Rtc(struct mRTCSource* rtc, struct GBTAMA5State* tama5, t diff -= 366; } ++year; + ++leapYear; } + dayOfWeek = (dayOfWeek + diff) % 7; year %= 100; + leapYear &= 3; - day = _tama6DayOfYearToDayOfMonth(diff, year); - month = _tama6DayOfYearToMonth(diff, year); + day = _tama6DayOfYearToDayOfMonth(diff, leapYear); + month = _tama6DayOfYearToMonth(diff, leapYear); + + timerRegs[GBTAMA6_RTC_PA0_WEEK] = dayOfWeek; + tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_LEAP_YEAR] = leapYear; timerRegs[GBTAMA6_RTC_PA0_DAY_1] = day % 10; timerRegs[GBTAMA6_RTC_PA0_DAY_10] = day / 10; @@ -1719,21 +1748,40 @@ void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) { tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_1] = out & 0xF; tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_10] = out >> 4; break; + case GBTAMA6_DISABLE_ALARM: + tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] &= 0xB; + tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] &= 0xB; + tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] &= 0xB; + tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] &= 0xB; + break; + case GBTAMA6_ENABLE_ALARM: + tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] |= 0x4; + tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] |= 0x4; + tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] |= 0x4; + tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] |= 0x4; + break; } break; case 0x4: // RTC access + address = tama5->registers[GBTAMA5_WRITE_LO]; + if (address >= GBTAMA6_RTC_PAGE) { + break; + } + out = tama5->registers[GBTAMA5_WRITE_HI]; switch (tama5->registers[GBTAMA5_ADDR_LO]) { case 0: - tama5->rtcTimerPage[out & 0xF] = out >> 4; + out &= _tama6RTCMask[address]; + tama5->rtcTimerPage[address] = out; break; case 2: - tama5->rtcAlarmPage[out & 0xF] = out >> 4; + out &= _tama6RTCMask[address | 0x10]; + tama5->rtcAlarmPage[address] = out; break; case 4: - tama5->rtcFreePage0[out & 0xF] = out >> 4; + tama5->rtcFreePage0[address] = out; break; case 6: - tama5->rtcFreePage1[out & 0xF] = out >> 4; + tama5->rtcFreePage1[address] = out; break; } break; @@ -1796,18 +1844,23 @@ uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) { break; } _latchTAMA6Rtc(memory->rtc, tama5, &memory->rtcLastLatch); + address = tama5->registers[GBTAMA5_WRITE_LO]; + if (address > GBTAMA6_RTC_PAGE) { + value = 0; + break; + } switch (tama5->registers[GBTAMA5_ADDR_LO]) { case 1: - value = tama5->rtcTimerPage[tama5->registers[GBTAMA5_WRITE_LO]]; + value = tama5->rtcTimerPage[address]; break; case 3: - value = tama5->rtcTimerPage[tama5->registers[GBTAMA5_WRITE_LO]]; + value = tama5->rtcTimerPage[address]; break; case 5: - value = tama5->rtcTimerPage[tama5->registers[GBTAMA5_WRITE_LO]]; + value = tama5->rtcTimerPage[address]; break; case 7: - value = tama5->rtcTimerPage[tama5->registers[GBTAMA5_WRITE_LO]]; + value = tama5->rtcTimerPage[address]; break; } break; diff --git a/src/gb/memory.c b/src/gb/memory.c index b1a4f84ed..501ebe7a1 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -773,6 +773,12 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) { state->tama5Registers.registers[i] |= memory->mbcState.tama5.registers[i * 2 + 1] << 4; state->tama5Registers.rtcTimerPage[i] = memory->mbcState.tama5.rtcTimerPage[i * 2] & 0xF; state->tama5Registers.rtcTimerPage[i] |= memory->mbcState.tama5.rtcTimerPage[i * 2 + 1] << 4; + state->tama5Registers.rtcAlarmPage[i] = memory->mbcState.tama5.rtcAlarmPage[i * 2] & 0xF; + state->tama5Registers.rtcAlarmPage[i] |= memory->mbcState.tama5.rtcAlarmPage[i * 2 + 1] << 4; + state->tama5Registers.rtcFreePage0[i] = memory->mbcState.tama5.rtcFreePage0[i * 2] & 0xF; + state->tama5Registers.rtcFreePage0[i] |= memory->mbcState.tama5.rtcFreePage0[i * 2 + 1] << 4; + state->tama5Registers.rtcFreePage1[i] = memory->mbcState.tama5.rtcFreePage1[i * 2] & 0xF; + state->tama5Registers.rtcFreePage1[i] |= memory->mbcState.tama5.rtcFreePage1[i * 2 + 1] << 4; } break; case GB_HuC3: @@ -892,6 +898,12 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) { memory->mbcState.tama5.registers[i * 2 + 1] = state->tama5Registers.registers[i] >> 4; memory->mbcState.tama5.rtcTimerPage[i * 2] = state->tama5Registers.rtcTimerPage[i] & 0xF; memory->mbcState.tama5.rtcTimerPage[i * 2 + 1] = state->tama5Registers.rtcTimerPage[i] >> 4; + memory->mbcState.tama5.rtcAlarmPage[i * 2] = state->tama5Registers.rtcAlarmPage[i] & 0xF; + memory->mbcState.tama5.rtcAlarmPage[i * 2 + 1] = state->tama5Registers.rtcAlarmPage[i] >> 4; + memory->mbcState.tama5.rtcFreePage0[i * 2] = state->tama5Registers.rtcFreePage0[i] & 0xF; + memory->mbcState.tama5.rtcFreePage0[i * 2 + 1] = state->tama5Registers.rtcFreePage0[i] >> 4; + memory->mbcState.tama5.rtcFreePage1[i * 2] = state->tama5Registers.rtcFreePage1[i] & 0xF; + memory->mbcState.tama5.rtcFreePage1[i * 2 + 1] = state->tama5Registers.rtcFreePage1[i] >> 4; } break; case GB_HuC3: diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index d795e7982..a77b1db6b 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -427,7 +427,7 @@ install(TARGETS ${BINARY_NAME}-qt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt BUNDLE DESTINATION ${APPDIR} COMPONENT ${BINARY_NAME}-qt) if(UNIX AND NOT APPLE) - install(FILES ${CMAKE_SOURCE_DIR}/res/qt.desktop DESTINATION share/applications RENAME ${BINARY_NAME}-qt.desktop COMPONENT ${BINARY_NAME}-qt) + install(FILES ${CMAKE_SOURCE_DIR}/res/qt.desktop DESTINATION share/applications RENAME io.mgba${PROJECT_NAME}.desktop COMPONENT ${BINARY_NAME}-qt) endif() if(UNIX AND NOT (APPLE AND DISTBUILD)) install(FILES ${CMAKE_SOURCE_DIR}/doc/${BINARY_NAME}-qt.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-qt)