mirror of https://github.com/n64decomp/mk64.git
362 lines
11 KiB
C
362 lines
11 KiB
C
#include <ultra64.h>
|
|
#include <macros.h>
|
|
#include "types.h"
|
|
|
|
/*void *__osGetCurrFaultedThread(); // extern
|
|
? osCreateMesgQueue(? *, ? *, ?); // extern
|
|
? osCreateThread(? *, ?, void (*)(s32 arg0), ?, ? *, s32); // extern
|
|
? osRecvMesg(? *, ? *, ?); // extern
|
|
? osSetEventMesg(?, ? *, ?); // extern
|
|
? osStartThread(? *); // extern
|
|
? osViSwapBuffer(s32); // extern
|
|
? osWritebackDCacheAll(s32, s32, s16, s16); // extern
|
|
? read_controllers(); // extern
|
|
void crash_screen_draw_info(uint_ptr arg0, void *arg1); // static
|
|
void crash_screen_draw_square(uint_ptr arg0); // static
|
|
void create_debug_thread(); // static
|
|
void func_800040C0(s32 arg0, s32 arg1, s32 arg2, u32 arg3); // static
|
|
void crash_screen_set_framebuffer(s32 arg0); // static
|
|
void *get_faulted_thread(); // static
|
|
void start_debug_thread(); // static
|
|
void thread9_crash_screen(s32 arg0); // static
|
|
extern void *gControllerOne;
|
|
extern s32 sCounter;
|
|
|
|
extern ? sCrashScreenButtonSequence;
|
|
extern ? D_80162790;
|
|
extern ? D_80162D40;
|
|
extern ? D_80162D58;
|
|
extern uintptr_t pFramebuffer;
|
|
extern s32 buttonSequenceIndex;
|
|
extern void *D_80162D64;
|
|
*/
|
|
|
|
|
|
|
|
OSThread D_80162790;
|
|
ALIGNED8 u8 gDebugThreadStack[0x400];
|
|
OSMesgQueue D_80162D40;
|
|
OSMesg D_80162D58;
|
|
uintptr_t pFramebuffer;
|
|
s32 sButtonSequenceIndex;
|
|
//void *D_80162D64;
|
|
|
|
#define DRAW_CODE 0xFFFF
|
|
#define CHARACTER_DASH 16
|
|
|
|
extern void osSetEventMesg(OSEvent, OSMesgQueue *, OSMesg);
|
|
extern s32 osRecvMesg(OSMesgQueue *, OSMesg *, s32);
|
|
extern void read_controllers();
|
|
|
|
extern struct Controller *gControllerOne;
|
|
|
|
//s32 shift = 0;
|
|
|
|
s32 sCounter = 0;
|
|
|
|
u8 crashScreenFont[][8] = {
|
|
#include "textures/crash_screen/crash_screen_font.ia1.inc.c"
|
|
};
|
|
|
|
u16 sCrashScreenButtonSequence[] = {
|
|
L_TRIG, U_JPAD, L_JPAD, D_JPAD, R_JPAD, R_TRIG, L_TRIG, B_BUTTON, A_BUTTON, DRAW_CODE
|
|
};
|
|
|
|
void crash_screen_draw_glyph(u16 *framebuffer, s32 x, s32 y, s32 glyph) {
|
|
s32 data;
|
|
s32 ptr;
|
|
s32 i, j;
|
|
|
|
for(i = 0; i < 8; i++) {
|
|
|
|
data = crashScreenFont[glyph][i];
|
|
|
|
for (j = 5; j >= 0; j--) {
|
|
|
|
ptr = (y + i) * 320 + (x + j);
|
|
|
|
if (data & 1) {
|
|
framebuffer[ptr] = 0xffff;
|
|
}
|
|
data = data >> 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MIPS_TO_C
|
|
//generated by mips_to_c commit bd0364fa19633bd6201f8007e2d0a7ed87825909
|
|
|
|
#define WHITE_COLOUR 0xFFFF
|
|
#define RED_COLOUR 0xF801
|
|
void crash_screen_draw_square(u16 *framebuffer) {
|
|
s32 temp_a0;
|
|
s32 temp_a1;
|
|
s32 temp_a1_2;
|
|
s32 temp_ra;
|
|
s32 temp_s0;
|
|
s32 temp_s1;
|
|
s32 temp_t0;
|
|
s32 temp_v1;
|
|
s32 phi_s2;
|
|
s32 phi_s0;
|
|
s16 *phi_v0;
|
|
s32 phi_v1;
|
|
void *phi_v0_2;
|
|
s32 phi_a1;
|
|
s32 phi_s1;
|
|
s32 phi_a0;
|
|
s32 phi_a1_2;
|
|
s32 phi_v1_2;
|
|
s32 phi_a0_2;
|
|
s32 phi_a0_3;
|
|
s32 phi_a1_3;
|
|
s32 phi_a1_4;
|
|
s32 i, j, k;
|
|
|
|
//phi_s2 = 0x28;
|
|
//phi_s0 = 0x2E;
|
|
phi_a0_2 = framebuffer;
|
|
//phi_a1_3 = arg1;
|
|
for (i = 46; i > 44; i--) {
|
|
//phi_s1 = phi_s2;
|
|
//phi_a0 = phi_a0_2;
|
|
//phi_a1_2 = phi_a1_3;
|
|
// phi_a0_3 = phi_a0_2;
|
|
//phi_a1_4 = phi_a1_3;
|
|
//if (phi_s2 < phi_s0) {
|
|
for (j = 40; j < i; j++) {
|
|
//phi_v1 = phi_s2;
|
|
//phi_v1_2 = phi_s2;
|
|
if (phi_s2 < phi_s0) {
|
|
//temp_a0 = i - j;
|
|
temp_t0 = (i - j) & 3;
|
|
//temp_ra = framebuffer + (phi_s1 * 0x280);
|
|
//phi_a0_3 = temp_a0;
|
|
if (temp_t0 != 0) {
|
|
phi_v0 = temp_ra + (phi_s2 * 2);
|
|
do { // (temp_t0 + j;) {
|
|
j++;
|
|
//temp_v1 = phi_v1 + 1;
|
|
//phi_v1 = temp_v1;
|
|
//phi_v1_2 = temp_v1;
|
|
if (i - j == 6) {
|
|
framebuffer[i * 640 + j * 2] = RED_COLOUR;
|
|
} else {
|
|
framebuffer[i * 640 + j * 2] = WHITE_COLOUR;
|
|
}
|
|
j += 2;
|
|
} while ((temp_t0 + j) != j);
|
|
phi_a1_4 = temp_v1 * 2;
|
|
if (temp_v1 != phi_s0) {
|
|
break; // goto 10
|
|
}
|
|
} else {
|
|
//block_10:
|
|
//temp_a1 = phi_v1_2 * 2;
|
|
phi_v0_2 = framebuffer[i * 640 + j * 2];
|
|
phi_a1 = temp_a1;
|
|
for (k = j + 8; k < j * 2; k += 8) {
|
|
//do {
|
|
//temp_a1_2 = phi_a1 + 8;
|
|
//phi_a1 = temp_a1_2;
|
|
//phi_a1_4 = temp_a1_2;
|
|
if (temp_a0 == 6) {
|
|
framebuffer[i * 640 + j * 2] = RED_COLOUR;
|
|
} else {
|
|
framebuffer[i * 640 + j * 2] = WHITE_COLOUR;
|
|
}
|
|
//if (temp_a0 == 6) {
|
|
// phi_v0_2->unk2 = RED_COLOUR;
|
|
//} else {
|
|
// phi_v0_2->unk2 = WHITE_COLOUR;
|
|
//}
|
|
//if (temp_a0 == 6) {
|
|
// phi_v0_2->unk4 = RED_COLOUR;
|
|
//} else {
|
|
// phi_v0_2->unk4 = WHITE_COLOUR;
|
|
//}
|
|
//if (temp_a0 == 6) {
|
|
// phi_v0_2->unk6 = RED_COLOUR;
|
|
//} else {
|
|
// phi_v0_2->unk6 = WHITE_COLOUR;
|
|
//}
|
|
//phi_v0_2 += 8;
|
|
} //while (temp_a1_2 != (phi_s0 * 2));
|
|
}
|
|
}
|
|
//temp_s1 = phi_s1 + 1;
|
|
//phi_s1 = temp_s1;
|
|
//phi_a0 = phi_a0_3;
|
|
//phi_a1_2 = phi_a1_4;
|
|
} //while (temp_s1 != phi_s0);
|
|
|
|
//temp_s0 = phi_s0 - 1;
|
|
//phi_s2 += 1;
|
|
//phi_s0 = temp_s0;
|
|
//phi_a0_2 = phi_a0;
|
|
//phi_a1_3 = phi_a1_2;
|
|
//i--;
|
|
} //while (temp_s0 != 44);
|
|
osWritebackDCacheAll();
|
|
osViSwapBuffer(framebuffer);
|
|
}
|
|
#else
|
|
GLOBAL_ASM("asm/non_matchings/crash_screen/crash_screen_draw_square.s")
|
|
#endif
|
|
|
|
/**
|
|
* Draws three black boxes then prints crash info in the following format:
|
|
* Line 1: threadId - address of faulted instruction - error code
|
|
* Line 2: Address in the return address register
|
|
* Line 3: Machine code of faulted instruction
|
|
*
|
|
* The R4300i manual discusses exceptions in more depth.
|
|
*
|
|
* @param framebuffer
|
|
* @param faulted thread
|
|
**/
|
|
void crash_screen_draw_info(u16 *framebuffer, OSThread *thread) {
|
|
__OSThreadContext *context = &thread->context;
|
|
s32 i, j, x, y, h;
|
|
uintptr_t faultedAddr;
|
|
u32 exception;
|
|
s32 math;
|
|
u32 crashInfo;
|
|
s32 temp;
|
|
|
|
// Draw three black boxes
|
|
for (h = 0; h < 3; h++) {
|
|
|
|
math = (48 + (sCounter * 24)) + h * 20;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
for (j = 0; j < 120; j++) {
|
|
// Set pixels to black
|
|
framebuffer[((i + math) * 320) + (j + 100)] = 0x0001;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw crash information over the black boxes.
|
|
temp = (sCounter * 24);
|
|
y = temp + 53;
|
|
crash_screen_draw_glyph(framebuffer, 108, y, thread->id & 0xF);
|
|
crash_screen_draw_glyph(framebuffer, 116, y, CHARACTER_DASH);
|
|
|
|
// Address of faulted instruction.
|
|
crashInfo = context->pc;
|
|
|
|
for (x = 180; x >= 124; x -= 8) {
|
|
crash_screen_draw_glyph(framebuffer, x, y, crashInfo & 0xF);
|
|
crashInfo >>= 4;
|
|
}
|
|
|
|
exception = (context->cause >> 2) & 0x1F;
|
|
crash_screen_draw_glyph(framebuffer, 188, y, CHARACTER_DASH);
|
|
crash_screen_draw_glyph(framebuffer, 196, y, exception >> 4);
|
|
crash_screen_draw_glyph(framebuffer, 204, y, exception & 0xF);
|
|
|
|
// Address in the Return Address register.
|
|
crashInfo = context->ra;
|
|
|
|
for (x = 180; x >= 124; x -= 8) {
|
|
crash_screen_draw_glyph(framebuffer, x, 73, crashInfo & 0xF);
|
|
crashInfo >>= 4;
|
|
}
|
|
|
|
// Address of faulted instruction.
|
|
faultedAddr = context->pc & (~3);
|
|
|
|
// Ensure the address to the faulted instruction is a memory address.
|
|
// @bug if this check fails, the ra register is printed a second time.
|
|
if ((faultedAddr > 0x80000000) && (faultedAddr < 0x803FFF7F)) {
|
|
// Cast the address to its value; the faulty machine code.
|
|
crashInfo = *(u32*)faultedAddr;
|
|
}
|
|
for (x = 180; x >= 124; x -= 4) {
|
|
crash_screen_draw_glyph(framebuffer, x, 93, crashInfo & 0xF);
|
|
x -= 4;
|
|
crashInfo >>= 4;
|
|
}
|
|
osWritebackDCacheAll();
|
|
osViSwapBuffer(framebuffer);
|
|
}
|
|
|
|
OSThread *get_faulted_thread(void) {
|
|
OSThread *thread;
|
|
|
|
thread = __osGetCurrFaultedThread();
|
|
while (thread->priority != -1) {
|
|
if (thread->priority > OS_PRIORITY_IDLE && thread->priority <= OS_PRIORITY_APPMAX
|
|
&& (thread->flags & 3) != 0) {
|
|
return thread;
|
|
}
|
|
thread = thread->tlnext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves faulted thread and displays debug info after the user inputs the button sequence.
|
|
* Button sequence: L, Up, Left, Down, Right, R, L, B, A
|
|
**/
|
|
void thread9_crash_screen(UNUSED void *arg0)
|
|
{
|
|
static OSThread *thread;
|
|
OSMesg mesg;
|
|
|
|
osSetEventMesg(12, &D_80162D40, (OSMesg) 16);
|
|
osSetEventMesg(10, &D_80162D40, (OSMesg) 16);
|
|
sButtonSequenceIndex = 0;
|
|
|
|
while (1) {
|
|
osRecvMesg(&D_80162D40, &mesg, 1);
|
|
thread = get_faulted_thread();
|
|
|
|
if (thread) {
|
|
// Run only on the first iteration.
|
|
if (sCounter == 0) {
|
|
crash_screen_draw_square(pFramebuffer);
|
|
|
|
while(1)
|
|
{
|
|
read_controllers();
|
|
|
|
if (!gControllerOne->buttonPressed) { continue; }
|
|
|
|
if (gControllerOne->buttonPressed == sCrashScreenButtonSequence[sButtonSequenceIndex]) {
|
|
sButtonSequenceIndex++;
|
|
} else {
|
|
sButtonSequenceIndex = 0;
|
|
}
|
|
|
|
// draws crash info when DRAW_CODE is reached
|
|
if (sCrashScreenButtonSequence[sButtonSequenceIndex] == DRAW_CODE) {
|
|
break;
|
|
}
|
|
}
|
|
crash_screen_draw_info(pFramebuffer, thread);
|
|
|
|
}
|
|
if (sCounter < 5) {
|
|
sCounter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void crash_screen_set_framebuffer(uintptr_t *framebuffer) {
|
|
pFramebuffer = framebuffer;
|
|
}
|
|
|
|
extern void thread9_crash_screen(void *);
|
|
|
|
void create_debug_thread(void) {
|
|
osCreateMesgQueue(&D_80162D40, &D_80162D58, 1);
|
|
osCreateThread((OSThread *) &D_80162790, 9, (void *)thread9_crash_screen, 0, &D_80162D40, 0x7F);
|
|
}
|
|
|
|
void start_debug_thread(void) {
|
|
osStartThread(&D_80162790);
|
|
}
|