panic screen, debug font, asmutil.s
[gbajam21] / src / debug.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <stdarg.h>
4 #include "gbaregs.h"
5 #include "intr.h"
6 #include "debug.h"
7 #include "util.h"
8
9 uint16_t vblperf_color[] = {
10         /* grn  cyan  yellow  orng    red    purple ... */
11         /* 60    30     20     15     12      10 ... */
12         0x3e0, 0xffc0, 0x3ff, 0x1ff, 0x001f, 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0xf81f
13 };
14
15 static void vblperf_intr(void)
16 {
17         vblperf_count++;
18 }
19
20 void vblperf_start(int palidx)
21 {
22         vblperf_palptr = (uint16_t*)CRAM_BG_ADDR + palidx;
23         intr_disable();
24         REG_DISPSTAT |= DISPSTAT_IEN_VBLANK;
25         interrupt(INTR_VBLANK, vblperf_intr);
26         unmask(INTR_VBLANK);
27         intr_enable();
28 }
29
30 void vblperf_stop(void)
31 {
32         intr_disable();
33         REG_DISPSTAT &= ~DISPSTAT_IEN_VBLANK;
34         interrupt(INTR_VBLANK, 0);
35         mask(INTR_VBLANK);
36         intr_enable();
37 }
38
39 uint32_t panic_regs[16];
40 void get_panic_regs(void);
41
42 void panic(uint32_t pc, const char *fmt, ...)
43 {
44         int y;
45         va_list ap;
46         uint32_t *reg;
47
48         get_panic_regs();
49
50         intr_disable();
51         REG_DISPCNT = 4 | DISPCNT_BG2;
52
53         set_bg_color(0, 31, 0, 0);
54         set_bg_color(0xff, 31, 31, 31);
55
56         fillblock_16byte((void*)VRAM_LFB_FB0_ADDR, 0, 240 * 160 / 16);
57
58         fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * 3, 0xffffffff, 240 / 16);
59         dbg_drawstr(44, 0, " Panic at %08x ", pc);
60
61         va_start(ap, fmt);
62         y = dbg_vdrawstr(0, 12, fmt, ap) + 8;
63         va_end(ap);
64
65         fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * (y + 4), 0xffffffff, 240 / 16);
66         y += 8;
67
68         reg = panic_regs;
69         y = dbg_drawstr(0, y, " r0 %08x  r1 %08x\n r2 %08x  r3 %08x\n r4 %08x  r5 %08x\n r6 %08x  r7 %08x\n",
70                         reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]);
71         y = dbg_drawstr(0, y, " r8 %08x  r9 %08x\nr10 %08x r11 %08x\n ip %08x  sp %08x\n lr %08x  pc %08x\n",
72                         reg[8], reg[9], reg[10], reg[11], reg[12], reg[13], reg[14], reg[15]);
73
74         for(;;);
75 }
76
77 void dbg_drawglyph(int x, int y, int c)
78 {
79         int i;
80         uint16_t pp;
81         unsigned char row;
82         uint16_t *ptr = (uint16_t*)VRAM_LFB_FB0_ADDR + (y << 7) - (y << 3) + (x >> 1);
83         unsigned char *fnt = font_8x8 + ((c & 0xff) << 3);
84
85         for(i=0; i<8; i++) {
86                 row = *fnt++;
87                 pp = row & 0x80 ? 0xff : 0;
88                 *ptr++ = pp | (row & 0x40 ? 0xff00 : 0);
89                 pp = row & 0x20 ? 0xff : 0;
90                 *ptr++ = pp | (row & 0x10 ? 0xff00 : 0);
91                 pp = row & 0x08 ? 0xff : 0;
92                 *ptr++ = pp | (row & 0x04 ? 0xff00 : 0);
93                 pp = row & 0x02 ? 0xff : 0;
94                 *ptr++ = pp | (row & 0x01 ? 0xff00 : 0);
95                 ptr += 120 - 4;
96         }
97 }
98
99 int dbg_vdrawstr(int x, int y, const char *fmt, va_list ap)
100 {
101         int startx, c;
102         char buf[128];
103         char *ptr = buf;
104
105         vsnprintf(buf, sizeof buf, fmt, ap);
106
107         startx = x;
108         while(*ptr) {
109                 if(y >= 160) break;
110
111                 c = *ptr++;
112                 switch(c) {
113                 case '\n':
114                         y += 8;
115                 case '\r':
116                         x = startx;
117                         break;
118
119                 default:
120                         dbg_drawglyph(x, y, c);
121                         x += 8;
122                         if(x >= 240 - 8) {
123                                 while(*ptr && isspace(*ptr)) ptr++;
124                                 x = 0;
125                                 y += 8;
126                         }
127                 }
128         }
129
130         return y;
131 }
132
133 int dbg_drawstr(int x, int y, const char *fmt, ...)
134 {
135         int res;
136         va_list ap;
137
138         va_start(ap, fmt);
139         res = dbg_vdrawstr(x, y, fmt, ap);
140         va_end(ap);
141         return res;
142 }
143
144 #ifdef EMUBUILD
145 __attribute__((target("arm")))
146 void emuprint(const char *fmt, ...)
147 {
148         char buf[128];
149         va_list ap;
150
151         va_start(ap, fmt);
152         vsnprintf(buf, sizeof buf, fmt, ap);
153         va_end(ap);
154
155         asm volatile(
156                 "mov r0, %0\n\t"
157                 "swi 0xff0000\n\t" :
158                 : "r" (buf)
159                 : "r0"
160         );
161 }
162 #else
163 void emuprint(const char *fmt, ...)
164 {
165 }
166 #endif