cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

crash_handler.s (8875B)


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