mirror of
https://github.com/zeldaret/oot.git
synced 2025-05-12 20:13:47 +00:00
More documentation for sched.c (#1219)
* More documentation for sched.c * VI retrace -> vertical retrace, attempt to clarify comment in viconfig * Further review changes, fix inconsistent capitalization of PreNMI (PRENMI -> PreNMI) * Fix typo Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Change TaskSwapBuffer, change comment on OS_SC_DRAM_DLIST to unimplemented * Rename SchedContext/gSchedContext to Scheduler/gScheduler * Comments fixes Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com> * Format Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com>
This commit is contained in:
parent
ee5ac838b6
commit
1738b19d63
20 changed files with 449 additions and 268 deletions
|
@ -19,7 +19,7 @@ void cleararena(void);
|
||||||
void bootproc(void);
|
void bootproc(void);
|
||||||
void Main_ThreadEntry(void* arg);
|
void Main_ThreadEntry(void* arg);
|
||||||
void Idle_ThreadEntry(void* arg);
|
void Idle_ThreadEntry(void* arg);
|
||||||
void ViConfig_UpdateVi(u32 mode);
|
void ViConfig_UpdateVi(u32 black);
|
||||||
void ViConfig_UpdateBlack(void);
|
void ViConfig_UpdateBlack(void);
|
||||||
s32 DmaMgr_CompareName(const char* name1, const char* name2);
|
s32 DmaMgr_CompareName(const char* name1, const char* name2);
|
||||||
s32 DmaMgr_DmaRomToRam(u32 rom, u32 ram, u32 size);
|
s32 DmaMgr_DmaRomToRam(u32 rom, u32 ram, u32 size);
|
||||||
|
@ -977,7 +977,7 @@ void MapMark_Draw(PlayState* play);
|
||||||
void PreNmiBuff_Init(PreNmiBuff* this);
|
void PreNmiBuff_Init(PreNmiBuff* this);
|
||||||
void PreNmiBuff_SetReset(PreNmiBuff* this);
|
void PreNmiBuff_SetReset(PreNmiBuff* this);
|
||||||
u32 PreNmiBuff_IsResetting(PreNmiBuff* this);
|
u32 PreNmiBuff_IsResetting(PreNmiBuff* this);
|
||||||
void MsgEvent_SendNullTask(void);
|
void Sched_FlushTaskQueue(void);
|
||||||
f32 OLib_Vec3fDist(Vec3f* a, Vec3f* b);
|
f32 OLib_Vec3fDist(Vec3f* a, Vec3f* b);
|
||||||
f32 OLib_Vec3fDistXZ(Vec3f* a, Vec3f* b);
|
f32 OLib_Vec3fDistXZ(Vec3f* a, Vec3f* b);
|
||||||
f32 OLib_ClampMinDist(f32 val, f32 min);
|
f32 OLib_ClampMinDist(f32 val, f32 min);
|
||||||
|
@ -1563,10 +1563,10 @@ void THA_Dt(TwoHeadArena* tha);
|
||||||
void func_800C3C20(void);
|
void func_800C3C20(void);
|
||||||
void func_800C3C80(AudioMgr* audioMgr);
|
void func_800C3C80(AudioMgr* audioMgr);
|
||||||
void AudioMgr_HandleRetrace(AudioMgr* audioMgr);
|
void AudioMgr_HandleRetrace(AudioMgr* audioMgr);
|
||||||
void AudioMgr_HandlePRENMI(AudioMgr* audioMgr);
|
void AudioMgr_HandlePreNMI(AudioMgr* audioMgr);
|
||||||
void AudioMgr_ThreadEntry(void* arg0);
|
void AudioMgr_ThreadEntry(void* arg0);
|
||||||
void AudioMgr_Unlock(AudioMgr* audioMgr);
|
void AudioMgr_Unlock(AudioMgr* audioMgr);
|
||||||
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, SchedContext* sched, IrqMgr* irqMgr);
|
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Scheduler* sched, IrqMgr* irqMgr);
|
||||||
void TitleSetup_InitImpl(GameState* gameState);
|
void TitleSetup_InitImpl(GameState* gameState);
|
||||||
void TitleSetup_Destroy(GameState* gameState);
|
void TitleSetup_Destroy(GameState* gameState);
|
||||||
void TitleSetup_Init(GameState* gameState);
|
void TitleSetup_Init(GameState* gameState);
|
||||||
|
@ -1630,24 +1630,6 @@ void PadMgr_HandlePreNMI(PadMgr* padmgr);
|
||||||
// fault.c (actual bug in game), and the compiler notices and won't compile it
|
// fault.c (actual bug in game), and the compiler notices and won't compile it
|
||||||
// void PadMgr_RequestPadData(PadMgr* padmgr, Input* inputs, s32 mode);
|
// void PadMgr_RequestPadData(PadMgr* padmgr, Input* inputs, s32 mode);
|
||||||
void PadMgr_Init(PadMgr* padmgr, OSMesgQueue* serialEventQueue, IrqMgr* irqMgr, OSId id, OSPri priority, void* stack);
|
void PadMgr_Init(PadMgr* padmgr, OSMesgQueue* serialEventQueue, IrqMgr* irqMgr, OSId id, OSPri priority, void* stack);
|
||||||
void Sched_SwapFrameBuffer(CfbInfo* cfbInfo);
|
|
||||||
void func_800C84E4(SchedContext* sc, CfbInfo* cfbInfo);
|
|
||||||
void Sched_HandleReset(SchedContext* sc);
|
|
||||||
void Sched_HandleStart(SchedContext* sc);
|
|
||||||
void Sched_QueueTask(SchedContext* sc, OSScTask* task);
|
|
||||||
void Sched_Yield(SchedContext* sc);
|
|
||||||
OSScTask* func_800C89D4(SchedContext* sc, OSScTask* task);
|
|
||||||
s32 Sched_Schedule(SchedContext* sc, OSScTask** sp, OSScTask** dp, s32 state);
|
|
||||||
void func_800C8BC4(SchedContext* sc, OSScTask* task);
|
|
||||||
u32 Sched_IsComplete(SchedContext* sc, OSScTask* task);
|
|
||||||
void Sched_RunTask(SchedContext* sc, OSScTask* spTask, OSScTask* dpTask);
|
|
||||||
void Sched_HandleEntry(SchedContext* sc);
|
|
||||||
void Sched_HandleRetrace(SchedContext* sc);
|
|
||||||
void Sched_HandleRSPDone(SchedContext* sc);
|
|
||||||
void Sched_HandleRDPDone(SchedContext* sc);
|
|
||||||
void Sched_SendEntryMsg(SchedContext* sc);
|
|
||||||
void Sched_ThreadEntry(void* arg);
|
|
||||||
void Sched_Init(SchedContext* sc, void* stack, OSPri priority, UNK_TYPE arg3, UNK_TYPE arg4, IrqMgr* irqMgr);
|
|
||||||
void SpeedMeter_InitImpl(SpeedMeter* this, u32 arg1, u32 y);
|
void SpeedMeter_InitImpl(SpeedMeter* this, u32 arg1, u32 y);
|
||||||
void SpeedMeter_Init(SpeedMeter* this);
|
void SpeedMeter_Init(SpeedMeter* this);
|
||||||
void SpeedMeter_Destroy(SpeedMeter* this);
|
void SpeedMeter_Destroy(SpeedMeter* this);
|
||||||
|
@ -2261,7 +2243,7 @@ void guMtxF2L(MtxF* m1, Mtx* m2);
|
||||||
// ? __ll_to_f(?);
|
// ? __ll_to_f(?);
|
||||||
// ? __ull_to_d(?);
|
// ? __ull_to_d(?);
|
||||||
// ? __ull_to_f(?);
|
// ? __ull_to_f(?);
|
||||||
u32* osViGetCurrentFramebuffer(void);
|
void* osViGetCurrentFramebuffer(void);
|
||||||
s32 __osSpSetPc(void* pc);
|
s32 __osSpSetPc(void* pc);
|
||||||
f32 absf(f32);
|
f32 absf(f32);
|
||||||
void* __osMemset(void* dest, s32 val, size_t len);
|
void* __osMemset(void* dest, s32 val, size_t len);
|
||||||
|
|
70
include/sched.h
Normal file
70
include/sched.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef SCHED_H
|
||||||
|
#define SCHED_H
|
||||||
|
|
||||||
|
#include "ultra64.h"
|
||||||
|
#include "irqmgr.h"
|
||||||
|
|
||||||
|
#define OS_SC_NEEDS_RDP 0x0001 // Task uses the RDP
|
||||||
|
#define OS_SC_NEEDS_RSP 0x0002 // Task uses the RSP
|
||||||
|
#define OS_SC_DRAM_DLIST 0x0004 // Unimplemented
|
||||||
|
#define OS_SC_PARALLEL_TASK 0x0010 // Unimplemented
|
||||||
|
#define OS_SC_LAST_TASK 0x0020 // Unimplemented
|
||||||
|
#define OS_SC_SWAPBUFFER 0x0040 // Swap framebuffer when done
|
||||||
|
|
||||||
|
#define OS_SC_DP OS_SC_NEEDS_RDP // Task is using the RDP
|
||||||
|
#define OS_SC_SP OS_SC_NEEDS_RSP // Task is using the RSP
|
||||||
|
#define OS_SC_YIELD 0x0010 // Task has been asked to yield
|
||||||
|
#define OS_SC_YIELDED 0x0020 // Task has yielded
|
||||||
|
|
||||||
|
#define OS_SC_RCP_MASK (OS_SC_NEEDS_RDP | OS_SC_NEEDS_RSP)
|
||||||
|
#define OS_SC_TYPE_MASK (OS_SC_NEEDS_RDP | OS_SC_NEEDS_RSP | OS_SC_DRAM_DLIST)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* 0x00 */ u16* framebuffer; // current framebuffer
|
||||||
|
/* 0x04 */ u16* swapBuffer; // framebuffer to swap to
|
||||||
|
/* 0x08 */ OSViMode* viMode;
|
||||||
|
/* 0x0C */ u32 viFeatures;
|
||||||
|
/* 0x10 */ u8 unk_10; // set to 0, never read
|
||||||
|
/* 0x11 */ s8 updateRate; // how many VIs should elapse before next swap
|
||||||
|
/* 0x12 */ s8 updateTimer; // counts down (in VIs) from updateRate to 0, swaps the framebuffer at 0
|
||||||
|
/* 0x14 */ f32 xScale;
|
||||||
|
/* 0x18 */ f32 yScale;
|
||||||
|
} CfbInfo; // size = 0x1C
|
||||||
|
|
||||||
|
typedef struct OSScTask {
|
||||||
|
/* 0x00 */ struct OSScTask* next;
|
||||||
|
/* 0x04 */ u32 state;
|
||||||
|
/* 0x08 */ u32 flags;
|
||||||
|
/* 0x0C */ CfbInfo* framebuffer; // The original libultra OSScTask had void* here, it would point directly to a framebuffer
|
||||||
|
/* 0x10 */ OSTask list;
|
||||||
|
/* 0x50 */ OSMesgQueue* msgQueue; // Notification queue, will receive a message when the task completes
|
||||||
|
/* 0x54 */ OSMesg msg;
|
||||||
|
/* 0x58 */ OSTime startTime; // These last two fields are a guess based on the original libultra OSScTask and padding in other structures, they are unused.
|
||||||
|
/* 0x60 */ OSTime totalTime;
|
||||||
|
} OSScTask; // size = 0x68
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* 0x0000 */ OSMesgQueue interruptQueue;
|
||||||
|
/* 0x0018 */ OSMesg interruptMsgBuf[8];
|
||||||
|
/* 0x0038 */ OSMesgQueue cmdQueue; // queue for receiving OSScTask pointers
|
||||||
|
/* 0x0050 */ OSMesg cmdMsgBuf[8];
|
||||||
|
/* 0x0070 */ OSThread thread;
|
||||||
|
/* 0x0220 */ OSScTask* audioListHead;
|
||||||
|
/* 0x0224 */ OSScTask* gfxListHead;
|
||||||
|
/* 0x0228 */ OSScTask* audioListTail;
|
||||||
|
/* 0x022C */ OSScTask* gfxListTail;
|
||||||
|
/* 0x0230 */ OSScTask* curRSPTask; // task currently using the RSP
|
||||||
|
/* 0x0234 */ OSScTask* curRDPTask; // task currently using the RDP
|
||||||
|
/* 0x0238 */ s32 retraceCount;
|
||||||
|
/* 0x023C */ s32 doAudio;
|
||||||
|
/* 0x0240 */ CfbInfo* curBuf; // current framebuffer (taken from buffer 1)
|
||||||
|
/* 0x0244 */ CfbInfo* pendingSwapBuf1; // buffer 1 (next buffer)
|
||||||
|
/* 0x0220 */ CfbInfo* pendingSwapBuf2; // buffer 2 (always NULL)
|
||||||
|
/* 0x0220 */ s32 isFirstSwap;
|
||||||
|
/* 0x0250 */ IrqMgrClient irqClient;
|
||||||
|
} Scheduler; // size = 0x258
|
||||||
|
|
||||||
|
void Sched_Notify(Scheduler* sc);
|
||||||
|
void Sched_Init(Scheduler* sc, void* stack, OSPri priority, UNK_TYPE arg3, UNK_TYPE arg4, IrqMgr* irqMgr);
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,7 +15,7 @@ extern u8 osAppNMIBuffer[0x40];
|
||||||
extern s8 D_80009430;
|
extern s8 D_80009430;
|
||||||
extern u32 gDmaMgrVerbose;
|
extern u32 gDmaMgrVerbose;
|
||||||
extern u32 gDmaMgrDmaBuffSize;
|
extern u32 gDmaMgrDmaBuffSize;
|
||||||
extern vu8 gViConfigUseDefault;
|
extern vu8 gViConfigBlack;
|
||||||
extern u8 gViConfigAdditionalScanLines;
|
extern u8 gViConfigAdditionalScanLines;
|
||||||
extern u32 gViConfigFeatures;
|
extern u32 gViConfigFeatures;
|
||||||
extern f32 gViConfigXScale;
|
extern f32 gViConfigXScale;
|
||||||
|
@ -184,7 +184,7 @@ extern PauseMapMarksData* gLoadedPauseMarkDataTable;
|
||||||
extern s32 gTrnsnUnkState;
|
extern s32 gTrnsnUnkState;
|
||||||
extern Color_RGBA8_u32 D_801614B0;
|
extern Color_RGBA8_u32 D_801614B0;
|
||||||
extern PreNmiBuff* gAppNmiBufferPtr;
|
extern PreNmiBuff* gAppNmiBufferPtr;
|
||||||
extern SchedContext gSchedContext;
|
extern Scheduler gScheduler;
|
||||||
extern PadMgr gPadMgr;
|
extern PadMgr gPadMgr;
|
||||||
extern u32 gSegments[NUM_SEGMENTS];
|
extern u32 gSegments[NUM_SEGMENTS];
|
||||||
extern volatile OSTime D_8016A520;
|
extern volatile OSTime D_8016A520;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "irqmgr.h"
|
#include "irqmgr.h"
|
||||||
#include "padmgr.h"
|
#include "padmgr.h"
|
||||||
#include "fault.h"
|
#include "fault.h"
|
||||||
|
#include "sched.h"
|
||||||
|
|
||||||
#define SCREEN_WIDTH 320
|
#define SCREEN_WIDTH 320
|
||||||
#define SCREEN_HEIGHT 240
|
#define SCREEN_HEIGHT 240
|
||||||
|
@ -116,30 +117,6 @@ typedef struct {
|
||||||
/* 0x000C */ Gfx* d;
|
/* 0x000C */ Gfx* d;
|
||||||
} TwoHeadGfxArena; // size = 0x10
|
} TwoHeadGfxArena; // size = 0x10
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x00 */ u16* fb1;
|
|
||||||
/* 0x04 */ u16* swapBuffer;
|
|
||||||
/* 0x08 */ OSViMode* viMode;
|
|
||||||
/* 0x0C */ u32 features;
|
|
||||||
/* 0x10 */ u8 unk_10;
|
|
||||||
/* 0x11 */ s8 updateRate;
|
|
||||||
/* 0x12 */ s8 updateRate2;
|
|
||||||
/* 0x13 */ u8 unk_13;
|
|
||||||
/* 0x14 */ f32 xScale;
|
|
||||||
/* 0x18 */ f32 yScale;
|
|
||||||
} CfbInfo; // size = 0x1C
|
|
||||||
|
|
||||||
typedef struct OSScTask {
|
|
||||||
/* 0x00 */ struct OSScTask* next;
|
|
||||||
/* 0x04 */ u32 state;
|
|
||||||
/* 0x08 */ u32 flags;
|
|
||||||
/* 0x0C */ CfbInfo* framebuffer;
|
|
||||||
/* 0x10 */ OSTask list;
|
|
||||||
/* 0x50 */ OSMesgQueue* msgQueue;
|
|
||||||
/* 0x54 */ OSMesg msg;
|
|
||||||
/* 0x58 */ char unk_58[0x10];
|
|
||||||
} OSScTask; // size = 0x68
|
|
||||||
|
|
||||||
typedef struct GraphicsContext {
|
typedef struct GraphicsContext {
|
||||||
/* 0x0000 */ Gfx* polyOpaBuffer; // Pointer to "Zelda 0"
|
/* 0x0000 */ Gfx* polyOpaBuffer; // Pointer to "Zelda 0"
|
||||||
/* 0x0004 */ Gfx* polyXluBuffer; // Pointer to "Zelda 1"
|
/* 0x0004 */ Gfx* polyXluBuffer; // Pointer to "Zelda 1"
|
||||||
|
@ -150,7 +127,6 @@ typedef struct GraphicsContext {
|
||||||
/* 0x0038 */ OSMesg msgBuff[0x08];
|
/* 0x0038 */ OSMesg msgBuff[0x08];
|
||||||
/* 0x0058 */ OSMesgQueue* schedMsgQueue;
|
/* 0x0058 */ OSMesgQueue* schedMsgQueue;
|
||||||
/* 0x005C */ OSMesgQueue queue;
|
/* 0x005C */ OSMesgQueue queue;
|
||||||
/* 0x0074 */ char unk_074[0x04];
|
|
||||||
/* 0x0078 */ OSScTask task;
|
/* 0x0078 */ OSScTask task;
|
||||||
/* 0x00E0 */ char unk_0E0[0xD0];
|
/* 0x00E0 */ char unk_0E0[0xD0];
|
||||||
/* 0x01B0 */ Gfx* workBuffer;
|
/* 0x01B0 */ Gfx* workBuffer;
|
||||||
|
@ -1580,54 +1556,9 @@ typedef struct {
|
||||||
/* 0x10 */ u32 data[1];
|
/* 0x10 */ u32 data[1];
|
||||||
} Yaz0Header; // size = 0x10 ("data" is not part of the header)
|
} Yaz0Header; // size = 0x10 ("data" is not part of the header)
|
||||||
|
|
||||||
// == Previously sched.h
|
|
||||||
|
|
||||||
#define OS_SC_NEEDS_RDP 0x0001
|
|
||||||
#define OS_SC_NEEDS_RSP 0x0002
|
|
||||||
#define OS_SC_DRAM_DLIST 0x0004
|
|
||||||
#define OS_SC_PARALLEL_TASK 0x0010
|
|
||||||
#define OS_SC_LAST_TASK 0x0020
|
|
||||||
#define OS_SC_SWAPBUFFER 0x0040
|
|
||||||
|
|
||||||
#define OS_SC_RCP_MASK 0x0003
|
|
||||||
#define OS_SC_TYPE_MASK 0x0007
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x0000 */ u16* curBuffer;
|
|
||||||
/* 0x0004 */ u16* nextBuffer;
|
|
||||||
} FrameBufferSwap;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x0000 */ OSMesgQueue interruptQueue;
|
|
||||||
/* 0x0018 */ OSMesg interruptMsgBuf[8];
|
|
||||||
/* 0x0038 */ OSMesgQueue cmdQueue;
|
|
||||||
/* 0x0050 */ OSMesg cmdMsgBuf[8];
|
|
||||||
/* 0x0070 */ OSThread thread;
|
|
||||||
/* 0x0220 */ OSScTask* audioListHead;
|
|
||||||
/* 0x0224 */ OSScTask* gfxListHead;
|
|
||||||
/* 0x0228 */ OSScTask* audioListTail;
|
|
||||||
/* 0x022C */ OSScTask* gfxListTail;
|
|
||||||
/* 0x0230 */ OSScTask* curRSPTask;
|
|
||||||
/* 0x0234 */ OSScTask* curRDPTask;
|
|
||||||
/* 0x0238 */ s32 retraceCnt;
|
|
||||||
/* 0x023C */ s32 doAudio;
|
|
||||||
/* 0x0240 */ CfbInfo* curBuf;
|
|
||||||
/* 0x0244 */ CfbInfo* pendingSwapBuf1;
|
|
||||||
/* 0x0220 */ CfbInfo* pendingSwapBuf2;
|
|
||||||
/* 0x0220 */ UNK_TYPE4 unk_24C;
|
|
||||||
/* 0x0250 */ IrqMgrClient irqClient;
|
|
||||||
} SchedContext; // size = 0x258
|
|
||||||
|
|
||||||
// ========================
|
|
||||||
|
|
||||||
#define OS_SC_DP 0x0001
|
|
||||||
#define OS_SC_SP 0x0002
|
|
||||||
#define OS_SC_YIELD 0x0010
|
|
||||||
#define OS_SC_YIELDED 0x0020
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x0000 */ IrqMgr* irqMgr;
|
/* 0x0000 */ IrqMgr* irqMgr;
|
||||||
/* 0x0004 */ SchedContext* sched;
|
/* 0x0004 */ Scheduler* sched;
|
||||||
/* 0x0008 */ OSScTask audioTask;
|
/* 0x0008 */ OSScTask audioTask;
|
||||||
/* 0x0070 */ AudioTask* rspTask;
|
/* 0x0070 */ AudioTask* rspTask;
|
||||||
/* 0x0074 */ OSMesgQueue interruptQueue;
|
/* 0x0074 */ OSMesgQueue interruptQueue;
|
||||||
|
@ -1823,7 +1754,6 @@ typedef struct {
|
||||||
/* 0x14 */ u8* dhtPtr[4];
|
/* 0x14 */ u8* dhtPtr[4];
|
||||||
/* 0x24 */ void* imageData;
|
/* 0x24 */ void* imageData;
|
||||||
/* 0x28 */ u32 mode; // 0 if Y V0 is 1 and 2 if Y V0 is 2
|
/* 0x28 */ u32 mode; // 0 if Y V0 is 1 and 2 if Y V0 is 2
|
||||||
/* 0x2C */ char unk_2C[4];
|
|
||||||
/* 0x30 */ OSScTask scTask;
|
/* 0x30 */ OSScTask scTask;
|
||||||
/* 0x98 */ OSMesgQueue mq;
|
/* 0x98 */ OSMesgQueue mq;
|
||||||
/* 0xB0 */ OSMesg msg;
|
/* 0xB0 */ OSMesg msg;
|
||||||
|
|
2
spec
2
spec
|
@ -337,7 +337,7 @@ beginseg
|
||||||
include "build/src/code/z_map_mark.o"
|
include "build/src/code/z_map_mark.o"
|
||||||
include "build/src/code/z_moji.o"
|
include "build/src/code/z_moji.o"
|
||||||
include "build/src/code/z_prenmi_buff.o"
|
include "build/src/code/z_prenmi_buff.o"
|
||||||
include "build/src/code/z_msgevent.o"
|
include "build/src/code/z_nulltask.o"
|
||||||
include "build/src/code/z_olib.o"
|
include "build/src/code/z_olib.o"
|
||||||
include "build/src/code/z_onepointdemo.o"
|
include "build/src/code/z_onepointdemo.o"
|
||||||
include "build/src/code/z_map_exp.o"
|
include "build/src/code/z_map_exp.o"
|
||||||
|
|
|
@ -10,7 +10,7 @@ OSViMode gViConfigMode;
|
||||||
u8 D_80013960;
|
u8 D_80013960;
|
||||||
|
|
||||||
s8 D_80009430 = 1;
|
s8 D_80009430 = 1;
|
||||||
vu8 gViConfigUseDefault = 1;
|
vu8 gViConfigBlack = true;
|
||||||
u8 gViConfigAdditionalScanLines = 0;
|
u8 gViConfigAdditionalScanLines = 0;
|
||||||
u32 gViConfigFeatures = OS_VI_DITHER_FILTER_ON | OS_VI_GAMMA_OFF;
|
u32 gViConfigFeatures = OS_VI_DITHER_FILTER_ON | OS_VI_GAMMA_OFF;
|
||||||
f32 gViConfigXScale = 1.0;
|
f32 gViConfigXScale = 1.0;
|
||||||
|
@ -75,8 +75,8 @@ void Idle_ThreadEntry(void* arg) {
|
||||||
|
|
||||||
D_80009430 = 1;
|
D_80009430 = 1;
|
||||||
osViSetMode(&gViConfigMode);
|
osViSetMode(&gViConfigMode);
|
||||||
ViConfig_UpdateVi(1);
|
ViConfig_UpdateVi(true);
|
||||||
osViBlack(1);
|
osViBlack(true);
|
||||||
osViSwapBuffer(0x803DA80); //! @bug Invalid vram address (probably intended to be 0x803DA800)
|
osViSwapBuffer(0x803DA80); //! @bug Invalid vram address (probably intended to be 0x803DA800)
|
||||||
osCreatePiManager(OS_PRIORITY_PIMGR, &gPiMgrCmdQueue, sPiMgrCmdBuff, ARRAY_COUNT(sPiMgrCmdBuff));
|
osCreatePiManager(OS_PRIORITY_PIMGR, &gPiMgrCmdQueue, sPiMgrCmdBuff, ARRAY_COUNT(sPiMgrCmdBuff));
|
||||||
StackCheck_Init(&sMainStackInfo, sMainStack, STACK_TOP(sMainStack), 0, 0x400, "main");
|
StackCheck_Init(&sMainStackInfo, sMainStack, STACK_TOP(sMainStack), 0, 0x400, "main");
|
||||||
|
|
|
@ -2,16 +2,21 @@
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
|
||||||
// this should probably go elsewhere but right now viconfig.o is the only object between idle and z_std_dma
|
// this should probably go elsewhere but right now viconfig.o is the only object between idle and z_std_dma
|
||||||
OSPiHandle* gCartHandle = 0;
|
OSPiHandle* gCartHandle = NULL;
|
||||||
|
|
||||||
|
void ViConfig_UpdateVi(u32 black) {
|
||||||
|
if (black) {
|
||||||
|
// Black the screen on next call to ViConfig_UpdateBlack, skip most VI configuration
|
||||||
|
|
||||||
void ViConfig_UpdateVi(u32 mode) {
|
|
||||||
if (mode != 0) {
|
|
||||||
osSyncPrintf(VT_COL(YELLOW, BLACK) "osViSetYScale1(%f);\n" VT_RST, 1.0f);
|
osSyncPrintf(VT_COL(YELLOW, BLACK) "osViSetYScale1(%f);\n" VT_RST, 1.0f);
|
||||||
|
|
||||||
if (osTvType == OS_TV_PAL) {
|
if (osTvType == OS_TV_PAL) {
|
||||||
osViSetMode(&osViModePalLan1);
|
osViSetMode(&osViModePalLan1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the VI y scale. The VI y scale is different between NTSC (1.0) and PAL (0.833)
|
||||||
|
// and should be reset to 1.0 during PreNMI to ensure there are no issues when restarting.
|
||||||
|
// (see section 30.4.3 VI Processing with PreNMI Events in the N64 Programming Manual)
|
||||||
osViSetYScale(1.0f);
|
osViSetYScale(1.0f);
|
||||||
} else {
|
} else {
|
||||||
osViSetMode(&gViConfigMode);
|
osViSetMode(&gViConfigMode);
|
||||||
|
@ -34,13 +39,13 @@ void ViConfig_UpdateVi(u32 mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gViConfigUseDefault = mode;
|
gViConfigBlack = black;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViConfig_UpdateBlack(void) {
|
void ViConfig_UpdateBlack(void) {
|
||||||
if (gViConfigUseDefault != 0) {
|
if (gViConfigBlack) {
|
||||||
osViBlack(1);
|
osViBlack(true);
|
||||||
} else {
|
} else {
|
||||||
osViBlack(0);
|
osViBlack(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
|
||||||
|
|
||||||
audioMgr->audioTask.msg = NULL;
|
audioMgr->audioTask.msg = NULL;
|
||||||
osSendMesg(&audioMgr->sched->cmdQueue, (OSMesg)&audioMgr->audioTask, OS_MESG_BLOCK);
|
osSendMesg(&audioMgr->sched->cmdQueue, (OSMesg)&audioMgr->audioTask, OS_MESG_BLOCK);
|
||||||
Sched_SendEntryMsg(audioMgr->sched);
|
Sched_Notify(audioMgr->sched);
|
||||||
}
|
}
|
||||||
|
|
||||||
D_8016A550 = osGetTime();
|
D_8016A550 = osGetTime();
|
||||||
|
@ -42,7 +42,7 @@ void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
|
||||||
audioMgr->rspTask = rspTask;
|
audioMgr->rspTask = rspTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMgr_HandlePRENMI(AudioMgr* audioMgr) {
|
void AudioMgr_HandlePreNMI(AudioMgr* audioMgr) {
|
||||||
// "Audio manager received OS_SC_PRE_NMI_MSG"
|
// "Audio manager received OS_SC_PRE_NMI_MSG"
|
||||||
osSyncPrintf("オーディオマネージャが OS_SC_PRE_NMI_MSG を受け取りました\n");
|
osSyncPrintf("オーディオマネージャが OS_SC_PRE_NMI_MSG を受け取りました\n");
|
||||||
Audio_PreNMI();
|
Audio_PreNMI();
|
||||||
|
@ -71,13 +71,13 @@ void AudioMgr_ThreadEntry(void* arg0) {
|
||||||
case OS_SC_RETRACE_MSG:
|
case OS_SC_RETRACE_MSG:
|
||||||
break;
|
break;
|
||||||
case OS_SC_PRE_NMI_MSG:
|
case OS_SC_PRE_NMI_MSG:
|
||||||
AudioMgr_HandlePRENMI(audioMgr);
|
AudioMgr_HandlePreNMI(audioMgr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OS_SC_PRE_NMI_MSG:
|
case OS_SC_PRE_NMI_MSG:
|
||||||
AudioMgr_HandlePRENMI(audioMgr);
|
AudioMgr_HandlePreNMI(audioMgr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ void AudioMgr_Unlock(AudioMgr* audioMgr) {
|
||||||
osRecvMesg(&audioMgr->lockQueue, NULL, OS_MESG_BLOCK);
|
osRecvMesg(&audioMgr->lockQueue, NULL, OS_MESG_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, SchedContext* sched, IrqMgr* irqMgr) {
|
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Scheduler* sched, IrqMgr* irqMgr) {
|
||||||
bzero(audioMgr, sizeof(AudioMgr));
|
bzero(audioMgr, sizeof(AudioMgr));
|
||||||
|
|
||||||
audioMgr->sched = sched;
|
audioMgr->sched = sched;
|
||||||
|
|
|
@ -218,7 +218,7 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) {
|
||||||
task->yield_data_size = sizeof(gGfxSPTaskYieldBuffer);
|
task->yield_data_size = sizeof(gGfxSPTaskYieldBuffer);
|
||||||
|
|
||||||
scTask->next = NULL;
|
scTask->next = NULL;
|
||||||
scTask->flags = OS_SC_RCP_MASK | OS_SC_SWAPBUFFER | OS_SC_LAST_TASK;
|
scTask->flags = OS_SC_NEEDS_RSP | OS_SC_NEEDS_RDP | OS_SC_SWAPBUFFER | OS_SC_LAST_TASK;
|
||||||
if (SREG(33) & 1) {
|
if (SREG(33) & 1) {
|
||||||
SREG(33) &= ~1;
|
SREG(33) &= ~1;
|
||||||
scTask->flags &= ~OS_SC_SWAPBUFFER;
|
scTask->flags &= ~OS_SC_SWAPBUFFER;
|
||||||
|
@ -229,10 +229,10 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) {
|
||||||
scTask->msg = NULL;
|
scTask->msg = NULL;
|
||||||
|
|
||||||
cfb = &sGraphCfbInfos[sGraphCfbInfoIdx++];
|
cfb = &sGraphCfbInfos[sGraphCfbInfoIdx++];
|
||||||
cfb->fb1 = gfxCtx->curFrameBuffer;
|
cfb->framebuffer = gfxCtx->curFrameBuffer;
|
||||||
cfb->swapBuffer = gfxCtx->curFrameBuffer;
|
cfb->swapBuffer = gfxCtx->curFrameBuffer;
|
||||||
cfb->viMode = gfxCtx->viMode;
|
cfb->viMode = gfxCtx->viMode;
|
||||||
cfb->features = gfxCtx->viFeatures;
|
cfb->viFeatures = gfxCtx->viFeatures;
|
||||||
cfb->xScale = gfxCtx->xScale;
|
cfb->xScale = gfxCtx->xScale;
|
||||||
cfb->yScale = gfxCtx->yScale;
|
cfb->yScale = gfxCtx->yScale;
|
||||||
cfb->unk_10 = 0;
|
cfb->unk_10 = 0;
|
||||||
|
@ -243,10 +243,10 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) {
|
||||||
|
|
||||||
if (1) {}
|
if (1) {}
|
||||||
|
|
||||||
gfxCtx->schedMsgQueue = &gSchedContext.cmdQueue;
|
gfxCtx->schedMsgQueue = &gScheduler.cmdQueue;
|
||||||
|
|
||||||
osSendMesg(&gSchedContext.cmdQueue, (OSMesg)scTask, OS_MESG_BLOCK);
|
osSendMesg(&gScheduler.cmdQueue, (OSMesg)scTask, OS_MESG_BLOCK);
|
||||||
Sched_SendEntryMsg(&gSchedContext);
|
Sched_Notify(&gScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) {
|
void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) {
|
||||||
|
|
|
@ -2,18 +2,20 @@
|
||||||
* @file irqmgr.c
|
* @file irqmgr.c
|
||||||
*
|
*
|
||||||
* This file implements a manager for forwarding three key system interrupt events to
|
* This file implements a manager for forwarding three key system interrupt events to
|
||||||
* registered clients. The architecture of this system appears to be derived in part from
|
* registered clients.
|
||||||
* the libultra sched module.
|
* Together with sched.c, these systems implement the libultra video and task scheduling
|
||||||
|
* model from the libultra "sched" module, with improved functionality in the handling of
|
||||||
|
* Pre-NMI related events.
|
||||||
*
|
*
|
||||||
* The interrupts the IRQ manager deals with are:
|
* The interrupts the IRQ manager deals with are:
|
||||||
* - VI Retrace
|
* - Vertical Retrace
|
||||||
* This event is sent to the IRQ manager by the OS VI manager which only supports
|
* This event is sent to the IRQ manager by the OS VI manager which only supports
|
||||||
* the forwarding of VI events to a single message queue. The IRQ manager will
|
* the forwarding of VI events to a single message queue. The IRQ manager will
|
||||||
* forward these events to every registered client. VI retrace events are received
|
* forward these events to every registered client. Vertical retrace events are
|
||||||
* when the Video Interface has reached the start of the vertical blanking interval,
|
* received when the Video Interface has reached the start of the vertical blanking
|
||||||
* happening at approximately 60Hz on NTSC and 50Hz on PAL. Many threads sit idle
|
* interval, happening at approximately 60Hz on NTSC and 50Hz on PAL. Many threads
|
||||||
* until a VI Retrace event wakes them up, at which point they will perform their
|
* sit idle until a vertical retrace event wakes them up, at which point they will
|
||||||
* task and then return to idle to await the next retrace.
|
* perform their task and then return to idle to await the next retrace.
|
||||||
*
|
*
|
||||||
* - Pre-NMI
|
* - Pre-NMI
|
||||||
* This event is sent to the IRQ manager by the OS Interrupt Handler when the reset
|
* This event is sent to the IRQ manager by the OS Interrupt Handler when the reset
|
||||||
|
@ -27,6 +29,8 @@
|
||||||
* is not to be confused with the hardware NMI interrupt signalled when the CPU is
|
* is not to be confused with the hardware NMI interrupt signalled when the CPU is
|
||||||
* to fully reset, as by the time that interrupt is received there is no time left
|
* to fully reset, as by the time that interrupt is received there is no time left
|
||||||
* to do anything.
|
* to do anything.
|
||||||
|
*
|
||||||
|
* @see sched.c
|
||||||
*/
|
*/
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
@ -183,7 +187,7 @@ void IrqMgr_CheckStacks(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI450(IrqMgr* irqMgr) {
|
void IrqMgr_HandlePreNMI450(IrqMgr* irqMgr) {
|
||||||
u64 nmi = IRQ_RESET_STATUS_NMI; // required to match
|
u64 nmi = IRQ_RESET_STATUS_NMI; // required to match
|
||||||
|
|
||||||
gIrqMgrResetStatus = nmi;
|
gIrqMgrResetStatus = nmi;
|
||||||
|
@ -195,7 +199,7 @@ void IrqMgr_HandlePRENMI450(IrqMgr* irqMgr) {
|
||||||
IrqMgr_SendMesgToClients(irqMgr, (OSMesg)&irqMgr->nmiMsg);
|
IrqMgr_SendMesgToClients(irqMgr, (OSMesg)&irqMgr->nmiMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI480(IrqMgr* irqMgr) {
|
void IrqMgr_HandlePreNMI480(IrqMgr* irqMgr) {
|
||||||
u32 result;
|
u32 result;
|
||||||
|
|
||||||
// Schedule a PRENMI500 message to be handled in 20ms
|
// Schedule a PRENMI500 message to be handled in 20ms
|
||||||
|
@ -212,13 +216,15 @@ void IrqMgr_HandlePRENMI480(IrqMgr* irqMgr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrqMgr_HandlePRENMI500(IrqMgr* irqMgr) {
|
void IrqMgr_HandlePreNMI500(IrqMgr* irqMgr) {
|
||||||
IrqMgr_CheckStacks();
|
IrqMgr_CheckStacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs on each VI retrace, measures the time elapsed between the first and second VI retrace
|
* Runs on each vertical retrace
|
||||||
* and dispatches VI retrace messages to each registered Irq Client
|
*
|
||||||
|
* Measures the time elapsed between the first and second vertical retrace and
|
||||||
|
* dispatches vertical retrace messages to each registered Irq Client
|
||||||
*/
|
*/
|
||||||
void IrqMgr_HandleRetrace(IrqMgr* irqMgr) {
|
void IrqMgr_HandleRetrace(IrqMgr* irqMgr) {
|
||||||
if (gIrqMgrRetraceTime == 0) {
|
if (gIrqMgrRetraceTime == 0) {
|
||||||
|
@ -257,20 +263,20 @@ void IrqMgr_ThreadEntry(void* arg) {
|
||||||
osSyncPrintf("PRENMI450_MSG\n");
|
osSyncPrintf("PRENMI450_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI450 message"
|
// "Scheduler: Receives PRENMI450 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI450メッセージを受信\n");
|
||||||
IrqMgr_HandlePRENMI450(irqMgr);
|
IrqMgr_HandlePreNMI450(irqMgr);
|
||||||
break;
|
break;
|
||||||
case IRQ_PRENMI480_MSG:
|
case IRQ_PRENMI480_MSG:
|
||||||
osSyncPrintf("PRENMI480_MSG\n");
|
osSyncPrintf("PRENMI480_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI480 message"
|
// "Scheduler: Receives PRENMI480 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI480メッセージを受信\n");
|
||||||
IrqMgr_HandlePRENMI480(irqMgr);
|
IrqMgr_HandlePreNMI480(irqMgr);
|
||||||
break;
|
break;
|
||||||
case IRQ_PRENMI500_MSG:
|
case IRQ_PRENMI500_MSG:
|
||||||
osSyncPrintf("PRENMI500_MSG\n");
|
osSyncPrintf("PRENMI500_MSG\n");
|
||||||
// "Scheduler: Receives PRENMI500 message"
|
// "Scheduler: Receives PRENMI500 message"
|
||||||
osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n");
|
osSyncPrintf("スケジューラ:PRENMI500メッセージを受信\n");
|
||||||
exit = true;
|
exit = true;
|
||||||
IrqMgr_HandlePRENMI500(irqMgr);
|
IrqMgr_HandlePreNMI500(irqMgr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// "Unexpected message received"
|
// "Unexpected message received"
|
||||||
|
|
|
@ -6,7 +6,7 @@ s32 gScreenHeight = SCREEN_HEIGHT;
|
||||||
u32 gSystemHeapSize = 0;
|
u32 gSystemHeapSize = 0;
|
||||||
|
|
||||||
PreNmiBuff* gAppNmiBufferPtr;
|
PreNmiBuff* gAppNmiBufferPtr;
|
||||||
SchedContext gSchedContext;
|
Scheduler gScheduler;
|
||||||
PadMgr gPadMgr;
|
PadMgr gPadMgr;
|
||||||
IrqMgr gIrqMgr;
|
IrqMgr gIrqMgr;
|
||||||
u32 gSegments[NUM_SEGMENTS];
|
u32 gSegments[NUM_SEGMENTS];
|
||||||
|
@ -80,13 +80,12 @@ void Main(void* arg) {
|
||||||
|
|
||||||
osSyncPrintf("タスクスケジューラの初期化\n"); // "Initialize the task scheduler"
|
osSyncPrintf("タスクスケジューラの初期化\n"); // "Initialize the task scheduler"
|
||||||
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
|
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
|
||||||
Sched_Init(&gSchedContext, STACK_TOP(sSchedStack), THREAD_PRI_SCHED, D_80013960, 1, &gIrqMgr);
|
Sched_Init(&gScheduler, STACK_TOP(sSchedStack), THREAD_PRI_SCHED, D_80013960, 1, &gIrqMgr);
|
||||||
|
|
||||||
IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQueue);
|
IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQueue);
|
||||||
|
|
||||||
StackCheck_Init(&sAudioStackInfo, sAudioStack, STACK_TOP(sAudioStack), 0, 0x100, "audio");
|
StackCheck_Init(&sAudioStackInfo, sAudioStack, STACK_TOP(sAudioStack), 0, 0x100, "audio");
|
||||||
AudioMgr_Init(&gAudioMgr, STACK_TOP(sAudioStack), THREAD_PRI_AUDIOMGR, THREAD_ID_AUDIOMGR, &gSchedContext,
|
AudioMgr_Init(&gAudioMgr, STACK_TOP(sAudioStack), THREAD_PRI_AUDIOMGR, THREAD_ID_AUDIOMGR, &gScheduler, &gIrqMgr);
|
||||||
&gIrqMgr);
|
|
||||||
|
|
||||||
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
|
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
|
||||||
PadMgr_Init(&gPadMgr, &sSerialEventQueue, &gIrqMgr, THREAD_ID_PADMGR, THREAD_PRI_PADMGR, STACK_TOP(sPadMgrStack));
|
PadMgr_Init(&gPadMgr, &sSerialEventQueue, &gIrqMgr, THREAD_ID_PADMGR, THREAD_PRI_PADMGR, STACK_TOP(sPadMgrStack));
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#define printSpStatus(x, name) \
|
#define printSpStatus(x, name) \
|
||||||
if (x & SP_STATUS_##name) \
|
if (x & SP_STATUS_##name) \
|
||||||
osSyncPrintf(#name " ")
|
osSyncPrintf(#name " ")
|
||||||
|
|
||||||
#define printDpStatus(x, name) \
|
#define printDpStatus(x, name) \
|
||||||
if (x & DPC_STATUS_##name) \
|
if (x & DPC_STATUS_##name) \
|
||||||
osSyncPrintf(#name " ")
|
osSyncPrintf(#name " ")
|
||||||
|
@ -44,9 +45,11 @@ void RcpUtils_PrintRegisterStatus(void) {
|
||||||
osSyncPrintf("\n");
|
osSyncPrintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcpUtils_Reset() {
|
void RcpUtils_Reset(void) {
|
||||||
RcpUtils_PrintRegisterStatus();
|
RcpUtils_PrintRegisterStatus();
|
||||||
|
// Flush the RDP pipeline and freeze clock counter
|
||||||
osDpSetStatus(DPC_SET_FREEZE | DPC_SET_FLUSH);
|
osDpSetStatus(DPC_SET_FREEZE | DPC_SET_FLUSH);
|
||||||
|
// Halt the RSP, disable interrupt on break and set "task done" signal
|
||||||
__osSpSetStatus(SP_SET_HALT | SP_SET_SIG2 | SP_CLR_INTR_BREAK);
|
__osSpSetStatus(SP_SET_HALT | SP_SET_SIG2 | SP_CLR_INTR_BREAK);
|
||||||
RcpUtils_PrintRegisterStatus();
|
RcpUtils_PrintRegisterStatus();
|
||||||
}
|
}
|
||||||
|
|
372
src/code/sched.c
372
src/code/sched.c
|
@ -1,32 +1,77 @@
|
||||||
|
/**
|
||||||
|
* @file sched.c
|
||||||
|
*
|
||||||
|
* This file implements a cooperative scheduler for managing tasks that run on the RSP and RDP
|
||||||
|
* asynchronously such as graphics and audio processing. Tasks are prepared and sent to it from
|
||||||
|
* other threads, where it is placed in a queue until the necessary resources are available. Tasks
|
||||||
|
* are usually ran in the order they are received, with one exception described below. Tasks can
|
||||||
|
* also request, through flags, whether the scheduler should swap the active framebuffer once the
|
||||||
|
* task completes.
|
||||||
|
* Together with irqmgr.c, these systems implement the libultra video and task scheduling model from
|
||||||
|
* the libultra "sched" module. Notably, the original sched module supports a wider range of ways to
|
||||||
|
* communicate with the RDP, while the Zelda 64 implementation only allows the RSP microcode to send
|
||||||
|
* commands to the RDP. The Zelda 64 implementation also has more complex behavior involving the
|
||||||
|
* framebuffers.
|
||||||
|
*
|
||||||
|
* There are four task types supported:
|
||||||
|
*
|
||||||
|
* M_NULTASK
|
||||||
|
* "NULL" tasks.
|
||||||
|
* Tasks of this type don't perform any operations, it can be used to "flush" the task queue. Threads
|
||||||
|
* can wait for this task to complete to ensure there are no more tasks queued in the scheduler.
|
||||||
|
*
|
||||||
|
* M_GFXTASK
|
||||||
|
* Graphics Processing tasks.
|
||||||
|
* Only these tasks can make use of the RDP.
|
||||||
|
*
|
||||||
|
* M_AUDTASK
|
||||||
|
* Audio Processing tasks.
|
||||||
|
* These tasks have a higher "priority" than other tasks. If an audio task is enqueued and another
|
||||||
|
* task is currently running, the scheduler will signal to the running task that it should "yield"
|
||||||
|
* the RSP to the audio task. The running task will save its current state and stop running, allowing
|
||||||
|
* the scheduler to send the audio task. This ensures that audio data is always available to be consumed
|
||||||
|
* by the audio DAC even if another task such as graphics is running slow, avoiding undesirable sound
|
||||||
|
* artifacts. This is the meaning of "cooperative" scheduler, the current task must acknowledge the
|
||||||
|
* yield request rather than be immediately interrupted as it would be in a preemptive scheduler.
|
||||||
|
*
|
||||||
|
* M_NJPEGTASK
|
||||||
|
* JPEG to RGBA16 decoding tasks.
|
||||||
|
*
|
||||||
|
* @see irqmgr.c
|
||||||
|
*/
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
#define RSP_DONE_MSG 667
|
#define RSP_DONE_MSG 667
|
||||||
#define RDP_DONE_MSG 668
|
#define RDP_DONE_MSG 668
|
||||||
#define ENTRY_MSG 670
|
#define NOTIFY_MSG 670 // original name: ENTRY_MSG
|
||||||
|
|
||||||
// data
|
|
||||||
vs32 sLogScheduler = false;
|
vs32 sLogScheduler = false;
|
||||||
|
|
||||||
// bss
|
|
||||||
OSTime sRSPGFXStartTime;
|
OSTime sRSPGFXStartTime;
|
||||||
OSTime sRSPAudioStartTime;
|
OSTime sRSPAudioStartTime;
|
||||||
OSTime sRSPOtherStartTime;
|
OSTime sRSPOtherStartTime;
|
||||||
OSTime sRDPStartTime;
|
OSTime sRDPStartTime;
|
||||||
|
|
||||||
void Sched_SwapFrameBuffer(CfbInfo* cfbInfo) {
|
/**
|
||||||
|
* Set the current framebuffer to the swapbuffer pointed to by the provided cfb
|
||||||
|
*/
|
||||||
|
void Sched_SwapFrameBufferImpl(CfbInfo* cfbInfo) {
|
||||||
u16 width;
|
u16 width;
|
||||||
|
|
||||||
LogUtils_CheckValidPointer("cfbinfo->swapbuffer", cfbInfo->swapBuffer, "../sched.c", 340);
|
LogUtils_CheckValidPointer("cfbinfo->swapbuffer", cfbInfo->swapBuffer, "../sched.c", 340);
|
||||||
|
|
||||||
if (cfbInfo->swapBuffer != NULL) {
|
if (cfbInfo->swapBuffer != NULL) {
|
||||||
|
// Register the swapbuffer to display on next VI
|
||||||
osViSwapBuffer(cfbInfo->swapBuffer);
|
osViSwapBuffer(cfbInfo->swapBuffer);
|
||||||
cfbInfo->updateRate2 = cfbInfo->updateRate;
|
cfbInfo->updateTimer = cfbInfo->updateRate;
|
||||||
|
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("osViSwapBuffer %08x %08x %08x\n", osViGetCurrentFramebuffer(), osViGetNextFramebuffer(),
|
osSyncPrintf("osViSwapBuffer %08x %08x %08x\n", osViGetCurrentFramebuffer(), osViGetNextFramebuffer(),
|
||||||
(cfbInfo != NULL ? cfbInfo->swapBuffer : NULL));
|
(cfbInfo != NULL) ? cfbInfo->swapBuffer : NULL);
|
||||||
}
|
}
|
||||||
width = cfbInfo->viMode != NULL ? cfbInfo->viMode->comRegs.width : (u32)gScreenWidth;
|
|
||||||
Fault_SetFrameBuffer(cfbInfo->swapBuffer, width, 0x10);
|
width = (cfbInfo->viMode != NULL) ? cfbInfo->viMode->comRegs.width : (u32)gScreenWidth;
|
||||||
|
Fault_SetFrameBuffer(cfbInfo->swapBuffer, width, 16);
|
||||||
|
|
||||||
if (HREG(80) == 0xD && HREG(95) != 0xD) {
|
if (HREG(80) == 0xD && HREG(95) != 0xD) {
|
||||||
HREG(81) = 0;
|
HREG(81) = 0;
|
||||||
|
@ -46,39 +91,41 @@ void Sched_SwapFrameBuffer(CfbInfo* cfbInfo) {
|
||||||
HREG(95) = 0xD;
|
HREG(95) = 0xD;
|
||||||
}
|
}
|
||||||
if (HREG(80) == 0xD && HREG(81) == 2) {
|
if (HREG(80) == 0xD && HREG(81) == 2) {
|
||||||
osViSetSpecialFeatures(HREG(82) != 0 ? OS_VI_GAMMA_ON : OS_VI_GAMMA_OFF);
|
osViSetSpecialFeatures((HREG(82) != 0) ? OS_VI_GAMMA_ON : OS_VI_GAMMA_OFF);
|
||||||
osViSetSpecialFeatures(HREG(83) != 0 ? OS_VI_DITHER_FILTER_ON : OS_VI_DITHER_FILTER_OFF);
|
osViSetSpecialFeatures((HREG(83) != 0) ? OS_VI_DITHER_FILTER_ON : OS_VI_DITHER_FILTER_OFF);
|
||||||
osViSetSpecialFeatures(HREG(84) != 0 ? OS_VI_GAMMA_DITHER_ON : OS_VI_GAMMA_DITHER_OFF);
|
osViSetSpecialFeatures((HREG(84) != 0) ? OS_VI_GAMMA_DITHER_ON : OS_VI_GAMMA_DITHER_OFF);
|
||||||
osViSetSpecialFeatures(HREG(85) != 0 ? OS_VI_DIVOT_ON : OS_VI_DIVOT_OFF);
|
osViSetSpecialFeatures((HREG(85) != 0) ? OS_VI_DIVOT_ON : OS_VI_DIVOT_OFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfbInfo->unk_10 = 0;
|
cfbInfo->unk_10 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_800C84E4(SchedContext* sc, CfbInfo* cfbInfo) {
|
void Sched_SwapFrameBuffer(Scheduler* sc, CfbInfo* cfbInfo) {
|
||||||
if (sc->unk_24C != 0) {
|
if (sc->isFirstSwap) {
|
||||||
sc->unk_24C = 0;
|
sc->isFirstSwap = false;
|
||||||
|
|
||||||
if (gIrqMgrResetStatus == IRQ_RESET_STATUS_IDLE) {
|
if (gIrqMgrResetStatus == IRQ_RESET_STATUS_IDLE) {
|
||||||
ViConfig_UpdateVi(0);
|
ViConfig_UpdateVi(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Sched_SwapFrameBufferImpl(cfbInfo);
|
||||||
|
}
|
||||||
|
|
||||||
Sched_SwapFrameBuffer(cfbInfo);
|
void Sched_HandlePreNMI(Scheduler* sc) {
|
||||||
}
|
|
||||||
|
|
||||||
void Sched_HandleReset(SchedContext* sc) {
|
|
||||||
OSTime now;
|
OSTime now;
|
||||||
|
|
||||||
if (sc->curRSPTask != NULL) {
|
if (sc->curRSPTask != NULL) {
|
||||||
now = osGetTime();
|
now = osGetTime();
|
||||||
|
|
||||||
if (sc->curRSPTask->framebuffer == NULL) {
|
if (sc->curRSPTask->framebuffer == NULL) {
|
||||||
|
// audio and jpeg tasks end up in here
|
||||||
LOG_TIME("(((u64)(now - audio_rsp_start_time)*(1000000LL/15625LL))/((62500000LL*3/4)/15625LL))",
|
LOG_TIME("(((u64)(now - audio_rsp_start_time)*(1000000LL/15625LL))/((62500000LL*3/4)/15625LL))",
|
||||||
OS_CYCLES_TO_USEC(now - sRSPAudioStartTime), "../sched.c", 421);
|
OS_CYCLES_TO_USEC(now - sRSPAudioStartTime), "../sched.c", 421);
|
||||||
} else if (OS_CYCLES_TO_USEC(now - sRSPGFXStartTime) > 1000000 ||
|
} else if (OS_CYCLES_TO_USEC(now - sRSPGFXStartTime) > 1000000 ||
|
||||||
OS_CYCLES_TO_USEC(now - sRDPStartTime) > 1000000) {
|
OS_CYCLES_TO_USEC(now - sRDPStartTime) > 1000000) {
|
||||||
|
// More than 1 second since the RSP or RDP tasks began, halt the RSP and RDP
|
||||||
RcpUtils_Reset();
|
RcpUtils_Reset();
|
||||||
|
// Manually send RSP/RDP done messages to the scheduler interrupt queue if appropriate
|
||||||
if (sc->curRSPTask != NULL) {
|
if (sc->curRSPTask != NULL) {
|
||||||
LOG_TIME("(((u64)(now - graph_rsp_start_time)*(1000000LL/15625LL))/((62500000LL*3/4)/15625LL))",
|
LOG_TIME("(((u64)(now - graph_rsp_start_time)*(1000000LL/15625LL))/((62500000LL*3/4)/15625LL))",
|
||||||
OS_CYCLES_TO_USEC(now - sRSPGFXStartTime), "../sched.c", 427);
|
OS_CYCLES_TO_USEC(now - sRSPGFXStartTime), "../sched.c", 427);
|
||||||
|
@ -93,11 +140,15 @@ void Sched_HandleReset(SchedContext* sc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_HandleStart(SchedContext* sc) {
|
void Sched_HandleNMI(Scheduler* sc) {
|
||||||
ViConfig_UpdateVi(1);
|
// black the screen and reset the VI y scale just in time for NMI reset
|
||||||
|
ViConfig_UpdateVi(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_QueueTask(SchedContext* sc, OSScTask* task) {
|
/**
|
||||||
|
* Enqueue a task to either the audio task list or the gfx task list
|
||||||
|
*/
|
||||||
|
void Sched_QueueTask(Scheduler* sc, OSScTask* task) {
|
||||||
s32 type = task->list.t.type;
|
s32 type = task->list.t.type;
|
||||||
|
|
||||||
ASSERT((type == M_AUDTASK) || (type == M_GFXTASK) || (type == M_NJPEGTASK) || (type == M_NULTASK),
|
ASSERT((type == M_AUDTASK) || (type == M_GFXTASK) || (type == M_NJPEGTASK) || (type == M_NULTASK),
|
||||||
|
@ -109,18 +160,22 @@ void Sched_QueueTask(SchedContext* sc, OSScTask* task) {
|
||||||
// "You have entered an audio task"
|
// "You have entered an audio task"
|
||||||
osSyncPrintf("オーディオタスクをエントリしました\n");
|
osSyncPrintf("オーディオタスクをエントリしました\n");
|
||||||
}
|
}
|
||||||
|
// Add to audio queue
|
||||||
if (sc->audioListTail != NULL) {
|
if (sc->audioListTail != NULL) {
|
||||||
sc->audioListTail->next = task;
|
sc->audioListTail->next = task;
|
||||||
} else {
|
} else {
|
||||||
sc->audioListHead = task;
|
sc->audioListHead = task;
|
||||||
}
|
}
|
||||||
sc->audioListTail = task;
|
sc->audioListTail = task;
|
||||||
sc->doAudio = 1;
|
|
||||||
|
// Set audio flag
|
||||||
|
sc->doAudio = true;
|
||||||
} else {
|
} else {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("グラフタスクをエントリしました\n"); // "Entered graph task"
|
// "Entered graph task"
|
||||||
|
osSyncPrintf("グラフタスクをエントリしました\n");
|
||||||
}
|
}
|
||||||
|
// Add to graphics queue
|
||||||
if (sc->gfxListTail != NULL) {
|
if (sc->gfxListTail != NULL) {
|
||||||
sc->gfxListTail->next = task;
|
sc->gfxListTail->next = task;
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,15 +184,17 @@ void Sched_QueueTask(SchedContext* sc, OSScTask* task) {
|
||||||
sc->gfxListTail = task;
|
sc->gfxListTail = task;
|
||||||
}
|
}
|
||||||
task->next = NULL;
|
task->next = NULL;
|
||||||
task->state = task->flags & (OS_SC_NEEDS_RDP | OS_SC_NEEDS_RSP);
|
task->state = task->flags & OS_SC_RCP_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_Yield(SchedContext* sc) {
|
void Sched_Yield(Scheduler* sc) {
|
||||||
if (!(sc->curRSPTask->state & OS_SC_YIELD)) {
|
if (!(sc->curRSPTask->state & OS_SC_YIELD)) {
|
||||||
|
// Not already been asked to yield
|
||||||
ASSERT(sc->curRSPTask->list.t.type != M_AUDTASK, "sc->curRSPTask->list.t.type != M_AUDTASK", "../sched.c", 496);
|
ASSERT(sc->curRSPTask->list.t.type != M_AUDTASK, "sc->curRSPTask->list.t.type != M_AUDTASK", "../sched.c", 496);
|
||||||
|
|
||||||
sc->curRSPTask->state |= OS_SC_YIELD;
|
sc->curRSPTask->state |= OS_SC_YIELD;
|
||||||
|
|
||||||
|
// Send yield request
|
||||||
osSpTaskYield();
|
osSpTaskYield();
|
||||||
|
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
|
@ -146,11 +203,16 @@ void Sched_Yield(SchedContext* sc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OSScTask* func_800C89D4(SchedContext* sc, OSScTask* task) {
|
/**
|
||||||
|
* Check if the framebuffer the gfx task wants to use is allowed
|
||||||
|
*/
|
||||||
|
OSScTask* Sched_GfxTaskFramebufferValid(Scheduler* sc, OSScTask* task) {
|
||||||
if (task == NULL) {
|
if (task == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there are pending swaps, wait until there are none (within 2 VI)
|
||||||
|
|
||||||
if (sc->pendingSwapBuf1 != NULL) {
|
if (sc->pendingSwapBuf1 != NULL) {
|
||||||
if (0) {
|
if (0) {
|
||||||
ASSERT(sc->pendingSwapBuf1 != NULL, "sc->pending_swapbuffer1", "../sched.c", UNK_LINE);
|
ASSERT(sc->pendingSwapBuf1 != NULL, "sc->pending_swapbuffer1", "../sched.c", UNK_LINE);
|
||||||
|
@ -165,48 +227,83 @@ OSScTask* func_800C89D4(SchedContext* sc, OSScTask* task) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sc->pendingSwapBuf2 != NULL ? sc->pendingSwapBuf2->swapBuffer : NULL) == task->framebuffer->fb1) {
|
// If the task's framebuffer is one of the pending swaps or NULL.
|
||||||
|
// In conjunction with the above, these checks are redundant as the pending swap buffers will only be
|
||||||
|
// NULL here, so these could have been simplified to checks for the task's framebuffer being non-NULL.
|
||||||
|
|
||||||
|
if (((sc->pendingSwapBuf2 != NULL) ? sc->pendingSwapBuf2->swapBuffer : NULL) == task->framebuffer->framebuffer) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sc->pendingSwapBuf1 != NULL ? sc->pendingSwapBuf1->swapBuffer : NULL) == task->framebuffer->fb1) {
|
if (((sc->pendingSwapBuf1 != NULL) ? sc->pendingSwapBuf1->swapBuffer : NULL) == task->framebuffer->framebuffer) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osViGetCurrentFramebuffer() == (u32*)task->framebuffer->fb1) {
|
// If the task's framebuffer is the current framebuffer, abort
|
||||||
|
|
||||||
|
if (osViGetCurrentFramebuffer() == task->framebuffer->framebuffer) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Sched_Schedule(SchedContext* sc, OSScTask** sp, OSScTask** dp, s32 state) {
|
/**
|
||||||
s32 ret = state;
|
* Schedules the next tasks to run on the RSP and RDP
|
||||||
|
*
|
||||||
|
* @param sc Scheduler
|
||||||
|
* @param spTaskOut Next task to run on the RSP
|
||||||
|
* @param dpTaskOut Next task to run on the RDP
|
||||||
|
* @param state Bits containing whether the RSP and RDP are currently in use
|
||||||
|
* @return Bits containing whether the RSP and RDP will be in use after starting the next tasks
|
||||||
|
*/
|
||||||
|
s32 Sched_Schedule(Scheduler* sc, OSScTask** spTaskOut, OSScTask** dpTaskOut, s32 state) {
|
||||||
|
s32 nextState = state;
|
||||||
OSScTask* gfxTask = sc->gfxListHead;
|
OSScTask* gfxTask = sc->gfxListHead;
|
||||||
OSScTask* audioTask = sc->audioListHead;
|
OSScTask* audioTask = sc->audioListHead;
|
||||||
|
|
||||||
if (sc->doAudio && (ret & OS_SC_SP)) {
|
if (sc->doAudio && (state & OS_SC_SP)) {
|
||||||
*sp = audioTask;
|
// Audio Task, RSP is available
|
||||||
ret &= ~OS_SC_SP;
|
|
||||||
sc->doAudio = 0;
|
// Return next audio task
|
||||||
|
*spTaskOut = audioTask;
|
||||||
|
// RSP required
|
||||||
|
nextState &= ~OS_SC_SP;
|
||||||
|
//! @bug If there is more than one audio task in the queue at any time, unsetting doAudio here
|
||||||
|
//! will cause only one task to be processed until a new audio task is enqueued. In practice, audio
|
||||||
|
//! tasks are sent infrequently enough that there are never two audio tasks in the queue.
|
||||||
|
sc->doAudio = false;
|
||||||
|
// Advance task queue
|
||||||
sc->audioListHead = sc->audioListHead->next;
|
sc->audioListHead = sc->audioListHead->next;
|
||||||
if (sc->audioListHead == NULL) {
|
if (sc->audioListHead == NULL) {
|
||||||
sc->audioListTail = NULL;
|
sc->audioListTail = NULL;
|
||||||
}
|
}
|
||||||
} else if (gfxTask != NULL) {
|
} else if (gfxTask != NULL) {
|
||||||
if (gfxTask->state & OS_SC_YIELDED || !(gfxTask->flags & OS_SC_NEEDS_RDP)) {
|
// GFX Task
|
||||||
if (ret & OS_SC_SP) {
|
|
||||||
*sp = gfxTask;
|
if ((gfxTask->state & OS_SC_YIELDED) || !(gfxTask->flags & OS_SC_NEEDS_RDP)) {
|
||||||
ret &= ~OS_SC_SP;
|
// If this is a yielded GFX task, or the RDP is not needed for this GFX task
|
||||||
|
|
||||||
|
if (state & OS_SC_SP) {
|
||||||
|
// If the RSP is available, return next graphics task
|
||||||
|
|
||||||
|
*spTaskOut = gfxTask;
|
||||||
|
// RSP required
|
||||||
|
nextState &= ~OS_SC_SP;
|
||||||
|
// Advance task queue
|
||||||
sc->gfxListHead = sc->gfxListHead->next;
|
sc->gfxListHead = sc->gfxListHead->next;
|
||||||
if (sc->gfxListHead == NULL) {
|
if (sc->gfxListHead == NULL) {
|
||||||
sc->gfxListTail = NULL;
|
sc->gfxListTail = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ret == (OS_SC_SP | OS_SC_DP)) {
|
} else if (state == (OS_SC_SP | OS_SC_DP)) {
|
||||||
if (gfxTask->framebuffer == NULL || func_800C89D4(sc, gfxTask) != NULL) {
|
// Both the RSP and RDP are available, check requested framebuffer
|
||||||
*sp = *dp = gfxTask;
|
if (gfxTask->framebuffer == NULL || Sched_GfxTaskFramebufferValid(sc, gfxTask) != NULL) {
|
||||||
ret &= ~(OS_SC_SP | OS_SC_DP);
|
// Return next graphics task
|
||||||
|
*spTaskOut = *dpTaskOut = gfxTask;
|
||||||
|
// RSP and RDP both required
|
||||||
|
nextState &= ~(OS_SC_SP | OS_SC_DP);
|
||||||
|
// Advance task queue
|
||||||
sc->gfxListHead = sc->gfxListHead->next;
|
sc->gfxListHead = sc->gfxListHead->next;
|
||||||
if (sc->gfxListHead == NULL) {
|
if (sc->gfxListHead == NULL) {
|
||||||
sc->gfxListTail = NULL;
|
sc->gfxListTail = NULL;
|
||||||
|
@ -214,41 +311,65 @@ s32 Sched_Schedule(SchedContext* sc, OSScTask** sp, OSScTask** dp, s32 state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return nextState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_800C8BC4(SchedContext* sc, OSScTask* task) {
|
/**
|
||||||
|
* Sets the next framebuffer to the framebuffer associated to `task`.
|
||||||
|
* If there is no current buffer or it is time to swap, this buffer will be swapped to
|
||||||
|
* immediately, otherwise it will be swapped to later in Sched_HandleRetrace.
|
||||||
|
*
|
||||||
|
* @see Sched_HandleRetrace
|
||||||
|
*/
|
||||||
|
void Sched_SetNextFramebufferFromTask(Scheduler* sc, OSScTask* task) {
|
||||||
if (sc->pendingSwapBuf1 == NULL) {
|
if (sc->pendingSwapBuf1 == NULL) {
|
||||||
sc->pendingSwapBuf1 = task->framebuffer;
|
sc->pendingSwapBuf1 = task->framebuffer;
|
||||||
|
|
||||||
LogUtils_CheckValidPointer("sc->pending_swapbuffer1", sc->pendingSwapBuf1, "../sched.c", 618);
|
LogUtils_CheckValidPointer("sc->pending_swapbuffer1", sc->pendingSwapBuf1, "../sched.c", 618);
|
||||||
|
|
||||||
if ((sc->curBuf == NULL) || (sc->curBuf->updateRate2 < 1)) {
|
if (sc->curBuf == NULL || sc->curBuf->updateTimer <= 0) {
|
||||||
func_800C84E4(sc, task->framebuffer);
|
Sched_SwapFrameBuffer(sc, task->framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Sched_IsComplete(SchedContext* sc, OSScTask* task) {
|
/**
|
||||||
|
* Checks if the task is done, i.e. it is no longer running on either the RSP or RDP.
|
||||||
|
* If so, send a message to the task's message queue if there is one, and swap the framebuffer
|
||||||
|
* if required.
|
||||||
|
*/
|
||||||
|
u32 Sched_TaskComplete(Scheduler* sc, OSScTask* task) {
|
||||||
|
// Check that the task has released both the RSP and RDP. For graphics tasks that use both,
|
||||||
|
// the RSP will typically finish before the RDP, as the RSP can halt while the RDP is still
|
||||||
|
// working through the command buffer.
|
||||||
if (!(task->state & (OS_SC_DP | OS_SC_SP))) {
|
if (!(task->state & (OS_SC_DP | OS_SC_SP))) {
|
||||||
|
// Send a message to the notify queue if there is one
|
||||||
if (task->msgQueue != NULL) {
|
if (task->msgQueue != NULL) {
|
||||||
osSendMesg(task->msgQueue, task->msg, OS_MESG_BLOCK);
|
osSendMesg(task->msgQueue, task->msg, OS_MESG_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swap the framebuffer if needed
|
||||||
if (task->flags & OS_SC_SWAPBUFFER) {
|
if (task->flags & OS_SC_SWAPBUFFER) {
|
||||||
func_800C8BC4(sc, task);
|
Sched_SetNextFramebufferFromTask(sc, task);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
/**
|
||||||
}
|
* Runs the next tasks. The scheduler doesn't support running RDP tasks without
|
||||||
|
* passthrough via the RSP, if there is no RSP task to run then the RDP task will
|
||||||
return 0;
|
* also do nothing.
|
||||||
}
|
*/
|
||||||
|
void Sched_RunTask(Scheduler* sc, OSScTask* spTask, OSScTask* dpTask) {
|
||||||
void Sched_RunTask(SchedContext* sc, OSScTask* spTask, OSScTask* dpTask) {
|
|
||||||
ASSERT(sc->curRSPTask == NULL, "sc->curRSPTask == NULL", "../sched.c", 663);
|
ASSERT(sc->curRSPTask == NULL, "sc->curRSPTask == NULL", "../sched.c", 663);
|
||||||
|
|
||||||
|
// If there is no RSP task there's nothing to do.
|
||||||
if (spTask != NULL) {
|
if (spTask != NULL) {
|
||||||
if (spTask->list.t.type == M_NULTASK) {
|
if (spTask->list.t.type == M_NULTASK) {
|
||||||
|
// NULTASK is a sync/flush operation, clear current RSP and RDP tasks
|
||||||
|
// and unset flags for this task
|
||||||
if (spTask->flags & OS_SC_NEEDS_RSP) {
|
if (spTask->flags & OS_SC_NEEDS_RSP) {
|
||||||
spTask->state &= ~OS_SC_SP;
|
spTask->state &= ~OS_SC_SP;
|
||||||
sc->curRSPTask = NULL;
|
sc->curRSPTask = NULL;
|
||||||
|
@ -257,14 +378,17 @@ void Sched_RunTask(SchedContext* sc, OSScTask* spTask, OSScTask* dpTask) {
|
||||||
spTask->state &= ~OS_SC_DP;
|
spTask->state &= ~OS_SC_DP;
|
||||||
sc->curRDPTask = NULL;
|
sc->curRDPTask = NULL;
|
||||||
}
|
}
|
||||||
Sched_IsComplete(sc, spTask);
|
// Finalize
|
||||||
|
Sched_TaskComplete(sc, spTask);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spTask->state &= ~(OS_SC_YIELD | OS_SC_YIELDED);
|
spTask->state &= ~(OS_SC_YIELD | OS_SC_YIELDED);
|
||||||
|
// Write back data cache and load the OSTask into the RSP
|
||||||
osWritebackDCacheAll();
|
osWritebackDCacheAll();
|
||||||
osSpTaskLoad(&spTask->list);
|
osSpTaskLoad(&spTask->list);
|
||||||
|
|
||||||
|
// Begin profiling timers
|
||||||
if (spTask->list.t.type == M_AUDTASK) {
|
if (spTask->list.t.type == M_AUDTASK) {
|
||||||
sRSPAudioStartTime = osGetTime();
|
sRSPAudioStartTime = osGetTime();
|
||||||
} else if (spTask->list.t.type == M_GFXTASK) {
|
} else if (spTask->list.t.type == M_GFXTASK) {
|
||||||
|
@ -273,14 +397,19 @@ void Sched_RunTask(SchedContext* sc, OSScTask* spTask, OSScTask* dpTask) {
|
||||||
sRSPOtherStartTime = osGetTime();
|
sRSPOtherStartTime = osGetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run RSP
|
||||||
osSpTaskStartGo(&spTask->list);
|
osSpTaskStartGo(&spTask->list);
|
||||||
|
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf(
|
osSyncPrintf(
|
||||||
"%08d:osSpTaskStartGo(%08x) %s\n", (u32)OS_CYCLES_TO_USEC(osGetTime()), &spTask->list,
|
"%08d:osSpTaskStartGo(%08x) %s\n", (u32)OS_CYCLES_TO_USEC(osGetTime()), &spTask->list,
|
||||||
(spTask->list.t.type == M_AUDTASK ? "AUDIO" : (spTask->list.t.type == M_GFXTASK ? "GRAPH" : "OTHER")));
|
(spTask->list.t.type == M_AUDTASK ? "AUDIO" : (spTask->list.t.type == M_GFXTASK ? "GRAPH" : "OTHER")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set currently running RSP task
|
||||||
sc->curRSPTask = spTask;
|
sc->curRSPTask = spTask;
|
||||||
|
|
||||||
|
// If the task also uses the RDP, set current running RDP task
|
||||||
if (spTask == dpTask && sc->curRDPTask == NULL) {
|
if (spTask == dpTask && sc->curRDPTask == NULL) {
|
||||||
sc->curRDPTask = dpTask;
|
sc->curRDPTask = dpTask;
|
||||||
sRDPStartTime = sRSPGFXStartTime;
|
sRDPStartTime = sRSPGFXStartTime;
|
||||||
|
@ -288,17 +417,26 @@ void Sched_RunTask(SchedContext* sc, OSScTask* spTask, OSScTask* dpTask) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_HandleEntry(SchedContext* sc) {
|
/**
|
||||||
|
* Runs when the scheduler has received a notification, either from another thread or
|
||||||
|
* on VI Retrace. Tasks that have been sent to it will be enqueued onto the audio or
|
||||||
|
* gfx task queue and one may be ran if the RSP is available.
|
||||||
|
*/
|
||||||
|
void Sched_HandleNotification(Scheduler* sc) {
|
||||||
OSScTask* nextRSP = NULL;
|
OSScTask* nextRSP = NULL;
|
||||||
OSScTask* nextRDP = NULL;
|
OSScTask* nextRDP = NULL;
|
||||||
s32 state;
|
s32 state;
|
||||||
OSScTask* task = NULL;
|
OSScTask* task = NULL;
|
||||||
|
|
||||||
|
// Enqueue any tasks sent by other threads
|
||||||
while (osRecvMesg(&sc->cmdQueue, (OSMesg*)&task, OS_MESG_NOBLOCK) != -1) {
|
while (osRecvMesg(&sc->cmdQueue, (OSMesg*)&task, OS_MESG_NOBLOCK) != -1) {
|
||||||
Sched_QueueTask(sc, task);
|
Sched_QueueTask(sc, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->doAudio != 0 && sc->curRSPTask != NULL) {
|
// If an audio task has been enqueued and there is currently an RSP task running,
|
||||||
|
// signal to the currently running task to yield the RSP so that the audio task may
|
||||||
|
// be ran as soon as possible.
|
||||||
|
if (sc->doAudio && sc->curRSPTask != NULL) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("[YIELD B]");
|
osSyncPrintf("[YIELD B]");
|
||||||
}
|
}
|
||||||
|
@ -306,7 +444,8 @@ void Sched_HandleEntry(SchedContext* sc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = ((sc->curRSPTask == 0) * 2) | (sc->curRDPTask == 0);
|
// Run next task in the queue if there is one and the necessary resources are available
|
||||||
|
state = ((sc->curRSPTask == NULL) << 1) | (sc->curRDPTask == NULL);
|
||||||
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
||||||
Sched_RunTask(sc, nextRSP, nextRDP);
|
Sched_RunTask(sc, nextRSP, nextRDP);
|
||||||
}
|
}
|
||||||
|
@ -315,42 +454,51 @@ void Sched_HandleEntry(SchedContext* sc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_HandleRetrace(SchedContext* sc) {
|
void Sched_HandleRetrace(Scheduler* sc) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("%08d:scHandleRetrace %08x\n", (u32)OS_CYCLES_TO_USEC(osGetTime()), osViGetCurrentFramebuffer());
|
osSyncPrintf("%08d:scHandleRetrace %08x\n", (u32)OS_CYCLES_TO_USEC(osGetTime()), osViGetCurrentFramebuffer());
|
||||||
}
|
}
|
||||||
ViConfig_UpdateBlack();
|
ViConfig_UpdateBlack();
|
||||||
sc->retraceCnt++;
|
sc->retraceCount++;
|
||||||
|
|
||||||
if (osViGetCurrentFramebuffer() == (u32*)(sc->pendingSwapBuf1 != NULL ? sc->pendingSwapBuf1->swapBuffer : NULL)) {
|
// Retrace handlers run after VI context swap. The last swap buffer may now be the current buffer.
|
||||||
|
if (osViGetCurrentFramebuffer() == ((sc->pendingSwapBuf1 != NULL) ? sc->pendingSwapBuf1->swapBuffer : NULL)) {
|
||||||
if (sc->curBuf != NULL) {
|
if (sc->curBuf != NULL) {
|
||||||
sc->curBuf->unk_10 = 0;
|
sc->curBuf->unk_10 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->pendingSwapBuf1 != NULL) {
|
if (sc->pendingSwapBuf1 != NULL) {
|
||||||
sc->pendingSwapBuf1->unk_10 = 0;
|
sc->pendingSwapBuf1->unk_10 = 0;
|
||||||
}
|
}
|
||||||
|
// Advance buffers
|
||||||
sc->curBuf = sc->pendingSwapBuf1;
|
sc->curBuf = sc->pendingSwapBuf1;
|
||||||
sc->pendingSwapBuf1 = sc->pendingSwapBuf2;
|
sc->pendingSwapBuf1 = sc->pendingSwapBuf2;
|
||||||
sc->pendingSwapBuf2 = NULL;
|
sc->pendingSwapBuf2 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->curBuf != NULL) {
|
if (sc->curBuf != NULL) {
|
||||||
if (sc->curBuf->updateRate2 > 0) {
|
// Swap the framebuffer when the update timer runs out
|
||||||
sc->curBuf->updateRate2--;
|
if (sc->curBuf->updateTimer > 0) {
|
||||||
|
sc->curBuf->updateTimer--;
|
||||||
}
|
}
|
||||||
if ((sc->curBuf->updateRate2 <= 0) && (sc->pendingSwapBuf1 != NULL)) {
|
if (sc->curBuf->updateTimer <= 0 && sc->pendingSwapBuf1 != NULL) {
|
||||||
func_800C84E4(sc, sc->pendingSwapBuf1);
|
Sched_SwapFrameBuffer(sc, sc->pendingSwapBuf1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sLogScheduler) {
|
|
||||||
osSyncPrintf("%08x %08x %08x %d\n", osViGetCurrentFramebuffer(), osViGetNextFramebuffer(),
|
|
||||||
sc->pendingSwapBuf1 != NULL ? sc->pendingSwapBuf1->swapBuffer : NULL,
|
|
||||||
sc->curBuf != NULL ? sc->curBuf->updateRate2 : 0);
|
|
||||||
}
|
|
||||||
Sched_HandleEntry(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sched_HandleRSPDone(SchedContext* sc) {
|
if (sLogScheduler) {
|
||||||
|
osSyncPrintf("%08x %08x %08x %d\n", osViGetCurrentFramebuffer(), osViGetNextFramebuffer(),
|
||||||
|
(sc->pendingSwapBuf1 != NULL) ? sc->pendingSwapBuf1->swapBuffer : NULL,
|
||||||
|
(sc->curBuf != NULL) ? sc->curBuf->updateTimer : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the notification handler to enqueue any waiting tasks and possibly run one
|
||||||
|
Sched_HandleNotification(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSP has signalled that the task has either completed or yielded.
|
||||||
|
*/
|
||||||
|
void Sched_HandleRSPDone(Scheduler* sc) {
|
||||||
OSScTask* curRSPTask;
|
OSScTask* curRSPTask;
|
||||||
OSScTask* nextRSP = NULL;
|
OSScTask* nextRSP = NULL;
|
||||||
OSScTask* nextRDP = NULL;
|
OSScTask* nextRDP = NULL;
|
||||||
|
@ -358,6 +506,7 @@ void Sched_HandleRSPDone(SchedContext* sc) {
|
||||||
|
|
||||||
ASSERT(sc->curRSPTask != NULL, "sc->curRSPTask", "../sched.c", 819);
|
ASSERT(sc->curRSPTask != NULL, "sc->curRSPTask", "../sched.c", 819);
|
||||||
|
|
||||||
|
// Task profiling
|
||||||
if (sc->curRSPTask->list.t.type == M_AUDTASK) {
|
if (sc->curRSPTask->list.t.type == M_AUDTASK) {
|
||||||
gRSPAudioTotalTime += osGetTime() - sRSPAudioStartTime;
|
gRSPAudioTotalTime += osGetTime() - sRSPAudioStartTime;
|
||||||
} else if (sc->curRSPTask->list.t.type == M_GFXTASK) {
|
} else if (sc->curRSPTask->list.t.type == M_GFXTASK) {
|
||||||
|
@ -366,16 +515,21 @@ void Sched_HandleRSPDone(SchedContext* sc) {
|
||||||
gRSPOtherTotalTime += osGetTime() - sRSPOtherStartTime;
|
gRSPOtherTotalTime += osGetTime() - sRSPOtherStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear current RSP task
|
||||||
curRSPTask = sc->curRSPTask;
|
curRSPTask = sc->curRSPTask;
|
||||||
sc->curRSPTask = NULL;
|
sc->curRSPTask = NULL;
|
||||||
|
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("RSP DONE %d %d", curRSPTask->state & 0x10, osSpTaskYielded(&curRSPTask->list));
|
osSyncPrintf("RSP DONE %d %d", curRSPTask->state & OS_SC_YIELD, osSpTaskYielded(&curRSPTask->list));
|
||||||
}
|
}
|
||||||
if (curRSPTask->state & OS_SC_YIELD && osSpTaskYielded(&curRSPTask->list)) {
|
|
||||||
|
if ((curRSPTask->state & OS_SC_YIELD) && osSpTaskYielded(&curRSPTask->list)) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("[YIELDED]\n");
|
osSyncPrintf("[YIELDED]\n");
|
||||||
}
|
}
|
||||||
|
// Task yielded, set yielded state
|
||||||
curRSPTask->state |= OS_SC_YIELDED;
|
curRSPTask->state |= OS_SC_YIELDED;
|
||||||
|
// Add it to the front of the queue
|
||||||
curRSPTask->next = sc->gfxListHead;
|
curRSPTask->next = sc->gfxListHead;
|
||||||
sc->gfxListHead = curRSPTask;
|
sc->gfxListHead = curRSPTask;
|
||||||
if (sc->gfxListTail == NULL) {
|
if (sc->gfxListTail == NULL) {
|
||||||
|
@ -385,10 +539,12 @@ void Sched_HandleRSPDone(SchedContext* sc) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("[NOT YIELDED]\n");
|
osSyncPrintf("[NOT YIELDED]\n");
|
||||||
}
|
}
|
||||||
|
// Task has completed on the RSP, unset RSP flag and check if the task is fully complete
|
||||||
curRSPTask->state &= ~OS_SC_SP;
|
curRSPTask->state &= ~OS_SC_SP;
|
||||||
Sched_IsComplete(sc, curRSPTask);
|
Sched_TaskComplete(sc, curRSPTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run next task in the queue if there is one and the necessary resources are available
|
||||||
state = ((sc->curRSPTask == NULL) << 1) | (sc->curRDPTask == NULL);
|
state = ((sc->curRSPTask == NULL) << 1) | (sc->curRDPTask == NULL);
|
||||||
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
||||||
Sched_RunTask(sc, nextRSP, nextRDP);
|
Sched_RunTask(sc, nextRSP, nextRDP);
|
||||||
|
@ -398,19 +554,31 @@ void Sched_HandleRSPDone(SchedContext* sc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_HandleRDPDone(SchedContext* sc) {
|
/**
|
||||||
|
* RDP has signalled task done upon reaching a DPFullSync command
|
||||||
|
*/
|
||||||
|
void Sched_HandleRDPDone(Scheduler* sc) {
|
||||||
OSScTask* curTask;
|
OSScTask* curTask;
|
||||||
OSScTask* nextRSP = NULL;
|
OSScTask* nextRSP = NULL;
|
||||||
OSScTask* nextRDP = NULL;
|
OSScTask* nextRDP = NULL;
|
||||||
s32 state;
|
s32 state;
|
||||||
|
|
||||||
|
// Task profiling
|
||||||
gRDPTotalTime = osGetTime() - sRDPStartTime;
|
gRDPTotalTime = osGetTime() - sRDPStartTime;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
ASSERT(sc->curRDPTask != NULL, "sc->curRDPTask", "../sched.c", 878);
|
ASSERT(sc->curRDPTask != NULL, "sc->curRDPTask", "../sched.c", 878);
|
||||||
ASSERT(sc->curRDPTask->list.t.type == M_GFXTASK, "sc->curRDPTask->list.t.type == M_GFXTASK", "../sched.c", 879);
|
ASSERT(sc->curRDPTask->list.t.type == M_GFXTASK, "sc->curRDPTask->list.t.type == M_GFXTASK", "../sched.c", 879);
|
||||||
|
|
||||||
|
// Clear current RDP task
|
||||||
curTask = sc->curRDPTask;
|
curTask = sc->curRDPTask;
|
||||||
sc->curRDPTask = NULL;
|
sc->curRDPTask = NULL;
|
||||||
|
|
||||||
|
// Task has completed on the RDP, unset RDP flag and check if the task is fully complete
|
||||||
curTask->state &= ~OS_SC_DP;
|
curTask->state &= ~OS_SC_DP;
|
||||||
Sched_IsComplete(sc, curTask);
|
Sched_TaskComplete(sc, curTask);
|
||||||
|
|
||||||
|
// Run next task in the queue if there is one and the necessary resources are available
|
||||||
state = ((sc->curRSPTask == NULL) << 1) | (sc->curRDPTask == NULL);
|
state = ((sc->curRSPTask == NULL) << 1) | (sc->curRDPTask == NULL);
|
||||||
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
if (Sched_Schedule(sc, &nextRSP, &nextRDP, state) != state) {
|
||||||
Sched_RunTask(sc, nextRSP, nextRDP);
|
Sched_RunTask(sc, nextRSP, nextRDP);
|
||||||
|
@ -420,17 +588,24 @@ void Sched_HandleRDPDone(SchedContext* sc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_SendEntryMsg(SchedContext* sc) {
|
/**
|
||||||
|
* Called by other threads in order to wake the scheduler up immediately to enqueue and
|
||||||
|
* possibly run a task that has been sent to the task queue. Otherwise, any pending tasks
|
||||||
|
* will be enqueued on next vertical retrace.
|
||||||
|
*
|
||||||
|
* Original name: osScKickEntryMsg
|
||||||
|
*/
|
||||||
|
void Sched_Notify(Scheduler* sc) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("osScKickEntryMsg\n");
|
osSyncPrintf("osScKickEntryMsg\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
osSendMesg(&sc->interruptQueue, (OSMesg)ENTRY_MSG, OS_MESG_BLOCK);
|
osSendMesg(&sc->interruptQueue, (OSMesg)NOTIFY_MSG, OS_MESG_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_ThreadEntry(void* arg) {
|
void Sched_ThreadEntry(void* arg) {
|
||||||
OSMesg msg = NULL;
|
OSMesg msg = NULL;
|
||||||
SchedContext* sc = (SchedContext*)arg;
|
Scheduler* sc = (Scheduler*)arg;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
|
@ -438,14 +613,15 @@ void Sched_ThreadEntry(void* arg) {
|
||||||
osSyncPrintf("%08d:待機中\n", (u32)OS_CYCLES_TO_USEC(osGetTime()));
|
osSyncPrintf("%08d:待機中\n", (u32)OS_CYCLES_TO_USEC(osGetTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Await interrupt messages, either from the OS, IrqMgr, or another thread
|
||||||
osRecvMesg(&sc->interruptQueue, &msg, OS_MESG_BLOCK);
|
osRecvMesg(&sc->interruptQueue, &msg, OS_MESG_BLOCK);
|
||||||
|
|
||||||
switch ((s32)msg) {
|
switch ((s32)msg) {
|
||||||
case ENTRY_MSG:
|
case NOTIFY_MSG:
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
osSyncPrintf("%08d:ENTRY_MSG\n", (u32)OS_CYCLES_TO_USEC(osGetTime()));
|
osSyncPrintf("%08d:ENTRY_MSG\n", (u32)OS_CYCLES_TO_USEC(osGetTime()));
|
||||||
}
|
}
|
||||||
Sched_HandleEntry(sc);
|
Sched_HandleNotification(sc);
|
||||||
continue;
|
continue;
|
||||||
case RSP_DONE_MSG:
|
case RSP_DONE_MSG:
|
||||||
if (sLogScheduler) {
|
if (sLogScheduler) {
|
||||||
|
@ -461,22 +637,24 @@ void Sched_ThreadEntry(void* arg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (((OSScMsg*)msg)->type) {
|
switch (((OSScMsg*)msg)->type) {
|
||||||
case 1:
|
case OS_SC_RETRACE_MSG:
|
||||||
Sched_HandleRetrace(sc);
|
Sched_HandleRetrace(sc);
|
||||||
continue;
|
continue;
|
||||||
case 4:
|
case OS_SC_PRE_NMI_MSG:
|
||||||
Sched_HandleReset(sc);
|
Sched_HandlePreNMI(sc);
|
||||||
continue;
|
continue;
|
||||||
case 3:
|
case OS_SC_NMI_MSG:
|
||||||
Sched_HandleStart(sc);
|
Sched_HandleNMI(sc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sched_Init(SchedContext* sc, void* stack, OSPri priority, UNK_TYPE arg3, UNK_TYPE arg4, IrqMgr* irqMgr) {
|
void Sched_Init(Scheduler* sc, void* stack, OSPri priority, UNK_TYPE arg3, UNK_TYPE arg4, IrqMgr* irqMgr) {
|
||||||
bzero(sc, sizeof(SchedContext));
|
bzero(sc, sizeof(Scheduler));
|
||||||
sc->unk_24C = 1;
|
sc->isFirstSwap = true;
|
||||||
|
|
||||||
|
// Create message queues for receiving interrupt events and tasks
|
||||||
osCreateMesgQueue(&sc->interruptQueue, sc->interruptMsgBuf, ARRAY_COUNT(sc->interruptMsgBuf));
|
osCreateMesgQueue(&sc->interruptQueue, sc->interruptMsgBuf, ARRAY_COUNT(sc->interruptMsgBuf));
|
||||||
osCreateMesgQueue(&sc->cmdQueue, sc->cmdMsgBuf, ARRAY_COUNT(sc->cmdMsgBuf));
|
osCreateMesgQueue(&sc->cmdQueue, sc->cmdMsgBuf, ARRAY_COUNT(sc->cmdMsgBuf));
|
||||||
osSetEventMesg(OS_EVENT_SP, &sc->interruptQueue, RSP_DONE_MSG);
|
osSetEventMesg(OS_EVENT_SP, &sc->interruptQueue, RSP_DONE_MSG);
|
||||||
|
|
|
@ -60,8 +60,8 @@ void Jpeg_ScheduleDecoderTask(JpegContext* ctx) {
|
||||||
ctx->scTask.framebuffer = NULL;
|
ctx->scTask.framebuffer = NULL;
|
||||||
ctx->scTask.list = sJpegTask;
|
ctx->scTask.list = sJpegTask;
|
||||||
|
|
||||||
osSendMesg(&gSchedContext.cmdQueue, (OSMesg)&ctx->scTask, OS_MESG_BLOCK);
|
osSendMesg(&gScheduler.cmdQueue, (OSMesg)&ctx->scTask, OS_MESG_BLOCK);
|
||||||
Sched_SendEntryMsg(&gSchedContext); // osScKickEntryMsg
|
Sched_Notify(&gScheduler);
|
||||||
osRecvMesg(&ctx->mq, NULL, OS_MESG_BLOCK);
|
osRecvMesg(&ctx->mq, NULL, OS_MESG_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ s32 Jpeg_Decode(void* data, void* zbuffer, void* work, u32 workSize) {
|
||||||
527);
|
527);
|
||||||
|
|
||||||
osCreateMesgQueue(&ctx.mq, &ctx.msg, 1);
|
osCreateMesgQueue(&ctx.mq, &ctx.msg, 1);
|
||||||
MsgEvent_SendNullTask();
|
Sched_FlushTaskQueue();
|
||||||
|
|
||||||
curTime = osGetTime();
|
curTime = osGetTime();
|
||||||
diff = curTime - time;
|
diff = curTime - time;
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
void MsgEvent_SendNullTask(void) {
|
|
||||||
OSScTask task;
|
|
||||||
OSMesgQueue queue;
|
|
||||||
OSMesg msg;
|
|
||||||
u32 pad2[1];
|
|
||||||
|
|
||||||
task.next = NULL;
|
|
||||||
task.flags = OS_SC_RCP_MASK;
|
|
||||||
task.msgQueue = &queue;
|
|
||||||
task.msg = NULL;
|
|
||||||
task.framebuffer = NULL;
|
|
||||||
task.list.t.type = M_NULTASK;
|
|
||||||
osCreateMesgQueue(task.msgQueue, &msg, 1);
|
|
||||||
osSendMesg(&gSchedContext.cmdQueue, (OSMesg)&task, OS_MESG_BLOCK);
|
|
||||||
Sched_SendEntryMsg(&gSchedContext);
|
|
||||||
osRecvMesg(&queue, NULL, OS_MESG_BLOCK);
|
|
||||||
}
|
|
27
src/code/z_nulltask.c
Normal file
27
src/code/z_nulltask.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the current thread until all queued scheduler tasks have completed.
|
||||||
|
*/
|
||||||
|
void Sched_FlushTaskQueue(void) {
|
||||||
|
OSScTask task;
|
||||||
|
OSMesgQueue queue;
|
||||||
|
OSMesg msg;
|
||||||
|
|
||||||
|
// Prepare a "NULL" task
|
||||||
|
task.next = NULL;
|
||||||
|
task.flags = OS_SC_NEEDS_RDP | OS_SC_NEEDS_RSP;
|
||||||
|
task.msgQueue = &queue;
|
||||||
|
task.msg = NULL;
|
||||||
|
task.framebuffer = NULL;
|
||||||
|
task.list.t.type = M_NULTASK;
|
||||||
|
osCreateMesgQueue(task.msgQueue, &msg, 1);
|
||||||
|
|
||||||
|
// Send it to and wake up the scheduler
|
||||||
|
osSendMesg(&gScheduler.cmdQueue, (OSMesg)&task, OS_MESG_BLOCK);
|
||||||
|
Sched_Notify(&gScheduler);
|
||||||
|
|
||||||
|
// Wait until the task has been processed, indicating that no task is
|
||||||
|
// running and the task queue is now empty.
|
||||||
|
osRecvMesg(&queue, NULL, OS_MESG_BLOCK);
|
||||||
|
}
|
|
@ -1183,7 +1183,7 @@ void Play_Draw(PlayState* this) {
|
||||||
PreRender_SetValues(&this->pauseBgPreRender, SCREEN_WIDTH, SCREEN_HEIGHT, gfxCtx->curFrameBuffer, gZBuffer);
|
PreRender_SetValues(&this->pauseBgPreRender, SCREEN_WIDTH, SCREEN_HEIGHT, gfxCtx->curFrameBuffer, gZBuffer);
|
||||||
|
|
||||||
if (R_PAUSE_MENU_MODE == 2) {
|
if (R_PAUSE_MENU_MODE == 2) {
|
||||||
MsgEvent_SendNullTask();
|
Sched_FlushTaskQueue();
|
||||||
PreRender_Calc(&this->pauseBgPreRender);
|
PreRender_Calc(&this->pauseBgPreRender);
|
||||||
R_PAUSE_MENU_MODE = 3;
|
R_PAUSE_MENU_MODE = 3;
|
||||||
} else if (R_PAUSE_MENU_MODE >= 4) {
|
} else if (R_PAUSE_MENU_MODE >= 4) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ void PreNMI_Update(PreNMIContext* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->timer == 0) {
|
if (this->timer == 0) {
|
||||||
ViConfig_UpdateVi(1);
|
ViConfig_UpdateVi(true);
|
||||||
func_80092320(this);
|
func_80092320(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
void osSpTaskYield(void) {
|
void osSpTaskYield(void) {
|
||||||
__osSpSetStatus(SP_STATUS_SIG3);
|
__osSpSetStatus(SP_SET_SIG0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
u32* osViGetCurrentFramebuffer(void) {
|
void* osViGetCurrentFramebuffer(void) {
|
||||||
register u32 prevInt = __osDisableInt();
|
register u32 prevInt = __osDisableInt();
|
||||||
u32* var1 = __osViCurr->buffer;
|
void* buffer = __osViCurr->buffer;
|
||||||
|
|
||||||
__osRestoreInt(prevInt);
|
__osRestoreInt(prevInt);
|
||||||
|
|
||||||
return var1;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue