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/crt0.s
1 .include "global.s"
2
3 ;; ****************************************
4 ;; Beginning of module
5 ;; BANKED: checked
6 .title "Runtime"
7 .module Runtime
8 .area _HEADER (ABS)
9
10 ;; RST vectors
11 ; .org 0x00 ; Trap, utilized by crash_handler.h
12
13 ; .org 0x08 ; --profile handler utilized by emu_debug.h
14
15 ; .org 0x10 ; empty
16
17 ; .org 0x18 ; empty
18
19 .org 0x20 ; RST 0x20 == call HL
20 .call_hl::
21 JP (HL)
22
23 .org 0x28 ; zero up to 256 bytes in C pointed by HL
24 .MemsetSmall::
25 LD (HL+),A
26 DEC C
27 RET Z
28 LD (HL+),A
29 DEC C
30 JR NZ,.MemsetSmall
31 ret
32
33 .org 0x30 ; copy up to 256 bytes in C from DE to HL
34 .MemcpySmall::
35 LD A, (DE)
36 LD (HL+), A
37 INC DE
38 DEC C
39 JR NZ,.MemcpySmall
40 RET
41
42 ; .org 0x38 ; crash handler utilized by crash_handler.h
43
44 ;; Hardware interrupt vectors
45 .org 0x40 ; VBL
46 .int_VBL:
47 PUSH AF
48 PUSH HL
49 LD HL,#.int_0x40
50 JP .int
51
52 ; .org 0x48 ; LCD
53
54 ; .org 0x50 ; TIM
55
56 ; .org 0x58 ; SIO
57
58 ; .org 0x60 ; JOY
59
60 ; .org 0x70
61 ;; space for drawing.s bit table
62
63 .org 0x80
64 .int::
65 PUSH BC
66 PUSH DE
67 1$:
68 LD A,(HL+)
69 OR (HL)
70 JR Z,.int_tail
71 PUSH HL
72 LD A,(HL-)
73 LD L,(HL)
74 LD H,A
75 RST 0x20 ; .call_hl
76 POP HL
77 INC HL
78 JR 1$
79 _wait_int_handler::
80 ADD SP,#4
81 .int_tail:
82 POP DE
83 POP BC
84 POP HL
85
86 ;; we return at least at the beginning of mode 2
87 WAIT_STAT
88
89 POP AF
90 RETI
91
92 ;; VBlank default interrupt routine
93 __standard_VBL_handler::
94 .std_vbl:
95 LD HL,#.sys_time
96 INC (HL)
97 JR NZ,2$
98 INC HL
99 INC (HL)
100 2$:
101 LD A, #1
102 LDH (.vbl_done),A
103
104 JP .refresh_OAM
105
106 _refresh_OAM::
107 WAIT_STAT
108 LD A, #>_shadow_OAM
109 JP .refresh_OAM_DMA
110
111 .clear_WRAM:
112 XOR A
113 LD BC, #l__DATA
114 LD HL, #s__DATA
115 CALL .memset_simple
116
117 LD A, #>_shadow_OAM
118 LDH (__shadow_OAM_base), A
119 LD H, A
120 XOR A
121 LD L, A
122 LD C, #(40 << 2) ; 40 entries 4 bytes each
123 JP .MemsetSmall
124
125 _set_interrupts::
126 DI
127 LDH (rIE),A
128 XOR A
129 EI
130 LDH (rIF),A ; Clear pending interrupts
131 RET
132
133 ;; Copy OAM data to OAM RAM
134 .start_refresh_OAM:
135 LDH A,(__shadow_OAM_base)
136 OR A
137 RET Z
138 .start_refresh_OAM_DMA:
139 LDH (rDMA),A ; Put A into DMA registers
140 LD A,#0x28 ; We need to wait 160 ns
141 1$:
142 DEC A
143 JR NZ,1$
144 RET
145 .end_refresh_OAM:
146
147 .org .MODE_TABLE
148 ;; Jump table for modes: 4 modes, 4 bytes each 16 bytes total
149 RET
150
151 ;; GameBoy Header
152 .org 0x100
153 .header:
154 JR .code_start
155
156 ;; Nintendo logo
157 .org 0x104
158 .db 0xCE,0xED,0x66,0x66,0xCC,0x0D,0x00,0x0B,0x03,0x73,0x00,0x83,0x00,0x0C,0x00,0x0D
159 .db 0x00,0x08,0x11,0x1F,0x88,0x89,0x00,0x0E,0xDC,0xCC,0x6E,0xE6,0xDD,0xDD,0xD9,0x99
160 .db 0xBB,0xBB,0x67,0x63,0x6E,0x0E,0xEC,0xCC,0xDD,0xDC,0x99,0x9F,0xBB,0xB9,0x33,0x3E
161
162 ;; Title of the game
163 .org 0x134
164 .asciz "Title"
165
166 .org 0x144
167 .db 0,0,0
168
169 ;; Cartridge type is ROM only
170 .org 0x147
171 .db 0
172
173 ;; ROM size is 32kB
174 .org 0x148
175 .db 0
176
177 ;; RAM size is 0kB
178 .org 0x149
179 .db 0
180
181 ;; Maker ID
182 .org 0x14A
183 .db 0x00,0x00
184
185 ;; Version number
186 .org 0x14C
187 .db 0x01
188
189 ;; Complement check
190 .org 0x14D
191 .db 0x00
192
193 ;; Checksum
194 .org 0x14E
195 .db 0x00,0x00
196
197 ;; ****************************************
198 .org 0x150
199
200 ;; soft reset: falldown to .code_start
201 .reset::
202 _reset::
203 LD A, (__is_GBA)
204 LD B, A
205 LD A, (__cpu)
206
207 ;; Initialization code
208 .code_start::
209 DI ; Disable interrupts
210
211 ;; switch off background, sprites and window
212 LD HL, #rLCDC
213 LD (HL), #LCDCF_ON
214
215 ;; preserve regs for the system detection
216 LD D, A ; Store CPU type in D
217 LD E, B ; Store GBA flag in E
218
219 ;; Initialize the stack
220 LD SP, #.STACK
221
222 PUSH DE
223 ;; Turn the screen off
224 CALL .display_off
225 ;; Clear the static storage
226 CALL .clear_WRAM
227 POP DE
228
229 ;; Store CPU type
230 LD A, D
231 LD (__cpu), A
232 CP #.CGB_TYPE
233 JR NZ, 1$
234 LD A, E
235 AND #0x01
236 LD (__is_GBA), A
237 1$:
238 XOR A
239
240 ;; Initialize the display
241 LDH (rSCY), A
242 LDH (rSCX), A
243 LDH (rSTAT), A
244 LDH (rWY), A
245 LD A, #.MINWNDPOSX
246 LDH (rWX), A
247
248 ;; Copy refresh_OAM routine to HRAM
249 LD DE, #.start_refresh_OAM ; source
250 LD HL, #.refresh_OAM ; dest
251 LD C, #(.end_refresh_OAM - .start_refresh_OAM) ; size
252 RST 0x30 ; call .MemcpySmall
253
254 ;; Clear the OAM by calling refresh_OAM
255 CALL .refresh_OAM
256
257 ;; Install interrupt routines
258 LD DE, #.std_vbl
259 CALL .add_VBL
260
261 ;; Standard color palettes
262 LD A, #0b11100100 ; Grey 3 = 11 (Black)
263 ; Grey 2 = 10 (Dark grey)
264 ; Grey 1 = 01 (Light grey)
265 ; Grey 0 = 00 (Transparent)
266 LDH (rBGP), A
267 LDH (rOBP0), A
268 LD A, #0b00011011
269 LDH (rOBP1), A
270
271 ;; Turn the screen on
272 LD A, #(LCDCF_ON | LCDCF_WIN9C00 | LCDCF_WINOFF | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_BGOFF)
273 LDH (rLCDC), A
274
275 LD A, #.VBL_IFLAG ; switch on VBlank interrupt only
276 LDH (rIE), A
277
278 XOR A
279 LDH (rIF), A
280
281 LDH (rAUDENA), A ; Turn sound off
282
283 ;; set default .mode (performed when clearing RAM)
284 ; LD (.mode), A
285
286 ;; zero system time counter (performed when clearing RAM)
287 ; LD HL,#.sys_time
288 ; LD (HL+), A
289 ; LD (HL), A
290
291 INC A
292 LDH (__current_bank), A ; current bank is 1 at startup
293
294 CALL gsinit
295
296 EI ; Enable interrupts
297
298 ;; Call the main function
299 CALL _main
300 _exit::
301 99$:
302 HALT
303 NOP
304 JR 99$ ; Wait forever
305
306 ;; Wait for VBL interrupt to be finished
307 .wait_vbl_done::
308 _wait_vbl_done::
309 _vsync::
310 ;; Check if the screen is on
311 LDH A, (rLCDC)
312 AND #LCDCF_ON
313 RET Z ; Return if screen is off
314 XOR A
315 LDH (.vbl_done), A ; Clear any previous sets of vbl_done
316 1$:
317 HALT ; Wait for any interrupt
318 NOP ; HALT sometimes skips the next instruction
319 LDH A, (.vbl_done) ; Was it a VBlank interrupt?
320 ;; Warning: we may lose a VBlank interrupt, if it occurs now
321 OR A
322 JR Z, 1$ ; No: back to sleep!
323 RET
324
325 ;; Remove interrupt routine in DE from the VBL interrupt list
326 ;; falldown to .remove_int
327 _remove_VBL::
328 .remove_VBL::
329 LD HL, #.int_0x40
330
331 ;; Remove interrupt DE from interrupt list HL if it exists
332 ;; Abort if a 0000 is found (end of list)
333 .remove_int::
334 1$:
335 LD A, (HL+)
336 LD C, A
337 LD A, (HL+)
338 LD B, A
339 OR C
340 RET Z ; No interrupt found
341
342 LD A, E
343 CP C
344 JR NZ, 1$
345 LD A, D
346 CP B
347 JR NZ, 1$
348
349 LD B, H
350 LD C, L
351 DEC BC
352 DEC BC
353
354 ;; Now do a memcpy from here until the end of the list
355 2$:
356 LD A, (HL+)
357 LD (BC), A
358 INC BC
359 LD D, A
360 LD A, (HL+)
361 LD (BC), A
362 INC BC
363 OR D
364 JR NZ, 2$
365 RET
366
367 ;; Add interrupt routine in DE to the VBL interrupt list
368 ;; falldown to .add_int
369 _add_VBL::
370 .add_VBL::
371 LD HL, #.int_0x40
372
373 ;; Add interrupt routine in DE to the interrupt list in HL
374 .add_int::
375 1$:
376 LD A, (HL+)
377 OR (HL)
378 JR Z, 2$
379 INC HL
380 JR 1$
381 2$:
382 LD A, D
383 LD (HL-), A
384 LD (HL), E
385 RET
386
387 ;; ****************************************
388
389 ;; Ordering of segments for the linker
390 ;; Code that really needs to be in bank 0
391 .area _HOME
392 ;; Similar to _HOME
393 .area _BASE
394 ;; Code
395 .area _CODE
396 ;; #pragma bank 0 workaround
397 .area _CODE_0
398 ;; Constant data
399 .area _LIT
400 ; ;; since _CODE_1 area base address is pre-defined in the linker from 0x4000,
401 ; ;; that moves initializer code and tables out of bank 0
402 ; .area _CODE_1
403 ;; Constant data, used to init _DATA
404 .area _INITIALIZER
405 ;; Code, used to init _DATA
406 .area _GSINIT
407 .area _GSFINAL
408 ;; Uninitialised ram data
409 .area _DATA
410 .area _BSS
411 ;; Initialised in ram data
412 .area _INITIALIZED
413 ;; For malloc
414 .area _HEAP
415 .area _HEAP_END
416 ;; High RAM area
417 .area _HRAM
418
419 .area _DATA
420 .start_crt_globals:
421
422 __cpu::
423 .ds 0x01 ; GB type (GB, PGB, CGB)
424 __is_GBA::
425 .ds 0x01 ; detect GBA
426 .mode::
427 .ds 0x01 ; Current mode
428 .sys_time::
429 _sys_time::
430 .ds 0x02 ; System time in VBL units
431 .int_0x40::
432 .blkw 0x06 ; 5 interrupt handlers: 1 built-in + 4 user-defined
433
434 .end_crt_globals:
435
436 .area _HRAM
437 .refresh_OAM::
438 .ds (.start_refresh_OAM_DMA - .start_refresh_OAM)
439 .refresh_OAM_DMA:
440 .ds (.end_refresh_OAM - .start_refresh_OAM_DMA)
441
442 .bndry 0x10
443
444 __current_bank::
445 .ds 0x01 ; Current bank
446 .vbl_done:
447 __vbl_done::
448 .ds 0x01 ; Is VBL interrupt finished?
449 __shadow_OAM_base::
450 .ds 0x01
451
452 ;; Runtime library
453 .area _GSINIT
454
455 gsinit::
456 ;; initialize static storage variables
457 LD BC, #l__INITIALIZER
458 LD HL, #s__INITIALIZER
459 LD DE, #s__INITIALIZED
460 CALL .memcpy_simple
461
462 .area _GSFINAL
463
464 RET
465
466 .area _HOME
467
468 ;; fills memory at HL of length BC with A, clobbers DE
469 .memset_simple::
470 LD E, A
471 LD A, B
472 OR C
473 RET Z
474 LD (HL), E
475 DEC BC
476 LD D, H
477 LD E, L
478 INC DE
479
480 ;; copies BC bytes from HL into DE
481 .memcpy_simple::
482 LD A, B
483 OR C
484 RET Z
485
486 SRL B
487 RR C
488 JR NC, 3$
489 LD A, (HL+)
490 LD (DE), A
491 INC DE
492 3$:
493 INC B
494 INC C
495 JR 2$
496 1$:
497 LD A, (HL+)
498 LD (DE), A
499 INC DE
500 LD A, (HL+)
501 LD (DE), A
502 INC DE
503 2$:
504 DEC C
505 JR NZ, 1$
506 DEC B
507 JR NZ, 1$
508 4$:
509 RET
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.