#include #include #include #include "types.h" #include "config.h" #include "profiler.h" #include "main.h" #include "memory.h" #include "segments.h" #include "segment_symbols.h" #include "common_structs.h" // Declarations (not in this file) void func_8008C214(void); void func_80091B78(void); void func_802A4D18(void); void func_802A7C08(void); void func_802A3E3C(void); void func_802A4160(void); void func_802A41D4(void); void func_802A3CB0(void); void audio_init(); void profiler_log_gfx_time(enum ProfilerGfxEvent eventID); void profiler_log_vblank_time(void); void create_thread(OSThread *thread, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri pri); void create_debug_thread(void); void start_debug_thread(void); struct SPTask *create_next_audio_frame_task(void); extern s32 D_800DC524; extern s32 D_800DC52C; extern OSThread gIdleThread; extern OSThread gVideoThread; extern u16 D_8015011C; extern OSMesgQueue D_8015F460; extern OSMesg D_8015F3E0; extern s32 D_80156820; extern f32 D_800DC594; struct VblankHandler *gVblankHandler1 = NULL; struct VblankHandler *gVblankHandler2 = NULL; struct SPTask *gActiveSPTask = NULL; struct SPTask *sCurrentAudioSPTask = NULL; struct SPTask* sCurrentDisplaySPTask = NULL; struct SPTask* D_800DC4B4 = NULL; struct SPTask* sNextDisplaySPTask = NULL; struct Controller gControllers[8]; struct Controller *D_800DC4BC = &gControllers[0]; struct Controller *D_800DC4C0 = &gControllers[1]; struct Controller *D_800DC4C4 = &gControllers[2]; struct Controller *D_800DC4C8 = &gControllers[3]; struct Controller *D_800DC4CC = &gControllers[4]; struct Controller *D_800DC4D0 = &gControllers[5]; struct Controller *D_800DC4D4 = &gControllers[6]; struct Controller *D_800DC4D8 = &gControllers[7]; Player gPlayers[8]; Player *D_800DC4DC = &gPlayers[0]; Player *D_800DC4E0 = &gPlayers[1]; Player *D_800DC4E4 = &gPlayers[2]; Player *D_800DC4E8 = &gPlayers[3]; Player *D_800DC4EC = &gPlayers[4]; Player *D_800DC4F0 = &gPlayers[5]; Player *D_800DC4F4 = &gPlayers[6]; Player *D_800DC4F8 = &gPlayers[7]; Player *D_800DC4FC = &gPlayers[0]; Player *D_800DC500 = &gPlayers[1]; Player *D_800DC504 = &gPlayers[2]; Player *D_800DC508 = &gPlayers[3]; s32 D_800DC50C = 0xffff; u16 D_800DC510 = 0; u16 D_800DC514 = 0; u16 D_800DC518 = 0; u16 D_800DC51C = 0; u16 gEnableDebugMode = 0; s32 D_800DC524 = 7; UNUSED s32 D_800DC528 = 1; s32 D_800DC52C = 0; s32 D_800DC530[2] = {0}; s32 gPlayerCountSelection1 = 2; s32 gModeSelection = 0; s32 D_800DC540 = 0; s32 D_800DC544 = 0; s32 D_800DC548 = 0; s32 gGlobalTimer = 0; UNUSED s32 D_800DC550 = 0; UNUSED s32 D_800DC554 = 0; UNUSED s32 D_800DC558 = 0; // Framebuffer rendering values (max 3) u16 sRenderedFramebuffer = 0; u16 sRenderingFramebuffer = 0; UNUSED u16 D_800DC564 = 0; s32 D_800DC568 = 0; s32 D_800DC56C[8] = {0}; s16 sNumVBlanks = 0; UNUSED s16 D_800DC590 = 0; float D_800DC594 = 0.0f; float gCourseTimer = 0.0f; extern u8 gControllerBits; extern OSContStatus gControllerStatuses; extern u16 sController1Unplugged; extern uintptr_t gPhysicalFramebuffers[3]; extern const f64 D_800EB640; extern struct VblankHandler sSoundVblankHandler; extern struct SPTask *gGfxSPTask; extern OSMesgQueue D_8014EF58, D_8014EF70, D_8014EF88, D_8014EFD0, gIntrMesgQueue; extern OSMesgQueue sSoundMesgQueue; extern OSMesg sSoundMesgBuf; extern OSMesg D_8014F004, D_8014F058, D_8014F018; extern Gfx *gDisplayListHead; extern u64 rspbootTextStart[], rspbootTextEnd[]; extern u64 gspF3DEXTextStart[], gspF3DEXTextEnd[]; extern u64 gspF3DLXTextStart[], gspF3DLXTextEnd[]; extern u64 gspF3DEXDataStart[]; extern u64 gspF3DLXDataStart[]; extern u32 gGfxSPTaskStack; extern u64 gGfxSPTaskOutputBuffer[]; extern u32 gGfxSPTaskOutputBufferSize; extern u8 gGfxSPTaskYieldBuffer[]; extern u32 gPrevLoadedAddress; extern u32 D_8015F734; extern u8 _data_segment2SegmentRomStart[]; extern u8 _data_segment2SegmentRomEnd[]; extern u8 _common_texturesSegmentRomStart[]; extern u8 _common_texturesSegmentRomEnd[]; extern u8 _data_802BA370SegmentRomStart[]; extern OSMesg *D_8014F098; extern OSIoMesg *D_8014F0A0; extern u32 gHeapEndPtr; extern u32 *D_801978D0; extern OSMesgQueue gSIEventMesgQueue; extern OSMesg gSIEventMesgBuf[3]; extern u32 D_801502B4; extern u32 D_802F9F80; extern s32 D_8031F780; extern s32 D_80344F80[]; extern s32 D_8036A780; extern s32 D_8015AB80; extern s32 D_801589D0; extern void thread5_game_logic(); extern void thread4_audio(); extern s32 D_8015CD30; extern f64 D_800EB610; extern s16 gCurrentlyLoadedCourseId; s32 D_800FD850[4]; extern struct GfxPool gGfxPools[2]; // Declarations (in this file) void thread1_idle(void *arg0); void thread3_video(void *arg0); // Message IDs #define MESG_SP_COMPLETE 100 #define MESG_DP_COMPLETE 101 #define MESG_VI_VBLANK 102 #define MESG_START_GFX_SPTASK 103 #define MESG_NMI_REQUEST 104 void create_thread(OSThread *thread, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri pri) { thread->next = NULL; thread->queue = NULL; osCreateThread(thread, id, entry, arg, sp, pri); } void main_func(void) { osInitialize(); //! Why is this using the gVideoThread as idle stack? create_thread(&gIdleThread, 1, thread1_idle, NULL, &gVideoThread, 100); osStartThread(&gIdleThread); } void thread1_idle(void *arg0) { osCreateViManager(OS_PRIORITY_VIMGR); if (osTvType == TV_TYPE_NTSC) { osViSetMode(&osViModeTable[OS_VI_NTSC_LAN1]); } else { osViSetMode(&osViModeTable[OS_VI_MPAL_LAN1]); } osViBlack(TRUE); osViSetSpecialFeatures(OS_VI_GAMMA_OFF); osCreatePiManager(OS_PRIORITY_PIMGR, &D_8015F460, &D_8015F3E0, 0x20); D_8015011C = (s16) osResetType; create_debug_thread(); start_debug_thread(); create_thread(&gVideoThread, 3, &thread3_video, arg0, &D_80156820, 100); osStartThread(&gVideoThread); osSetThreadPri(NULL, 0); // halt while (1); } void setup_mesg_queues(void) { osCreateMesgQueue(&D_8014EF58, &D_8014F004, 1); osCreateMesgQueue(&D_8014EFD0, &D_8014F058, 0x10); osCreateMesgQueue(&gIntrMesgQueue, &D_8014F018, 0x10); osViSetEvent(&gIntrMesgQueue, (OSMesg) 0x66, 1); osSetEventMesg(4, &gIntrMesgQueue, (OSMesg) 0x64); osSetEventMesg(9, &gIntrMesgQueue, (OSMesg) 0x65); } void start_sptask(s32 taskType) { if (taskType == M_AUDTASK) { gActiveSPTask = sCurrentAudioSPTask; } else { gActiveSPTask = sCurrentDisplaySPTask; } osSpTaskLoad(&gActiveSPTask->task); osSpTaskStartGo(&gActiveSPTask->task); gActiveSPTask->state = SPTASK_STATE_RUNNING; } // Most similar to create_task_structure from SM64, with additional provisions // to load both F3DEX and F3DLX, depending on the number of players void func_800006E8(void) { gGfxSPTask->msgqueue = &D_8014EF88; gGfxSPTask->msg = (OSMesg) 2; gGfxSPTask->task.t.type = M_GFXTASK; gGfxSPTask->task.t.flags = (1 << 1); gGfxSPTask->task.t.ucode_boot = rspbootTextStart; gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspbootTextEnd - (u8 *) rspbootTextStart); if (D_800DC50C != 4 || gPlayerCountSelection1 - 1 == 0) { gGfxSPTask->task.t.ucode = gspF3DEXTextStart; gGfxSPTask->task.t.ucode_data = gspF3DEXDataStart; } else { gGfxSPTask->task.t.ucode = gspF3DLXTextStart; gGfxSPTask->task.t.ucode_data = gspF3DLXDataStart; } gGfxSPTask->task.t.flags = 0; gGfxSPTask->task.t.flags = (1 << 1); gGfxSPTask->task.t.ucode_size = SP_UCODE_SIZE; gGfxSPTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE; gGfxSPTask->task.t.dram_stack = (u64 *) &gGfxSPTaskStack; gGfxSPTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8; gGfxSPTask->task.t.output_buff = (u64 *) &gGfxSPTaskOutputBuffer; gGfxSPTask->task.t.output_buff_size = (u64 *) &gGfxSPTaskOutputBufferSize; gGfxSPTask->task.t.data_ptr = (u64 *) &gGfxPool->buffer[0x3418]; gGfxSPTask->task.t.data_size = (gDisplayListHead - &gGfxPool->buffer[0x3418]) * sizeof(Gfx); func_8008C214(); gGfxSPTask->task.t.yield_data_ptr = (u64 *) &gGfxSPTaskYieldBuffer; gGfxSPTask->task.t.yield_data_size = 0xD00; /* Not equal to OS_YIELD_DATA_SIZE */ } void init_controllers(void) { osCreateMesgQueue(&gSIEventMesgQueue, &gSIEventMesgBuf[0], ARRAY_COUNT(gSIEventMesgBuf)); osSetEventMesg(OS_EVENT_SI, &gSIEventMesgQueue, (OSMesg) 0x33333333); osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses); if ((gControllerBits & 1) == 0) { sController1Unplugged = TRUE; return; } sController1Unplugged = FALSE; } #ifdef MIPS_TO_C //generated by mips_to_c commit ffee479fae41a1cdc3e454e9b9d75bbd226a160f void func_80000934(s32 arg0) { s32 temp_a2; u16 temp_a1; u16 temp_t4; void *temp_v0; void *temp_v1; u16 phi_a1; u16 phi_a0; u16 phi_a0_2; u16 phi_a0_3; u16 phi_a0_4; if (sController1Unplugged == 0) { // potantial sizeof structs? temp_v1 = (arg0 * 6) + &gControllerPads; temp_v0 = (arg0 * 0x10) + &gControllers; temp_v0->unk0 = (s16) temp_v1->unk2; temp_v0->unk2 = (s16) temp_v1->unk3; temp_t4 = temp_v1->unk0 | 0x2000; phi_a1 = temp_v1->unk0; if ((temp_v1->unk0 & 4) != 0) { temp_v1->unk0 = temp_t4; phi_a1 = temp_t4 & 0xFFFF; } temp_v0->unk6 = (s16) ((phi_a1 ^ temp_v0->unk4) & phi_a1); temp_v0->unk8 = (s16) ((temp_v1->unk0 ^ temp_v0->unk4) & temp_v0->unk4); temp_v0->unk4 = (u16) temp_v1->unk0; phi_a0_4 = (u16)0U; if ((s32) temp_v0->unk0 < -0x32) { phi_a0_4 = (u16)0x200U; } phi_a0_3 = phi_a0_4; if ((s32) temp_v0->unk0 >= 0x33) { phi_a0_3 = (phi_a0_4 | 0x100) & 0xFFFF; } phi_a0_2 = phi_a0_3; if ((s32) temp_v0->unk2 < -0x32) { phi_a0_2 = (phi_a0_3 | 0x400) & 0xFFFF; } phi_a0 = phi_a0_2; if ((s32) temp_v0->unk2 >= 0x33) { phi_a0 = (phi_a0_2 | 0x800) & 0xFFFF; } temp_a1 = temp_v0->unkA; temp_v0->unkA = phi_a0; temp_a2 = phi_a0 ^ temp_a1; temp_v0->unkC = (s16) (phi_a0 & temp_a2); temp_v0->unkE = (s16) (temp_a1 & temp_a2); } } #else GLOBAL_ASM("asm/non_matchings/main/func_80000934.s") #endif #ifdef MIPS_TO_C // generated by mips_to_c commit cae1414eb1bf34873a831a523692fe29870a6f3b void *read_controllers(void) { ? sp1C; osContStartReadData(&gSIEventMesgQueue); osRecvMesg(&gSIEventMesgQueue, &sp1C, 1); osContGetReadData(&gControllerPads); func_80000934(0); func_80000934(1); func_80000934(2); func_80000934(3); D_800DC4CC->unk4 = (s16) (((D_800DC4BC->unk4 | D_800DC4C0->unk4) | D_800DC4C4->unk4) | D_800DC4C8->unk4); D_800DC4CC->unk6 = (s16) (((D_800DC4BC->unk6 | D_800DC4C0->unk6) | D_800DC4C4->unk6) | D_800DC4C8->unk6); D_800DC4CC->unk8 = (s16) (((D_800DC4BC->unk8 | D_800DC4C0->unk8) | D_800DC4C4->unk8) | D_800DC4C8->unk8); D_800DC4CC->unkA = (s16) (((D_800DC4BC->unkA | D_800DC4C0->unkA) | D_800DC4C4->unkA) | D_800DC4C8->unkA); D_800DC4CC->unkC = (s16) (((D_800DC4BC->unkC | D_800DC4C0->unkC) | D_800DC4C4->unkC) | D_800DC4C8->unkC); D_800DC4CC->unkE = (s16) (((D_800DC4BC->unkE | D_800DC4C0->unkE) | D_800DC4C4->unkE) | D_800DC4C8->unkE); return &D_800DC4CC; } #else GLOBAL_ASM("asm/non_matchings/main/read_controllers.s") #endif void func_80000BEC(void) { D_801502B4 = VIRTUAL_TO_PHYSICAL(&D_802F9F80); } // send_sp_task_message from SM64 void func_80000C0C(OSMesg arg0) { osWritebackDCacheAll(); osSendMesg(&D_8014EFD0, arg0, OS_MESG_NOBLOCK); } // similar to send_display_list from SM64 void send_display_list(struct SPTask *spTask) { osWritebackDCacheAll(); spTask->state = SPTASK_STATE_NOT_STARTED; if (sCurrentDisplaySPTask == NULL) { sCurrentDisplaySPTask = spTask; sNextDisplaySPTask = NULL; osSendMesg(&gIntrMesgQueue, (OSMesg) MESG_START_GFX_SPTASK, OS_MESG_NOBLOCK); } else{ sNextDisplaySPTask = spTask; } } void func_80000CA8(void) { func_802A7C08(); func_802A3E3C(); func_802A4160(); func_802A41D4(); func_802A3CB0(); } // Similar to end_master_display_list in SM64 void func_80000CE8(void) { gDPFullSync(gDisplayListHead++); gSPEndDisplayList(gDisplayListHead++); func_800006E8(); } // clear_frame_buffer from SM64, with a few edits //! TODO: Why did void* work for matching void *clear_framebuffer(s32 color) { gDPPipeSync(gDisplayListHead++); gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); gDPSetFillColor(gDisplayListHead++, color); gDPFillRectangle(gDisplayListHead++, 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); gDPPipeSync(gDisplayListHead++); gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); } void rendering_init(void) { gGfxPool = &gGfxPools[0]; set_segment_base_addr(1, gGfxPool->buffer); gGfxSPTask = &gGfxPool->spTask; gDisplayListHead = &gGfxPool->buffer[0x3418]; func_80000CA8(); clear_framebuffer(0); func_80000CE8(); send_display_list(&gGfxPool->spTask); sRenderingFramebuffer++; gGlobalTimer++; } void config_gfx_pool(void) { gGfxPool = &gGfxPools[gGlobalTimer & 1]; set_segment_base_addr(1, gGfxPool->buffer); gDisplayListHead = &gGfxPool->buffer[0x3418]; gGfxSPTask = &gGfxPool->spTask; } void display_and_vsync(void) { profiler_log_thread5_time(2); osRecvMesg(&D_8014EF88, &D_8014F098, 1); send_display_list(&gGfxPool->spTask); profiler_log_thread5_time(3); osRecvMesg(&D_8014EF70, &D_8014F098, 1); osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[sRenderedFramebuffer])); profiler_log_thread5_time(4); osRecvMesg(&D_8014EF70, &D_8014F098, 1); func_800046AC(gPhysicalFramebuffers[sRenderedFramebuffer]); if (++sRenderedFramebuffer == 3) { sRenderedFramebuffer = 0; } if (++sRenderingFramebuffer == 3) { sRenderingFramebuffer = 0; } gGlobalTimer++; } void func_8000105C(void) { bzero(SEG_80280000, 0xDF00); osWritebackDCacheAll(); dma_copy(SEG_80280000, &_code_80280000SegmentRomStart, ALIGN16((u32)&_code_80280000SegmentRomEnd - (u32)&_code_80280000SegmentRomStart)); osInvalICache(SEG_80280000, 0xDF00); osInvalDCache(SEG_80280000, 0xDF00); } void func_800010CC(void) { bzero(SEG_8028DF00, 0x2C470); osWritebackDCacheAll(); dma_copy(SEG_8028DF00, &_code_8028DF00SegmentRomStart, ALIGN16((u32)&_code_8028DF00SegmentRomEnd - (u32)&_code_8028DF00SegmentRomStart)); osInvalICache(SEG_8028DF00, 0x2C470); osInvalDCache(SEG_8028DF00, 0x2C470); } // Similar to dma_read in SM64 #ifdef MIPS_TO_C //generated by mips_to_c commit ffee479fae41a1cdc3e454e9b9d75bbd226a160f void dma_copy(s32 arg0, s32 arg1, u32 arg2) { s32 temp_s1; s32 temp_s2; u32 temp_s0; s32 phi_s2; s32 phi_s1; u32 phi_s0; u32 phi_s0_2; s32 phi_s2_2; s32 phi_s1_2; osInvalDCache(arg2); phi_s0_2 = arg2; phi_s2_2 = arg1; phi_s1_2 = arg0; if (arg2 >= 0x101U) { phi_s2 = arg1; phi_s1 = arg0; phi_s0 = arg2; loop_2: osPiStartDma(&D_8014F0A0, 0, 0, phi_s2, phi_s1, 0x100, &D_8014EF58); osRecvMesg(&D_8014EF58, &D_8014F098, 1); temp_s0 = phi_s0 - 0x100; temp_s2 = phi_s2 + 0x100; temp_s1 = phi_s1 + 0x100; phi_s2 = temp_s2; phi_s1 = temp_s1; phi_s0 = temp_s0; phi_s0_2 = temp_s0; phi_s2_2 = temp_s2; phi_s1_2 = temp_s1; if (temp_s0 >= 0x101U) { goto loop_2; } } if (phi_s0_2 != 0) { osPiStartDma(&D_8014F0A0, 0, 0, phi_s2_2, phi_s1_2, phi_s0_2, &D_8014EF58); osRecvMesg(&D_8014EF58, &D_8014F098, 1); } } #else GLOBAL_ASM("asm/non_matchings/main/dma_copy.s") #endif // Resembles setup_game_memory from SM64 #ifdef NON_MATCHING void init_game(void) { s32 sp38;//0x38(sp) u32 *sp2C; s32 temp_t7; s32 sp40; s32 texture_seg; //u32 temp_a1; UNUSED s16 unknown_padding; func_800010CC(); gHeapEndPtr = SEG_8028DF00; set_segment_base_addr(0, 0x80000000); func_802A7CF0(&D_801978D0, 0x80242F00); func_80000BEC(); osInvalDCache(SEG_802BA370, 0x5810); osPiStartDma(&D_8014F0A0, 0, 0, &_data_802BA370SegmentRomStart, SEG_802BA370, 0x5810, &D_8014EF58); osRecvMesg(&D_8014EF58, &D_8014F098, 1); set_segment_base_addr(2, func_802A7D70(&_data_segment2SegmentRomStart, &_data_segment2SegmentRomEnd)); texture_seg = ALIGN16((u32)&_common_texturesSegmentRomEnd - (u32)&_common_texturesSegmentRomStart); sp2C = SEG_8028DF00 - texture_seg; osPiStartDma(&D_8014F0A0, 0, 0, &_common_texturesSegmentRomStart, SEG_8028DF00 - texture_seg, texture_seg, &D_8014EF58); osRecvMesg(&D_8014EF58, &D_8014F098, 1); //need to match this sp40 = texture_seg + 4; sp40 = ALIGN16(sp2C[1]); sp38 = gPrevLoadedAddress; mio0decode(texture_seg, sp38); set_segment_base_addr(0xD, sp38); gPrevLoadedAddress += sp40; D_8015F734 = gPrevLoadedAddress; } #else GLOBAL_ASM("asm/non_matchings/main/init_game.s") #endif void func_80001404(void) { D_800DC524 = 0; clear_framebuffer(0); } #ifdef MIPS_TO_C // generated by mips_to_c commit cae1414eb1bf34873a831a523692fe29870a6f3b void *func_8000142C(void) { s32 temp_s0; s32 temp_s0_2; s32 temp_s0_3; s32 temp_s0_4; void *temp_v0; void *temp_v0_2; s32 phi_s0; s32 phi_s0_2; s32 phi_s0_3; s32 phi_s0_4; u16 phi_a0; D_80150112 = (u16)0; D_80164AF0 = (u16)0; if (D_800DC5FC != 0) { func_80290B14(); } if (D_800DC5C0 != 0) { return func_802A38B4(); } if ((s32) sNumVBlanks >= 6) { sNumVBlanks = (u16)5; } if ((s32) sNumVBlanks < 0) { sNumVBlanks = (u16)1; } func_802A4EF4(); if (D_800DC52C != 0) { if (D_800DC52C != 1) { if (D_800DC52C != 2) { if (D_800DC52C != 3) { } else { if (3 == *(void *)0x800DC538) { if (gCurrentCourseId != 2) { if (gCurrentCourseId != 9) { if (gCurrentCourseId != 0x10) { if (gCurrentCourseId != 0x12) { D_80150114 = 2; } else { block_79: D_80150114 = 3; } } else { goto block_79; } } else { goto block_79; } } else { goto block_79; } } else { if (*(void *)0x800E0000 != 0xF) { if (*(void *)0x800E0000 != 0x11) { if (*(void *)0x800E0000 != 0x12) { if (*(void *)0x800E0000 != 0x13) { D_80150114 = 3; } else { block_85: D_80150114 = 2; } } else { D_80150114 = 4; } } else { goto block_85; } } else { goto block_85; } } if (D_800DC5FC == 0) { if (D_80150114 > 0) { phi_s0 = 0; loop_90: if (D_8015011E != 0) { gCourseTimer = (f32) ((f64) gCourseTimer + D_800EB610); } func_802909F0(); func_802A0D54(); func_800382DC(); func_8001EE98(D_800DC4FC, D_800DDB40, 0); func_80029158(); func_8001EE98(D_800DC4E0, D_800DDB44, 1); func_800291E8(); func_8001EE98(D_800DC4E4, D_800DDB48, 2); func_800291F0(); func_8001EE98(D_800DC4E8, D_800DDB4C, 3); func_800291F8(); func_8028F474(); func_80059AC8(); update_simple_objects(); func_802966A0(); func_8028FCBC(); temp_s0 = (s32) ((phi_s0 + 1) << 0x10) >> 0x10; phi_s0 = temp_s0; if (temp_s0 < D_80150114) { goto loop_90; } } func_80022744(); } func_8005A070(); sNumVBlanks = (u16)0; profiler_log_thread5_time(1); func_802A7C08(); func_802A3E3C(); if (D_800DC5B0 != 0) { func_802A41D4(); } D_8015F788 = 0; if (D_800DC5E8 == 0) { func_802A6BB0(); func_802A6E94(); func_802A7178(); func_802A68CC(); } else { if (D_800DC5E8 == 1) { func_802A68CC(); func_802A6E94(); func_802A7178(); func_802A6BB0(); } else { if (D_800DC5E8 == 2) { func_802A68CC(); func_802A6BB0(); func_802A7178(); func_802A6E94(); } else { func_802A68CC(); func_802A6BB0(); func_802A6E94(); func_802A7178(); } } } } } else { if (*(void *)0x800DC5A0 == 0x12) { D_80150114 = 3; } else { D_80150114 = 2; } if (D_800DC5FC == 0) { if (D_80150114 > 0) { phi_s0_2 = 0; loop_47: if (D_8015011E != 0) { gCourseTimer = (f32) ((f64) gCourseTimer + D_800EB600); } func_802909F0(); func_802A0D54(); func_800382DC(); func_8001EE98(D_800DC4FC, D_800DDB40, 0); func_80029060(); func_8001EE98(D_800DC500, D_800DDB44, 1); func_80029150(); func_8028F474(); func_80059AC8(); update_simple_objects(); func_802966A0(); func_8028FCBC(); temp_s0_2 = (s32) ((phi_s0_2 + 1) << 0x10) >> 0x10; phi_s0_2 = temp_s0_2; if (temp_s0_2 < D_80150114) { goto loop_47; } } func_80022744(); } func_8005A070(); profiler_log_thread5_time(1); sNumVBlanks = (u16)0; func_802A7C08(); func_802A3E3C(); if (D_800DC5B0 != 0) { func_802A41D4(); } D_8015F788 = 0; if (D_800DC5E8 == 0) { func_802A5FAC(); func_802A5CB4(); } else { func_802A5CB4(); func_802A5FAC(); } } } else { if (*(void *)0x800DC5A0 == 0x12) { D_80150114 = 3; } else { D_80150114 = 2; } if (D_800DC5FC == 0) { if (D_80150114 > 0) { phi_s0_3 = 0; loop_63: if (D_8015011E != 0) { gCourseTimer = (f32) ((f64) gCourseTimer + D_800EB608); } func_802909F0(); func_802A0D54(); func_800382DC(); func_8001EE98(D_800DC4FC, D_800DDB40, 0); func_80029060(); func_8001EE98(D_800DC500, D_800DDB44, 1); func_80029150(); func_8028F474(); func_80059AC8(); update_simple_objects(); func_802966A0(); func_8028FCBC(); temp_s0_3 = (s32) ((phi_s0_3 + 1) << 0x10) >> 0x10; phi_s0_3 = temp_s0_3; if (temp_s0_3 < D_80150114) { goto loop_63; } } func_80022744(); } profiler_log_thread5_time(1); sNumVBlanks = (u16)0; func_8005A070(); func_802A7C08(); func_802A3E3C(); if (D_800DC5B0 != 0) { func_802A41D4(); } D_8015F788 = 0; if (D_800DC5E8 == 0) { func_802A65B8(); func_802A62A4(); } else { func_802A62A4(); func_802A65B8(); } } block_104: phi_a0 = gEnableDebugMode; } else { D_80150114 = 2; func_80005F44(); if (D_800DC5FC == 0) { if (D_80150114 > 0) { phi_s0_4 = 0; loop_16: if (D_8015011E != 0) { gCourseTimer = (f32) ((f64) gCourseTimer + D_800EB5F8); } func_802909F0(); func_802A0D54(); func_800382DC(); func_8001EE98(D_800DC4FC, D_800DDB40, 0); func_80028F70(); func_8028F474(); func_80059AC8(); update_simple_objects(); func_802966A0(); func_8028FCBC(); temp_s0_4 = (s32) ((phi_s0_4 + 1) << 0x10) >> 0x10; phi_s0_4 = temp_s0_4; if (temp_s0_4 < D_80150114) { goto loop_16; } } func_80022744(); } func_8005A070(); sNumVBlanks = (u16)0; profiler_log_thread5_time(1); D_8015F788 = 0; func_802A59A4(); if (gEnableDebugMode == 0) { D_800DC514 = (u16)0; phi_a0 = gEnableDebugMode; } else { if (D_800DC514 != 0) { if ((D_800DC4BC->unk6 & 0x10) != 0) { if ((D_800DC4BC->unk4 & 0x8000) != 0) { if ((D_800DC4BC->unk4 & 0x4000) != 0) { D_800DC514 = (u16)0U; } } } D_801625E8 = (s16) D_800DC5EC->unk38; if ((s32) D_800DDB40->unk26 < 0x2000) { func_80057A50(0x28, 0x64, &D_800EB5D0, D_801625E8); } else { if ((s32) D_800DDB40->unk26 < 0x6000) { func_80057A50(0x28, 0x64, &D_800EB5D8, D_801625E8); } else { if ((s32) D_800DDB40->unk26 < 0xA000) { func_80057A50(0x28, 0x64, &D_800EB5E0, D_801625E8); } else { if ((s32) D_800DDB40->unk26 < 0xE000) { func_80057A50(0x28, 0x64, &D_800EB5E8, D_801625E8); } else { func_80057A50(0x28, 0x64, &D_800EB5F0, D_801625E8); } } } } goto block_104; } else { phi_a0 = gEnableDebugMode; if (((*(void *)0x800DC4BC)->unk6 & 0x20) != 0) { phi_a0 = gEnableDebugMode; if (((*(void *)0x800DC4BC)->unk4 & 0x8000) != 0) { phi_a0 = gEnableDebugMode; if (((*(void *)0x800DC4BC)->unk4 & 0x4000) != 0) { D_800DC514 = (u16)1U; phi_a0 = gEnableDebugMode; } } } } } } if (phi_a0 == 0) { gEnableResourceMeters = 0; } else { if (gEnableResourceMeters != 0) { resource_display(phi_a0); if ((D_800DC4BC->unk4 & 0x20) == 0) { if ((D_800DC4BC->unk4 & 0x10) != 0) { if ((D_800DC4BC->unk6 & 0x4000) != 0) { gEnableResourceMeters = 0; } } } } else { if ((D_800DC4BC->unk4 & 0x20) == 0) { if ((D_800DC4BC->unk4 & 0x10) != 0) { if ((D_800DC4BC->unk6 & 0x4000) != 0) { gEnableResourceMeters = 1; } } } } } func_802A4300(); func_800591B4(); func_80093E20(); temp_v0 = gDisplayListHead; gDisplayListHead = (void *) (temp_v0 + 8); temp_v0->unk4 = 0; temp_v0->unk0 = 0xE9000000; temp_v0_2 = gDisplayListHead; gDisplayListHead = (void *) (temp_v0_2 + 8); temp_v0_2->unk4 = 0; temp_v0_2->unk0 = 0xB8000000; return temp_v0_2; } #else GLOBAL_ASM("asm/non_matchings/main/func_8000142C.s") #endif #ifdef MIPS_TO_C // Cannot match until data compilable void func_80001ECC(void) { switch (D_800DC50C) { case 7: func_80001404(); break; case 0: case 1: case 2: case 3: osViBlack(0); func_800B0350(); func_80000CA8(); func_80094A64(gGfxPool); break; case 4: func_8000142C(); break; case 5: func_80281548(); break; case 9: func_802802AC(); // Duplicate return node #7. Try simplifying control flow for better match break; } } #else GLOBAL_ASM("asm/non_matchings/main/func_80001ECC.s") #endif void interrupt_gfx_sptask(void) { if (gActiveSPTask->task.t.type == M_GFXTASK) { gActiveSPTask->state = SPTASK_STATE_INTERRUPTED; osSpTaskYield(); } } // likely receive_new_tasks from SM64 #ifdef MIPS_TO_C // generated by mips_to_c commit cae1414eb1bf34873a831a523692fe29870a6f3b s32 func_80001FAC(void) { void *sp40; s32 temp_ret; s32 temp_ret_2; s32 temp_v0; s32 temp_v0_2; s32 phi_return; temp_ret = osRecvMesg(&D_8014EFD0, &sp40, 0); phi_return = temp_ret; if (temp_ret != -1) { loop_2: sp40->unk48 = 0; if (sp40->unk0 != 1) { if (sp40->unk0 == 2) { D_800DC4B4 = sp40; } } else { sNextDisplaySPTask = sp40; } temp_ret_2 = osRecvMesg(&D_8014EFD0, &sp40, 0); phi_return = temp_ret_2; if (temp_ret_2 != -1) { goto loop_2; } } if (sCurrentAudioSPTask == 0) { temp_v0 = D_800DC4B4; phi_return = temp_v0; if (temp_v0 != 0) { sCurrentAudioSPTask = temp_v0; D_800DC4B4 = 0; phi_return = temp_v0; } } if (sCurrentDisplaySPTask == 0) { temp_v0_2 = sNextDisplaySPTask; phi_return = temp_v0_2; if (temp_v0_2 != 0) { sCurrentDisplaySPTask = temp_v0_2; sNextDisplaySPTask = 0; phi_return = temp_v0_2; } } return phi_return; } #else // suppress warning until matching s32 func_80001FAC(void); GLOBAL_ASM("asm/non_matchings/main/func_80001FAC.s") #endif // likely set_vblank_handler from SM64 void func_800020D8(s32 arg0, struct VblankHandler *arg1, OSMesgQueue *arg2, OSMesg *arg3) { arg1->queue = arg2; arg1->msg = arg3; switch (arg0) { case 1: gVblankHandler1 = arg1; break; case 2: gVblankHandler2 = arg1; break; } } void start_gfx_sptask(void) { if (gActiveSPTask == NULL && sCurrentDisplaySPTask != NULL && sCurrentDisplaySPTask->state == SPTASK_STATE_NOT_STARTED) { profiler_log_gfx_time(TASKS_QUEUED); start_sptask(M_GFXTASK); } } // Similar to handle_vblank from SM64 void func_80002168(void) { D_800DC594 += D_800EB640; sNumVBlanks++; func_80001FAC(); if (sCurrentAudioSPTask != NULL) { if (gActiveSPTask != NULL) { interrupt_gfx_sptask(); } else { profiler_log_vblank_time(); start_sptask(M_AUDTASK); } } else { if (gActiveSPTask == NULL && sCurrentDisplaySPTask != NULL && sCurrentDisplaySPTask->state != 3) { profiler_log_gfx_time(0); start_sptask(M_GFXTASK); } } if (gVblankHandler1 != NULL) { osSendMesg(gVblankHandler1->queue, gVblankHandler1->msg, 0); } if (gVblankHandler2 != NULL) { osSendMesg(gVblankHandler2->queue, gVblankHandler2->msg, 0); } } // likely handle_dp_complete from SM64 void func_80002284(void) { if (sCurrentDisplaySPTask->msgqueue != 0) { osSendMesg(sCurrentDisplaySPTask->msgqueue, sCurrentDisplaySPTask->msg, OS_MESG_NOBLOCK); } profiler_log_gfx_time(RDP_COMPLETE); sCurrentDisplaySPTask->state = SPTASK_STATE_FINISHED_DP; sCurrentDisplaySPTask = NULL; } #ifdef MIPS_TO_C //generated by mips_to_c commit ffee479fae41a1cdc3e454e9b9d75bbd226a160f void *func_800022DC(void) { void *sp1C; s32 temp_a0; void *temp_a3; void *phi_a3; void *phi_return; temp_a3 = gActiveSPTask; gActiveSPTask = NULL; if (temp_a3->unk48 == 2) { sp1C = temp_a3; if (osSpTaskYielded(temp_a3, temp_a3) == 0) { temp_a3->unk48 = 3; profiler_log_gfx_time(1, temp_a3); } profiler_log_vblank_time(); return start_sptask(2); } temp_a3->unk48 = 3; if (temp_a3->unk0 == 2) { sp1C = temp_a3; profiler_log_vblank_time(temp_a3, temp_a3); phi_a3 = temp_a3; phi_return = sCurrentDisplaySPTask; if (sCurrentDisplaySPTask != 0) { phi_a3 = temp_a3; phi_return = sCurrentDisplaySPTask; if (sCurrentDisplaySPTask->unk48 != 3) { if (sCurrentDisplaySPTask->unk48 != 2) { sp1C = temp_a3; profiler_log_gfx_time(0, temp_a3); } sp1C = temp_a3; phi_a3 = temp_a3; phi_return = start_sptask(1, temp_a3); } } sCurrentAudioSPTask = 0; temp_a0 = phi_a3->unk40; if (temp_a0 != 0) { return osSendMesg(temp_a0, phi_a3->unk44, 0, phi_a3); } } else { phi_return = profiler_log_gfx_time(1, temp_a3); } return phi_return; } #else GLOBAL_ASM("asm/non_matchings/main/func_800022DC.s") #endif #ifdef MIPS_TO_C // generated by mips_to_c commit cae1414eb1bf34873a831a523692fe29870a6f3b /* void thread3_video(void *arg0) { u64 *temp_v0; s32 i; gPhysicalFramebuffers[0] = (uintptr_t *) &D_8031F780; gPhysicalFramebuffers[1] = (uintptr_t *) &D_80344F80; gPhysicalFramebuffers[2] = (uintptr_t *) &D_8036A780; //phi_v0 = &D_80344F80; //loop_1: // potential unrolled loop? temp_v0 = &D_80344F80[0]; for (i = 0; i < D_8036A780; i++) { temp_v0[i] = 0; } //if (D_80344F80 != &D_8036A780) { // goto loop_1; //} setup_mesg_queues(); init_game(); create_thread(&D_8015AB80, 4, &thread4_audio, 0, &D_8015CD30, 0x14); osStartThread(&D_8015AB80); create_thread(&D_801589D0, 5, &thread5_game_logic, 0, &D_8015AB80, 0xA); osStartThread(&D_801589D0); // manual work while (1) { OSMesg msg; osRecvMesg(&gIntrMesgQueue, &msg, OS_MESG_BLOCK); switch ((u32) msg) { case MESG_SP_COMPLETE: func_800022DC(); break; case MESG_DP_COMPLETE: func_80002284(); break; case MESG_VI_VBLANK: func_80002168(); break; case MESG_START_GFX_SPTASK: start_gfx_sptask(); break; } } } */ #else GLOBAL_ASM("asm/non_matchings/main/thread3_video.s") #endif void func_800025D4(void) { func_80091B78(); D_800DC52C = 0; func_802A4D18(); } void func_80002600(void) { func_80091B78(); D_800DC52C = 0; func_802A4D18(); } void func_8000262C(void) { func_80091B78(); D_800DC52C = 0; func_802A4D18(); } void func_80002658(void) { func_80091B78(); D_800DC52C = 0; func_802A4D18(); } #ifdef MIPS_TO_C void func_80002684(void) { switch (D_800DC50C) { case 0: func_80002658(); gCurrentlyLoadedCourseId = 255; break; case 1: func_800025D4(); gCurrentlyLoadedCourseId = 255; break; case 2: func_80002600(); gCurrentlyLoadedCourseId = 255; break; case 3: func_8000262C(); gCurrentlyLoadedCourseId = 255; break; case 4: func_800010CC(); func_80002A18(); break; case 5: gCurrentlyLoadedCourseId = 255; func_8000105C(); load_ending_sequence_royalraceway(); break; case 9: gCurrentlyLoadedCourseId = 255; func_800010CC(); func_8000105C(); func_80280420(); // Duplicate return node #9. Try simplifying control flow for better match break; } } #else GLOBAL_ASM("asm/non_matchings/main/func_80002684.s") #endif extern OSMesg* D_8014F008; extern OSMesg* D_8014F00C; extern s32 D_8014EF48; extern s32 D_800DC600; extern s32 D_8015F8B8, D_8015F8BC, D_8015F8C0, D_8015F8C4, D_8015F8C8, D_8015F8CC; void thread5_game_logic(s32 arg0) { osCreateMesgQueue(&D_8014EF88, &D_8014F00C, 1); osCreateMesgQueue(&D_8014EF70, &D_8014F008, 1); init_controllers(); if (D_8015011C == 0) { func_80003010(); } func_800020D8(2, &D_8014EF48, &D_8014EF70, (OSMesg) 1); D_8015F8B8 = (s32) D_800DC600; D_8015F8BC = (s32) (D_800DC600 + 2); D_8015F8C0 = (s32) (D_800DC600 + 0xB); D_8015F8C4 = (s32) (D_800DC600 + 0x17); D_8015F8C8 = (s32) (D_800DC600 + 0x19); D_8015F8CC = (s32) (D_800DC600 + 0x1C); rendering_init(); read_controllers(); func_800C5CB8(); loop_3: func_800CB2C4(); if (D_800DC524 != D_800DC50C) { D_800DC50C = (s32) D_800DC524; func_80002684(); } profiler_log_thread5_time(0); config_gfx_pool(); read_controllers(); func_80001ECC(); func_80000CE8(); display_and_vsync(); goto loop_3; } void thread4_audio(UNUSED s32 arg0) { UNUSED u32 unused[3]; audio_init(); osCreateMesgQueue(&sSoundMesgQueue, &sSoundMesgBuf, 1); func_800020D8(1, &sSoundVblankHandler, &sSoundMesgQueue, (OSMesg) 0x200); while (TRUE) { OSMesg msg; struct SPTask *spTask; osRecvMesg(&sSoundMesgQueue, &msg, 1); profiler_log_thread4_time(); spTask = create_next_audio_frame_task(); if (spTask != NULL) { func_80000C0C(spTask); } profiler_log_thread4_time(); } }