Files
SpaghettiKart/src/crash_screen.c
coco875 a1f0d32d66 Update decomp clang (#67)
* Update menus.c (#634)

* Update common_data.yml (#635)

* Renames for screenId and other changes (#636)

* screenId renames

* Rename surface map to collision mesh (#637)

* Rename some stack vars (#638)

* Fix syntax error (#639)

* Rename some stack vars

* Update collision.c

* Collision Documentation (#640)

* Collision related renames

* update doxygen (#649)

* change bool (#644)

Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>

* Update (#642)

* Delete trig_tables_bss.c (#650)

* fix typo audio (#656)

* fix typo src actor (#657)

Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>

* fix typo include (#658)

* fix course (#659)

* fix typo debug (#660)

* fix typo data (#661)

* replace number with const (#665)

* fix typo buffers (#655)

* fix typo buffers

* tweak ld file

* rename to sMemoryPool

* add a warning

---------

* fix typo src (#654)

* fix typo src

* fix non matcing

* Update code_80091750.c

---------

* fix typo racing (#653)

* fix typo racing

* get it match

* replace G_LINE3D to G_QUAD

---------

* fix typo src (#652)

* fix ending typo (#651)

* Action more info when it doesn't match and fix first diff (#662)

* Update linux-compile.yml

* fix first-diff

* Update first-diff.py

---------

* document texture of kart (#663)

* document texture of kart

* change screenPlayerId to screenId

* some documentation around object

* Revert "some documentation around object"

This reverts commit cbb39078e036bf2a417bed67359e910213acab28.

* more rename

---------

* Make evaluate_collision_players_palm_tree better (#667)

This matches just the same as before,	but using those two casts instead of
shifts seems more likely to be accurate to the original source code

Signed-off-by: Gabriel Ravier <gabravier@gmail.com>

* add fedora instruciton (#666)

* start documenting animation (#668)

* start documenting animation

* Update course_data.c

* change comment

* update libultra asm (#648)

* update libultra asm

* fix gcc __osThreadTail

---------

* Document Vehicles (#641)

* start doc collision

* fix merge

* finish rename fonction related to vehicle

* document around waypoint of vehicle

* make some modification

* make some change and rename one

* copy_ to oldPos

* doc smoke ferry and train

* some rename

* fix some renaming

* precise index

* rename a funciton

* simplify waypoint_vehicles

* change some name

* change some name

* rename move_to_point_direction

* fix some conflict

* Update code_80005FD0.c

* Update code_80005FD0.h

---------

* Label a save info loop (#645)

* save info

* more gcc progress

* fix a value and do a rename (#669)

* update clang and add action (#664)

* update clang and add action

* try clang on course folder only

* forget two file

* Update course_displaylists.inc.c

* forget few other file

* Update course_vertices.inc.c

* format all code while get it match

* second pass

* format other dir

* disable clang format on bad ido code

* fix some tabulation

* revert format on tool dir

* Update clang-format.yml

* ignore gbi.h

* add some read me instruction

* fix error

* format and fixing error

* Update README.md

---------

* Update linkonly_generator.py (#670)

* format more file

* update

* fix compilation issue

* remove course_metadata folder

* re add course metadata folder

* fix banshee bordwalk crash

* fix windows eurk

* Update CMakeLists.txt

---------
2024-08-27 17:47:39 -06:00

259 lines
7.1 KiB
C

#include <libultraship.h>
#include <macros.h>
#include <mk64.h>
#include <stdarg.h>
#include <string.h>
#include "crash_screen.h"
#include "main.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;
u16* pFramebuffer;
s32 sButtonSequenceIndex;
#define DRAW_CODE 0xFFFF
#define CHARACTER_DASH 16
extern void osSetEventMesg(OSEvent, OSMesgQueue*, OSMesg);
extern s32 osRecvMesg(OSMesgQueue*, OSMesg*, s32);
s32 sCounter = 0;
#ifdef TARGET_N64
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;
}
}
}
void crash_screen_draw_square(u16* framebuffer);
// Functionally Equivallent.
#ifdef NON_MATCHING
// 0xRGBA (I think A maybe not).
#define WHITE_COLOUR 0xFFFF
#define RED_COLOUR 0xF801
/**
* The big mismatch is the handling of the '6' used in the if statement
* In the target assembly that 6 is saved to 5 different temp registers,
* while in this non-matching decomp its only saved to one temp register.
* This seems to be related to how the innermost for loop is unrolled, but
* its not clear why the target assembley would save the same immediate to
* 5 different registers instead of just re-using one
* There's some stack related differences too, maybe that's related?
**/
void crash_screen_draw_square(u16* framebuffer) {
s32 s0_end;
s32 s2_start;
s32 row;
s32 column;
for (s2_start = 0x28, s0_end = s2_start + 6; s0_end != 0x2C; s0_end--, s2_start++) {
for (row = s2_start; row < s0_end; row++) {
for (column = s2_start; column < s0_end; column++) {
framebuffer[row * 320 + column] = s0_end - s2_start == 6 ? 0xF801 : 0xFFFF;
}
}
}
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
**/
// 0xRGBA
#define BLACK_COLOUR 0x0001
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)] = BLACK_COLOUR;
}
}
}
// 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, newMesg);
osSetEventMesg(10, &D_80162D40, newMesg);
sButtonSequenceIndex = 0;
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(pFramebuffer);
#ifndef DEBUG
while (true) {
read_controllers();
if (!gControllerOne->buttonPressed) {
continue;
}
if (!gControllerOne->buttonPressed) {
continue;
}
// draws crash info when DRAW_CODE is reached
if (sCrashScreenButtonSequence[sButtonSequenceIndex] == DRAW_CODE) {
break;
}
}
#endif
#if DEBUG
crash_screen_draw(thread);
#else
crash_screen_draw_info(pFramebuffer, thread);
#endif
}
if (sCounter < 5) {
sCounter++;
}
}
}
}
#endif
void crash_screen_set_framebuffer(u16* framebuffer) {
pFramebuffer = framebuffer;
}
extern void thread9_crash_screen(void*);
void create_debug_thread(void) {
#ifdef TARGET_N64
osCreateMesgQueue(&D_80162D40, &D_80162D58, 1);
osCreateThread((OSThread*) &D_80162790, 9, (void*) thread9_crash_screen, 0, &D_80162D40, 0x7F);
#endif
}
void start_debug_thread(void) {
// osStartThread(&D_80162790);
}