diff options
| author | Tharo <17233964+Thar0@users.noreply.github.com> | 2022-02-02 21:43:34 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-02 16:43:34 -0500 |
| commit | c8f4d66b009ad400f54538d6293afd5971c87776 (patch) | |
| tree | 35b628e097b755e512b91fb0706432c8c62be275 /src/code | |
| parent | cd1d08d34f32ec97396786e83783fc37b7a68858 (diff) | |
Documentation for fault.c and fault_drawer.c (#1106)
* Mostly document fault and fault_drawer
* FaultDrawer printf functions return s32
* Review Suggestions for comments
Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>
* Some further review suggestions
* Further changes from suggestions
* Fix Fault_AddClient doc comment
* Bug comment for memdump overrun, add more to Fault_PadCallback bug comment
* mb -> MB, comment about bss above externs
* Fix color codes
Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>
Diffstat (limited to 'src/code')
| -rw-r--r-- | src/code/audio_heap.c | 2 | ||||
| -rw-r--r-- | src/code/code_800E6840.c | 4 | ||||
| -rw-r--r-- | src/code/fault.c | 1029 | ||||
| -rw-r--r-- | src/code/fault_drawer.c | 232 | ||||
| -rw-r--r-- | src/code/game.c | 2 | ||||
| -rw-r--r-- | src/code/graph.c | 2 | ||||
| -rw-r--r-- | src/code/irqmgr.c | 4 | ||||
| -rw-r--r-- | src/code/padmgr.c | 4 | ||||
| -rw-r--r-- | src/code/sched.c | 2 | ||||
| -rw-r--r-- | src/code/z_onepointdemo.c | 2 |
10 files changed, 772 insertions, 511 deletions
diff --git a/src/code/audio_heap.c b/src/code/audio_heap.c index ba398c5c4..b81a5fc76 100644 --- a/src/code/audio_heap.c +++ b/src/code/audio_heap.c @@ -989,7 +989,7 @@ void AudioHeap_Init(void) { AudioLoad_InitAsyncLoads(); gAudioContext.unk_4 = 0x1000; AudioLoad_LoadPermanentSamples(); - intMask = osSetIntMask(1); + intMask = osSetIntMask(OS_IM_NONE); osWritebackDCacheAll(); osSetIntMask(intMask); } diff --git a/src/code/code_800E6840.c b/src/code/code_800E6840.c index 129502b52..caaaea332 100644 --- a/src/code/code_800E6840.c +++ b/src/code/code_800E6840.c @@ -1,14 +1,14 @@ #include "global.h" void Audio_InvalDCache(void* buf, s32 size) { - OSIntMask prevMask = osSetIntMask(1); + OSIntMask prevMask = osSetIntMask(OS_IM_NONE); osInvalDCache(buf, size); osSetIntMask(prevMask); } void Audio_WritebackDCache(void* buf, s32 size) { - OSIntMask prevMask = osSetIntMask(1); + OSIntMask prevMask = osSetIntMask(OS_IM_NONE); osWritebackDCache(buf, size); osSetIntMask(prevMask); diff --git a/src/code/fault.c b/src/code/fault.c index 3897ba858..e68ab9a26 100644 --- a/src/code/fault.c +++ b/src/code/fault.c @@ -1,8 +1,56 @@ +/** + * @file fault.c + * + * This file implements the screen that may be viewed when the game crashes. + * This is the second version of the crash screen, originally used in Majora's Mask. + * + * When the game crashes, a red bar will be drawn to the top-left of the screen, indicating that the + * crash screen is available for use. Once this bar appears, it is possible to open the crash screen + * with the following button combination: + * + * (L & R & Z) + DPad-Up + C-Down + C-Up + DPad-Down + DPad-Left + C-Left + C-Right + DPad-Right + (B & A & START) + * + * When entering this button combination, buttons that are &'d together must all be pressed together. + * The L & R presses and B & A presses may be interchanged in the order they are pressed. + * + * "Clients" may be registered with the crash screen to extend its functionality. There are + * two kinds of client, "Client" and "AddressConverterClient". Clients contribute one or + * more pages to the crash debugger, while Address Converter Clients allow the crash screen to look up + * the virtual addresses of dynamically allocated overlays. + * + * The crash screen has multiple pages: + * - Thread Context + * This page shows information about the thread on which the program crashed. It displays + * the cause of the crash, state of general-purpose registers, state of floating-point registers + * and the floating-point status register. If a floating-point exception caused the crash, it will + * be displayed next to the floating-point status register. + * - Stack Trace + * This page displays a full backtrace from the crashing function back to the start of the thread. It + * displays the Program Counter for each function and, if applicable, the Virtual Program Counter + * for relocated functions in overlays. + * - Client Pages + * After the stack trace page, currently registered clients are processed and their pages are displayed. + * - Memory Dump + * This page implements a scrollable memory dump. + * - End Screen + * This page informs you that there are no more pages to display. + * + * To navigate the pages, START and A may be used to advance to the next page, and L toggles whether to + * automatically scroll to the next page after some time has passed. + * DPad-Up may be pressed to enable sending fault pages over osSyncPrintf as well as displaying them on-screen. + * DPad-Down disables sending fault pages over osSyncPrintf. + */ #include "global.h" #include "vt.h" #include "alloca.h" -// data +void FaultDrawer_Init(void); +void FaultDrawer_SetOsSyncPrintfEnabled(u32 enabled); +void FaultDrawer_DrawRecImpl(s32 xStart, s32 yStart, s32 xEnd, s32 yEnd, u16 color); +void FaultDrawer_FillScreen(void); +void FaultDrawer_SetInputCallback(void (*callback)(void)); +void FaultDrawer_SetDrawerFB(void* fb, u16 w, u16 h); + const char* sExceptionNames[] = { "Interrupt", "TLB modification", @@ -22,119 +70,140 @@ const char* sExceptionNames[] = { "Floating point exception", "Watchpoint exception", "Virtual coherency on data", - "Unimplemented operation", - "Invalid operation", - "Division by zero", - "Overflow", - "Underflow", - "Inexact operation", }; -// bss -extern FaultThreadStruct* sFaultStructPtr; -extern u8 sFaultIsWaitingForInput; +const char* sFpExceptionNames[] = { + "Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow", "Inexact operation", +}; + +// TODO: import .bss (has reordering issues) +extern FaultMgr* sFaultInstance; +extern u8 sFaultAwaitingInput; extern char sFaultStack[0x600]; extern StackEntry sFaultThreadInfo; -extern FaultThreadStruct gFaultStruct; +extern FaultMgr gFaultMgr; + +typedef struct { + /* 0x00 */ s32 (*callback)(void*, void*); + /* 0x04 */ void* arg0; + /* 0x08 */ void* arg1; + /* 0x0C */ s32 ret; + /* 0x10 */ OSMesgQueue* queue; + /* 0x14 */ OSMesg msg; +} FaultClientTask; // size = 0x18 -void Fault_SleepImpl(u32 duration) { - u64 value = (duration * OS_CPU_COUNTER) / 1000ull; +void Fault_SleepImpl(u32 msec) { + u64 cycles = (msec * OS_CPU_COUNTER) / 1000ull; - Sleep_Cycles(value); + Sleep_Cycles(cycles); } void Fault_ClientProcessThread(void* arg) { - FaultClientContext* ctx = (FaultClientContext*)arg; + FaultClientTask* task = (FaultClientTask*)arg; - if (ctx->callback != 0) { - ctx->ret = ctx->callback(ctx->param0, ctx->param1); + // Run the callback + if (task->callback != NULL) { + task->ret = task->callback(task->arg0, task->arg1); } - if (ctx->queue != NULL) { - osSendMesg(ctx->queue, ctx->msg, OS_MESG_BLOCK); + // Send completion notification + if (task->queue != NULL) { + osSendMesg(task->queue, task->msg, OS_MESG_BLOCK); } } -void Fault_ProcessClientContext(FaultClientContext* ctx) { +void Fault_ClientRunTask(FaultClientTask* task) { OSMesgQueue queue; OSMesg msg; OSMesg recMsg; - OSThread* thread; + OSThread* thread = NULL; OSTimer timer; - u32 timerMsgVal; - - timerMsgVal = 666; - thread = NULL; + u32 timerMsgVal = 666; osCreateMesgQueue(&queue, &msg, 1); - ctx->queue = &queue; - ctx->msg = NULL; + task->queue = &queue; + task->msg = NULL; - if (sFaultStructPtr->currClientThreadSp != 0) { + if (sFaultInstance->clientThreadSp != NULL) { + // Run the fault client callback on a separate thread thread = alloca(sizeof(OSThread)); - osCreateThread(thread, 2, Fault_ClientProcessThread, ctx, sFaultStructPtr->currClientThreadSp, + + osCreateThread(thread, 2, Fault_ClientProcessThread, task, sFaultInstance->clientThreadSp, OS_PRIORITY_APPMAX - 1); osStartThread(thread); } else { - Fault_ClientProcessThread(ctx); + // Run the fault client callback on this thread + Fault_ClientProcessThread(task); } + // Await done while (true) { - osSetTimer(&timer, OS_USEC_TO_CYCLES(1000000), 0, &queue, (OSMesg)timerMsgVal); + osSetTimer(&timer, OS_SEC_TO_CYCLES(1), 0, &queue, (OSMesg)timerMsgVal); osRecvMesg(&queue, &recMsg, OS_MESG_BLOCK); if (recMsg != (OSMesg)666) { break; } - if (!sFaultIsWaitingForInput) { - ctx->ret = -1; + if (!sFaultAwaitingInput) { + task->ret = -1; break; } } osStopTimer(&timer); + // Destroy thread if a thread was used if (thread != NULL) { osStopThread(thread); osDestroyThread(thread); } } -u32 Fault_ProcessClient(u32 callback, u32 param0, u32 param1) { - FaultClientContext a; +s32 Fault_ProcessClient(void* callback, void* arg0, void* arg1) { + FaultClientTask task; - a.callback = callback; - a.param0 = param0; - a.param1 = param1; - a.ret = 0; - Fault_ProcessClientContext(&a); - return a.ret; + task.callback = callback; + task.arg0 = arg0; + task.arg1 = arg1; + task.ret = 0; + Fault_ClientRunTask(&task); + return task.ret; } -void Fault_AddClient(FaultClient* client, void* callback, void* param0, void* param1) { +/** + * Registers a fault client. + * + * Clients contribute at least one page to the crash screen, drawn by `callback`. + * Arguments are passed on to the callback through `arg0` and `arg1`. + * + * The callback is intended to be + * `void (*callback)(void* arg0, void* arg1)` + */ +void Fault_AddClient(FaultClient* client, void* callback, void* arg0, void* arg1) { OSIntMask mask; s32 alreadyExists = false; - mask = osSetIntMask(1); + mask = osSetIntMask(OS_IM_NONE); + // Ensure the client is not already registered { - FaultClient* iter = sFaultStructPtr->clients; + FaultClient* iterClient = sFaultInstance->clients; - while (iter != NULL) { - if (iter == client) { + while (iterClient != NULL) { + if (iterClient == client) { alreadyExists = true; goto end; } - iter = iter->next; + iterClient = iterClient->next; } } client->callback = callback; - client->param1 = param0; - client->param2 = param1; - client->next = sFaultStructPtr->clients; - sFaultStructPtr->clients = client; + client->arg0 = arg0; + client->arg1 = arg1; + client->next = sFaultInstance->clients; + sFaultInstance->clients = client; end: osSetIntMask(mask); @@ -143,35 +212,33 @@ end: } } +/** + * Removes a fault client so that the page is no longer displayed if a crash occurs. + */ void Fault_RemoveClient(FaultClient* client) { - FaultClient* iter; - FaultClient* lastIter; + FaultClient* iterClient = sFaultInstance->clients; + FaultClient* lastClient = NULL; OSIntMask mask; - u32 listIsEmpty; + s32 listIsEmpty = false; - iter = sFaultStructPtr->clients; - listIsEmpty = 0; - lastIter = NULL; + mask = osSetIntMask(OS_IM_NONE); - mask = osSetIntMask(1); - - while (iter != NULL) { - if (iter == client) { - if (lastIter != NULL) { - lastIter->next = client->next; + while (iterClient != NULL) { + if (iterClient == client) { + if (lastClient != NULL) { + lastClient->next = client->next; } else { - sFaultStructPtr->clients = client; - if (sFaultStructPtr->clients) { - sFaultStructPtr->clients = client->next; + sFaultInstance->clients = client; + if (sFaultInstance->clients) { + sFaultInstance->clients = client->next; } else { - listIsEmpty = 1; + listIsEmpty = true; } } break; } - - lastIter = iter; - iter = iter->next; + lastClient = iterClient; + iterClient = iterClient->next; } osSetIntMask(mask); @@ -181,28 +248,40 @@ void Fault_RemoveClient(FaultClient* client) { } } -void Fault_AddAddrConvClient(FaultAddrConvClient* client, void* callback, void* param) { +/** + * Registers an address converter client. This enables the crash screen to look up virtual + * addresses of overlays relocated during runtime. Address conversion is carried out by + * `callback`, which either returns a virtual address or NULL if the address could not + * be converted. + * + * The callback is intended to be + * `uintptr_t (*callback)(uintptr_t addr, void* arg)` + * The callback may return 0 if it could not convert the address + * The callback may return -1 to be unregistered + */ +void Fault_AddAddrConvClient(FaultAddrConvClient* client, void* callback, void* arg) { OSIntMask mask; - u32 alreadyExists = false; + s32 alreadyExists = false; - mask = osSetIntMask(1); + mask = osSetIntMask(OS_IM_NONE); + // Ensure the client is not already registered { - FaultAddrConvClient* iter = sFaultStructPtr->addrConvClients; + FaultAddrConvClient* iterClient = sFaultInstance->addrConvClients; - while (iter != NULL) { - if (iter == client) { + while (iterClient != NULL) { + if (iterClient == client) { alreadyExists = true; goto end; } - iter = iter->next; + iterClient = iterClient->next; } } client->callback = callback; - client->param = param; - client->next = sFaultStructPtr->addrConvClients; - sFaultStructPtr->addrConvClients = client; + client->arg = arg; + client->next = sFaultInstance->addrConvClients; + sFaultInstance->addrConvClients = client; end: osSetIntMask(mask); @@ -212,34 +291,30 @@ end: } void Fault_RemoveAddrConvClient(FaultAddrConvClient* client) { - FaultAddrConvClient* iter; - FaultAddrConvClient* lastIter; + FaultAddrConvClient* iterClient = sFaultInstance->addrConvClients; + FaultAddrConvClient* lastClient = NULL; OSIntMask mask; - u32 listIsEmpty; - - iter = sFaultStructPtr->addrConvClients; - listIsEmpty = 0; - lastIter = NULL; + s32 listIsEmpty = false; - mask = osSetIntMask(1); + mask = osSetIntMask(OS_IM_NONE); - while (iter != NULL) { - if (iter == client) { - if (lastIter != NULL) { - lastIter->next = client->next; + while (iterClient != NULL) { + if (iterClient == client) { + if (lastClient != NULL) { + lastClient->next = client->next; } else { - sFaultStructPtr->addrConvClients = client; - if (sFaultStructPtr->addrConvClients != NULL) { - sFaultStructPtr->addrConvClients = client->next; + sFaultInstance->addrConvClients = client; + + if (sFaultInstance->addrConvClients != NULL) { + sFaultInstance->addrConvClients = client->next; } else { - listIsEmpty = 1; + listIsEmpty = true; } } break; } - - lastIter = iter; - iter = iter->next; + lastClient = iterClient; + iterClient = iterClient->next; } osSetIntMask(mask); @@ -250,135 +325,157 @@ void Fault_RemoveAddrConvClient(FaultAddrConvClient* client) { } } -u32 Fault_ConvertAddress(FaultAddrConvClient* client) { - u32 ret; - FaultAddrConvClient* iter = sFaultStructPtr->addrConvClients; - - while (iter != NULL) { - if (iter->callback != 0) { - ret = Fault_ProcessClient(iter->callback, client, iter->param); - if ((s32)ret == -1) { - Fault_RemoveAddrConvClient(iter); +/** + * Converts `addr` to a virtual address via the registered + * address converter clients + */ +uintptr_t Fault_ConvertAddress(uintptr_t addr) { + s32 ret; + FaultAddrConvClient* client = sFaultInstance->addrConvClients; + + while (client != NULL) { + if (client->callback != NULL) { + ret = Fault_ProcessClient(client->callback, addr, client->arg); + if (ret == -1) { + Fault_RemoveAddrConvClient(client); } else if (ret != 0) { - return ret; + return (uintptr_t)ret; } } - iter = iter->next; + client = client->next; } return 0; } -void Fault_Sleep(u32 duration) { - Fault_SleepImpl(duration); +void Fault_Sleep(u32 msec) { + Fault_SleepImpl(msec); } +void PadMgr_RequestPadData(Input* input, s32 mode); + void Fault_PadCallback(Input* input) { - //! @bug This function is not called correctly and thus will crash from reading a bad pointer at 0x800C7E4C + //! @bug This function is not called correctly, it is missing a leading PadMgr* argument. This + //! renders the crash screen unusable. + //! In Majora's Mask, PadMgr functions were changed to not require this argument, and this was + //! likely just not addressed when backporting. PadMgr_RequestPadData(input, 0); } -void Fault_UpdatePadImpl() { - sFaultStructPtr->padCallback(&sFaultStructPtr->padInput); +void Fault_UpdatePadImpl(void) { + sFaultInstance->padCallback(&sFaultInstance->padInput); } -u32 Fault_WaitForInputImpl() { - Input* input = &sFaultStructPtr->padInput; +/** + * Awaits user input + * + * L toggles auto-scroll + * DPad-Up enables osSyncPrintf output + * DPad-Down disables osSyncPrintf output + * A and DPad-Right continues and returns true + * DPad-Left continues and returns false + */ +u32 Fault_WaitForInputImpl(void) { + Input* input = &sFaultInstance->padInput; s32 count = 600; - u32 kDown; + u32 pressedBtn; while (true) { - Fault_Sleep(0x10); + Fault_Sleep(1000 / 60); Fault_UpdatePadImpl(); - kDown = input->press.button; + pressedBtn = input->press.button; - if (kDown == BTN_L) { - sFaultStructPtr->faultActive = !sFaultStructPtr->faultActive; + if (pressedBtn == BTN_L) { + sFaultInstance->autoScroll = !sFaultInstance->autoScroll; } - if (sFaultStructPtr->faultActive) { + if (sFaultInstance->autoScroll) { if (count-- < 1) { return false; } } else { - if (kDown == BTN_A || kDown == BTN_DRIGHT) { + if (pressedBtn == BTN_A || pressedBtn == BTN_DRIGHT) { return false; } - if (kDown == BTN_DLEFT) { + if (pressedBtn == BTN_DLEFT) { return true; } - if (kDown == BTN_DUP) { + if (pressedBtn == BTN_DUP) { FaultDrawer_SetOsSyncPrintfEnabled(true); } - if (kDown == BTN_DDOWN) { + if (pressedBtn == BTN_DDOWN) { FaultDrawer_SetOsSyncPrintfEnabled(false); } } } } -void Fault_WaitForInput() { - sFaultIsWaitingForInput = 1; +void Fault_WaitForInput(void) { + sFaultAwaitingInput = true; Fault_WaitForInputImpl(); - sFaultIsWaitingForInput = 0; + sFaultAwaitingInput = false; } void Fault_DrawRec(s32 x, s32 y, s32 w, s32 h, u16 color) { FaultDrawer_DrawRecImpl(x, y, x + w - 1, y + h - 1, color); } -void Fault_FillScreenBlack() { - FaultDrawer_SetForeColor(0xFFFF); - FaultDrawer_SetBackColor(1); +void Fault_FillScreenBlack(void) { + FaultDrawer_SetForeColor(GPACK_RGBA5551(255, 255, 255, 1)); + FaultDrawer_SetBackColor(GPACK_RGBA5551(0, 0, 0, 1)); FaultDrawer_FillScreen(); - FaultDrawer_SetBackColor(0); + FaultDrawer_SetBackColor(GPACK_RGBA5551(0, 0, 0, 0)); } -void Fault_FillScreenRed() { - FaultDrawer_SetForeColor(0xFFFF); - FaultDrawer_SetBackColor(0xF001); +void Fault_FillScreenRed(void) { + FaultDrawer_SetForeColor(GPACK_RGBA5551(255, 255, 255, 1)); + FaultDrawer_SetBackColor(GPACK_RGBA5551(240, 0, 0, 1)); FaultDrawer_FillScreen(); - FaultDrawer_SetBackColor(0); + FaultDrawer_SetBackColor(GPACK_RGBA5551(0, 0, 0, 0)); } void Fault_DrawCornerRec(u16 color) { - Fault_DrawRec(0x16, 0x10, 8, 1, color); + Fault_DrawRec(22, 16, 8, 1, color); } void Fault_PrintFReg(s32 idx, f32* value) { u32 raw = *(u32*)value; - s32 v0 = ((raw & 0x7F800000) >> 0x17) - 0x7F; + s32 exp = ((raw & 0x7F800000) >> 0x17) - 0x7F; - if ((v0 >= -0x7E && v0 < 0x80) || raw == 0) { + if ((exp >= -0x7E && exp < 0x80) || raw == 0) { FaultDrawer_Printf("F%02d:%14.7e ", idx, *value); } else { + // Print subnormal floats as their ieee-754 hex representation FaultDrawer_Printf("F%02d: %08x(16) ", idx, raw); } } void Fault_LogFReg(s32 idx, f32* value) { u32 raw = *(u32*)value; - s32 v0 = ((raw & 0x7F800000) >> 0x17) - 0x7F; + s32 exp = ((raw & 0x7F800000) >> 0x17) - 0x7F; - if ((v0 >= -0x7E && v0 < 0x80) || raw == 0) { + if ((exp >= -0x7E && exp < 0x80) || raw == 0) { osSyncPrintf("F%02d:%14.7e ", idx, *value); } else { osSyncPrintf("F%02d: %08x(16) ", idx, *(u32*)value); } } -void Fault_PrintFPCR(u32 value) { +void Fault_PrintFPCSR(u32 value) { s32 i; - u32 flag = 0x20000; + u32 flag = FPCSR_CE; FaultDrawer_Printf("FPCSR:%08xH ", value); - for (i = 0; i < 6; i++) { + + // Go through each of the six causes and print the name of + // the first cause that is set + for (i = 0; i < ARRAY_COUNT(sFpExceptionNames); i++) { if (value & flag) { - FaultDrawer_Printf("(%s)", sExceptionNames[i + 18]); + FaultDrawer_Printf("(%s)", sFpExceptionNames[i]); break; } flag >>= 1; @@ -386,37 +483,37 @@ void Fault_PrintFPCR(u32 value) { FaultDrawer_Printf("\n"); } -void Fault_LogFPCR(u32 value) { +void Fault_LogFPCSR(u32 value) { s32 i; - u32 flag = 0x20000; + u32 flag = FPCSR_CE; osSyncPrintf("FPCSR:%08xH ", value); - for (i = 0; i < 6; i++) { + for (i = 0; i < ARRAY_COUNT(sFpExceptionNames); i++) { if (value & flag) { - osSyncPrintf("(%s)\n", sExceptionNames[i + 18]); + osSyncPrintf("(%s)\n", sFpExceptionNames[i]); break; } flag >>= 1; } } -void Fault_PrintThreadContext(OSThread* t) { +void Fault_PrintThreadContext(OSThread* thread) { __OSThreadContext* ctx; - s32 causeStrIdx = (s32)((((u32)t->context.cause >> 2) & 0x1F) << 0x10) >> 0x10; + s16 causeStrIdx = _SHIFTR((u32)thread->context.cause, 2, 5); - if (causeStrIdx == 0x17) { - causeStrIdx = 0x10; + if (causeStrIdx == 23) { // Watchpoint + causeStrIdx = 16; } - if (causeStrIdx == 0x1F) { - causeStrIdx = 0x11; + if (causeStrIdx == 31) { // Virtual coherency on data + causeStrIdx = 17; } FaultDrawer_FillScreen(); FaultDrawer_SetCharPad(-2, 4); - FaultDrawer_SetCursor(0x16, 0x14); + FaultDrawer_SetCursor(22, 20); - ctx = &t->context; - FaultDrawer_Printf("THREAD:%d (%d:%s)\n", t->id, causeStrIdx, sExceptionNames[causeStrIdx]); + ctx = &thread->context; + FaultDrawer_Printf("THREAD:%d (%d:%s)\n", thread->id, causeStrIdx, sExceptionNames[causeStrIdx]); FaultDrawer_SetCharPad(-1, 0); FaultDrawer_Printf("PC:%08xH SR:%08xH VA:%08xH\n", (u32)ctx->pc, (u32)ctx->sr, (u32)ctx->badvaddr); @@ -431,8 +528,9 @@ void Fault_PrintThreadContext(OSThread* t) { FaultDrawer_Printf("T9:%08xH GP:%08xH SP:%08xH\n", (u32)ctx->t9, (u32)ctx->gp, (u32)ctx->sp); FaultDrawer_Printf("S8:%08xH RA:%08xH LO:%08xH\n\n", (u32)ctx->s8, (u32)ctx->ra, (u32)ctx->lo); - Fault_PrintFPCR(ctx->fpcsr); + Fault_PrintFPCSR(ctx->fpcsr); FaultDrawer_Printf("\n"); + Fault_PrintFReg(0, &ctx->fp0.f.f_even); Fault_PrintFReg(2, &ctx->fp2.f.f_even); FaultDrawer_Printf("\n"); @@ -440,40 +538,41 @@ void Fault_PrintThreadContext(OSThread* t) { Fault_PrintFReg(6, &ctx->fp6.f.f_even); FaultDrawer_Printf("\n"); Fault_PrintFReg(8, &ctx->fp8.f.f_even); - Fault_PrintFReg(0xA, &ctx->fp10.f.f_even); + Fault_PrintFReg(10, &ctx->fp10.f.f_even); FaultDrawer_Printf("\n"); - Fault_PrintFReg(0xC, &ctx->fp12.f.f_even); - Fault_PrintFReg(0xE, &ctx->fp14.f.f_even); + Fault_PrintFReg(12, &ctx->fp12.f.f_even); + Fault_PrintFReg(14, &ctx->fp14.f.f_even); FaultDrawer_Printf("\n"); - Fault_PrintFReg(0x10, &ctx->fp16.f.f_even); - Fault_PrintFReg(0x12, &ctx->fp18.f.f_even); + Fault_PrintFReg(16, &ctx->fp16.f.f_even); + Fault_PrintFReg(18, &ctx->fp18.f.f_even); FaultDrawer_Printf("\n"); - Fault_PrintFReg(0x14, &ctx->fp20.f.f_even); - Fault_PrintFReg(0x16, &ctx->fp22.f.f_even); + Fault_PrintFReg(20, &ctx->fp20.f.f_even); + Fault_PrintFReg(22, &ctx->fp22.f.f_even); FaultDrawer_Printf("\n"); - Fault_PrintFReg(0x18, &ctx->fp24.f.f_even); - Fault_PrintFReg(0x1A, &ctx->fp26.f.f_even); + Fault_PrintFReg(24, &ctx->fp24.f.f_even); + Fault_PrintFReg(26, &ctx->fp26.f.f_even); FaultDrawer_Printf("\n"); - Fault_PrintFReg(0x1C, &ctx->fp28.f.f_even); - Fault_PrintFReg(0x1E, &ctx->fp30.f.f_even); + Fault_PrintFReg(28, &ctx->fp28.f.f_even); + Fault_PrintFReg(30, &ctx->fp30.f.f_even); FaultDrawer_Printf("\n"); + FaultDrawer_SetCharPad(0, 0); } -void Fault_LogThreadContext(OSThread* t) { +void Fault_LogThreadContext(OSThread* thread) { __OSThreadContext* ctx; - s32 causeStrIdx = (s32)((((u32)t->context.cause >> 2) & 0x1F) << 0x10) >> 0x10; + s16 causeStrIdx = _SHIFTR((u32)thread->context.cause, 2, 5); - if (causeStrIdx == 0x17) { - causeStrIdx = 0x10; + if (causeStrIdx == 23) { // Watchpoint + causeStrIdx = 16; } - if (causeStrIdx == 0x1F) { - causeStrIdx = 0x11; + if (causeStrIdx == 31) { // Virtual coherency on data + causeStrIdx = 17; } - ctx = &t->context; + ctx = &thread->context; osSyncPrintf("\n"); - osSyncPrintf("THREAD ID:%d (%d:%s)\n", t->id, causeStrIdx, sExceptionNames[causeStrIdx]); + osSyncPrintf("THREAD ID:%d (%d:%s)\n", thread->id, causeStrIdx, sExceptionNames[causeStrIdx]); osSyncPrintf("PC:%08xH SR:%08xH VA:%08xH\n", (u32)ctx->pc, (u32)ctx->sr, (u32)ctx->badvaddr); osSyncPrintf("AT:%08xH V0:%08xH V1:%08xH\n", (u32)ctx->at, (u32)ctx->v0, (u32)ctx->v1); @@ -487,8 +586,10 @@ void Fault_LogThreadContext(OSThread* t) { osSyncPrintf("T9:%08xH GP:%08xH SP:%08xH\n", (u32)ctx->t9, (u32)ctx->gp, (u32)ctx->sp); osSyncPrintf("S8:%08xH RA:%08xH LO:%08xH\n", (u32)ctx->s8, (u32)ctx->ra, (u32)ctx->lo); osSyncPrintf("\n"); - Fault_LogFPCR(ctx->fpcsr); + + Fault_LogFPCSR(ctx->fpcsr); osSyncPrintf("\n"); + Fault_LogFReg(0, &ctx->fp0.f.f_even); Fault_LogFReg(2, &ctx->fp2.f.f_even); osSyncPrintf("\n"); @@ -496,55 +597,66 @@ void Fault_LogThreadContext(OSThread* t) { Fault_LogFReg(6, &ctx->fp6.f.f_even); osSyncPrintf("\n"); Fault_LogFReg(8, &ctx->fp8.f.f_even); - Fault_LogFReg(0xA, &ctx->fp10.f.f_even); + Fault_LogFReg(10, &ctx->fp10.f.f_even); osSyncPrintf("\n"); - Fault_LogFReg(0xC, &ctx->fp12.f.f_even); - Fault_LogFReg(0xE, &ctx->fp14.f.f_even); + Fault_LogFReg(12, &ctx->fp12.f.f_even); + Fault_LogFReg(14, &ctx->fp14.f.f_even); osSyncPrintf("\n"); - Fault_LogFReg(0x10, &ctx->fp16.f.f_even); - Fault_LogFReg(0x12, &ctx->fp18.f.f_even); + Fault_LogFReg(16, &ctx->fp16.f.f_even); + Fault_LogFReg(18, &ctx->fp18.f.f_even); osSyncPrintf("\n"); - Fault_LogFReg(0x14, &ctx->fp20.f.f_even); - Fault_LogFReg(0x16, &ctx->fp22.f.f_even); + Fault_LogFReg(20, &ctx->fp20.f.f_even); + Fault_LogFReg(22, &ctx->fp22.f.f_even); osSyncPrintf("\n"); - Fault_LogFReg(0x18, &ctx->fp24.f.f_even); - Fault_LogFReg(0x1A, &ctx->fp26.f.f_even); + Fault_LogFReg(24, &ctx->fp24.f.f_even); + Fault_LogFReg(26, &ctx->fp26.f.f_even); osSyncPrintf("\n"); - Fault_LogFReg(0x1C, &ctx->fp28.f.f_even); - Fault_LogFReg(0x1E, &ctx->fp30.f.f_even); + Fault_LogFReg(28, &ctx->fp28.f.f_even); + Fault_LogFReg(30, &ctx->fp30.f.f_even); osSyncPrintf("\n"); } -OSThread* Fault_FindFaultedThread() { - OSThread* iter = __osGetActiveQueue(); - - while (iter->priority != -1) { - if (iter->priority > 0 && iter->priority < 0x7F && (iter->flags & 3)) { - return iter; +/** + * Iterates through the active thread queue for a user thread with either + * the CPU break or Fault flag set. + */ +OSThread* Fault_FindFaultedThread(void) { + OSThread* thread = __osGetActiveQueue(); + + // OS_PRIORITY_THREADTAIL indicates the end of the thread queue + while (thread->priority != OS_PRIORITY_THREADTAIL) { + if (thread->priority > OS_PRIORITY_IDLE && thread->priority < OS_PRIORITY_APPMAX && + (thread->flags & (OS_FLAG_CPU_BREAK | OS_FLAG_FAULT))) { + return thread; } - iter = iter->tlnext; + thread = thread->tlnext; } return NULL; } void Fault_Wait5Seconds(void) { - OSTime start[2]; // to make the function allocate 0x28 bytes of stack instead of 0x20 + s32 pad; + OSTime start = osGetTime(); - start[0] = osGetTime(); do { - Fault_Sleep(0x10); - } while ((osGetTime() - start[0]) < OS_USEC_TO_CYCLES(5000000) + 1); + Fault_Sleep(1000 / 60); + } while ((osGetTime() - start) < OS_SEC_TO_CYCLES(5) + 1); - sFaultStructPtr->faultActive = true; + sFaultInstance->autoScroll = true; } -void Fault_WaitForButtonCombo() { - Input* input = &sFaultStructPtr->padInput; +/** + * Waits for the following button combination to be entered before returning: + * + * (L & R & Z) + DPad-Up + C-Down + C-Up + DPad-Down + DPad-Left + C-Left + C-Right + DPad-Right + (B & A & START) + */ +void Fault_WaitForButtonCombo(void) { + Input* input = &sFaultInstance->padInput; s32 state; u32 s1; u32 s2; - u32 kDown; - u32 kCur; + u32 pressedBtn; + u32 curBtn; if (1) {} if (1) {} @@ -556,43 +668,43 @@ void Fault_WaitForButtonCombo() { osSyncPrintf(VT_FGCOL(WHITE) "KeyWaitB'(LR左" VT_FGCOL(YELLOW) "右 +" VT_FGCOL(RED) "START" VT_FGCOL( WHITE) ")" VT_RST "\n"); - FaultDrawer_SetForeColor(0xFFFF); - FaultDrawer_SetBackColor(1); + FaultDrawer_SetForeColor(GPACK_RGBA5551(255, 255, 255, 1)); + FaultDrawer_SetBackColor(GPACK_RGBA5551(0, 0, 0, 1)); state = 0; s1 = 0; s2 = 1; while (state != 11) { - Fault_Sleep(0x10); + Fault_Sleep(1000 / 60); Fault_UpdatePadImpl(); - kDown = input->press.button; - kCur = input->cur.button; + pressedBtn = input->press.button; + curBtn = input->cur.button; - if ((kCur == 0) && (s1 == s2)) { + if (curBtn == 0 && s1 == s2) { s1 = 0; - } else if (kDown != 0) { + } else if (pressedBtn != 0) { if (s1 == s2) { state = 0; } switch (state) { case 0: - if (kCur == (BTN_Z | BTN_L | BTN_R) && kDown == BTN_Z) { + if (curBtn == (BTN_Z | BTN_L | BTN_R) && pressedBtn == BTN_Z) { state = s2; s1 = s2; } break; case 1: - if (kDown == BTN_DUP) { + if (pressedBtn == BTN_DUP) { state = 2; } else { state = 0; } break; case 2: - if (kDown == BTN_CDOWN) { + if (pressedBtn == BTN_CDOWN) { state = 3; s1 = s2; } else { @@ -600,14 +712,14 @@ void Fault_WaitForButtonCombo() { } break; case 3: - if (kDown == BTN_CUP) { + if (pressedBtn == BTN_CUP) { state = 4; } else { state = 0; } break; case 4: - if (kDown == BTN_DDOWN) { + if (pressedBtn == BTN_DDOWN) { state = 5; s1 = s2; } else { @@ -615,14 +727,14 @@ void Fault_WaitForButtonCombo() { } break; case 5: - if (kDown == BTN_DLEFT) { + if (pressedBtn == BTN_DLEFT) { state = 6; } else { state = 0; } break; case 6: - if (kDown == BTN_CLEFT) { + if (pressedBtn == BTN_CLEFT) { state = 7; s1 = s2; } else { @@ -630,14 +742,14 @@ void Fault_WaitForButtonCombo() { } break; case 7: - if (kDown == BTN_CRIGHT) { + if (pressedBtn == BTN_CRIGHT) { state = 8; } else { state = 0; } break; case 8: - if (kDown == BTN_DRIGHT) { + if (pressedBtn == BTN_DRIGHT) { state = 9; s1 = s2; } else { @@ -645,32 +757,32 @@ void Fault_WaitForButtonCombo() { } break; case 9: - if (kDown == (BTN_A | BTN_B)) { + if (pressedBtn == (BTN_A | BTN_B)) { state = 10; - } else if (kDown == BTN_A) { + } else if (pressedBtn == BTN_A) { state = 0x5B; - } else if (kDown == BTN_B) { + } else if (pressedBtn == BTN_B) { state = 0x5C; } else { state = 0; } break; case 0x5B: - if (kDown == BTN_B) { + if (pressedBtn == BTN_B) { state = 10; } else { state = 0; } break; case 0x5C: - if (kDown == BTN_A) { + if (pressedBtn == BTN_A) { state = 10; } else { state = 0; } break; case 10: - if (kDown == BTN_START) { + if (pressedBtn == BTN_START) { state = 11; } else { state = 0; @@ -683,32 +795,40 @@ void Fault_WaitForButtonCombo() { } } -void Fault_DrawMemDumpPage(const char* title, u32* addr, u32 param_3) { - u32* alignedAddr; +void Fault_DrawMemDumpContents(const char* title, uintptr_t addr, u32 arg2) { + uintptr_t alignedAddr = addr; u32* writeAddr; s32 y; s32 x; - alignedAddr = addr; - - if (alignedAddr < (u32*)0x80000000) { - alignedAddr = (u32*)0x80000000; + // Ensure address is within the bounds of RDRAM (Fault_DrawMemDump has already done this) + if (alignedAddr < K0BASE) { + alignedAddr = K0BASE; } - if (alignedAddr > (u32*)0x807FFF00) { - alignedAddr = (u32*)0x807FFF00; + // 8MB RAM, leave room to display 0x100 bytes on the final page + //! @bug The loop below draws 22 * 4 * 4 = 0x160 bytes per page. Due to this, by scrolling further than + //! 0x807FFEA0 some invalid bytes are read from outside of 8MB RDRAM space. This does not cause a crash, + //! however the values it displays are meaningless. On N64 hardware these invalid addresses are read as 0. + if (alignedAddr > K0BASE + 0x800000 - 0x100) { + alignedAddr = K0BASE + 0x800000 - 0x100; } - alignedAddr = (u32*)((u32)alignedAddr & ~3); - writeAddr = alignedAddr; + // Ensure address is word-aligned + alignedAddr &= ~3; + writeAddr = (u32*)alignedAddr; + + // Reset screen Fault_FillScreenBlack(); FaultDrawer_SetCharPad(-2, 0); - FaultDrawer_DrawText(0x24, 0x12, "%s %08x", title != NULL ? title : "PrintDump", alignedAddr); - if (alignedAddr >= (u32*)0x80000000 && alignedAddr < (u32*)0xC0000000) { - for (y = 0x1C; y != 0xE2; y += 9) { - FaultDrawer_DrawText(0x18, y, "%06x", writeAddr); - for (x = 0x52; x != 0x122; x += 0x34) { - FaultDrawer_DrawText(x, y, "%08x", *writeAddr++); + FaultDrawer_DrawText(36, 18, "%s %08x", title != NULL ? title : "PrintDump", alignedAddr); + + // Draw memory page contents + if (alignedAddr >= K0BASE && alignedAddr < K2BASE) { + for (y = 0; y < 22; y++) { + FaultDrawer_DrawText(24, 28 + y * 9, "%06x", writeAddr); + for (x = 0; x < 4; x++) { + FaultDrawer_DrawText(82 + x * 52, 28 + y * 9, "%08x", *writeAddr++); } } } @@ -716,54 +836,79 @@ void Fault_DrawMemDumpPage(const char* title, u32* addr, u32 param_3) { FaultDrawer_SetCharPad(0, 0); } -void Fault_DrawMemDump(u32 pc, u32 sp, u32 unk0, u32 unk1) { - Input* input = &sFaultStructPtr->padInput; - u32 addr = pc; - s32 count; +/** + * Draws the memory dump page. + * + * DPad-Up scrolls up. + * DPad-Down scrolls down. + * Holding Z while scrolling speeds up scrolling by a factor of 0x10. + * Holding B while scrolling speeds up scrolling by a factor of 0x100. + * + * L toggles auto-scrolling pages. + * START and A move on to the next page. + * + * @param pc Program counter, pressing C-Up jumps to this address + * @param sp Stack pointer, pressing C-Down jumps to this address + * @param cLeftJump Unused parameter, pressing C-Left jumps to this address + * @param cRightJump Unused parameter, pressing C-Right jumps to this address + */ +void Fault_DrawMemDump(uintptr_t pc, uintptr_t sp, uintptr_t cLeftJump, uintptr_t cRightJump) { + Input* input = &sFaultInstance->padInput; + uintptr_t addr = pc; + s32 scrollCountdown; u32 off; do { - count = 0; - if (addr < 0x80000000) { - addr = 0x80000000; + scrollCountdown = 0; + // Ensure address is within the bounds of RDRAM + if (addr < K0BASE) { + addr = K0BASE; } - if (addr > 0x807FFF00) { - addr = 0x807FFF00; + // 8MB RAM, leave room to display 0x100 bytes on the final page + if (addr > K0BASE + 0x800000 - 0x100) { + addr = K0BASE + 0x800000 - 0x100; } + // Align the address to 0x10 bytes and draw the page contents addr &= ~0xF; - Fault_DrawMemDumpPage("Dump", (u32*)addr, 0); - count = 600; + Fault_DrawMemDumpContents("Dump", addr, 0); + scrollCountdown = 600; - while (sFaultStructPtr->faultActive) { - if (count == 0) { + while (sFaultInstance->autoScroll) { + // Count down until it's time to move on to the next page + if (scrollCountdown == 0) { return; } - count--; - Fault_Sleep(0x10); + scrollCountdown--; + Fault_Sleep(1000 / 60); Fault_UpdatePadImpl(); if (CHECK_BTN_ALL(input->press.button, BTN_L)) { - sFaultStructPtr->faultActive = false; + // Disable auto-scrolling + sFaultInstance->autoScroll = false; } } + // Wait for input do { - Fault_Sleep(0x10); + Fault_Sleep(1000 / 60); Fault_UpdatePadImpl(); } while (input->press.button == 0); + // Move to next page if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->cur.button, BTN_A)) { return; } + // Memory dump controls + off = 0x10; if (CHECK_BTN_ALL(input->cur.button, BTN_Z)) { - off = 0x100; + off *= 0x10; } if (CHECK_BTN_ALL(input->cur.button, BTN_B)) { - off <<= 8; + off *= 0x100; } if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { @@ -779,107 +924,161 @@ void Fault_DrawMemDump(u32 pc, u32 sp, u32 unk0, u32 unk1) { addr = sp; } if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { - addr = unk0; + addr = cLeftJump; } if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) { - addr = unk1; + addr = cRightJump; } } while (!CHECK_BTN_ALL(input->press.button, BTN_L)); - sFaultStructPtr->faultActive = true; + // Resume auto-scroll and move to next page + sFaultInstance->autoScroll = true; } -void Fault_WalkStack(u32* spPtr, u32* pcPtr, u32* raPtr) { - u32 sp = *spPtr; - u32 pc = *pcPtr; - u32 ra = *raPtr; - s32 count = 0x10000; - u32 lastOpc; - u32 opc; - u16 opcHi; - s16 opcLo; +/** + * Searches a single function's stack frame for the function it was called from. + * There are two cases that must be covered: Leaf and non-leaf functions. + * + * A leaf function is one that does not call any other function, in this case the + * return address need not be saved to the stack. Since a leaf function does not + * call other functions, only the function the stack trace begins in could possibly + * be a leaf function, in which case the return address is in the thread context's + * $ra already, as it never left. + * + * The procedure is therefore + * - Iterate instructions + * - Once jr $ra is found, set pc to $ra + * - Done after delay slot + * + * A non-leaf function calls other functions, it is necessary for the return address + * to be saved to the stack. In these functions, it is important to keep track of the + * stack frame size of each function. + * + * The procedure is therefore + * - Iterate instructions + * - If lw $ra <imm>($sp) is found, fetch the saved $ra from stack memory + * - If addiu $sp, $sp, <imm> is found, modify $sp by the immediate value + * - If jr $ra is found, set pc to $ra + * - Done after delay slot + * + * Note that searching for one jr $ra is sufficient, as only leaf functions can have + * multiple jr $ra in the same function. + * + * There is also additional handling for eret and j. Neither of these instructions + * appear in IDO compiled C, however do show up in the exception handler. It is not + * possible to backtrace through an eret as an interrupt can occur at any time, so + * there is no choice but to give up here. For j instructions, they can be followed + * and the backtrace may continue as normal. + */ +void Fault_WalkStack(uintptr_t* spPtr, uintptr_t* pcPtr, uintptr_t* raPtr) { + uintptr_t sp = *spPtr; + uintptr_t pc = *pcPtr; + uintptr_t ra = *raPtr; + s32 count = 0x10000; // maximum number of instructions to search through + u32 lastInsn; + u32 insn; + u16 insnHi; + s16 insnLo; u32 imm; - if (sp & 3 || sp < 0x80000000 || sp >= 0xA0000000 || ra & 3 || ra < 0x80000000 || ra >= 0xA0000000) { - *spPtr = 0; - *pcPtr = 0; - *raPtr = 0; + // ensure $sp and $ra are aligned and valid pointers, if they aren't a stack + // trace cannot be generated + if (sp % 4 != 0 || !IS_KSEG0(sp) || ra % 4 != 0 || !IS_KSEG0(ra)) { + *raPtr = *pcPtr = *spPtr = 0; return; } - if (pc & 3 || pc < 0x80000000 || pc >= 0xA0000000) { + // ensure pc is aligned and a valid pointer, if not a stack trace cannot + // be generated + if (pc % 4 != 0 || !IS_KSEG0(pc)) { *pcPtr = ra; return; } - lastOpc = 0; + lastInsn = 0; while (true) { - opc = HW_REG(pc, u32); - opcHi = opc >> 16; - opcLo = opc & 0xFFFF; - imm = opcLo; - if (opcHi == 0x8FBF) { - ra = HW_REG(sp + imm, u32); - } else if (opcHi == 0x27BD) { + insn = *(u32*)K0_TO_K1(pc); + insnHi = insn >> 16; + insnLo = insn & 0xFFFF; + imm = insnLo; + + if (insnHi == 0x8FBF) { + // lw $ra, <imm>($sp) + // read return address saved on the stack + ra = *(uintptr_t*)K0_TO_K1(sp + imm); + } else if (insnHi == 0x27BD) { + // addiu $sp, $sp, <imm> + // stack pointer increment or decrement sp += imm; - } else if (opc == 0x42000018) { - sp = 0; - pc = 0; - ra = 0; - goto end; + } else if (insn == 0x42000018) { + // eret + // cannot backtrace through an eret, give up + ra = pc = sp = 0; + goto done; } - if (lastOpc == 0x3E00008) { + if (lastInsn == 0x03E00008) { + // jr $ra + // return to previous function pc = ra; - goto end; - } else if (lastOpc >> 26 == 2) { - pc = pc >> 28 << 28 | lastOpc << 6 >> 4; - goto end; + goto done; + } else if (lastInsn >> 26 == 2) { + // j <target> + // extract jump target + pc = pc >> 28 << 28 | lastInsn << 6 >> 4; + goto done; } - lastOpc = opc; - pc += 4; + + lastInsn = insn; + pc += sizeof(u32); if (count == 0) { break; } count--; } - sp = 0; - pc = 0; - ra = 0; + // Hit the maximum number of instructions to search, give up + ra = pc = sp = 0; -end: +done: *spPtr = sp; *pcPtr = pc; *raPtr = ra; } +/** + * Draws the stack trace page contents for the specified thread + */ void Fault_DrawStackTrace(OSThread* thread, s32 x, s32 y, s32 height) { s32 line; - u32 sp = thread->context.sp; - u32 ra = thread->context.ra; - u32 pc = thread->context.pc; - u32 addr; + uintptr_t sp = thread->context.sp; + uintptr_t ra = thread->context.ra; + uintptr_t pc = thread->context.pc; + uintptr_t addr; FaultDrawer_DrawText(x, y, "SP PC (VPC)"); - for (line = 1; line < height && (ra != 0 || sp != 0) && pc != (u32)__osCleanupThread; line++) { + + // Backtrace from the current function to the start of the thread + for (line = 1; line < height && (ra != 0 || sp != 0) && pc != (uintptr_t)__osCleanupThread; line++) { FaultDrawer_DrawText(x, y + line * 8, "%08x %08x", sp, pc); + // Convert relocated address to virtual address if applicable addr = Fault_ConvertAddress(pc); if (addr != 0) { FaultDrawer_Printf(" -> %08x", addr); } + // Search one function for the previous function Fault_WalkStack(&sp, &pc, &ra); } } void Fault_LogStackTrace(OSThread* thread, s32 height) { s32 line; - u32 sp = thread->context.sp; - u32 ra = thread->context.ra; - u32 pc = thread->context.pc; - u32 addr; + uintptr_t sp = thread->context.sp; + uintptr_t ra = thread->context.ra; + uintptr_t pc = thread->context.pc; + uintptr_t addr; s32 pad; osSyncPrintf("STACK TRACE\nSP PC (VPC)\n"); - for (line = 1; line < height && (ra != 0 || sp != 0) && pc != (u32)__osCleanupThread; line++) { + for (line = 1; line < height && (ra != 0 || sp != 0) && pc != (uintptr_t)__osCleanupThread; line++) { osSyncPrintf("%08x %08x", sp, pc); addr = Fault_ConvertAddress(pc); if (addr != 0) { @@ -890,30 +1089,30 @@ void Fault_LogStackTrace(OSThread* thread, s32 height) { } } -void Fault_ResumeThread(OSThread* t) { - t->context.cause = 0; - t->context.fpcsr = 0; - t->context.pc += 4; - *(u32*)t->context.pc = 0xD; - osWritebackDCache(t->context.pc, 4); - osInvalICache(t->context.pc, 4); - osStartThread(t); +void Fault_ResumeThread(OSThread* thread) { + thread->context.cause = 0; + thread->context.fpcsr = 0; + thread->context.pc += sizeof(u32); + *(u32*)thread->context.pc = 0x0000000D; // write in a break instruction + osWritebackDCache(thread->context.pc, 4); + osInvalICache(thread->context.pc, 4); + osStartThread(thread); } -void Fault_CommitFB() { - u16* fb; +void Fault_DisplayFrameBuffer(void) { + void* fb; osViSetYScale(1.0f); osViSetMode(&osViModeNtscLan1); osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_ON); osViBlack(false); - if (sFaultStructPtr->fb) { - fb = sFaultStructPtr->fb; + if (sFaultInstance->fb) { + fb = sFaultInstance->fb; } else { - fb = (u16*)osViGetNextFramebuffer(); - if ((u32)fb == 0x80000000) { - fb = (u16*)((osMemSize | 0x80000000) - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])); + fb = osViGetNextFramebuffer(); + if ((uintptr_t)fb == K0BASE) { + fb = (PHYS_TO_K0(osMemSize) - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])); } } @@ -921,56 +1120,63 @@ void Fault_CommitFB() { FaultDrawer_SetDrawerFB(fb, SCREEN_WIDTH, SCREEN_HEIGHT); } +/** + * Runs all registered fault clients. Each fault client displays a page + * on the crash screen. + */ void Fault_ProcessClients(void) { - FaultClient* iter = sFaultStructPtr->clients; + FaultClient* client = sFaultInstance->clients; s32 idx = 0; - while (iter != NULL) { - if (iter->callback != 0) { + while (client != NULL) { + if (client->callback != NULL) { Fault_FillScreenBlack(); FaultDrawer_SetCharPad(-2, 0); - FaultDrawer_Printf("\x1a" - "8CallBack (%d) %08x %08x %08x\n" - "\x1a" - "7", - idx++, iter, iter->param1, iter->param2); + FaultDrawer_Printf(FAULT_COLOR(DARK_GRAY) "CallBack (%d) %08x %08x %08x\n" FAULT_COLOR(WHITE), idx++, + client, client->arg0, client->arg1); FaultDrawer_SetCharPad(0, 0); - Fault_ProcessClient(iter->callback, iter->param1, iter->param2); + Fault_ProcessClient(client->callback, client->arg0, client->arg1); Fault_WaitForInput(); - Fault_CommitFB(); + Fault_DisplayFrameBuffer(); } - iter = iter->next; + client = client->next; } } -void Fault_UpdatePad() { +void Fault_UpdatePad(void) { Fault_UpdatePadImpl(); } +#define FAULT_MSG_CPU_BREAK ((OSMesg)1) +#define FAULT_MSG_FAULT ((OSMesg)2) +#define FAULT_MSG_UNK ((OSMesg)3) + void Fault_ThreadEntry(void* arg) { OSMesg msg; OSThread* faultedThread; s32 pad; - osSetEventMesg(OS_EVENT_CPU_BREAK, &sFaultStructPtr->queue, 1); - osSetEventMesg(OS_EVENT_FAULT, &sFaultStructPtr->queue, 2); + // Direct OS event messages to the fault event queue + osSetEventMesg(OS_EVENT_CPU_BREAK, &sFaultInstance->queue, FAULT_MSG_CPU_BREAK); + osSetEventMesg(OS_EVENT_FAULT, &sFaultInstance->queue, FAULT_MSG_FAULT); while (true) { do { - osRecvMesg(&sFaultStructPtr->queue, &msg, OS_MESG_BLOCK); + // Wait for a thread to hit a fault + osRecvMesg(&sFaultInstance->queue, &msg, OS_MESG_BLOCK); - if (msg == (OSMesg)1) { - sFaultStructPtr->msgId = 1; + if (msg == FAULT_MSG_CPU_BREAK) { + sFaultInstance->msgId = (u32)FAULT_MSG_CPU_BREAK; osSyncPrintf("フォルトマネージャ:OS_EVENT_CPU_BREAKを受信しました\n"); - } else if (1 && msg == (OSMesg)2) { - sFaultStructPtr->msgId = 2; + } else if (msg == FAULT_MSG_FAULT) { + sFaultInstance->msgId = (u32)FAULT_MSG_FAULT; osSyncPrintf("フォルトマネージャ:OS_EVENT_FAULTを受信しました\n"); - } else if (msg == (OSMesg)3) { + } else if (msg == FAULT_MSG_UNK) { Fault_UpdatePad(); faultedThread = NULL; continue; } else { - sFaultStructPtr->msgId = 3; + sFaultInstance->msgId = (u32)FAULT_MSG_UNK; osSyncPrintf("フォルトマネージャ:不明なメッセージを受信しました\n"); } @@ -983,97 +1189,120 @@ void Fault_ThreadEntry(void* arg) { } } while (faultedThread == NULL); - __osSetFpcCsr(__osGetFpcCsr() & -0xF81); - sFaultStructPtr->faultedThread = faultedThread; + // Disable floating-point related exceptions + __osSetFpcCsr(__osGetFpcCsr() & ~(FPCSR_EV | FPCSR_EZ | FPCSR_EO | FPCSR_EU | FPCSR_EI)); + sFaultInstance->faultedThread = faultedThread; - while (!sFaultStructPtr->faultHandlerEnabled) { + while (!sFaultInstance->faultHandlerEnabled) { Fault_Sleep(1000); } + Fault_Sleep(1000 / 2); - Fault_Sleep(500); - Fault_CommitFB(); + // Show fault framebuffer + Fault_DisplayFrameBuffer(); - if (sFaultStructPtr->faultActive) { + if (sFaultInstance->autoScroll) { Fault_Wait5Seconds(); } else { - Fault_DrawCornerRec(0xF801); + // Draw error bar signifying the crash screen is available + Fault_DrawCornerRec(GPACK_RGBA5551(255, 0, 0, 1)); Fault_WaitForButtonCombo(); } - sFaultStructPtr->faultActive = true; - FaultDrawer_SetForeColor(0xFFFF); - FaultDrawer_SetBackColor(0); + // Set auto-scrolling and default colors + sFaultInstance->autoScroll = true; + FaultDrawer_SetForeColor(GPACK_RGBA5551(255, 255, 255, 1)); + FaultDrawer_SetBackColor(GPACK_RGBA5551(0, 0, 0, 0)); + // Draw pages do { + // Thread context page Fault_PrintThreadContext(faultedThread); Fault_LogThreadContext(faultedThread); Fault_WaitForInput(); + // Stack trace page Fault_FillScreenBlack(); - FaultDrawer_DrawText(0x78, 0x10, "STACK TRACE"); - Fault_DrawStackTrace(faultedThread, 0x24, 0x18, 0x16); - Fault_LogStackTrace(faultedThread, 0x32); + FaultDrawer_DrawText(120, 16, "STACK TRACE"); + Fault_DrawStackTrace(faultedThread, 36, 24, 22); + Fault_LogStackTrace(faultedThread, 50); Fault_WaitForInput(); + // Client pages Fault_ProcessClients(); - Fault_DrawMemDump(faultedThread->context.pc - 0x100, (u32)faultedThread->context.sp, 0, 0); + // Memory dump page + Fault_DrawMemDump(faultedThread->context.pc - 0x100, (uintptr_t)faultedThread->context.sp, 0, 0); + // End page Fault_FillScreenRed(); - FaultDrawer_DrawText(0x40, 0x50, " CONGRATURATIONS! "); - FaultDrawer_DrawText(0x40, 0x5A, "All Pages are displayed."); - FaultDrawer_DrawText(0x40, 0x64, " THANK YOU! "); - FaultDrawer_DrawText(0x40, 0x6E, " You are great debugger!"); + FaultDrawer_DrawText(64, 80, " CONGRATURATIONS! "); + FaultDrawer_DrawText(64, 90, "All Pages are displayed."); + FaultDrawer_DrawText(64, 100, " THANK YOU! "); + FaultDrawer_DrawText(64, 110, " You are great debugger!"); Fault_WaitForInput(); - } while (!sFaultStructPtr->exitDebugger); + } while (!sFaultInstance->exit); - while (!sFaultStructPtr->exitDebugger) {} + while (!sFaultInstance->exit) {} Fault_ResumeThread(faultedThread); } } -void Fault_SetFB(void* fb, u16 w, u16 h) { - sFaultStructPtr->fb = fb; +void Fault_SetFrameBuffer(void* fb, u16 w, u16 h) { + sFaultInstance->fb = fb; FaultDrawer_SetDrawerFB(fb, w, h); } void Fault_Init(void) { - sFaultStructPtr = &gFaultStruct; - bzero(sFaultStructPtr, sizeof(FaultThreadStruct)); - FaultDrawer_SetDefault(); + sFaultInstance = &gFaultMgr; + bzero(sFaultInstance, sizeof(FaultMgr)); + FaultDrawer_Init(); FaultDrawer_SetInputCallback(Fault_WaitForInput); - sFaultStructPtr->exitDebugger = false; - sFaultStructPtr->msgId = 0; - sFaultStructPtr->faultHandlerEnabled = false; - sFaultStructPtr->faultedThread = NULL; - sFaultStructPtr->padCallback = Fault_PadCallback; - sFaultStructPtr->clients = NULL; - sFaultStructPtr->faultActive = false; - gFaultStruct.faultHandlerEnabled = true; - osCreateMesgQueue(&sFaultStructPtr->queue, &sFaultStructPtr->msg, 1); + sFaultInstance->exit = false; + sFaultInstance->msgId = 0; + sFaultInstance->faultHandlerEnabled = false; + sFaultInstance->faultedThread = NULL; + sFaultInstance->padCallback = Fault_PadCallback; + sFaultInstance->clients = NULL; + sFaultInstance->autoScroll = false; + gFaultMgr.faultHandlerEnabled = true; + osCreateMesgQueue(&sFaultInstance->queue, &sFaultInstance->msg, 1); StackCheck_Init(&sFaultThreadInfo, &sFaultStack, sFaultStack + sizeof(sFaultStack), 0, 0x100, "fault"); - osCreateThread(&sFaultStructPtr->thread, 2, Fault_ThreadEntry, 0, sFaultStack + sizeof(sFaultStack), + osCreateThread(&sFaultInstance->thread, 2, Fault_ThreadEntry, 0, sFaultStack + sizeof(sFaultStack), OS_PRIORITY_APPMAX); - osStartThread(&sFaultStructPtr->thread); + osStartThread(&sFaultInstance->thread); } -void Fault_HangupFaultClient(const char* arg0, const char* arg1) { - osSyncPrintf("HungUp on Thread %d\n", osGetThreadId(0)); - osSyncPrintf("%s\n", arg0 != NULL ? arg0 : "(NULL)"); - osSyncPrintf("%s\n", arg1 != NULL ? arg1 : "(NULL)"); - FaultDrawer_Printf("HungUp on Thread %d\n", osGetThreadId(0)); - FaultDrawer_Printf("%s\n", arg0 != NULL ? arg0 : "(NULL)"); - FaultDrawer_Printf("%s\n", arg1 != NULL ? arg1 : "(NULL)"); +/** + * Fault page for Hungup crashes. Displays the thread id and two messages + * specified in arguments to `Fault_AddHungupAndCrashImpl`. + */ +void Fault_HungupFaultClient(const char* exp1, const char* exp2) { + osSyncPrintf("HungUp on Thread %d\n", osGetThreadId(NULL)); + osSyncPrintf("%s\n", exp1 != NULL ? exp1 : "(NULL)"); + osSyncPrintf("%s\n", exp2 != NULL ? exp2 : "(NULL)"); + FaultDrawer_Printf("HungUp on Thread %d\n", osGetThreadId(NULL)); + FaultDrawer_Printf("%s\n", exp1 != NULL ? exp1 : "(NULL)"); + FaultDrawer_Printf("%s\n", exp2 != NULL ? exp2 : "(NULL)"); } -void Fault_AddHungupAndCrashImpl(const char* arg0, const char* arg1) { +/** + * Immediately crashes the current thread, for cases where an irrecoverable + * error occurs. The parameters specify two messages detailing the error, one + * or both may be NULL. + */ +void Fault_AddHungupAndCrashImpl(const char* exp1, const char* exp2) { FaultClient client; s32 pad; - Fault_AddClient(&client, Fault_HangupFaultClient, (void*)arg0, (void*)arg1); - *(u32*)0x11111111 = 0; // trigger an exception + Fault_AddClient(&client, Fault_HungupFaultClient, (void*)exp1, (void*)exp2); + *(u32*)0x11111111 = 0; // trigger an exception via unaligned memory access } -void Fault_AddHungupAndCrash(const char* filename, u32 line) { +/** + * Like `Fault_AddHungupAndCrashImpl`, however provides a fixed message containing + * filename and line number + */ +void Fault_AddHungupAndCrash(const char* file, s32 line) { char msg[256]; - sprintf(msg, "HungUp %s:%d", filename, line); + sprintf(msg, "HungUp %s:%d", file, line); Fault_AddHungupAndCrashImpl(msg, NULL); } diff --git a/src/code/fault_drawer.c b/src/code/fault_drawer.c index 229200b15..a9d99e37b 100644 --- a/src/code/fault_drawer.c +++ b/src/code/fault_drawer.c @@ -1,7 +1,35 @@ +/** + * @file fault_drawer.c + * + * Implements routines for drawing text with a fixed font directly to a framebuffer, used in displaying + * the crash screen implemented by fault.c + */ #include "global.h" #include "vt.h" -// rodata +typedef struct { + /* 0x00 */ u16* fb; + /* 0x04 */ u16 w; + /* 0x08 */ u16 h; + /* 0x0A */ u16 yStart; + /* 0x0C */ u16 yEnd; + /* 0x0E */ u16 xStart; + /* 0x10 */ u16 xEnd; + /* 0x12 */ u16 foreColor; + /* 0x14 */ u16 backColor; + /* 0x14 */ u16 cursorX; + /* 0x16 */ u16 cursorY; + /* 0x18 */ const u32* fontData; + /* 0x1C */ u8 charW; + /* 0x1D */ u8 charH; + /* 0x1E */ s8 charWPad; + /* 0x1F */ s8 charHPad; + /* 0x20 */ u16 printColors[10]; + /* 0x34 */ u8 escCode; // bool + /* 0x35 */ u8 osSyncPrintfEnabled; + /* 0x38 */ void (*inputCallback)(void); +} FaultDrawer; // size = 0x3C + const u32 sFaultDrawerFont[] = { 0x00DFFD00, 0x0AEEFFA0, 0x0DF22DD0, 0x06611DC0, 0x01122DD0, 0x06719900, 0x011EED10, 0x077EF700, 0x01562990, 0x05589760, 0x0DD22990, 0x05599770, 0x04DFFD40, 0x026EF700, 0x00000000, 0x00000000, 0x08BFFB00, 0x0EFFFFC0, @@ -34,25 +62,27 @@ const u32 sFaultDrawerFont[] = { 0x05546F50, 0x00A99800, 0x02222080, 0x02001888, }; +#define FAULT_DRAWER_CURSOR_X 22 +#define FAULT_DRAWER_CURSOR_Y 16 + FaultDrawer sFaultDrawerDefault = { - (u16*)(0x80400000 - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])), // fb - SCREEN_WIDTH, // w - SCREEN_HEIGHT, // h - 16, // yStart - 223, // yEnd - 22, // xStart - 297, // xEnd - GPACK_RGBA5551(255, 255, 255, 255), // foreColor - GPACK_RGBA5551(0, 0, 0, 0), // backColor - 22, // cursorX - 16, // cursorY - sFaultDrawerFont, // font + (u16*)(PHYS_TO_K0(0x400000) - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])), + SCREEN_WIDTH, + SCREEN_HEIGHT, + FAULT_DRAWER_CURSOR_Y, + SCREEN_HEIGHT - FAULT_DRAWER_CURSOR_Y - 1, + FAULT_DRAWER_CURSOR_X, + SCREEN_WIDTH - FAULT_DRAWER_CURSOR_X - 1, + GPACK_RGBA5551(255, 255, 255, 1), + GPACK_RGBA5551(0, 0, 0, 0), + FAULT_DRAWER_CURSOR_X, + FAULT_DRAWER_CURSOR_Y, + sFaultDrawerFont, 8, 8, 0, 0, { - // printColors GPACK_RGBA5551(0, 0, 0, 1), GPACK_RGBA5551(255, 0, 0, 1), GPACK_RGBA5551(0, 255, 0, 1), @@ -64,23 +94,23 @@ FaultDrawer sFaultDrawerDefault = { GPACK_RGBA5551(120, 120, 120, 1), GPACK_RGBA5551(176, 176, 176, 1), }, - 0, // escCode - 0, // osSyncPrintfEnabled - NULL, // inputCallback + false, + false, + NULL, }; -FaultDrawer sFaultDrawerStruct; +FaultDrawer sFaultDrawer; char D_8016B6C0[0x20]; void FaultDrawer_SetOsSyncPrintfEnabled(u32 enabled) { - sFaultDrawerStruct.osSyncPrintfEnabled = enabled; + sFaultDrawer.osSyncPrintfEnabled = enabled; } void FaultDrawer_DrawRecImpl(s32 xStart, s32 yStart, s32 xEnd, s32 yEnd, u16 color) { u16* fb; s32 x, y; - s32 xDiff = sFaultDrawerStruct.w - xStart; - s32 yDiff = sFaultDrawerStruct.h - yStart; + s32 xDiff = sFaultDrawer.w - xStart; + s32 yDiff = sFaultDrawer.h - yStart; s32 xSize = xEnd - xStart + 1; s32 ySize = yEnd - yStart + 1; @@ -93,12 +123,12 @@ void FaultDrawer_DrawRecImpl(s32 xStart, s32 yStart, s32 xEnd, s32 yEnd, u16 col ySize = yDiff; } - fb = sFaultDrawerStruct.fb + sFaultDrawerStruct.w * yStart + xStart; + fb = sFaultDrawer.fb + sFaultDrawer.w * yStart + xStart; for (y = 0; y < ySize; y++) { for (x = 0; x < xSize; x++) { *fb++ = color; } - fb += sFaultDrawerStruct.w - xSize; + fb += sFaultDrawer.w - xSize; } osWritebackDCacheAll(); @@ -110,31 +140,29 @@ void FaultDrawer_DrawChar(char c) { s32 x, y; const u32* dataPtr; u32 data; - s32 cursorX = sFaultDrawerStruct.cursorX; - s32 cursorY = sFaultDrawerStruct.cursorY; - const u32** fontData = &sFaultDrawerStruct.fontData; + s32 cursorX = sFaultDrawer.cursorX; + s32 cursorY = sFaultDrawer.cursorY; + const u32** fontData = &sFaultDrawer.fontData; s32 shift = c % 4; dataPtr = &fontData[0][(((c / 8) * 16) + ((c & 4) >> 2))]; - fb = sFaultDrawerStruct.fb + (sFaultDrawerStruct.w * cursorY) + cursorX; + fb = sFaultDrawer.fb + (sFaultDrawer.w * cursorY) + cursorX; - if ((sFaultDrawerStruct.xStart <= cursorX) && - ((sFaultDrawerStruct.charW + cursorX - 1) <= sFaultDrawerStruct.xEnd) && - (sFaultDrawerStruct.yStart <= cursorY) && - ((sFaultDrawerStruct.charH + cursorY - 1) <= sFaultDrawerStruct.yEnd)) { - for (y = 0; y < sFaultDrawerStruct.charH; y++) { + if ((sFaultDrawer.xStart <= cursorX) && ((sFaultDrawer.charW + cursorX - 1) <= sFaultDrawer.xEnd) && + (sFaultDrawer.yStart <= cursorY) && ((sFaultDrawer.charH + cursorY - 1) <= sFaultDrawer.yEnd)) { + for (y = 0; y < sFaultDrawer.charH; y++) { u32 mask = 0x10000000 << shift; data = *dataPtr; - for (x = 0; x < sFaultDrawerStruct.charW; x++) { + for (x = 0; x < sFaultDrawer.charW; x++) { if (mask & data) { - fb[x] = sFaultDrawerStruct.foreColor; - } else if (sFaultDrawerStruct.backColor & 1) { - fb[x] = sFaultDrawerStruct.backColor; + fb[x] = sFaultDrawer.foreColor; + } else if (sFaultDrawer.backColor & 1) { + fb[x] = sFaultDrawer.backColor; } mask >>= 4; } - fb += sFaultDrawerStruct.w; + fb += sFaultDrawer.w; dataPtr += 2; } } @@ -142,37 +170,40 @@ void FaultDrawer_DrawChar(char c) { s32 FaultDrawer_ColorToPrintColor(u16 color) { s32 i; - for (i = 0; i < 10; i++) { - if (color == sFaultDrawerStruct.printColors[i]) { + + for (i = 0; i < ARRAY_COUNT(sFaultDrawer.printColors); i++) { + if (color == sFaultDrawer.printColors[i]) { return i; } } return -1; } -void FaultDrawer_UpdatePrintColor() { +void FaultDrawer_UpdatePrintColor(void) { s32 idx; - if (sFaultDrawerStruct.osSyncPrintfEnabled) { + if (sFaultDrawer.osSyncPrintfEnabled) { osSyncPrintf(VT_RST); - idx = FaultDrawer_ColorToPrintColor(sFaultDrawerStruct.foreColor); - if (idx >= 0 && idx < 8) { + + idx = FaultDrawer_ColorToPrintColor(sFaultDrawer.foreColor); + if (idx >= 0 && idx < ARRAY_COUNT(sFaultDrawer.printColors) - 2) { osSyncPrintf(VT_SGR("3%d"), idx); } - idx = FaultDrawer_ColorToPrintColor(sFaultDrawerStruct.backColor); - if (idx >= 0 && idx < 8) { + + idx = FaultDrawer_ColorToPrintColor(sFaultDrawer.backColor); + if (idx >= 0 && idx < ARRAY_COUNT(sFaultDrawer.printColors) - 2) { osSyncPrintf(VT_SGR("4%d"), idx); } } } void FaultDrawer_SetForeColor(u16 color) { - sFaultDrawerStruct.foreColor = color; + sFaultDrawer.foreColor = color; FaultDrawer_UpdatePrintColor(); } void FaultDrawer_SetBackColor(u16 color) { - sFaultDrawerStruct.backColor = color; + sFaultDrawer.backColor = color; FaultDrawer_UpdatePrintColor(); } @@ -181,101 +212,102 @@ void FaultDrawer_SetFontColor(u16 color) { } void FaultDrawer_SetCharPad(s8 padW, s8 padH) { - sFaultDrawerStruct.charWPad = padW; - sFaultDrawerStruct.charHPad = padH; + sFaultDrawer.charWPad = padW; + sFaultDrawer.charHPad = padH; } void FaultDrawer_SetCursor(s32 x, s32 y) { - if (sFaultDrawerStruct.osSyncPrintfEnabled) { - osSyncPrintf(VT_CUP("%d", "%d"), - (y - sFaultDrawerStruct.yStart) / (sFaultDrawerStruct.charH + sFaultDrawerStruct.charHPad), - (x - sFaultDrawerStruct.xStart) / (sFaultDrawerStruct.charW + sFaultDrawerStruct.charWPad)); + if (sFaultDrawer.osSyncPrintfEnabled) { + osSyncPrintf(VT_CUP("%d", "%d"), (y - sFaultDrawer.yStart) / (sFaultDrawer.charH + sFaultDrawer.charHPad), + (x - sFaultDrawer.xStart) / (sFaultDrawer.charW + sFaultDrawer.charWPad)); } - sFaultDrawerStruct.cursorX = x; - sFaultDrawerStruct.cursorY = y; + sFaultDrawer.cursorX = x; + sFaultDrawer.cursorY = y; } -void FaultDrawer_FillScreen() { - if (sFaultDrawerStruct.osSyncPrintfEnabled) { +void FaultDrawer_FillScreen(void) { + if (sFaultDrawer.osSyncPrintfEnabled) { osSyncPrintf(VT_CLS); } - FaultDrawer_DrawRecImpl(sFaultDrawerStruct.xStart, sFaultDrawerStruct.yStart, sFaultDrawerStruct.xEnd, - sFaultDrawerStruct.yEnd, sFaultDrawerStruct.backColor | 1); - FaultDrawer_SetCursor(sFaultDrawerStruct.xStart, sFaultDrawerStruct.yStart); + FaultDrawer_DrawRecImpl(sFaultDrawer.xStart, sFaultDrawer.yStart, sFaultDrawer.xEnd, sFaultDrawer.yEnd, + sFaultDrawer.backColor | 1); + FaultDrawer_SetCursor(sFaultDrawer.xStart, sFaultDrawer.yStart); } -void* FaultDrawer_FormatStringFunc(void* arg, const char* str, u32 count) { +void* FaultDrawer_PrintCallback(void* arg, const char* str, u32 count) { for (; count != 0; count--, str++) { s32 curXStart; s32 curXEnd; - if (sFaultDrawerStruct.escCode) { - sFaultDrawerStruct.escCode = false; - if (*str > 0x30 && *str < 0x3A) { - FaultDrawer_SetForeColor(sFaultDrawerStruct.printColors[*str - 0x30]); + if (sFaultDrawer.escCode) { + sFaultDrawer.escCode = false; + if (*str > '0' && *str <= '9') { + FaultDrawer_SetForeColor(sFaultDrawer.printColors[*str - '0']); } - curXStart = sFaultDrawerStruct.cursorX; - curXEnd = sFaultDrawerStruct.xEnd - sFaultDrawerStruct.charW; + curXStart = sFaultDrawer.cursorX; + curXEnd = sFaultDrawer.xEnd - sFaultDrawer.charW; } else { switch (*str) { case '\n': - if (sFaultDrawerStruct.osSyncPrintfEnabled) { + if (sFaultDrawer.osSyncPrintfEnabled) { osSyncPrintf("\n"); } - sFaultDrawerStruct.cursorX = sFaultDrawerStruct.w; - curXStart = sFaultDrawerStruct.cursorX; - curXEnd = sFaultDrawerStruct.xEnd - sFaultDrawerStruct.charW; + sFaultDrawer.cursorX = sFaultDrawer.w; + curXStart = sFaultDrawer.cursorX; + curXEnd = sFaultDrawer.xEnd - sFaultDrawer.charW; break; - case '\x1A': - sFaultDrawerStruct.escCode = true; - curXStart = sFaultDrawerStruct.cursorX; - curXEnd = sFaultDrawerStruct.xEnd - sFaultDrawerStruct.charW; + case FAULT_ESC: + sFaultDrawer.escCode = true; + curXStart = sFaultDrawer.cursorX; + curXEnd = sFaultDrawer.xEnd - sFaultDrawer.charW; break; default: - if (sFaultDrawerStruct.osSyncPrintfEnabled) { + if (sFaultDrawer.osSyncPrintfEnabled) { osSyncPrintf("%c", *str); } FaultDrawer_DrawChar(*str); - sFaultDrawerStruct.cursorX += sFaultDrawerStruct.charW + sFaultDrawerStruct.charWPad; + sFaultDrawer.cursorX += sFaultDrawer.charW + sFaultDrawer.charWPad; - curXStart = sFaultDrawerStruct.cursorX; - curXEnd = sFaultDrawerStruct.xEnd - sFaultDrawerStruct.charW; + curXStart = sFaultDrawer.cursorX; + curXEnd = sFaultDrawer.xEnd - sFaultDrawer.charW; + break; } } if (curXEnd <= curXStart) { - sFaultDrawerStruct.cursorX = sFaultDrawerStruct.xStart; - sFaultDrawerStruct.cursorY += sFaultDrawerStruct.charH + sFaultDrawerStruct.charHPad; - if (sFaultDrawerStruct.yEnd - sFaultDrawerStruct.charH <= sFaultDrawerStruct.cursorY) { - if (sFaultDrawerStruct.inputCallback) { - sFaultDrawerStruct.inputCallback(); + sFaultDrawer.cursorX = sFaultDrawer.xStart; + sFaultDrawer.cursorY += sFaultDrawer.charH + sFaultDrawer.charHPad; + if (sFaultDrawer.yEnd - sFaultDrawer.charH <= sFaultDrawer.cursorY) { + if (sFaultDrawer.inputCallback) { + sFaultDrawer.inputCallback(); FaultDrawer_FillScreen(); } - sFaultDrawerStruct.cursorY = sFaultDrawerStruct.yStart; + sFaultDrawer.cursorY = sFaultDrawer.yStart; } } } - osWritebackDCacheAll(); return arg; } -void FaultDrawer_VPrintf(const char* str, char* args) { // va_list - _Printf(FaultDrawer_FormatStringFunc, (char*)&sFaultDrawerStruct, str, args); +s32 FaultDrawer_VPrintf(const char* fmt, va_list args) { + return _Printf(FaultDrawer_PrintCallback, &sFaultDrawer, fmt, args); } -void FaultDrawer_Printf(const char* fmt, ...) { +s32 FaultDrawer_Printf(const char* fmt, ...) { + s32 ret; va_list args; va_start(args, fmt); - FaultDrawer_VPrintf(fmt, args); + ret = FaultDrawer_VPrintf(fmt, args); va_end(args); + return ret; } void FaultDrawer_DrawText(s32 x, s32 y, const char* fmt, ...) { @@ -289,20 +321,20 @@ void FaultDrawer_DrawText(s32 x, s32 y, const char* fmt, ...) { } void FaultDrawer_SetDrawerFB(void* fb, u16 w, u16 h) { - sFaultDrawerStruct.fb = fb; - sFaultDrawerStruct.w = w; - sFaultDrawerStruct.h = h; + sFaultDrawer.fb = fb; + sFaultDrawer.w = w; + sFaultDrawer.h = h; } -void FaultDrawer_SetInputCallback(void (*callback)()) { - sFaultDrawerStruct.inputCallback = callback; +void FaultDrawer_SetInputCallback(void (*callback)(void)) { + sFaultDrawer.inputCallback = callback; } -void FaultDrawer_WritebackFBDCache() { - osWritebackDCache(sFaultDrawerStruct.fb, sFaultDrawerStruct.w * sFaultDrawerStruct.h * 2); +void FaultDrawer_WritebackFBDCache(void) { + osWritebackDCache(sFaultDrawer.fb, sFaultDrawer.w * sFaultDrawer.h * sizeof(u16)); } -void FaultDrawer_SetDefault() { - bcopy(&sFaultDrawerDefault, &sFaultDrawerStruct, sizeof(FaultDrawer)); - sFaultDrawerStruct.fb = (u16*)((osMemSize | 0x80000000) - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])); +void FaultDrawer_Init(void) { + bcopy(&sFaultDrawerDefault, &sFaultDrawer, sizeof(FaultDrawer)); + sFaultDrawer.fb = (u16*)(PHYS_TO_K0(osMemSize) - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])); } diff --git a/src/code/game.c b/src/code/game.c index cc7128616..887141535 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -17,7 +17,7 @@ void GameState_FaultPrint(void) { FaultDrawer_DrawText(120, 180, "%08x", sLastButtonPressed); for (i = 0; i < ARRAY_COUNT(sBtnChars); i++) { if (sLastButtonPressed & (1 << i)) { - FaultDrawer_DrawText((i * 8) + 0x78, 0xBE, "%c", sBtnChars[i]); + FaultDrawer_DrawText((i * 8) + 120, 190, "%c", sBtnChars[i]); } } } diff --git a/src/code/graph.c b/src/code/graph.c index 16f539345..0567c016f 100644 --- a/src/code/graph.c +++ b/src/code/graph.c @@ -134,7 +134,7 @@ void Graph_Init(GraphicsContext* gfxCtx) { gfxCtx->yScale = gViConfigYScale; osCreateMesgQueue(&gfxCtx->queue, gfxCtx->msgBuff, ARRAY_COUNT(gfxCtx->msgBuff)); func_800D31F0(); - Fault_AddClient(&sGraphFaultClient, Graph_FaultClient, 0, 0); + Fault_AddClient(&sGraphFaultClient, Graph_FaultClient, NULL, NULL); } void Graph_Destroy(GraphicsContext* gfxCtx) { diff --git a/src/code/irqmgr.c b/src/code/irqmgr.c index 6e7118bff..50ba2def9 100644 --- a/src/code/irqmgr.c +++ b/src/code/irqmgr.c @@ -23,7 +23,7 @@ void IrqMgr_AddClient(IrqMgr* this, IrqMgrClient* c, OSMesgQueue* msgQ) { LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 97); LogUtils_CheckNullPointer("msgQ", msgQ, "../irqmgr.c", 98); - prevInt = osSetIntMask(1); + prevInt = osSetIntMask(OS_IM_NONE); c->queue = msgQ; c->prev = this->clients; @@ -48,7 +48,7 @@ void IrqMgr_RemoveClient(IrqMgr* this, IrqMgrClient* c) { LogUtils_CheckNullPointer("this", this, "../irqmgr.c", 129); LogUtils_CheckNullPointer("c", c, "../irqmgr.c", 130); - prevInt = osSetIntMask(1); + prevInt = osSetIntMask(OS_IM_NONE); while (iter != NULL) { if (iter == c) { diff --git a/src/code/padmgr.c b/src/code/padmgr.c index e77500670..68c34d369 100644 --- a/src/code/padmgr.c +++ b/src/code/padmgr.c @@ -165,7 +165,7 @@ void PadMgr_RumbleStop(PadMgr* padMgr) { for (i = 0; i < 4; i++) { if (osMotorInit(ctrlrQ, &padMgr->pfs[i], i) == 0) { - if ((gFaultStruct.msgId == 0) && (padMgr->rumbleOnFrames != 0)) { + if ((gFaultMgr.msgId == 0) && (padMgr->rumbleOnFrames != 0)) { osSyncPrintf(VT_FGCOL(YELLOW)); // "Stop vibration pack" osSyncPrintf("padmgr: %dコン: %s\n", i + 1, "振動パック 停止"); @@ -297,7 +297,7 @@ void PadMgr_HandleRetraceMsg(PadMgr* padMgr) { } padMgr->validCtrlrsMask = mask; - if (gFaultStruct.msgId) { + if (gFaultMgr.msgId != 0) { PadMgr_RumbleStop(padMgr); } else if (padMgr->rumbleOffFrames > 0) { --padMgr->rumbleOffFrames; diff --git a/src/code/sched.c b/src/code/sched.c index bc14c9a7a..cf8f6eced 100644 --- a/src/code/sched.c +++ b/src/code/sched.c @@ -26,7 +26,7 @@ void Sched_SwapFrameBuffer(CfbInfo* cfbInfo) { (cfbInfo != NULL ? cfbInfo->swapBuffer : NULL)); } width = cfbInfo->viMode != NULL ? cfbInfo->viMode->comRegs.width : (u32)gScreenWidth; - Fault_SetFB(cfbInfo->swapBuffer, width, 0x10); + Fault_SetFrameBuffer(cfbInfo->swapBuffer, width, 0x10); if (HREG(80) == 0xD && HREG(95) != 0xD) { HREG(81) = 0; diff --git a/src/code/z_onepointdemo.c b/src/code/z_onepointdemo.c index 4a8f9e738..22de34f2e 100644 --- a/src/code/z_onepointdemo.c +++ b/src/code/z_onepointdemo.c @@ -1318,7 +1318,7 @@ s32 OnePointCutscene_Attention(GlobalContext* globalCtx, Actor* actor) { // If the previous attention cutscene has an actor in the same category, skip this actor. if (actor->category == vLastHigherCat) { - osSyncPrintf("→ " VT_FGCOL(PURPLE) "×" VT_RST " (%d)\n", actor->id); + osSyncPrintf("→ " VT_FGCOL(MAGENTA) "×" VT_RST " (%d)\n", actor->id); return SUBCAM_NONE; } osSyncPrintf("→ " VT_FGCOL(BLUE) "○" VT_RST " (%d)\n", actor->id); |
