git.y1.nz

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.