gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/libc/targets/sm83/gb/crash_handler.s
1 ; Crash handler support
2 ; Original code by ISSOtm
3 ; Adapted by Toxa from gb-starter-kit: https://github.com/ISSOtm/gb-starter-kit
4
5 .include "global.s"
6
7 .globl _font_ibm
8
9 SCRN_X = 160 ; Width of screen in pixels
10 SCRN_Y = 144 ; Height of screen in pixels
11 SCRN_X_B = 20 ; Width of screen in bytes
12 SCRN_Y_B = 18 ; Height of screen in bytes
13
14 SCRN_VX = 256 ; Virtual width of screen in pixels
15 SCRN_VY = 256 ; Virtual height of screen in pixels
16 SCRN_VX_B = 32 ; Virtual width of screen in bytes
17 SCRN_VY_B = 32 ; Virtual height of screen in bytes
18
19
20 .area _CRASH_HEADER(ABS)
21
22 .org 0x00
23 nop
24 nop
25 rst 0x38
26
27 .org 0x38
28 di
29 jp ___HandleCrash
30
31
32 .area _HOME
33
34 ___HandleCrash::
35
36 ; We will use VRAM as scratch, since we are going to overwrite it for
37 ; screen output anyways. The thing is, we need to turn the LCD off
38 ; *without* affecting flags... fun task, eh?
39
40 ; Note: it's assumed that this was jumped to with IME off.
41 ; Don't call this directly, use `rst Crash`.
42
43 ld (wCrashA), a ; We need to have at least one working register, so...
44 ldh a, (rIE) ; We're also going to overwrite this
45 ld (wCrashIE), a
46 ldh a, (rLCDC)
47 ld (wCrashLCDC), a
48 ld a, #LCDCF_ON ; LCDCF_ON Make sure the LCD is turned on to avoid waiting infinitely
49 ldh (rLCDC), a
50 ld a, #IEF_VBLANK ; IEF_VBLANK
51 ldh (rIE), a
52 ld a, #0 ; `xor a` would overwrite flags
53 ldh (rIF), a ; No point in backing up that register, it's always changing
54 halt ; With interrupts disabled, this will exit when `IE & IF != 0`
55 nop ; Handle hardware bug if it becomes true *before* starting to execute the instruction (1-cycle window)
56
57 ; We're now in VBlank! So we can now use VRAM as scratch for some cycles
58 ld a, #0
59 ldh (rLCDC), a ; Turn off LCD so VRAM can always be safely accessed
60 ; Save regs
61 ld (vCrashSP), sp
62 ld sp, #vCrashSP
63 push hl
64 push de
65 push bc
66 ld a, (wCrashA)
67 push af
68
69 ; We need to have all the data in bank 0, but we can't guarantee we were there
70 ldh a, (rVBK)
71 ld e, a
72 bit #0, a
73 jr z, .bank0
74 ; Oh noes. We need to copy the data across banks!
75 ld hl, #vCrashAF
76 ld c, #(5 * 2)
77 .copyAcross:
78 ld b, (hl)
79 xor a
80 ldh (rVBK), a
81 ld (hl), b
82 inc l ; inc hl
83 inc a ; ld a, 1
84 ldh (rVBK), a
85 dec c
86 jr nz, .copyAcross
87 .bank0:
88 xor a
89 ldh (rAUDENA), a ; Kill sound for this screen
90
91 ldh (rVBK), a
92 ld a, e
93 ld (vCrashVBK), a ; copy vCrashVBK across banks
94
95 ld a, #1
96 ldh (rVBK), a
97 ld hl, #vCrashDumpScreen
98 ld b, #SCRN_Y_B
99 .writeAttrRow:
100 xor a
101 ld c, #(SCRN_X_B + 1)
102 rst #0x28 ; .MemsetSmall
103 ld a, l
104 add a, #(SCRN_VX_B - SCRN_X_B - 1)
105 ld l, a
106 dec b
107 jr nz, .writeAttrRow
108 xor a
109 ldh (rVBK), a
110
111 ; Load palettes
112 ld a, #0x03
113 ldh (rBGP), a
114 ld a, #0x80
115 ldh (rBCPS), a
116 xor a
117 ld c, #rBCPD
118 ldh (c), a
119 ldh (c), a
120 dec a ; ld a, $FF
121 ldh (c), a
122 ldh (c), a
123 ldh (c), a
124 ldh (c), a
125 ldh (c), a
126 ldh (c), a
127
128 ld a, #(SCRN_VY - SCRN_Y)
129 ldh (rSCY), a
130 ld a, #(SCRN_VX - SCRN_X - 4)
131 ldh (rSCX), a
132
133 call loadfont
134
135 ; Copy the registers to the dump viewers
136 ld hl, #vDumpHL
137 ld de, #vCrashHL
138 ld c, #4
139 rst #0x30 ; .MemcpySmall
140
141 ; We're now going to draw the screen, top to bottom
142 ld hl, #vCrashDumpScreen
143
144 ; First 3 lines of text
145 ld de, #.header
146 ld b, #3
147 .writeHeaderLine:
148 ld a, #0x20 ; " "
149 ld (hl+), a
150 ld c, #19
151 rst #0x30 ; .MemcpySmall
152 ld a, #0x20 ; " "
153 ld (hl+), a
154 ld a, l
155 add a, #(SCRN_VX_B - SCRN_X_B - 1)
156 ld l, a
157 dec b
158 jr nz, .writeHeaderLine
159
160 ; Blank line
161 ld a, #0x20 ; " "
162 ld c, #(SCRN_X_B + 1)
163 rst #0x28 ; .MemsetSmall
164
165 ; AF and console model
166 ld l, #<vCrashDumpScreenRow4
167 ld c, #4
168 rst #0x30 ; .MemcpySmall
169 pop bc
170 call .printHexBC
171 ld c, #8
172 rst #0x30 ; .MemcpySmall
173 ld a, (__cpu)
174 call .printHexA
175 ld a, #0x20 ; " "
176 ld (hl+), a
177 ld (hl+), a
178 ld (hl+), a
179
180 ; BC and DE
181 ld l, #<vCrashDumpScreenRow5
182 ld c, #4
183 rst #0x30 ; .MemcpySmall
184 pop bc
185 call .printHexBC
186 ld c, #6
187 rst #0x30 ; .MemcpySmall
188 pop bc
189 call .printHexBC
190 ld a, #0x20
191 ld (hl+), a
192 ld (hl+), a
193 ld (hl+), a
194
195 ; Now, the two memory dumps
196 .writeDump:
197 ld a, l
198 add a, #(SCRN_VX_B - SCRN_X_B - 1)
199 ld l, a
200 ld c, #4
201 rst #0x30 ; .MemcpySmall
202 pop bc
203 push bc
204 call .printHexBC
205 ld de, #.viewStr
206 ld c, #7
207 rst #0x30 ; .MemcpySmall
208 pop de
209 call .printDump
210 ld de, #.spStr
211 bit #7, l
212 jr z, .writeDump
213
214 ld de, #.hwRegsStrs
215 ld l, #<vCrashDumpScreenRow14
216 ld c, #6
217 rst #0x30 ; .MemcpySmall
218 ld a, (wCrashLCDC)
219 call .printHexA
220 ld c, #4
221 rst #0x30 ; .MemcpySmall
222 ldh a, (rKEY1)
223 call .printHexA
224 ld c, #4
225 rst #0x30 ; .MemcpySmall
226 ld a, (wCrashIE)
227 call .printHexA
228 ld (hl), #0x20 ; " "
229
230 ld l, #<vCrashDumpScreenRow15
231 ld c, #7
232 rst #0x30 ; .MemcpySmall
233 .writeBank:
234 ld a, #0x20 ; " "
235 ld (hl+), a
236 ld a, (de)
237 inc de
238 ld (hl+), a
239 cp #0x20 ; " "
240 jr z, .banksDone
241 ld a, (de)
242 inc de
243 ld c, a
244 ld a, (de)
245 inc de
246 ld b, a
247 ld a, (bc)
248 call .printHexA
249 jr .writeBank
250 .banksDone:
251
252 ; Start displaying
253 ld a, #(LCDCF_ON | LCDCF_BG9C00 | LCDCF_BGON)
254 ldh (rLCDC), a
255
256 .loop:
257 ; The code never lags, and IE is equal to IEF_VBLANK
258 xor a
259 ldh (rIF), a
260 halt
261 nop
262
263 jr .loop
264
265 .printHexBC:
266 call .printHexB
267 ld a, c
268 .printHexA:
269 ld b, a
270 .printHexB:
271 ld a, b
272 and #0xF0
273 swap a
274 add a, #0x30
275 cp #0x3a
276 jr c, 1$
277 add a, #(0x41 - 0x3a)
278 1$: ld (hl+), a
279 ld a, b
280 and #0x0F
281 add a, #0x30
282 cp #0x3a
283 jr c, 2$
284 add a, #(0x41 - 0x3a)
285 2$: ld (hl+), a
286 ret
287
288 .printDump:
289 ld b, d
290 ld c, e
291 call .printHexBC
292 ld a, #0x20 ; " "
293 ld (hl+), a
294 ld (hl+), a
295 ld a, e
296 sub #8
297 ld e, a
298 ld a, d
299 sbc #0
300 ld d, a
301 .writeDumpLine:
302 ld a, l
303 add a, #(SCRN_VX_B - SCRN_X_B - 1)
304 ld l, a
305 ld a, #0x20 ; " "
306 ld (hl+), a
307 .writeDumpWord:
308 ld a, (de)
309 inc de
310 call .printHexA
311 ld a, (de)
312 inc de
313 call .printHexA
314 ld a, #0x20 ; " "
315 ld (hl+), a
316 bit 4, l
317 jr nz, .writeDumpWord
318 ld a, l
319 and #0x7F
320 jr nz, .writeDumpLine
321 ret
322
323 loadfont:
324 xor a
325 cpl
326 ld hl, #0x9000
327 ld c, #16
328 rst #0x28 ; .MemsetSmall
329 ld hl, #(0x9000 + ' ' * 16)
330 ld c, #16
331 rst #0x28 ; .MemsetSmall
332
333 ld de, #(_font_ibm + 2 + '0') ; recode table
334 ld hl, #(0x9000 + '0' * 16) ; destination
335 push hl
336 ld c, #(16 * 3)
337 1$:
338 ld a, (de)
339 inc de
340 push de
341
342 swap a
343 ld l, a
344 and #0x0f
345 ld h, a
346 ld a, l
347 and #0xf0
348 srl h
349 rra
350 ld l, a
351 ld de, #(_font_ibm + 2 + 128)
352 add hl, de
353
354 ld d, h
355 ld e, l
356
357 ldhl sp, #2
358 ld a, (hl+)
359 ld h, (hl)
360 ld l, a
361
362 ld b, #8
363 2$:
364 ld a, (de)
365 cpl
366 inc de
367 ld (hl+), a
368 ld (hl+), a
369
370 dec b
371 jr nz, 2$
372
373 ld d, h
374 ld a, l
375 ldhl sp, #2
376 ld (hl+), a
377 ld (hl), d
378
379 pop de
380
381 dec c
382 jr nz, 1$
383
384 add sp, #2
385 ret
386
387 .header:
388 ; 0123456789ABCDEFGHI 19 chars
389 .ascii "KERNEL PANIC PLEASE"
390 .ascii "SEND A CLEAR PIC OF"
391 .ascii "THIS SCREEN TO DEVS"
392 .ascii " AF:"
393 .ascii " MODEL:"
394 .ascii " BC:"
395 .ascii " DE:"
396 .ascii " HL:"
397 .viewStr:
398 .ascii " VIEW:"
399 .spStr:
400 .ascii " SP:"
401 .hwRegsStrs:
402 .ascii " LCDC:"
403 .ascii " K1:"
404 .ascii " IE:"
405 .ascii " BANK:"
406 .ascii "R"
407 .dw __current_bank
408 .ascii "V"
409 .dw vCrashVBK
410 .ascii "W"
411 .dw rSVBK
412 .ascii " "
413
414
415 .area _DATA
416
417 wCrashA:
418 .ds 1 ; We need at least one working register, and A allows accessing memory
419 wCrashIE:
420 .ds 1
421 wCrashLCDC:
422 .ds 1
423
424
425 .area _CRASH_SCRATCH(ABS)
426
427 .org 0x9C00
428
429 ; Put the crash dump screen at the bottom-right of the 9C00 tilemap, since that tends to be unused space
430 .ds SCRN_VX_B * (SCRN_VY_B - SCRN_Y_B - 2) ; 2 rows reserved as scratch space
431
432 .ds SCRN_X_B ; Try not to overwrite the window area
433 .ds 2 * 1 ; Free stack entries (we spill into the above by 1 entry, though :/)
434 ; These are the initial values of the registers
435 ; They are popped off the stack when printed, freeing up stack space
436
437 vCrashAF:
438 .ds 2
439 vCrashBC:
440 .ds 2
441 vCrashDE:
442 .ds 2
443 vCrashHL:
444 .ds 2
445 vCrashSP:
446 .ds 2
447
448 .ds SCRN_X_B
449 vHeldKeys:
450 .ds 1 ; Keys held on previous frame
451 vUnlockCounter:
452 .ds 1 ; How many frames until dumps are "unlocked"
453 vWhichDump:
454 .ds 1
455 vDumpHL:
456 .ds 2
457 vDumpSP:
458 .ds 2
459 vCrashVBK:
460 .ds 1
461 .ds 4 ; Unused
462
463 .ds SCRN_VX_B - SCRN_X_B - 1
464 vCrashDumpScreen:
465 vCrashDumpScreenRow0 = vCrashDumpScreen + 1 * SCRN_VX_B
466 vCrashDumpScreenRow1 = vCrashDumpScreen + 2 * SCRN_VX_B
467 vCrashDumpScreenRow2 = vCrashDumpScreen + 3 * SCRN_VX_B
468 vCrashDumpScreenRow3 = vCrashDumpScreen + 4 * SCRN_VX_B
469 vCrashDumpScreenRow4 = vCrashDumpScreen + 5 * SCRN_VX_B
470 vCrashDumpScreenRow5 = vCrashDumpScreen + 6 * SCRN_VX_B
471 vCrashDumpScreenRow6 = vCrashDumpScreen + 7 * SCRN_VX_B
472 vCrashDumpScreenRow7 = vCrashDumpScreen + 8 * SCRN_VX_B
473 vCrashDumpScreenRow8 = vCrashDumpScreen + 9 * SCRN_VX_B
474 vCrashDumpScreenRow9 = vCrashDumpScreen + 10 * SCRN_VX_B
475 vCrashDumpScreenRow10 = vCrashDumpScreen + 11 * SCRN_VX_B
476 vCrashDumpScreenRow11 = vCrashDumpScreen + 12 * SCRN_VX_B
477 vCrashDumpScreenRow12 = vCrashDumpScreen + 13 * SCRN_VX_B
478 vCrashDumpScreenRow13 = vCrashDumpScreen + 14 * SCRN_VX_B
479 vCrashDumpScreenRow14 = vCrashDumpScreen + 15 * SCRN_VX_B
480 vCrashDumpScreenRow15 = vCrashDumpScreen + 16 * SCRN_VX_B
481 vCrashDumpScreenRow16 = vCrashDumpScreen + 17 * SCRN_VX_B
482 vCrashDumpScreenRow17 = vCrashDumpScreen + 18 * SCRN_VX_B
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.