Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/crash_screen.c
7858 views
1
#include <ultra64.h>
2
#include <stdarg.h>
3
#include <string.h>
4
5
#include "sm64.h"
6
7
#if defined(TARGET_N64) && (defined(VERSION_EU) || defined(VERSION_SH))
8
9
#include "lib/src/printf.h"
10
#include "math_util.h"
11
12
u8 gCrashScreenCharToGlyph[128] = {
13
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
14
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, 43, -1, -1, 37, 38, -1, 42,
15
-1, 39, 44, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 36, -1, -1, -1, -1, 40, -1, 10,
16
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
17
33, 34, 35, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
18
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
19
};
20
21
u32 gCrashScreenFont[7 * 9 + 1] = {
22
#include "textures/crash_screen/crash_screen_font.ia1.inc.c"
23
};
24
25
26
char *gCauseDesc[18] = {
27
"Interrupt",
28
"TLB modification",
29
"TLB exception on load",
30
"TLB exception on store",
31
"Address error on load",
32
"Address error on store",
33
"Bus error on inst.",
34
"Bus error on data",
35
"System call exception",
36
"Breakpoint exception",
37
"Reserved instruction",
38
"Coprocessor unusable",
39
"Arithmetic overflow",
40
"Trap exception",
41
"Virtual coherency on inst.",
42
"Floating point exception",
43
"Watchpoint exception",
44
"Virtual coherency on data",
45
};
46
47
char *gFpcsrDesc[6] = {
48
"Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow",
49
"Inexact operation",
50
};
51
52
53
54
extern u64 osClockRate;
55
56
struct {
57
OSThread thread;
58
u64 stack[0x800 / sizeof(u64)];
59
OSMesgQueue mesgQueue;
60
OSMesg mesg;
61
u16 *framebuffer;
62
u16 width;
63
u16 height;
64
} gCrashScreen;
65
66
void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) {
67
u16 *ptr;
68
s32 i, j;
69
70
ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x;
71
for (i = 0; i < h; i++) {
72
for (j = 0; j < w; j++) {
73
// 0xe738 = 0b1110011100111000
74
*ptr = ((*ptr & 0xe738) >> 2) | 1;
75
ptr++;
76
}
77
ptr += gCrashScreen.width - w;
78
}
79
}
80
81
void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) {
82
const u32 *data;
83
u16 *ptr;
84
u32 bit;
85
u32 rowMask;
86
s32 i, j;
87
88
data = &gCrashScreenFont[glyph / 5 * 7];
89
ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x;
90
91
for (i = 0; i < 7; i++) {
92
bit = 0x80000000U >> ((glyph % 5) * 6);
93
rowMask = *data++;
94
95
for (j = 0; j < 6; j++) {
96
*ptr++ = (bit & rowMask) ? 0xffff : 1;
97
bit >>= 1;
98
}
99
ptr += gCrashScreen.width - 6;
100
}
101
}
102
103
static char *write_to_buf(char *buffer, const char *data, size_t size) {
104
return (char *) memcpy(buffer, data, size) + size;
105
}
106
107
void crash_screen_print(s32 x, s32 y, const char *fmt, ...) {
108
char *ptr;
109
u32 glyph;
110
s32 size;
111
char buf[0x100];
112
113
va_list args;
114
va_start(args, fmt);
115
116
size = _Printf(write_to_buf, buf, fmt, args);
117
118
if (size > 0) {
119
ptr = buf;
120
121
#ifdef VERSION_SH
122
while (size > 0) {
123
#else
124
while (*ptr) {
125
#endif
126
127
glyph = gCrashScreenCharToGlyph[*ptr & 0x7f];
128
129
if (glyph != 0xff) {
130
crash_screen_draw_glyph(x, y, glyph);
131
}
132
133
#ifdef VERSION_SH
134
size--;
135
#endif
136
137
ptr++;
138
x += 6;
139
}
140
}
141
142
va_end(args);
143
}
144
145
void crash_screen_sleep(s32 ms) {
146
u64 cycles = ms * 1000LL * osClockRate / 1000000ULL;
147
osSetTime(0);
148
while (osGetTime() < cycles) {
149
}
150
}
151
152
void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void *addr) {
153
u32 bits;
154
s32 exponent;
155
156
bits = *(u32 *) addr;
157
exponent = ((bits & 0x7f800000U) >> 0x17) - 0x7f;
158
if ((exponent >= -0x7e && exponent <= 0x7f) || bits == 0) {
159
crash_screen_print(x, y, "F%02d:%.3e", regNum, *(f32 *) addr);
160
} else {
161
crash_screen_print(x, y, "F%02d:---------", regNum);
162
}
163
}
164
165
void crash_screen_print_fpcsr(u32 fpcsr) {
166
s32 i;
167
u32 bit;
168
169
bit = 1 << 17;
170
crash_screen_print(30, 155, "FPCSR:%08XH", fpcsr);
171
for (i = 0; i < 6; i++) {
172
if (fpcsr & bit) {
173
crash_screen_print(132, 155, "(%s)", gFpcsrDesc[i]);
174
return;
175
}
176
bit >>= 1;
177
}
178
}
179
180
void draw_crash_screen(OSThread *thread) {
181
s16 cause;
182
__OSThreadContext *tc = &thread->context;
183
184
cause = (tc->cause >> 2) & 0x1f;
185
if (cause == 23) // EXC_WATCH
186
{
187
cause = 16;
188
}
189
if (cause == 31) // EXC_VCED
190
{
191
cause = 17;
192
}
193
194
#ifdef VERSION_SH
195
osWritebackDCacheAll();
196
#endif
197
198
crash_screen_draw_rect(25, 20, 270, 25);
199
crash_screen_print(30, 25, "THREAD:%d (%s)", thread->id, gCauseDesc[cause]);
200
crash_screen_print(30, 35, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr);
201
#ifdef VERSION_EU
202
osWritebackDCacheAll();
203
#endif
204
crash_screen_sleep(2000);
205
crash_screen_draw_rect(25, 45, 270, 185);
206
crash_screen_print(30, 50, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0,
207
(u32) tc->v1);
208
crash_screen_print(30, 60, "A0:%08XH A1:%08XH A2:%08XH", (u32) tc->a0, (u32) tc->a1,
209
(u32) tc->a2);
210
crash_screen_print(30, 70, "A3:%08XH T0:%08XH T1:%08XH", (u32) tc->a3, (u32) tc->t0,
211
(u32) tc->t1);
212
crash_screen_print(30, 80, "T2:%08XH T3:%08XH T4:%08XH", (u32) tc->t2, (u32) tc->t3,
213
(u32) tc->t4);
214
crash_screen_print(30, 90, "T5:%08XH T6:%08XH T7:%08XH", (u32) tc->t5, (u32) tc->t6,
215
(u32) tc->t7);
216
crash_screen_print(30, 100, "S0:%08XH S1:%08XH S2:%08XH", (u32) tc->s0, (u32) tc->s1,
217
(u32) tc->s2);
218
crash_screen_print(30, 110, "S3:%08XH S4:%08XH S5:%08XH", (u32) tc->s3, (u32) tc->s4,
219
(u32) tc->s5);
220
crash_screen_print(30, 120, "S6:%08XH S7:%08XH T8:%08XH", (u32) tc->s6, (u32) tc->s7,
221
(u32) tc->t8);
222
crash_screen_print(30, 130, "T9:%08XH GP:%08XH SP:%08XH", (u32) tc->t9, (u32) tc->gp,
223
(u32) tc->sp);
224
crash_screen_print(30, 140, "S8:%08XH RA:%08XH", (u32) tc->s8, (u32) tc->ra);
225
crash_screen_print_fpcsr(tc->fpcsr);
226
#ifdef VERSION_EU
227
osWritebackDCacheAll();
228
#endif
229
crash_screen_print_float_reg(30, 170, 0, &tc->fp0.f.f_even);
230
crash_screen_print_float_reg(120, 170, 2, &tc->fp2.f.f_even);
231
crash_screen_print_float_reg(210, 170, 4, &tc->fp4.f.f_even);
232
crash_screen_print_float_reg(30, 180, 6, &tc->fp6.f.f_even);
233
crash_screen_print_float_reg(120, 180, 8, &tc->fp8.f.f_even);
234
crash_screen_print_float_reg(210, 180, 10, &tc->fp10.f.f_even);
235
crash_screen_print_float_reg(30, 190, 12, &tc->fp12.f.f_even);
236
crash_screen_print_float_reg(120, 190, 14, &tc->fp14.f.f_even);
237
crash_screen_print_float_reg(210, 190, 16, &tc->fp16.f.f_even);
238
crash_screen_print_float_reg(30, 200, 18, &tc->fp18.f.f_even);
239
crash_screen_print_float_reg(120, 200, 20, &tc->fp20.f.f_even);
240
crash_screen_print_float_reg(210, 200, 22, &tc->fp22.f.f_even);
241
crash_screen_print_float_reg(30, 210, 24, &tc->fp24.f.f_even);
242
crash_screen_print_float_reg(120, 210, 26, &tc->fp26.f.f_even);
243
crash_screen_print_float_reg(210, 210, 28, &tc->fp28.f.f_even);
244
crash_screen_print_float_reg(30, 220, 30, &tc->fp30.f.f_even);
245
#ifdef VERSION_EU
246
osWritebackDCacheAll();
247
#endif
248
osViBlack(FALSE);
249
osViSwapBuffer(gCrashScreen.framebuffer);
250
}
251
252
OSThread *get_crashed_thread(void) {
253
OSThread *thread;
254
255
thread = __osGetCurrFaultedThread();
256
while (thread->priority != -1) {
257
if (thread->priority > OS_PRIORITY_IDLE && thread->priority < OS_PRIORITY_APPMAX
258
&& (thread->flags & 3) != 0) {
259
return thread;
260
}
261
thread = thread->tlnext;
262
}
263
return NULL;
264
}
265
266
void thread2_crash_screen(UNUSED void *arg) {
267
OSMesg mesg;
268
OSThread *thread;
269
270
osSetEventMesg(OS_EVENT_CPU_BREAK, &gCrashScreen.mesgQueue, (OSMesg) 1);
271
osSetEventMesg(OS_EVENT_FAULT, &gCrashScreen.mesgQueue, (OSMesg) 2);
272
do {
273
osRecvMesg(&gCrashScreen.mesgQueue, &mesg, 1);
274
thread = get_crashed_thread();
275
} while (thread == NULL);
276
draw_crash_screen(thread);
277
for (;;) {
278
}
279
}
280
281
void crash_screen_set_framebuffer(u16 *framebuffer, u16 width, u16 height) {
282
#ifdef VERSION_EU
283
gCrashScreen.framebuffer = framebuffer;
284
#else
285
gCrashScreen.framebuffer = (u16 *)((uintptr_t)framebuffer | 0xa0000000);
286
#endif
287
gCrashScreen.width = width;
288
gCrashScreen.height = height;
289
}
290
291
void crash_screen_init(void) {
292
#ifdef VERSION_EU
293
gCrashScreen.framebuffer = (u16 *) (osMemSize | 0x80000000) - SCREEN_WIDTH * SCREEN_HEIGHT;
294
#else
295
gCrashScreen.framebuffer = (u16 *) (osMemSize | 0xA0000000) - SCREEN_WIDTH * SCREEN_HEIGHT;
296
#endif
297
gCrashScreen.width = SCREEN_WIDTH;
298
#ifdef VERSION_EU
299
gCrashScreen.height = SCREEN_HEIGHT;
300
#else
301
gCrashScreen.height = 0x10;
302
#endif
303
osCreateMesgQueue(&gCrashScreen.mesgQueue, &gCrashScreen.mesg, 1);
304
osCreateThread(&gCrashScreen.thread, 2, thread2_crash_screen, NULL,
305
(u8 *) gCrashScreen.stack + sizeof(gCrashScreen.stack),
306
#ifdef VERSION_EU
307
OS_PRIORITY_APPMAX
308
#else
309
OS_PRIORITY_RMON
310
#endif
311
);
312
osStartThread(&gCrashScreen.thread);
313
}
314
315
#endif
316
317