crt0.s (11779B)
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 ; MEGADUCK entry point/reset 12 JP .code_start 13 14; .org 0x08 ; --profile handler utilized by emu_debug.h 15 16; .org 0x10 ; empty 17 18; .org 0x18 ; empty 19 20 .org 0x20 ; RST 0x20 == call HL 21.call_hl:: 22 JP (HL) 23 24 .org 0x28 ; zero up to 256 bytes in C pointed by HL 25.MemsetSmall:: 26 LD (HL+),A 27 DEC C 28 JR NZ,.MemsetSmall 29 ret 30 31 .org 0x30 ; copy up to 256 bytes in C from DE to HL 32.MemcpySmall:: 33 LD A, (DE) 34 LD (HL+), A 35 INC DE 36 DEC C 37 JR NZ,.MemcpySmall 38 RET 39 40; .org 0x38 ; crash handler utilized by crash_handler.h 41 42 ;; Hardware interrupt vectors 43 .org 0x40 ; VBL 44.int_VBL: 45 PUSH AF 46 PUSH HL 47 LD HL,#.int_0x40 48 JP .int 49 50; .org 0x48 ; LCD 51 52; .org 0x50 ; TIM 53 54; .org 0x58 ; SIO 55 56; .org 0x60 ; JOY 57 58; .org 0x70 59 ;; space for drawing.s bit table 60 61 .org 0x80 62.int:: 63 PUSH BC 64 PUSH DE 651$: 66 LD A,(HL+) 67 OR (HL) 68 JR Z,.int_tail 69 PUSH HL 70 LD A,(HL-) 71 LD L,(HL) 72 LD H,A 73 RST 0x20 ; .call_hl 74 POP HL 75 INC HL 76 JR 1$ 77_wait_int_handler:: 78 ADD SP,#4 79.int_tail: 80 POP DE 81 POP BC 82 POP HL 83 84 ;; we return at least at the beginning of mode 2 85 WAIT_STAT 86 87 POP AF 88 RETI 89 90 ;; VBlank default interrupt routine 91__standard_VBL_handler:: 92.std_vbl: 93 LD HL,#.sys_time 94 INC (HL) 95 JR NZ,2$ 96 INC HL 97 INC (HL) 982$: 99 CALL .refresh_OAM 100 101 LD A, #1 102 LDH (.vbl_done),A 103 RET 104 105_refresh_OAM:: 106 WAIT_STAT 107 LD A, #>_shadow_OAM 108 JP .refresh_OAM + (.refresh_OAM_DMA - .start_refresh_OAM) 109 110.clear_WRAM: 111 PUSH DE 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 RST 0x28 124 POP DE 125 RET 126 127 .org 0x150 128 129 ;; soft reset: falldown to .code_start 130.reset:: 131_reset:: 132 133 ;; Initialization code 134.code_start:: 135 DI ; Disable interrupts 136 ;; Initialize the stack 137 LD SP, #.STACK 138 139 CALL .clear_WRAM 140 141; LD (.mode),A ; Clearing (.mode) is performed when clearing RAM 142 143 ;; Store CPU type 144 LD A, #.DMG_TYPE ; MEGADUCK is always a DMG 145 LD (__cpu), A 146 XOR A 147 LD (__is_GBA), A ; and it is never GBA 148 149 ;; Turn the screen off 150 CALL .display_off 151 152 XOR A 153 ;; Initialize the display 154 LDH (.SCY),A 155 LDH (.SCX),A 156 LDH (.STAT),A 157 LDH (.WY),A 158 LD A,#0x07 159 LDH (.WX),A 160 161 ;; Copy refresh_OAM routine to HRAM 162 LD DE,#.start_refresh_OAM ; source 163 LD HL,#.refresh_OAM ; dest 164 LD C,#(.end_refresh_OAM - .start_refresh_OAM) ; size 165 RST 0x30 ; call .MemcpySmall 166 167 ;; Clear the OAM by calling refresh_OAM 168 CALL .refresh_OAM 169 170 ;; Install interrupt routines 171 LD BC,#.std_vbl 172 CALL .add_VBL 173 174 ;; Standard color palettes 175 LD A,#0b11100100 ; Grey 3 = 11 (Black) 176 ; Grey 2 = 10 (Dark grey) 177 ; Grey 1 = 01 (Light grey) 178 ; Grey 0 = 00 (Transparent) 179 LDH (.BGP),A 180 LDH (.OBP0),A 181 LD A,#0b00011011 182 LDH (.OBP1),A 183 184 ;; Turn the screen on 185 LD A,#(LCDCF_ON | LCDCF_WIN9C00 | LCDCF_WINOFF | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_BGOFF) 186 LDH (.LCDC),A 187 XOR A 188 LDH (.IF),A 189 LD A,#.VBL_IFLAG ; switch on VBlank interrupt only 190 LDH (.IE),A 191 192 LDH (__current_bank),A ; current bank is 1 at startup 193 194 XOR A 195 196 LD HL,#.sys_time 197 LD (HL+),A 198 LD (HL),A 199 200 LDH (.NR52),A ; Turn sound off 201 202 CALL gsinit 203 204 EI ; Enable interrupts 205 206 ;; Call the main function 207 CALL _main 208_exit:: 20999$: 210 HALT 211 NOP 212 JR 99$ ; Wait forever 213 214_set_interrupts:: 215 DI 216 LDA HL,2(SP) ; Skip return address 217 XOR A 218 LDH (.IF),A ; Clear pending interrupts 219 LD A,(HL) 220 EI ; Enable interrupts 221 LDH (.IE),A ; interrupts are still disabled here 222 RET 223 224 ;; Copy OAM data to OAM RAM 225.start_refresh_OAM: 226 LDH A,(__shadow_OAM_base) 227 OR A 228 RET Z 229.refresh_OAM_DMA: 230 LDH (.DMA),A ; Put A into DMA registers 231 LD A,#0x28 ; We need to wait 160 ns 2321$: 233 DEC A 234 JR NZ,1$ 235 RET 236.end_refresh_OAM: 237 238 .org .MODE_TABLE 239 ;; Jump table for modes 240 RET 241 242 ;; **************************************** 243 244 ;; Ordering of segments for the linker 245 ;; Code that really needs to be in bank 0 246 .area _HOME 247 ;; Similar to _HOME 248 .area _BASE 249 ;; Code 250 .area _CODE 251 ;; #pragma bank 0 workaround 252 .area _CODE_0 253 ;; Constant data 254 .area _LIT 255; ;; since _CODE_1 area base address is pre-defined in the linker from 0x4000, 256; ;; that moves initializer code and tables out of bank 0 257; .area _CODE_1 258 ;; Constant data, used to init _DATA 259 .area _INITIALIZER 260 ;; Code, used to init _DATA 261 .area _GSINIT 262 .area _GSFINAL 263 ;; Uninitialised ram data 264 .area _DATA 265 .area _BSS 266 ;; Initialised in ram data 267 .area _INITIALIZED 268 ;; For malloc 269 .area _HEAP 270 .area _HEAP_END 271 272 .area _DATA 273__cpu:: 274 .ds 0x01 ; GB type (GB, PGB, CGB) 275__is_GBA:: 276 .ds 0x01 ; detect GBA 277.mode:: 278 .ds 0x01 ; Current mode 279.sys_time:: 280_sys_time:: 281 .ds 0x02 ; System time in VBL units 282.int_0x40:: 283 .blkw 0x0A ; 4 interrupt handlers (built-in + user-defined) 284 285 .area _HRAM (ABS) 286 287 .org 0xFF90 288__current_bank:: ; Current bank 289 .ds 0x01 290.vbl_done: 291 .ds 0x01 ; Is VBL interrupt finished? 292__shadow_OAM_base:: 293 .ds 0x01 294 295 ;; Runtime library 296 .area _GSINIT 297gsinit:: 298 ;; initialize static storage variables 299 LD BC, #l__INITIALIZER 300 LD HL, #s__INITIALIZER 301 LD DE, #s__INITIALIZED 302 call .memcpy_simple 303 304 .area _GSFINAL 305 ret 306 307 .area _HOME 308 309 ;; fills memory at HL of length BC with A, clobbers DE 310.memset_simple:: 311 LD E, A 312 LD A, B 313 OR C 314 RET Z 315 LD (HL), E 316 DEC BC 317 LD D, H 318 LD E, L 319 INC DE 320 321 ;; copies BC bytes from HL into DE 322.memcpy_simple:: 323 LD A, B 324 OR C 325 RET Z 326 327 SRL B 328 RR C 329 JR NC,3$ 330 LD A, (HL+) 331 LD (DE), A 332 INC DE 3333$: 334 INC B 335 INC C 336 JR 2$ 3371$: 338 LD A, (HL+) 339 LD (DE), A 340 INC DE 341 LD A, (HL+) 342 LD (DE), A 343 INC DE 3442$: 345 DEC C 346 JR NZ,1$ 347 DEC B 348 JR NZ,1$ 3494$: 350 RET 351 352 ;; Remove interrupt routine in BC from the VBL interrupt list 353 ;; falldown to .remove_int 354.remove_VBL:: 355 LD HL,#.int_0x40 356 357 ;; Remove interrupt BC from interrupt list HL if it exists 358 ;; Abort if a 0000 is found (end of list) 359.remove_int:: 3601$: 361 LD A,(HL+) 362 LD E,A 363 LD D,(HL) 364 INC HL 365 OR D 366 RET Z ; No interrupt found 367 368 LD A,E 369 CP C 370 JR NZ,1$ 371 LD A,D 372 CP B 373 JR NZ,1$ 374 375 LD D,H 376 LD E,L 377 DEC DE 378 DEC DE 379 380 ;; Now do a memcpy from here until the end of the list 3812$: 382 LD A,(HL+) 383 LD (DE),A 384 LD B,A 385 INC DE 386 LD A,(HL+) 387 LD (DE),A 388 INC DE 389 OR B 390 RET Z 391 JR 2$ 392 393 ;; Add interrupt routine in BC to the VBL interrupt list 394 ;; falldown to .add_int 395.add_VBL:: 396 LD HL,#.int_0x40 397 398 ;; Add interrupt routine in BC to the interrupt list in HL 399.add_int:: 4001$: 401 LD A,(HL+) 402 OR (HL) 403 JR Z,2$ 404 INC HL 405 JR 1$ 4062$: 407 LD A,B 408 LD (HL-),A 409 LD (HL),C 410 RET 411 412 ;; Wait for VBL interrupt to be finished 413.wait_vbl_done:: 414_wait_vbl_done:: 415 ;; Check if the screen is on 416 LDH A,(.LCDC) 417 AND #LCDCF_ON 418 RET Z ; Return if screen is off 419 XOR A 420 LDH (.vbl_done),A ; Clear any previous sets of vbl_done 4211$: 422 HALT ; Wait for any interrupt 423 NOP ; HALT sometimes skips the next instruction 424 LDH A,(.vbl_done) ; Was it a VBlank interrupt? 425 ;; Warning: we may lose a VBlank interrupt, if it occurs now 426 OR A 427 JR Z,1$ ; No: back to sleep! 428 RET 429 430.display_off:: 431_display_off:: 432 ;; Check if the screen is on 433 LDH A,(.LCDC) 434 AND #LCDCF_ON 435 RET Z ; Return if screen is off 4361$: ; We wait for the *NEXT* VBL 437 LDH A,(.LY) 438 CP #0x92 ; Smaller than or equal to 0x91? 439 JR NC,1$ ; Loop until smaller than or equal to 0x91 4402$: 441 LDH A,(.LY) 442 CP #0x91 ; Bigger than 0x90? 443 JR C,2$ ; Loop until bigger than 0x90 444 445 LDH A,(.LCDC) 446 AND #~LCDCF_ON 447 LDH (.LCDC),A ; Turn off screen 448 RET 449 450_remove_VBL:: 451 PUSH BC 452 LDA HL,4(SP) ; Skip return address and registers 453 LD A,(HL+) 454 LD C,A 455 LD B,(HL) 456 CALL .remove_VBL 457 POP BC 458 RET 459 460_add_VBL:: 461 PUSH BC 462 LDA HL, 4(SP) ; Skip return address and registers 463 LD A,(HL+) 464 LD C,A 465 LD B,(HL) 466 CALL .add_VBL 467 POP BC 468 RET