void __CtrlTimerUpdate(u64 userdata, int cyclesLate) { // This only runs in timer mode (ctrlCycle > 0.) _dbg_assert_msg_(SCECTRL, ctrlCycle > 0, "Ctrl: sampling cycle should be > 0"); __CtrlDoSample(); CoreTiming::ScheduleEvent(usToCycles(ctrlCycle), ctrlTimer, 0); }
ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { ResultCode result = StartImpl(parameter); if (result.IsError()) return result; // Schedule the update event CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id)); return result; }
void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { CoreTiming::UnscheduleEvent(vtimerTimer, vt->GetUID()); vt->nvt.schedule = schedule; if (vt->nvt.active == 1 && vt->nvt.handlerAddr != 0) CoreTiming::ScheduleEvent(usToCycles(vt->nvt.schedule), vtimerTimer, vt->GetUID()); }
void EmuScreen::render() { if (invalid_) return; // Reapply the graphics state of the PSP ReapplyGfxState(); // We just run the CPU until we get to vblank. This will quickly sync up pretty nicely. // The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully... int blockTicks = usToCycles(1000000 / 10); // Run until CORE_NEXTFRAME while (coreState == CORE_RUNNING) { u64 nowTicks = CoreTiming::GetTicks(); mipsr4k.RunLoopUntil(nowTicks + blockTicks); } // Hopefully coreState is now CORE_NEXTFRAME if (coreState == CORE_NEXTFRAME) { // set back to running for the next frame coreState = CORE_RUNNING; } else if (coreState == CORE_POWERDOWN) { ILOG("SELF-POWERDOWN!"); screenManager()->switchScreen(new MenuScreen()); } if (invalid_) return; if (g_Config.bBufferedRendering) fbo_unbind(); UIShader_Prepare(); uiTexture->Bind(0); glstate.viewport.set(0, 0, pixel_xres, pixel_yres); glstate.viewport.restore(); ui_draw2d.Begin(UIShader_Get(), DBMODE_NORMAL); if (g_Config.bShowTouchControls) DrawGamepad(ui_draw2d); DrawWatermark(); glsl_bind(UIShader_Get()); ui_draw2d.End(); ui_draw2d.Flush(); // Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it? #if defined(USING_GLES2) bool hasDiscard = false; // TODO if (hasDiscard) { //glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT); } #endif }
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) { if (timeoutPtr == 0 || semaWaitTimer == 0) return; // This should call __KernelMutexTimeout() later, unless we cancel it. int micro = (int) Memory::Read_U32(timeoutPtr); CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); }
void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { CoreTiming::UnscheduleEvent(vtimerTimer, vt->GetUID()); vt->nvt.schedule = schedule; if (vt->nvt.active == 1) // this delay makes the test pass, not sure if it's right CoreTiming::ScheduleEvent(usToCycles(vt->nvt.schedule + 372), vtimerTimer, vt->GetUID()); }
virtual void handleResult(int result) { // A non-zero result means to reschedule. // TODO: Do sysclock alarms return a different value unit? if (result > 0) __KernelScheduleAlarm(alarm, usToCycles(result)); else if (result < 0) WARN_LOG(HLE, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result); }
void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) { if (timeoutPtr == 0 || lwMutexWaitTimer == 0) return; // This should call __KernelMutexTimeout() later, unless we cancel it. int micro = (int) Memory::Read_U32(timeoutPtr); CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread()); }
void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1); }
void __UmdWaitStat(u32 timeout) { // This happens to be how the hardware seems to time things. if (timeout <= 4) timeout = 15; else if (timeout <= 215) timeout = 250; CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimeoutEvent, __KernelGetCurThread()); }
void Timer::Set(s64 initial, s64 interval) { // Ensure we get rid of any previous scheduled event Cancel(); initial_delay = initial; interval_delay = interval; u64 initial_microseconds = initial / 1000; CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, callback_handle); }
u32 hleDelayResult(u32 result, const char *reason, int usec) { if (__KernelIsDispatchEnabled()) { CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, __KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, result, 0, false, reason); } else WARN_LOG(HLE, "Dispatch disabled, not delaying HLE result (right thing to do?)"); return result; }
SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr) { u64 micro; if (Memory::IsValidAddress(microPtr)) micro = Memory::Read_U64(microPtr); else return -1; DEBUG_LOG(HLE, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr); return __KernelSetAlarm(usToCycles(micro), handlerPtr, commonPtr); }
void __UmdWaitStat(u32 timeout) { if (umdStatTimer == 0) umdStatTimer = CoreTiming::RegisterEvent("MutexTimeout", &__UmdStatTimeout); // This happens to be how the hardware seems to time things. if (timeout <= 4) timeout = 15; else if (timeout <= 215) timeout = 250; CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimer, __KernelGetCurThread()); }
static void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; // PSP_UMD_READY will be returned when sceKernelGetCompiledSdkVersion() != 0 if (sceKernelGetCompiledSdkVersion() != 0) { notifyArg |= PSP_UMD_READY; } if (driveCBId != 0) __KernelNotifyCallback(driveCBId, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1); }
void Timer::Signal(int cycles_late) { LOG_TRACE(Kernel, "Timer %u fired", GetObjectId()); signaled = true; // Resume all waiting threads WakeupAllWaitingThreads(); if (interval_delay != 0) { // Reschedule the timer with the interval delay u64 interval_microseconds = interval_delay / 1000; CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, timer_callback_event_type, callback_handle); } }
static int DisplayWaitForVblanks(const char *reason, int vblanks, bool callbacks = false) { const s64 ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks; const s64 cyclesToNextVblank = msToCycles(frameMs) - ticksIntoFrame; // These syscalls take about 115 us, so if the next vblank is before then, we're waiting extra. // At least, on real firmware a wait >= 16500 into the frame will wait two. if (cyclesToNextVblank <= usToCycles(115)) { ++vblanks; } vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks)); __KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, callbacks, reason); return hleLogSuccessVerboseI(SCEDISPLAY, 0, "waiting for %d vblanks", vblanks); }
void Timer::Set(s64 initial, s64 interval) { // Ensure we get rid of any previous scheduled event Cancel(); initial_delay = initial; interval_delay = interval; if (initial == 0) { // Immediately invoke the callback Signal(0); } else { u64 initial_microseconds = initial / 1000; CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, callback_handle); } }
void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) { if (timeoutPtr == 0 || eventFlagWaitTimer == 0) return; int micro = (int) Memory::Read_U32(timeoutPtr); // This seems like the actual timing of timeouts on hardware. if (micro <= 1) micro = 5; else if (micro <= 209) micro = 240; // This should call __KernelEventFlagTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread()); }
/// Handles updating the current Applet every time it's called. static void AppletUpdateEvent(u64 applet_id, int cycles_late) { Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); std::shared_ptr<Applet> applet = Applet::Get(id); ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); applet->Update(); // If the applet is still running after the last update, reschedule the event if (applet->IsRunning()) { CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, applet_update_event, applet_id); } else { // Otherwise the applet has terminated, in which case we should clean it up applets[id] = nullptr; } }
void __KernelWaitMbx(Mbx *m, u32 timeoutPtr) { if (timeoutPtr == 0 || mbxWaitTimer == -1) return; int micro = (int) Memory::Read_U32(timeoutPtr); // This seems to match the actual timing. if (micro <= 2) micro = 10; else if (micro <= 209) micro = 250; // This should call __KernelMbxTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), mbxWaitTimer, __KernelGetCurThread()); }
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) { if (timeoutPtr == 0 || semaWaitTimer == -1) return; int micro = (int) Memory::Read_U32(timeoutPtr); // This happens to be how the hardware seems to time things. if (micro <= 3) micro = 15; else if (micro <= 249) micro = 250; // This should call __KernelSemaTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); }
static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr) { if (timeoutPtr == 0 || waitTimer == -1) return true; int micro = (int) Memory::Read_U32(timeoutPtr); if (micro <= 2) { // Don't wait or reschedule, just timeout immediately. return false; } if (micro <= 210) micro = 250; CoreTiming::ScheduleEvent(usToCycles(micro), waitTimer, __KernelGetCurThread()); return true; }
int __DmacMemcpy(u32 dst, u32 src, u32 size) { Memory::Memcpy(dst, Memory::GetPointer(src), size); src &= ~0x40000000; dst &= ~0x40000000; if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { gpu->UpdateMemory(dst, src, size); } // This number seems strangely reproducible. if (size >= 272) { // Approx. 225 MiB/s or 235929600 B/s, so let's go with 236 B/us. int delayUs = size / 236; dmacMemcpyDeadline = CoreTiming::GetTicks() + usToCycles(delayUs); return hleDelayResult(0, "dmac copy", delayUs); } return 0; }
void __KernelSetVplTimeout(u32 timeoutPtr) { if (timeoutPtr == 0 || vplWaitTimer == -1) return; int micro = (int) Memory::Read_U32(timeoutPtr); // This happens to be how the hardware seems to time things. if (micro <= 5) micro = 10; // Yes, this 7 is reproducible. 6 is (a lot) longer than 7. else if (micro == 7) micro = 15; else if (micro <= 215) micro = 250; CoreTiming::ScheduleEvent(usToCycles(micro), vplWaitTimer, __KernelGetCurThread()); }
void __GeInit() { memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks)); ge_pending_cb.clear(); __RegisterIntrHandler(PSP_GE_INTR, new GeIntrHandler()); geSyncEvent = CoreTiming::RegisterEvent("GeSyncEvent", &__GeExecuteSync); geInterruptEvent = CoreTiming::RegisterEvent("GeInterruptEvent", &__GeExecuteInterrupt); geCycleEvent = CoreTiming::RegisterEvent("GeCycleEvent", &__GeCheckCycles); listWaitingThreads.clear(); drawWaitingThreads.clear(); // When we're using separate CPU/GPU threads, we need to keep them in sync. if (IsOnSeparateCPUThread()) { CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0); } }
void NativeRender() { glstate.Restore(); ReapplyGfxState(); s64 blockTicks = usToCycles(1000000 / 10); while(coreState == CORE_RUNNING) { PSP_RunLoopFor((int)blockTicks); } // Hopefully coreState is now CORE_NEXTFRAME if(coreState == CORE_NEXTFRAME) { // set back to running for the next frame coreState = CORE_RUNNING; } }
void NativeRender() { glstate.Restore(); ReapplyGfxState(); s64 blockTicks = usToCycles(1000000 / 10); while(coreState == CORE_RUNNING) { u64 nowTicks = CoreTiming::GetTicks(); mipsr4k.RunLoopUntil(nowTicks + blockTicks); } // Hopefully coreState is now CORE_NEXTFRAME if(coreState == CORE_NEXTFRAME) { // set back to running for the next frame coreState = CORE_RUNNING; } }
virtual void handleResult(int result) { // A non-zero result means to reschedule. if (result > 0) { u32 error; Alarm *alarm = kernelObjects.Get<Alarm>(alarmID, error); __KernelScheduleAlarm(alarm, (u64) usToCycles(result)); } else { if (result < 0) WARN_LOG(HLE, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result); // Delete the alarm if it's not rescheduled. kernelObjects.Destroy<Alarm>(alarmID); __ReleaseSubIntrHandler(PSP_SYSTIMER0_INTR, alarmID); } }
u32 sceCtrlSetSamplingCycle(u32 cycle) { DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingCycle(%u)", cycle); if ((cycle > 0 && cycle < 5555) || cycle > 20000) { WARN_LOG(SCECTRL, "SCE_KERNEL_ERROR_INVALID_VALUE=sceCtrlSetSamplingCycle(%u)", cycle); return SCE_KERNEL_ERROR_INVALID_VALUE; } u32 prev = ctrlCycle; ctrlCycle = cycle; if (prev > 0) CoreTiming::UnscheduleEvent(ctrlTimer, 0); if (cycle > 0) CoreTiming::ScheduleEvent(usToCycles(ctrlCycle), ctrlTimer, 0); return prev; }