From c8e624850bf2ec02b5a506595e82257604be807c Mon Sep 17 00:00:00 2001 From: capriots <29807355+capriots@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:45:26 +0200 Subject: [PATCH] cellRtc: improvements --- rpcs3/Emu/Cell/Modules/cellRtc.cpp | 397 ++++++++++++----------------- rpcs3/Emu/Cell/Modules/cellRtc.h | 17 +- 2 files changed, 168 insertions(+), 246 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/rpcs3/Emu/Cell/Modules/cellRtc.cpp index eeeeb12a1c..11e29b923a 100644 --- a/rpcs3/Emu/Cell/Modules/cellRtc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRtc.cpp @@ -9,7 +9,6 @@ LOG_CHANNEL(cellRtc); -// clang-format off template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -36,54 +35,6 @@ void fmt_class_string::format(std::string& out, u64 arg) return unknown; }); } -// clang-format on - -// Grabbed from JPCSP -// This is the # of microseconds between January 1, 0001 and January 1, 1970. -constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ULL; -// This is the # of microseconds between January 1, 0001 and January 1, 1601 (for Win32 FILETIME.) -constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ULL; - -constexpr u64 EPOCH_AS_FILETIME = 116444736000000000ULL; - -// Also stores leap year -constexpr u8 DAYS_IN_MONTH[24] = {0x1F, 0x1C, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F}; - -s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) -{ - return s64{seconds} + s64{minutes} * 60 + s64{hours} * 3600 + s64{days} * 86400 + s64{s64{years} - 70} * 31536000 + s64{(years - 69) / 4} * 86400 - s64{(years - 1) / 100} * 86400 + - s64{(years + 299) / 400} * 86400; -} - -u64 convertToWin32FILETIME(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) -{ - s64 unixtime = convertToUNIXTime(seconds, minutes, hours, days, years); - u64 win32time = static_cast(unixtime) * 10000000 + EPOCH_AS_FILETIME; - u64 win32filetime = win32time | win32time >> 32; - return win32filetime; -} - -// TODO make all this use tick resolution and figure out the magic numbers -// TODO MULHDU instruction returns high 64 bit of the 128 bit result of two 64-bit regs multiplication -// need to be replaced with utils::mulh64, utils::umulh64, utils::div128, utils::udiv128 in needed places -// cellRtcSetTick / cellRtcSetWin32FileTime / cellRtcSetCurrentTick / cellRtcSetCurrentSecureTick -// TODO undo optimized division - -// Internal helper functions in cellRtc - -error_code set_secure_rtc_time(u64 time) -{ - return sys_ss_secure_rtc(0x3003 /* SET_TIME */, time, 0, 0); // TODO -} - -error_code get_secure_rtc_time(u64 unk1, u64 unk2, u64 unk3) -{ - return sys_ss_secure_rtc(0x3002 /* GET_TIME */, unk1, unk2, unk3); // TODO -} - -// End of internal helper functions - -// Helper methods static inline char ascii(u8 num) { @@ -100,11 +51,9 @@ static bool is_leap_year(u32 year) return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } -// End of helper methods - error_code cellRtcGetCurrentTick(vm::ptr pTick) { - cellRtc.todo("cellRtcGetCurrentTick(pTick=*0x%x)", pTick); + cellRtc.trace("cellRtcGetCurrentTick(pTick=*0x%x)", pTick); if (!vm::check_addr(pTick.addr())) { @@ -115,7 +64,7 @@ error_code cellRtcGetCurrentTick(vm::ptr pTick) vm::var nsec; error_code ret = sys_time_get_current_time(sec, nsec); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } @@ -127,7 +76,7 @@ error_code cellRtcGetCurrentTick(vm::ptr pTick) error_code cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone) { - cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone); + cellRtc.notice("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone); if (!vm::check_addr(pClock.addr())) { @@ -144,7 +93,7 @@ error_code cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone vm::var nsec; error_code ret = sys_time_get_current_time(sec, nsec); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } @@ -159,7 +108,7 @@ error_code cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone error_code cellRtcGetCurrentClockLocalTime(vm::ptr pClock) { - cellRtc.todo("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock); + cellRtc.trace("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock); if (!vm::check_addr(pClock.addr())) { @@ -170,7 +119,7 @@ error_code cellRtcGetCurrentClockLocalTime(vm::ptr pClock) vm::var summertime; error_code ret = sys_time_get_timezone(timezone, summertime); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } @@ -190,14 +139,14 @@ error_code cellRtcGetCurrentClockLocalTime(vm::ptr pClock) vm::var nsec; ret = sys_time_get_current_time(sec, nsec); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } tick->tick = *nsec / 1000 + *sec * cellRtcGetTickResolution() + RTC_MAGIC_OFFSET; - cellRtcTickAddMinutes(tick, tick, s64{*timezone} + s64{*summertime}); + cellRtcTickAddMinutes(tick, tick, *timezone + *summertime); cellRtcSetTick(pClock, tick); return CELL_OK; @@ -319,7 +268,7 @@ error_code cellRtcFormatRfc2822LocalTime(vm::ptr pszDateTime, vm::cptr summertime; error_code ret = sys_time_get_timezone(timezone, summertime); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } @@ -449,7 +398,7 @@ error_code cellRtcFormatRfc3339LocalTime(vm::ptr pszDateTime, vm::cptr summertime; error_code ret = sys_time_get_timezone(timezone, summertime); - if (ret != CELL_OK) + if (ret < CELL_OK) { return ret; } @@ -773,7 +722,7 @@ error_code cellRtcParseDateTime(vm::ptr pUtc, vm::cptr pszDat cellRtc.warning("cellRtcParseDateTime(): ASCII value 0x%x at position %d is not a digit", pszDateTime[pos], pos); } - day = digit(pszDateTime[pos]); + day = static_cast(pszDateTime[pos]) - '0'; // Needs to be sign extended first to match LLE for values from 0x80 to 0xb0 pos++; } @@ -1006,7 +955,7 @@ error_code cellRtcParseRfc3339(vm::ptr pUtc, vm::cptr pszDate error_code cellRtcGetTick(vm::cptr pTime, vm::ptr pTick) { - cellRtc.notice("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + cellRtc.trace("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); if (!vm::check_addr(pTime.addr())) { @@ -1110,7 +1059,7 @@ u64 date_time_to_tick(CellRtcDateTime date_time) error_code cellRtcSetTick(vm::ptr pTime, vm::cptr pTick) { - cellRtc.notice("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + cellRtc.trace("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); if (!vm::check_addr(pTime.addr())) { @@ -1262,7 +1211,7 @@ error_code cellRtcTickAddWeeks(vm::ptr pTick0, vm::cptr pTick0, vm::cptr pTick1, s32 iAdd) { - cellRtc.trace("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + cellRtc.notice("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); if (!vm::check_addr(pTick0.addr())) { @@ -1277,41 +1226,28 @@ error_code cellRtcTickAddMonths(vm::ptr pTick0, vm::cptr date_time; cellRtcSetTick(date_time, pTick1); - // Not pretty, but works + const s32 total_months = date_time->year * 12 + date_time->month + iAdd - 1; + const u16 new_year = total_months / 12; + const u16 new_month = total_months - new_year * 12 + 1; - s64 total_months = (date_time->year * 12ULL) + date_time->month + iAdd + -1; - s32 total_months_s32 = ::narrow(total_months); - u32 unk_1 = total_months_s32 >> 0x1f; - u64 unk_2 = ((total_months_s32 / 6 + unk_1) >> 1) - unk_1; - u32 unk_3 = ::narrow(unk_2); - unk_1 = unk_3 & 0xffff; - u64 unk_4 = (total_months - ((u64{unk_3} << 4) - (unk_3 << 2))) + 1; - if (((unk_2 & 0xffff) == 0) || ((unk_3 = unk_4 & 0xffff, (unk_4 & 0xffff) == 0 || unk_3 > 12))) + u16 month_days; + + if (new_year == 0u || new_month < 1u || new_month > 12u) { - return CELL_RTC_ERROR_INVALID_ARG; - } - - u32 uVar1 = ((s64{unk_1} * 0x51eb851f) >> 0x20); - - // Leap year check - u32 month_idx; - if ((unk_1 == (uVar1 >> 7) * 400) || ((unk_1 != (uVar1 >> 5) * 100 && ((unk_2 & 3) == 0)))) - { - month_idx = unk_3 + 11; + month_days = static_cast(CELL_RTC_ERROR_INVALID_ARG); // LLE writes the error to this variable } else { - month_idx = unk_3 - 1; + month_days = is_leap_year(new_year) ? DAYS_IN_MONTH_LEAP[new_month - 1] : DAYS_IN_MONTH[new_month - 1]; } - u32 month_days = DAYS_IN_MONTH[month_idx]; if (month_days < date_time->day) { date_time->day = month_days; } - date_time->month = ::narrow(unk_4); - date_time->year = ::narrow(unk_2); + date_time->month = new_month; + date_time->year = new_year; cellRtcGetTick(date_time, pTick0); return CELL_OK; @@ -1319,7 +1255,7 @@ error_code cellRtcTickAddMonths(vm::ptr pTick0, vm::cptr pTick0, vm::cptr pTick1, s32 iAdd) { - cellRtc.trace("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + cellRtc.notice("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); if (!vm::check_addr(pTick0.addr())) { @@ -1334,33 +1270,26 @@ error_code cellRtcTickAddYears(vm::ptr pTick0, vm::cptr date_time; cellRtcSetTick(date_time, pTick1); - u64 total_years = iAdd + date_time->year; - u32 unk_1 = total_years & 0xffff; - if (unk_1 == 0 || date_time->month == 0 || date_time->month > 12) - { - return CELL_RTC_ERROR_INVALID_ARG; - } + const u16 month = date_time->month; + const u16 new_year = date_time->year + iAdd; - u32 uVar1 = ((s64{unk_1} * 0x51eb851f) >> 0x20); + u16 month_days; - // Leap year check - u32 month_idx; - if ((unk_1 == (uVar1 >> 7) * 400) || ((unk_1 != (uVar1 >> 5) * 100 && ((total_years & 3) == 0)))) + if (new_year == 0u || month < 1u || month > 12u) { - month_idx = date_time->month + 0xb; + month_days = static_cast(CELL_RTC_ERROR_INVALID_ARG); // LLE writes the error to this variable } else { - month_idx = date_time->month - 1; + month_days = is_leap_year(new_year) ? DAYS_IN_MONTH_LEAP[month - 1] : DAYS_IN_MONTH[month - 1]; } - u32 month_days = DAYS_IN_MONTH[month_idx]; if (month_days < date_time->day) { date_time->day = month_days; } - date_time->year = ::narrow(total_years); + date_time->year = new_year; cellRtcGetTick(date_time, pTick0); return CELL_OK; @@ -1368,7 +1297,7 @@ error_code cellRtcTickAddYears(vm::ptr pTick0, vm::cptr pUtc, vm::ptr pLocalTime) { - cellRtc.todo("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime); + cellRtc.trace("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime); vm::var timezone; vm::var summertime; @@ -1376,7 +1305,7 @@ error_code cellRtcConvertUtcToLocalTime(vm::cptr pUtc, vm::ptr pUtc, vm::ptr pLocalTime, vm::ptr pUtc) { - cellRtc.todo("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc); + cellRtc.notice("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc); vm::var timezone; vm::var summertime; @@ -1392,7 +1321,7 @@ error_code cellRtcConvertLocalTimeToUtc(vm::cptr pLocalTime, vm::pt error_code ret = sys_time_get_timezone(timezone, summertime); if (-1 < ret) { - ret = cellRtcTickAddMinutes(pUtc, pLocalTime, -(s64{*timezone} + s64{*summertime})); + ret = cellRtcTickAddMinutes(pUtc, pLocalTime, -(*timezone + *summertime)); } return ret; @@ -1400,23 +1329,41 @@ error_code cellRtcConvertLocalTimeToUtc(vm::cptr pLocalTime, vm::pt error_code cellRtcGetCurrentSecureTick(vm::ptr tick) { - cellRtc.todo("cellRtcGetCurrentSecureTick(*0x%x)", tick); + cellRtc.notice("cellRtcGetCurrentSecureTick(tick=*0x%x)", tick); if (!vm::check_addr(tick.addr())) { return CELL_RTC_ERROR_INVALID_POINTER; } - // TODO + tick->tick = RTC_SYSTEM_TIME_MIN; - tick->tick = 0xe01d003a63a000; + const vm::var time{0}; + const vm::var status{0}; - return CELL_OK; + error_code ret = sys_ss_secure_rtc(0x3002, 0, time.addr(), status.addr()); + + if (ret >= CELL_OK) + { + tick->tick += *time * cellRtcGetTickResolution(); + } + else if (ret == static_cast(SYS_SS_RTC_ERROR_UNK)) + { + switch (*status) + { + case 1: ret = CELL_RTC_ERROR_NO_CLOCK; break; + case 2: ret = CELL_RTC_ERROR_NOT_INITIALIZED; break; + case 4: ret = CELL_RTC_ERROR_INVALID_VALUE; break; + case 8: ret = CELL_RTC_ERROR_NO_CLOCK; break; + } + } + + return ret; } error_code cellRtcGetDosTime(vm::cptr pDateTime, vm::ptr puiDosTime) { - cellRtc.todo("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime); + cellRtc.notice("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1430,27 +1377,26 @@ error_code cellRtcGetDosTime(vm::cptr pDateTime, vm::ptr p if (pDateTime->year < 1980) { - if (puiDosTime) + if (puiDosTime) // Should always evaluate to true, nullptr was already checked above { *puiDosTime = 0; - return -1; - } - } - else if (pDateTime->year >= 2108) - { - if (puiDosTime) - { - *puiDosTime = 0xff9fbf7d; // kHighDosTime - return -1; - } - } - else - { - if (!puiDosTime) - { - return CELL_OK; } + return -1; + } + + if (pDateTime->year >= 2108) + { + if (puiDosTime) // Should always evaluate to true, nullptr was already checked above + { + *puiDosTime = 0xff9fbf7d; // kHighDosTime + } + + return -1; + } + + if (puiDosTime) // Should always evaluate to true, nullptr was already checked above + { s32 year = ((pDateTime->year - 1980) & 0x7F) << 9; s32 month = ((pDateTime->month) & 0xF) << 5; s32 hour = ((pDateTime->hour) & 0x1F) << 11; @@ -1460,65 +1406,59 @@ error_code cellRtcGetDosTime(vm::cptr pDateTime, vm::ptr p s32 ymd = year | month | day; s32 hms = hour | minute | second; *puiDosTime = (ymd << 16) | hms; - - return CELL_OK; } - return -1; + return CELL_OK; } -error_code cellRtcGetSystemTime(vm::cptr pDateTime, vm::ptr pTick) +error_code cellRtcGetSystemTime(vm::cptr pDateTime, vm::ptr pTimeStamp) { - cellRtc.todo("cellRtcGetSystemTime(pDateTime=*0x%x, pTick=*0x%x)", pDateTime, pTick); + cellRtc.notice("cellRtcGetSystemTime(pDateTime=*0x%x, pTimeStamp=*0x%x)", pDateTime, pTimeStamp); if (!vm::check_addr(pDateTime.addr())) { return CELL_RTC_ERROR_INVALID_POINTER; } - if (!vm::check_addr(pTick.addr())) + if (!vm::check_addr(pTimeStamp.addr())) { return CELL_RTC_ERROR_INVALID_POINTER; } - error_code ret; vm::var tick; cellRtcGetTick(pDateTime, tick); - if (tick->tick < 63082281600000000) // Max time + if (tick->tick < RTC_SYSTEM_TIME_MIN) { - ret = CELL_RTC_ERROR_INVALID_VALUE; - if (pTick) + if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above { - pTick->tick = 0; - } - } - else - { - if (tick->tick < 0xeb5325dc3ec23f) // 66238041600999999 - { - ret = CELL_OK; - if (pTick) - { - pTick->tick = (tick->tick + 0xff1fe2ffc59c6000) / cellRtcGetTickResolution(); - } - } - else - { - ret = CELL_RTC_ERROR_INVALID_VALUE; - if (pTick) - { - pTick->tick = 0xbc19137f; // 1 day? - } + *pTimeStamp = 0; } + + return CELL_RTC_ERROR_INVALID_VALUE; } - return ret; + if (tick->tick >= RTC_SYSTEM_TIME_MAX + cellRtcGetTickResolution()) + { + if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above + { + *pTimeStamp = (RTC_SYSTEM_TIME_MAX - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution(); + } + + return CELL_RTC_ERROR_INVALID_VALUE; + } + + if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above + { + *pTimeStamp = (tick->tick - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution(); + } + + return CELL_OK; } error_code cellRtcGetTime_t(vm::cptr pDateTime, vm::ptr piTime) { - cellRtc.todo("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); + cellRtc.notice("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1533,30 +1473,27 @@ error_code cellRtcGetTime_t(vm::cptr pDateTime, vm::ptr pi vm::var tick; cellRtcGetTick(pDateTime, tick); - error_code ret; if (tick->tick < RTC_MAGIC_OFFSET) { - ret = CELL_RTC_ERROR_INVALID_VALUE; - if (piTime) + if (piTime) // Should always evaluate to true, nullptr was already checked above { *piTime = 0; } - } - else - { - ret = CELL_OK; - if (piTime) - { - *piTime = (tick->tick + 0xff23400100d44000) / cellRtcGetTickResolution(); - } + + return CELL_RTC_ERROR_INVALID_VALUE; } - return ret; + if (piTime) // Should always evaluate to true, nullptr was already checked above + { + *piTime = (tick->tick - RTC_MAGIC_OFFSET) / cellRtcGetTickResolution(); + } + + return CELL_OK; } error_code cellRtcGetWin32FileTime(vm::cptr pDateTime, vm::ptr pulWin32FileTime) { - cellRtc.todo("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime); + cellRtc.notice("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1571,83 +1508,73 @@ error_code cellRtcGetWin32FileTime(vm::cptr pDateTime, vm::ptr< vm::var tick; cellRtcGetTick(pDateTime, tick); - error_code ret; if (tick->tick < RTC_FILETIME_OFFSET) { - ret = CELL_RTC_ERROR_INVALID_VALUE; - if (pulWin32FileTime) + if (pulWin32FileTime) // Should always evaluate to true, nullptr was already checked above { *pulWin32FileTime = 0; } - } - else - { - ret = CELL_OK; - if (pulWin32FileTime) - { - *pulWin32FileTime = tick->tick * 10 + 0xf8fe31e8dd890000; - } + + return CELL_RTC_ERROR_INVALID_VALUE; } - return ret; + if (pulWin32FileTime) // Should always evaluate to true, nullptr was already checked above + { + *pulWin32FileTime = (tick->tick - RTC_FILETIME_OFFSET) * 10; + } + + return CELL_OK; } error_code cellRtcSetCurrentSecureTick(vm::ptr pTick) { - cellRtc.todo("cellRtcSetCurrentSecureTick(pTick=*0x%x)", pTick); + cellRtc.notice("cellRtcSetCurrentSecureTick(pTick=*0x%x)", pTick); if (!pTick) { return CELL_RTC_ERROR_INVALID_POINTER; } - u64 uVar1 = pTick->tick + 0xff1fe2ffc59c6000; - if (uVar1 >= 0xb3625a1cbe000) // 3155760000000000 + if (pTick->tick > RTC_SYSTEM_TIME_MAX) { return CELL_RTC_ERROR_INVALID_VALUE; } - return set_secure_rtc_time(uVar1 / cellRtcGetTickResolution()); + return sys_ss_secure_rtc(0x3003, (pTick->tick - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution(), 0, 0); } error_code cellRtcSetCurrentTick(vm::cptr pTick) { - cellRtc.todo("cellRtcSetCurrentTick(pTick=*0x%x)", pTick); + cellRtc.notice("cellRtcSetCurrentTick(pTick=*0x%x)", pTick); if (!pTick) { return CELL_RTC_ERROR_INVALID_POINTER; } - //u64 tmp = pTick->tick + 0xff23400100d44000; - if (!(0xdcbffeff2bbfff < pTick->tick)) + if (pTick->tick < RTC_MAGIC_OFFSET) { - return CELL_RTC_ERROR_INVALID_ARG; + return CELL_RTC_ERROR_INVALID_VALUE; } - // TODO syscall not implemented - /* - u64 tmp2 = sys_time_get_system_time(tmp / cellRtcGetTickResolution(), (tmp % cellRtcGetTickResolution()) * 1000); + const u64 unix_time = pTick->tick - RTC_MAGIC_OFFSET; - return (tmp2 & (tmp2 | tmp2 - 1) >> 0x1f); - */ - return CELL_OK; + const error_code ret = sys_time_set_current_time(unix_time / cellRtcGetTickResolution(), unix_time % cellRtcGetTickResolution() * 1000); + + return ret >= CELL_OK ? CELL_OK : ret; } error_code cellRtcSetConf(s64 unk1, s64 unk2, u32 timezone, u32 summertime) { - cellRtc.todo("cellRtcSetConf(unk1=0x%x, unk2=0x%x, timezone=%d, summertime=%d)", unk1, unk2, timezone, summertime); + cellRtc.notice("cellRtcSetConf(unk1=0x%x, unk2=0x%x, timezone=%d, summertime=%d)", unk1, unk2, timezone, summertime); // Seems the first 2 args are ignored :| - // TODO Syscall not implemented - // return sys_time_set_timezone(timezone, summertime); - - return CELL_OK; + return sys_time_set_timezone(timezone, summertime); } error_code cellRtcSetDosTime(vm::ptr pDateTime, u32 uiDosTime) { - cellRtc.todo("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime); + cellRtc.notice("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1668,7 +1595,7 @@ error_code cellRtcSetDosTime(vm::ptr pDateTime, u32 uiDosTime) return CELL_OK; } -u32 cellRtcGetTickResolution() +constexpr u32 cellRtcGetTickResolution() { // Amount of ticks in a second return 1000000; @@ -1676,7 +1603,7 @@ u32 cellRtcGetTickResolution() error_code cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) { - cellRtc.todo("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); + cellRtc.notice("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1693,7 +1620,7 @@ error_code cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) error_code cellRtcSetSystemTime(vm::ptr pDateTime, u64 iTime) { - cellRtc.todo("cellRtcSetSystemTime(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); + cellRtc.notice("cellRtcSetSystemTime(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1701,14 +1628,16 @@ error_code cellRtcSetSystemTime(vm::ptr pDateTime, u64 iTime) } vm::var tick; - tick->tick = iTime * cellRtcGetTickResolution() + 0xe01d003a63a000; + tick->tick = iTime * cellRtcGetTickResolution() + RTC_SYSTEM_TIME_MIN; - return cellRtcSetTick(pDateTime, tick); + cellRtcSetTick(pDateTime, tick); + + return CELL_OK; } error_code cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin32FileTime) { - cellRtc.todo("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); + cellRtc.notice("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); if (!vm::check_addr(pDateTime.addr())) { @@ -1723,7 +1652,7 @@ error_code cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin error_code cellRtcIsLeapYear(s32 year) { - cellRtc.todo("cellRtcIsLeapYear(year=%d)", year); + cellRtc.notice("cellRtcIsLeapYear(year=%d)", year); if (year < 1) { @@ -1735,22 +1664,17 @@ error_code cellRtcIsLeapYear(s32 year) error_code cellRtcGetDaysInMonth(s32 year, s32 month) { - cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month); + cellRtc.notice("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month); if ((year <= 0) || (month <= 0) || (month > 12)) { return CELL_RTC_ERROR_INVALID_ARG; } - if (is_leap_year(year)) - { - return not_an_error(DAYS_IN_MONTH[month + 11]); - } - - return not_an_error(DAYS_IN_MONTH[month - 1]); + return not_an_error(is_leap_year(year) ? DAYS_IN_MONTH_LEAP[month - 1] : DAYS_IN_MONTH[month - 1]); } -error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) +s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) { cellRtc.trace("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day); @@ -1760,13 +1684,16 @@ error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) month += 12; } - return not_an_error(((month * 0xd + 8) / 5 + ((year + (year >> 2) + (year < 0 && (year & 3U) != 0)) - year / 100) + year / 400 + day) % 7); + return ((month * 13 + 8) / 5 + year + year / 4 - year / 100 + year / 400 + day) % 7; } error_code cellRtcCheckValid(vm::cptr pTime) { - cellRtc.todo("cellRtcCheckValid(pTime=*0x%x)", pTime); - cellRtc.todo("cellRtcCheckValid year: %d, month: %d, day: %d, hour: %d, minute: %d, second: %d, microsecond: %d\n", pTime->year, pTime->month, pTime->day, pTime->hour, pTime->minute, pTime->second, pTime->microsecond); + cellRtc.notice("cellRtcCheckValid(pTime=*0x%x)", pTime); + + ensure(!!pTime); // Not checked on LLE + + cellRtc.notice("cellRtcCheckValid year: %d, month: %d, day: %d, hour: %d, minute: %d, second: %d, microsecond: %d", pTime->year, pTime->month, pTime->day, pTime->hour, pTime->minute, pTime->second, pTime->microsecond); if (pTime->year == 0 || pTime->year >= 10000) { @@ -1778,19 +1705,9 @@ error_code cellRtcCheckValid(vm::cptr pTime) return CELL_RTC_ERROR_INVALID_MONTH; } - s32 month_idx; + const auto& days_in_month = is_leap_year(pTime->year) ? DAYS_IN_MONTH_LEAP : DAYS_IN_MONTH; - if (is_leap_year(pTime->year)) - { - // Leap year check - month_idx = pTime->month + 11; - } - else - { - month_idx = pTime->month - 1; - } - - if (pTime->day == 0 || pTime->day > DAYS_IN_MONTH[month_idx]) + if (pTime->day == 0 || pTime->day > days_in_month[pTime->month - 1]) { return CELL_RTC_ERROR_INVALID_DAY; } @@ -1818,9 +1735,11 @@ error_code cellRtcCheckValid(vm::cptr pTime) return CELL_OK; } -error_code cellRtcCompareTick(vm::cptr pTick0, vm::cptr pTick1) +s32 cellRtcCompareTick(vm::cptr pTick0, vm::cptr pTick1) { - cellRtc.todo("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1); + cellRtc.notice("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1); + + ensure(!!pTick0 && !!pTick1); // Not checked on LLE s32 ret = -1; if (pTick1->tick <= pTick0->tick) @@ -1828,7 +1747,7 @@ error_code cellRtcCompareTick(vm::cptr pTick0, vm::cptrtick < pTick0->tick; } - return not_an_error(ret); + return ret; } DECLARE(ppu_module_manager::cellRtc) diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.h b/rpcs3/Emu/Cell/Modules/cellRtc.h index ddf9f4dd81..6bb635e3e0 100644 --- a/rpcs3/Emu/Cell/Modules/cellRtc.h +++ b/rpcs3/Emu/Cell/Modules/cellRtc.h @@ -38,10 +38,18 @@ struct CellRtcDateTime be_t microsecond; // 0 to 999999 }; +constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ull; // 1970-01-01 00:00:00.000000 +constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ull; // 1601-01-01 00:00:00.000000 +constexpr u64 RTC_SYSTEM_TIME_MIN = 63082281600000000ull; // 2000-01-01 00:00:00.000000 +constexpr u64 RTC_SYSTEM_TIME_MAX = 66238041599999999ull; // 2099-12-31 23:59:59.999999 + constexpr u32 DAYS_IN_400_YEARS = 365 * 400 + 97; constexpr u16 DAYS_IN_100_YEARS = 365 * 100 + 24; constexpr u16 DAYS_IN_4_YEARS = 365 * 4 + 1; +constexpr std::array DAYS_IN_MONTH = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +constexpr std::array DAYS_IN_MONTH_LEAP = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + constexpr std::array MONTH_OFFSET = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, umax }; constexpr std::array MONTH_OFFSET_LEAP = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, umax }; @@ -50,17 +58,12 @@ constexpr std::array MONTH_NAMES = { "january", "febru constexpr std::array TIME_ZONE_NAMES = { "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt", "nzdt", "nzst", "idle", "nzt", "aesst", "acsst", "cadt", "sadt", "aest", "east", "gst", "ligt", "acst", "sast", "cast", "awsst", "jst", "kst", "wdt", "mt", "awst", "cct", "wadt", "wst", "jt", "wast", "it", "bt", "eetdst", "eet", "cetdst", "fwt", "ist", "mest", "metdst", "sst", "bst", "cet", "dnt", "fst", "met", "mewt", "mez", "nor", "set", "swt", "wetdst", "wet", "wat", "ndt", "adt", "nft", "nst", "ast", "ydt", "hdt", "yst", "ahst", "cat", "nt", "idlw" }; constexpr std::array TIME_ZONE_VALUES = { 0, -10, -8, -12, -10, -14, -12, -16, -14, 26, 24, 24, 24, 22, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 16, 16, 16, 16, 15, 14, 7, 6, 6, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, -2, -3, -6, -5, -5, -8, -16, -18, -18, -20, -20, -22, -24 }; // In units of 30 minutes -error_code cellRtcTickAddYears(vm::ptr pTick0, vm::cptr pTick1, s32 iAdd); -error_code cellRtcTickAddMonths(vm::ptr pTick0, vm::cptr pTick1, s32 lAdd); -error_code cellRtcTickAddDays(vm::ptr pTick0, vm::cptr pTick1, s32 lAdd); -error_code cellRtcTickAddHours(vm::ptr pTick0, vm::cptr pTick1, s32 lAdd); error_code cellRtcTickAddMinutes(vm::ptr pTick0, vm::cptr pTick1, s64 lAdd); -error_code cellRtcTickAddSeconds(vm::ptr pTick0, vm::cptr pTick1, s64 lAdd); error_code cellRtcSetTick(vm::ptr pTime, vm::cptr pTick); -u32 cellRtcGetTickResolution(); +constexpr u32 cellRtcGetTickResolution(); error_code cellRtcCheckValid(vm::cptr pTime); -error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day); +s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day); error_code cellRtcGetTick(vm::cptr pTime, vm::ptr pTick); error_code cellRtcGetCurrentTick(vm::ptr pTick);