Add crash screen enhancement (#360)

* Add crash screen enhancement
This commit is contained in:
MegaMech 2023-08-09 18:51:37 -06:00 committed by GitHub
parent 727ceadfb4
commit de5c688e42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 301 additions and 19 deletions

View File

@ -25,7 +25,8 @@ TARGET_N64 ?= 1
COMPILER ?= ido
$(eval $(call validate-option,COMPILER,ido gcc))
# options for debuging. Set this to 1 and modify the macros in include/debug.h
# Add debug tools with 'make DEBUG=1' and modify the macros in include/debug.h
# Run make clean first. Add '#define CRASH_SCREEN_ENHANCEMENT' to the top of main.c
DEBUG ?= 0
# VERSION - selects the version of the game to build

View File

@ -116,6 +116,7 @@ SECTIONS
BUILD_DIR/src/audio/external.o(.text);
BUILD_DIR/src/audio/port_eu.o(.text);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.text);
BUILD_DIR/src/debug/debug.o(.text);
BUILD_DIR/src/os/sprintf.o(.text);
#endif
@ -266,6 +267,7 @@ SECTIONS
BUILD_DIR/src/audio/playback.o(.data);
BUILD_DIR/src/audio/effects.o(.data);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.data);
BUILD_DIR/src/debug/debug.o(.data);
BUILD_DIR/src/os/sprintf.o(.data);
#endif
@ -311,6 +313,7 @@ SECTIONS
BUILD_DIR/src/audio/external.o(.rodata);
BUILD_DIR/src/audio/port_eu.o(.rodata);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.rodata);
BUILD_DIR/src/debug/debug.o(.rodata);
BUILD_DIR/src/os/sprintf.o(.rodata);
#endif
@ -346,6 +349,7 @@ SECTIONS
BUILD_DIR/src/code_800AF9B0.o(.bss);
BUILD_DIR/src/menus.o(.bss);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.bss);
BUILD_DIR/src/debug/debug.o(.bss);
BUILD_DIR/src/os/sprintf.o(.bss);
#endif

View File

@ -1,12 +1,20 @@
#include <ultra64.h>
#include <macros.h>
#include "types.h"
#include <types.h>
#include <config.h>
#include <stdarg.h>
#include <string.h>
#include "crash_screen.h"
#ifdef CRASH_SCREEN_ENHANCEMENT
#include "debug/crash_screen_enhancement.h"
#endif
OSThread D_80162790;
ALIGNED8 u8 gDebugThreadStack[0x400];
OSMesgQueue D_80162D40;
OSMesg D_80162D58;
uintptr_t *pFramebuffer;
u16 *pFramebuffer;
s32 sButtonSequenceIndex;
#define DRAW_CODE 0xFFFF
@ -212,17 +220,17 @@ void thread9_crash_screen(UNUSED void *arg0)
osSetEventMesg(10, &D_80162D40, (OSMesg) 16);
sButtonSequenceIndex = 0;
while (1) {
while (TRUE) {
osRecvMesg(&D_80162D40, &mesg, 1);
thread = get_faulted_thread();
if (thread) {
// Run only on the first iteration.
if (sCounter == 0) {
crash_screen_draw_square((u16 *)pFramebuffer);
//#define SKIP_DRAW_SQUARE
#ifndef SKIP_DRAW_SQUARE
while(1)
crash_screen_draw_square(pFramebuffer);
//#define SKIP_DRAW_SQUARE
#ifndef SKIP_DRAW_SQUARE
while(TRUE)
{
read_controllers();
@ -239,8 +247,12 @@ void thread9_crash_screen(UNUSED void *arg0)
break;
}
}
#endif
crash_screen_draw_info((u16 *) pFramebuffer, thread);
#endif
#ifdef CRASH_SCREEN_ENHANCEMENT
crash_screen_draw(thread);
#else
crash_screen_draw_info(pFramebuffer, thread);
#endif
}
if (sCounter < 5) {
@ -250,7 +262,7 @@ void thread9_crash_screen(UNUSED void *arg0)
}
}
void crash_screen_set_framebuffer(uintptr_t *framebuffer) {
void crash_screen_set_framebuffer(u16 *framebuffer) {
pFramebuffer = framebuffer;
}

6
src/crash_screen.h Normal file
View File

@ -0,0 +1,6 @@
#include <ultra64.h>
#include <macros.h>
extern u16 *pFramebuffer;
void crash_screen_set_framebuffer(u16*);

View File

@ -0,0 +1,221 @@
#include <ultra64.h>
#include <macros.h>
#include <types.h>
#include <config.h>
#include <stdarg.h>
#include <string.h>
#include "../crash_screen.h"
#include "crash_screen_enhancement.h"
s32 _Printf(char *(*prout)(char *, const char *, size_t), char *dst, const char *fmt, va_list args);
u32 crashScreenFont2[7 * 9 + 1] = {
0x70871c30,0x8988a250,0x88808290,0x88831c90,0x888402f8,0x88882210,0x71cf9c10,0xf9cf9c70,0x8228a288,0xf200a288,0x0bc11c78,0x0a222208,0x8a222288,0x71c21c70,0x23c738f8,0x5228a480,0x8a282280,0x8bc822f0,0xfa282280,0x8a28a480,0x8bc738f8,0xf9c89c08,0x82288808,0x82088808,0xf2ef8808,0x82288888,0x82288888,0x81c89c70,0x8a08a270,0x920da288,0xa20ab288,0xc20aaa88,0xa208a688,0x9208a288,0x8be8a270,0xf1cf1cf8,0x8a28a220,0x8a28a020,0xf22f1c20,0x82aa0220,0x82492220,0x81a89c20,0x8a28a288,0x8a28a288,0x8a289488,0x8a2a8850,0x894a9420,0x894aa220,0x70852220,0xf8011000,0x08020800,0x10840400,0x20040470,0x40840400,0x80020800,0xf8011000,0x70800000,0x88822200,0x08820400,0x108f8800,0x20821000,0x00022200,0x20800020
};
extern u64 osClockRate;
u8 gCrashScreenCharToGlyph[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, 43, -1, -1, 37, 38, -1, 42,
-1, 39, 44, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 36, -1, -1, -1, -1, 40, -1, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
};
char *gCauseDesc[18] = {
"Interrupt",
"TLB modification",
"TLB exception on load",
"TLB exception on store",
"Address error on load",
"Address error on store",
"Bus error on inst.",
"Bus error on data",
"System call exception",
"Breakpoint exception",
"Reserved instruction",
"Coprocessor unusable",
"Arithmetic overflow",
"Trap exception",
"Virtual coherency on inst.",
"Floating point exception",
"Watchpoint exception",
"Virtual coherency on data",
};
char *gFpcsrDesc[6] = {
"Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow",
"Inexact operation",
};
void crash_screen_draw_glyph_enhancement(s32 x, s32 y, s32 glyph) {
const u32 *data;
u16 *ptr;
u32 bit;
u32 rowMask;
s32 i, j;
data = &crashScreenFont2[glyph / 5 * 7];
ptr = pFramebuffer + SCREEN_WIDTH * y + x;
for (i = 0; i < 7; i++) {
bit = 0x80000000U >> ((glyph % 5) * 6);
rowMask = *data++;
for (j = 0; j < 6; j++) {
*ptr++ = (bit & rowMask) ? 0xffff : 1;
bit >>= 1;
}
ptr += SCREEN_WIDTH - 6;
}
}
void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) {
u16 *ptr;
s32 i, j;
ptr = pFramebuffer + SCREEN_WIDTH * y + x;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
// 0xe738 = 0b1110011100111000
*ptr = ((*ptr & 0xe738) >> 2) | 1;
ptr++;
}
ptr += SCREEN_WIDTH - w;
}
}
static char *write_to_buf(char *buffer, const char *data, size_t size) {
return (char *) memcpy(buffer, data, size) + size;
}
void crash_screen_print(s32 x, s32 y, const char *fmt, ...) {
char *ptr;
u32 glyph;
s32 size;
char buf[0x100];
va_list args;
va_start(args, fmt);
size = _Printf(write_to_buf, buf, fmt, args);
if (size > 0) {
ptr = buf;
while (size > 0) {
glyph = gCrashScreenCharToGlyph[*ptr & 0x7f];
if (glyph != 0xff) {
crash_screen_draw_glyph_enhancement(x, y, glyph);
}
size--;
ptr++;
x += 6;
}
}
va_end(args);
}
void crash_screen_sleep(s32 ms) {
u64 cycles = ms * 1000LL * osClockRate / 1000000ULL;
osSetTime(0);
while (osGetTime() < cycles) {
}
}
void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void *addr) {
u32 bits;
s32 exponent;
bits = *(u32 *) addr;
exponent = ((bits & 0x7f800000U) >> 0x17) - 0x7f;
if ((exponent >= -0x7e && exponent <= 0x7f) || bits == 0) {
crash_screen_print(x, y, "F%02d:%.3e", regNum, *(f32 *) addr);
} else {
crash_screen_print(x, y, "F%02d:---------", regNum);
}
}
void crash_screen_print_fpcsr(u32 fpcsr) {
s32 i;
u32 bit;
bit = 1 << 17;
crash_screen_print(30, 155, "FPCSR:%08XH", fpcsr);
for (i = 0; i < 6; i++) {
if (fpcsr & bit) {
crash_screen_print(132, 155, "(%s)", gFpcsrDesc[i]);
return;
}
bit >>= 1;
}
}
void crash_screen_draw(OSThread* thread) {
s16 cause;
__OSThreadContext *tc = &thread->context;
cause = (tc->cause >> 2) & 0x1f;
if (cause == 23) { // EXC_WATCH
cause = 16;
}
if (cause == 31) { // EXC_VCED
cause = 17;
}
osWritebackDCacheAll();
crash_screen_draw_rect(25, 20, 270, 25);
crash_screen_print(30, 25, "THREAD:%d (%s)", thread->id, gCauseDesc[cause]);
crash_screen_print(30, 35, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr);
crash_screen_sleep(2000);
crash_screen_draw_rect(25, 45, 270, 185);
crash_screen_print(30, 50, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0,
(u32) tc->v1);
crash_screen_print(30, 60, "A0:%08XH A1:%08XH A2:%08XH", (u32) tc->a0, (u32) tc->a1,
(u32) tc->a2);
crash_screen_print(30, 70, "A3:%08XH T0:%08XH T1:%08XH", (u32) tc->a3, (u32) tc->t0,
(u32) tc->t1);
crash_screen_print(30, 80, "T2:%08XH T3:%08XH T4:%08XH", (u32) tc->t2, (u32) tc->t3,
(u32) tc->t4);
crash_screen_print(30, 90, "T5:%08XH T6:%08XH T7:%08XH", (u32) tc->t5, (u32) tc->t6,
(u32) tc->t7);
crash_screen_print(30, 100, "S0:%08XH S1:%08XH S2:%08XH", (u32) tc->s0, (u32) tc->s1,
(u32) tc->s2);
crash_screen_print(30, 110, "S3:%08XH S4:%08XH S5:%08XH", (u32) tc->s3, (u32) tc->s4,
(u32) tc->s5);
crash_screen_print(30, 120, "S6:%08XH S7:%08XH T8:%08XH", (u32) tc->s6, (u32) tc->s7,
(u32) tc->t8);
crash_screen_print(30, 130, "T9:%08XH GP:%08XH SP:%08XH", (u32) tc->t9, (u32) tc->gp,
(u32) tc->sp);
crash_screen_print(30, 140, "S8:%08XH RA:%08XH", (u32) tc->s8, (u32) tc->ra);
crash_screen_print_fpcsr(tc->fpcsr);
crash_screen_print_float_reg(30, 170, 0, &tc->fp0.f.f_even);
crash_screen_print_float_reg(120, 170, 2, &tc->fp2.f.f_even);
crash_screen_print_float_reg(210, 170, 4, &tc->fp4.f.f_even);
crash_screen_print_float_reg(30, 180, 6, &tc->fp6.f.f_even);
crash_screen_print_float_reg(120, 180, 8, &tc->fp8.f.f_even);
crash_screen_print_float_reg(210, 180, 10, &tc->fp10.f.f_even);
crash_screen_print_float_reg(30, 190, 12, &tc->fp12.f.f_even);
crash_screen_print_float_reg(120, 190, 14, &tc->fp14.f.f_even);
crash_screen_print_float_reg(210, 190, 16, &tc->fp16.f.f_even);
crash_screen_print_float_reg(30, 200, 18, &tc->fp18.f.f_even);
crash_screen_print_float_reg(120, 200, 20, &tc->fp20.f.f_even);
crash_screen_print_float_reg(210, 200, 22, &tc->fp22.f.f_even);
crash_screen_print_float_reg(30, 210, 24, &tc->fp24.f.f_even);
crash_screen_print_float_reg(120, 210, 26, &tc->fp26.f.f_even);
crash_screen_print_float_reg(210, 210, 28, &tc->fp28.f.f_even);
crash_screen_print_float_reg(30, 220, 30, &tc->fp30.f.f_even);
osViBlack(FALSE);
osViSwapBuffer(pFramebuffer);
}

View File

@ -0,0 +1,37 @@
#include <ultra64.h>
#include <macros.h>
void crash_screen_draw(OSThread* thread);
// Add this to the top of main.c or crash_screen.c
//#define CRASH_SCREEN_ENHANCEMENT
/**
* Example of how to force crash screen to run.
* Make sure to include the header crash_screen_enhancement.h in main.h
*/
// void display_and_vsync(void) {
// profiler_log_thread5_time(BEFORE_DISPLAY_LISTS);
// osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
// exec_display_list(&gGfxPool->spTask);
// profiler_log_thread5_time(AFTER_DISPLAY_LISTS);
// osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
// osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[sRenderedFramebuffer]));
// profiler_log_thread5_time(THREAD5_END);
// osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
// crash_screen_set_framebuffer((uintptr_t *) gPhysicalFramebuffers[sRenderedFramebuffer]);
// crash_screen_draw((u16 *) gPhysicalFramebuffers[sRenderedFramebuffer], &gGameLoopThread);
// Add this line ^
// if (++sRenderedFramebuffer == 3) {
// sRenderedFramebuffer = 0;
// }
// if (++sRenderingFramebuffer == 3) {
// sRenderingFramebuffer = 0;
// }
// gGlobalTimer++;
// }

View File

@ -33,6 +33,7 @@
#include "actors.h"
#include "staff_ghosts.h"
#include <debug.h>
#include "crash_screen.h"
// Declarations (not in this file)
void func_80091B78(void);
@ -133,7 +134,7 @@ Gfx *gDisplayListHead;
struct SPTask *gGfxSPTask;
s32 D_801502A0;
s32 D_801502A4;
u32 gPhysicalFramebuffers[3];
u16 *gPhysicalFramebuffers[3];
u32 D_801502B4;
UNUSED u32 D_801502B8;
UNUSED u32 D_801502BC;
@ -435,7 +436,6 @@ void config_gfx_pool(void) {
* Yields to the VI framerate twice, locking the game at 30 FPS.
* Selects the next framebuffer to be rendered and displayed.
*/
void crash_screen_set_framebuffer(uintptr_t*);
void display_and_vsync(void) {
profiler_log_thread5_time(BEFORE_DISPLAY_LISTS);
osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
@ -445,7 +445,8 @@ void display_and_vsync(void) {
osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[sRenderedFramebuffer]));
profiler_log_thread5_time(THREAD5_END);
osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
crash_screen_set_framebuffer((uintptr_t *) gPhysicalFramebuffers[sRenderedFramebuffer]);
crash_screen_set_framebuffer(gPhysicalFramebuffers[sRenderedFramebuffer]);
if (++sRenderedFramebuffer == 3) {
sRenderedFramebuffer = 0;
}
@ -1032,16 +1033,15 @@ void thread3_video(UNUSED void *arg0) {
OSMesg msg;
UNUSED s32 pad[4];
gPhysicalFramebuffers[0] = (u32) &gFramebuffer0;
gPhysicalFramebuffers[1] = (u32) &gFramebuffer1;
gPhysicalFramebuffers[2] = (u32) &gFramebuffer2;
gPhysicalFramebuffers[0] = (u16 *) &gFramebuffer0;
gPhysicalFramebuffers[1] = (u16 *) &gFramebuffer1;
gPhysicalFramebuffers[2] = (u16 *) &gFramebuffer2;
// Clear framebuffer.
framebuffer1 = (u64 *) &gFramebuffer1;
for (i = 0; i < 19200; i++) {
framebuffer1[i] = 0;
}
setup_mesg_queues();
setup_game_memory();
@ -1144,6 +1144,7 @@ void thread5_game_loop(UNUSED void *arg) {
if (!wasSoftReset) {
clear_nmi_buffer();
}
set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) OS_EVENT_SW2);
// These variables track stats such as player wins.
// In the event of a console reset, it remembers them.

View File

@ -73,7 +73,7 @@ extern s32 D_800DC56C[];
extern u16 D_80152308;
extern u32 gPhysicalFramebuffers[];
extern u16 *gPhysicalFramebuffers[];
extern OSIoMesg gDmaIoMesg;
extern OSMesg gMainReceivedMesg;
extern OSMesgQueue gDmaMesgQueue;